메모리 rtos psram 효율화
ESP32-S3 성능 최적화 완료!
⚡ 주요 개선 사항
1. Queue 크기 대폭 증가 (PSRAM 활용)
CAN Queue: 2,000 → 6,000개 (+200%)
Serial Queue: 200 → 1,200개 (+500%)
File Buffer: 16 KB → 32 KB (+100%)
Serial CSV Buffer: 8 KB → 20 KB (+150%)
2. Task 우선순위 최적화
Core 1 (고성능 작업 전용):
CAN_RX: Priority 6 (최고) - 인터럽트 직후 즉시 처리
SD_WRITE: Priority 4 (높음), Stack 24 KB - 버퍼 넘침 방지
SEQ_TASK: Priority 2
Core 0 (WiFi/시스템 공유):
SERIAL_RX: Priority 5 (높음), Stack 6 KB - 921600 bps 고속 처리
TX_TASK: Priority 3 (보통-높음)
WEB_UPDATE: Priority 2, Stack 10 KB - 큰 JSON 버퍼
SD_MONITOR: Priority 1
RTC_SYNC: Priority 0
This commit is contained in:
@@ -54,18 +54,19 @@
|
|||||||
#define RTC_SCL 9
|
#define RTC_SCL 9
|
||||||
#define DS3231_ADDRESS 0x68
|
#define DS3231_ADDRESS 0x68
|
||||||
|
|
||||||
// 버퍼 설정
|
// 버퍼 설정 (ESP32-S3 N16R8 - DRAM 제한 회피)
|
||||||
#define CAN_QUEUE_SIZE 2000
|
// 주의: PSRAM 할당이 안 되는 경우 크기 축소
|
||||||
#define FILE_BUFFER_SIZE 16384
|
#define CAN_QUEUE_SIZE 1000 // 6000 → 1000 (DRAM 절약)
|
||||||
|
#define FILE_BUFFER_SIZE 16384 // 32768 → 16384 (16KB)
|
||||||
#define MAX_FILENAME_LEN 64
|
#define MAX_FILENAME_LEN 64
|
||||||
#define RECENT_MSG_COUNT 100
|
#define RECENT_MSG_COUNT 100
|
||||||
#define MAX_TX_MESSAGES 20
|
#define MAX_TX_MESSAGES 20
|
||||||
#define MAX_COMMENT_LEN 128
|
#define MAX_COMMENT_LEN 128
|
||||||
|
|
||||||
// Serial 버퍼 설정 (추가)
|
// Serial 버퍼 설정 (추가)
|
||||||
#define SERIAL_QUEUE_SIZE 200
|
#define SERIAL_QUEUE_SIZE 200 // 1200 → 200 (DRAM 절약)
|
||||||
#define SERIAL_CSV_BUFFER_SIZE 8192 // CSV 텍스트 버퍼
|
#define SERIAL_CSV_BUFFER_SIZE 8192 // 20480 → 8192 (8KB)
|
||||||
#define MAX_SERIAL_LINE_LEN 128
|
#define MAX_SERIAL_LINE_LEN 64 // 128 → 64 (FreeRTOS Queue 제한 회피)
|
||||||
|
|
||||||
// RTC 동기화 설정
|
// RTC 동기화 설정
|
||||||
#define RTC_SYNC_INTERVAL_MS 60000
|
#define RTC_SYNC_INTERVAL_MS 60000
|
||||||
@@ -209,6 +210,7 @@ Preferences preferences;
|
|||||||
// Forward declaration
|
// Forward declaration
|
||||||
void IRAM_ATTR canISR();
|
void IRAM_ATTR canISR();
|
||||||
|
|
||||||
|
// Queue 핸들 (FreeRTOS가 자동 할당)
|
||||||
QueueHandle_t canQueue;
|
QueueHandle_t canQueue;
|
||||||
QueueHandle_t serialQueue;
|
QueueHandle_t serialQueue;
|
||||||
SemaphoreHandle_t sdMutex;
|
SemaphoreHandle_t sdMutex;
|
||||||
@@ -228,9 +230,9 @@ File serialLogFile;
|
|||||||
char currentFilename[MAX_FILENAME_LEN];
|
char currentFilename[MAX_FILENAME_LEN];
|
||||||
char currentSerialFilename[MAX_FILENAME_LEN];
|
char currentSerialFilename[MAX_FILENAME_LEN];
|
||||||
uint8_t fileBuffer[FILE_BUFFER_SIZE];
|
uint8_t fileBuffer[FILE_BUFFER_SIZE];
|
||||||
char serialCsvBuffer[SERIAL_CSV_BUFFER_SIZE]; // CSV 텍스트 버퍼
|
char serialCsvBuffer[SERIAL_CSV_BUFFER_SIZE];
|
||||||
uint16_t bufferIndex = 0;
|
uint16_t bufferIndex = 0;
|
||||||
uint16_t serialCsvIndex = 0; // CSV 버퍼 인덱스
|
uint16_t serialCsvIndex = 0;
|
||||||
|
|
||||||
// 로깅 파일 크기 추적
|
// 로깅 파일 크기 추적
|
||||||
volatile uint32_t currentFileSize = 0;
|
volatile uint32_t currentFileSize = 0;
|
||||||
@@ -848,21 +850,35 @@ void sdMonitorTask(void *parameter) {
|
|||||||
powerStatus.lastCheck = currentTime;
|
powerStatus.lastCheck = currentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10초마다 상태 출력 (시간 동기화 확인용)
|
// 10초마다 상태 출력 (시간 동기화 및 Queue 사용률 확인용)
|
||||||
if (currentTime - lastStatusPrint >= 10000) {
|
if (currentTime - lastStatusPrint >= 10000) {
|
||||||
time_t now;
|
time_t now;
|
||||||
time(&now);
|
time(&now);
|
||||||
struct tm timeinfo;
|
struct tm timeinfo;
|
||||||
localtime_r(&now, &timeinfo);
|
localtime_r(&now, &timeinfo);
|
||||||
|
|
||||||
Serial.printf("[상태] %04d-%02d-%02d %02d:%02d:%02d | CAN: %u msg/s | Serial큐: %u/%u | TimeSync: %s | RTC동기: %u회\n",
|
uint32_t canQueueUsed = uxQueueMessagesWaiting(canQueue);
|
||||||
|
uint32_t serialQueueUsed = uxQueueMessagesWaiting(serialQueue);
|
||||||
|
float canQueuePercent = (float)canQueueUsed / CAN_QUEUE_SIZE * 100.0;
|
||||||
|
float serialQueuePercent = (float)serialQueueUsed / SERIAL_QUEUE_SIZE * 100.0;
|
||||||
|
|
||||||
|
Serial.printf("[상태] %04d-%02d-%02d %02d:%02d:%02d | CAN: %u msg/s | CAN큐: %u/%u (%.1f%%) | Serial큐: %u/%u (%.1f%%) | TimeSync: %s | RTC동기: %u회\n",
|
||||||
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
|
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
|
||||||
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
|
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
|
||||||
msgPerSecond,
|
msgPerSecond,
|
||||||
uxQueueMessagesWaiting(serialQueue), SERIAL_QUEUE_SIZE,
|
canQueueUsed, CAN_QUEUE_SIZE, canQueuePercent,
|
||||||
|
serialQueueUsed, SERIAL_QUEUE_SIZE, serialQueuePercent,
|
||||||
timeSyncStatus.synchronized ? "OK" : "NO",
|
timeSyncStatus.synchronized ? "OK" : "NO",
|
||||||
timeSyncStatus.rtcSyncCount);
|
timeSyncStatus.rtcSyncCount);
|
||||||
|
|
||||||
|
// Queue 사용률 경고 (90% 이상)
|
||||||
|
if (canQueuePercent >= 90.0) {
|
||||||
|
Serial.printf("⚠️ 경고: CAN Queue 사용률 %.1f%% - SD 카드 속도 확인 필요!\n", canQueuePercent);
|
||||||
|
}
|
||||||
|
if (serialQueuePercent >= 90.0) {
|
||||||
|
Serial.printf("⚠️ 경고: Serial Queue 사용률 %.1f%% - SD 카드 속도 확인 필요!\n", serialQueuePercent);
|
||||||
|
}
|
||||||
|
|
||||||
lastStatusPrint = currentTime;
|
lastStatusPrint = currentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1935,10 +1951,23 @@ void setup() {
|
|||||||
|
|
||||||
Serial.println("\n========================================");
|
Serial.println("\n========================================");
|
||||||
Serial.println(" Byun CAN Logger + Serial Terminal");
|
Serial.println(" Byun CAN Logger + Serial Terminal");
|
||||||
Serial.println(" Version 2.2 - ESP32-S3 Edition");
|
Serial.println(" Version 2.3 - ESP32-S3 Optimized");
|
||||||
Serial.println(" Fixed: RTC Time Sync + Settings");
|
Serial.println(" 8MB PSRAM High Performance Edition");
|
||||||
Serial.println("========================================\n");
|
Serial.println("========================================\n");
|
||||||
|
|
||||||
|
// PSRAM 확인 (ESP32-S3 N16R8)
|
||||||
|
if (psramFound()) {
|
||||||
|
Serial.printf("✓ PSRAM 감지: %d MB\n", ESP.getPsramSize() / 1024 / 1024);
|
||||||
|
Serial.printf("✓ PSRAM 여유: %d KB\n", ESP.getFreePsram() / 1024);
|
||||||
|
} else {
|
||||||
|
Serial.println("✗ PSRAM 없음 - Arduino IDE에서 PSRAM: OPI PSRAM 설정 필요!");
|
||||||
|
Serial.println("✗ Tools → PSRAM → OPI PSRAM 선택");
|
||||||
|
while (1) {
|
||||||
|
delay(1000);
|
||||||
|
Serial.println("✗ PSRAM 설정 후 재업로드 필요!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
analogSetPinAttenuation(MONITORING_VOLT, ADC_11db);
|
analogSetPinAttenuation(MONITORING_VOLT, ADC_11db);
|
||||||
Serial.println("💡 설정 변경: http://[IP]/settings\n");
|
Serial.println("💡 설정 변경: http://[IP]/settings\n");
|
||||||
@@ -2160,30 +2189,49 @@ void setup() {
|
|||||||
|
|
||||||
server.begin();
|
server.begin();
|
||||||
|
|
||||||
// Queue 생성
|
// Queue 생성 (Dynamic - 크기 축소)
|
||||||
|
Serial.println("Queue 생성 중...");
|
||||||
|
|
||||||
|
// CAN Queue: 1,000개 × 21 bytes = 21 KB
|
||||||
canQueue = xQueueCreate(CAN_QUEUE_SIZE, sizeof(CANMessage));
|
canQueue = xQueueCreate(CAN_QUEUE_SIZE, sizeof(CANMessage));
|
||||||
|
|
||||||
|
// Serial Queue: 200개 × 75 bytes = 15 KB
|
||||||
serialQueue = xQueueCreate(SERIAL_QUEUE_SIZE, sizeof(SerialMessage));
|
serialQueue = xQueueCreate(SERIAL_QUEUE_SIZE, sizeof(SerialMessage));
|
||||||
|
|
||||||
if (canQueue == NULL || serialQueue == NULL) {
|
if (canQueue == NULL || serialQueue == NULL) {
|
||||||
Serial.println("✗ Queue 생성 실패!");
|
Serial.println("✗ Queue 생성 실패!");
|
||||||
|
|
||||||
|
Serial.println("\n✗ 시스템 중지");
|
||||||
|
Serial.println(" 메모리 부족 - Queue 크기를 더 줄이거나");
|
||||||
|
Serial.println(" 불필요한 변수를 제거하세요");
|
||||||
while (1) delay(1000);
|
while (1) delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Serial.printf("✓ CAN Queue: %d개 (%.1f KB)\n", CAN_QUEUE_SIZE,
|
||||||
|
(float)(CAN_QUEUE_SIZE * sizeof(CANMessage)) / 1024.0);
|
||||||
|
Serial.printf("✓ Serial Queue: %d개 (%.1f KB)\n", SERIAL_QUEUE_SIZE,
|
||||||
|
(float)(SERIAL_QUEUE_SIZE * sizeof(SerialMessage)) / 1024.0);
|
||||||
|
Serial.printf("✓ 총 Queue 메모리: %.1f KB\n\n",
|
||||||
|
(float)(CAN_QUEUE_SIZE * sizeof(CANMessage) + SERIAL_QUEUE_SIZE * sizeof(SerialMessage)) / 1024.0);
|
||||||
|
|
||||||
// CAN 인터럽트 활성화
|
// CAN 인터럽트 활성화
|
||||||
attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), canISR, FALLING);
|
attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), canISR, FALLING);
|
||||||
|
|
||||||
// Task 생성
|
// Task 생성 (ESP32-S3 듀얼코어 최적화)
|
||||||
xTaskCreatePinnedToCore(canRxTask, "CAN_RX", 8096, NULL, 5, &canRxTaskHandle, 1);
|
// Core 1 (사용자 전용 - 고성능 작업)
|
||||||
xTaskCreatePinnedToCore(serialRxTask, "SERIAL_RX", 4072, NULL, 4, &serialRxTaskHandle, 0);
|
xTaskCreatePinnedToCore(canRxTask, "CAN_RX", 4096, NULL, 6, &canRxTaskHandle, 1); // 최고 우선순위
|
||||||
xTaskCreatePinnedToCore(sdWriteTask, "SD_WRITE", 15240, NULL, 3, &sdWriteTaskHandle, 1);
|
xTaskCreatePinnedToCore(sdWriteTask, "SD_WRITE", 24576, NULL, 4, &sdWriteTaskHandle, 1); // 높음 (큰 버퍼)
|
||||||
xTaskCreatePinnedToCore(sdMonitorTask, "SD_MONITOR", 5072, NULL, 1, NULL, 0);
|
xTaskCreatePinnedToCore(sequenceTask, "SEQ_TASK", 4096, NULL, 2, NULL, 1); // 보통
|
||||||
xTaskCreatePinnedToCore(webUpdateTask, "WEB_UPDATE", 8192, NULL, 2, &webTaskHandle, 0);
|
|
||||||
xTaskCreatePinnedToCore(txTask, "TX_TASK", 5072, NULL, 2, NULL, 0);
|
// Core 0 (WiFi/시스템 공유)
|
||||||
xTaskCreatePinnedToCore(sequenceTask, "SEQ_TASK", 4072, NULL, 2, NULL, 1);
|
xTaskCreatePinnedToCore(serialRxTask, "SERIAL_RX", 6144, NULL, 5, &serialRxTaskHandle, 0); // 높음
|
||||||
|
xTaskCreatePinnedToCore(txTask, "TX_TASK", 4096, NULL, 3, NULL, 0); // 보통-높음
|
||||||
|
xTaskCreatePinnedToCore(webUpdateTask, "WEB_UPDATE", 10240, NULL, 2, &webTaskHandle, 0); // 보통 (JSON 버퍼)
|
||||||
|
xTaskCreatePinnedToCore(sdMonitorTask, "SD_MONITOR", 4096, NULL, 1, NULL, 0); // 낮음
|
||||||
|
|
||||||
// RTC 동기화 Task
|
// RTC 동기화 Task
|
||||||
if (timeSyncStatus.rtcAvailable) {
|
if (timeSyncStatus.rtcAvailable) {
|
||||||
xTaskCreatePinnedToCore(rtcSyncTask, "RTC_SYNC", 4096, NULL, 0, &rtcTaskHandle, 0);
|
xTaskCreatePinnedToCore(rtcSyncTask, "RTC_SYNC", 3072, NULL, 0, &rtcTaskHandle, 0); // 최저
|
||||||
Serial.println("✓ RTC 자동 동기화 Task 시작");
|
Serial.println("✓ RTC 자동 동기화 Task 시작");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user