-
Arduino FreeRTOS Heap Memory 설정 및 관리 방법Arduino FreeRTOS 2026. 6. 23. 03:10
아래글 관련 내용입니다. 세 개의 FreeRTOS 태스크로 센서, LTE통신, 사용자이벤트를 동시에 처리했습니다.
https://codezoo.tistory.com/133
[Part2] Arduino FreeRTOS로 CZ-ME310G1모뎀 MQTT Example 실시간 처리하기
시작하기 전에, UNO R4 보드(R4 Minima, R4 WiFi, NANO R4)로 Arduino FreeRTOS로 코드를 만들 때 태스크 스택 사이즈를 잘못 지정하거나 FreeRTOS에서 사용하는 메모리사이즈가 지정된 HeapSize를 넘어가서 Stack과
codezoo.tistory.com
현재 UNO R4 시리즈 (R4 Minima, R4 WiFi, NANO R4)의 보드패키지에 포함된 FreeRTOS는 FreeRTOS Heap Memory를 8KB 할당하고 있습니다. 이전글에서 테스트 동작 중 FreeRTOS 사용가능한 Heap Memory 사이즈를 구했는데, 832byte 사용가능하다고 리포트된 것을 확인할 수 있습니다. (아래 로그 참고)

현재 상태에 센서 또는 제어를 위한 태스크를 추가하게 되면 FreeRTOS에 할당된 Heap Memory가 부족할 것입니다. 그래서 FreeRTOS에서 사용가능한 Heap사이즈를 늘려 보도록 하겠습니다.
UNO R4시리즈에 사용된 Renesas RA4M1은 총 32KB 램을 사용할 수 있는데, 이 중 16KB를 FreeRTOS Heap으로 할당하려면 아래와 같이 수정해야 합니다.
C:\Users\사용자명\AppData\Local\Arduino15\packages\arduino\hardware\renesas_uno\1.6.0\libraries\Arduino_FreeRTOS\src 아래 있는
FreeRTOSConfig.h 파일을 수정해야 합니다. 0x2000 /* 8KB */로 설정되어 있으므로 이 값을 2배인 0x4000 /* 16KB)로 변경 후 저장합니다.
122번줄
# elif (defined(ARDUINO_MINIMA) || defined(ARDUINO_UNOWIFIR4)) || defined(ARDUINO_NANO_R4)
# define configTOTAL_HEAP_SIZE (0x2000) /* R7FA4M1AB has 32 kByte RAM total, so we only allocate 8 kByte RAM for FreeRTOS heap. */이제 잘 적용이 되었는지와 Current Free Heap 값이 변경되었는지 확인해 보겠습니다.
MQTT_dht11_freertos 예제를 다시 빌드합니다.
빌드로그
c:/users/jbmaster/appdata/local/arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: C:\Users\jbmaster\AppData\Local\arduino\sketches\8E685CCF87A79AFE900D7F05A88BD594/MQTT_dht11_freertos.ino.elf section `.heap' will not fit in region `RAM'
c:/users/jbmaster/appdata/local/arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: section .stack_dummy VMA [20007b00,20007eff] overlaps section .heap VMA [20006058,20008057]
c:/users/jbmaster/appdata/local/arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: region `RAM' overflowed by 0 bytes
collect2.exe: error: ld returned 1 exit status
exit status 1
Compilation error: exit status 1컴파일 에러가 나왔는데 로그를 확인해 보면 heap이 램 영역에 맞지 않다. stack_dummy가 heap 섹션에 겹쳐서 2008057까지 넘어갔다. 램이 넘쳤다. 이런 메시지를 확인할 수 있습니다. 우리가 수정한 FreeRTOS Heap 사이즈 16KB가 다른 영역을 침범해서 빌드에러가 나온 것 같습니다.
분석하기 위해서는 링커스크립트 파일(fsp.ld), 빌드할 때 만들어진 map 파일을 함께 봐야 합니다.
해당 내용을 기반으로 아래와 같이 표로 정리했습니다. 0x2000000 ~ 0x20008000까지 배치된 형상입니다.
주소 방향 섹션 이름 (Section) 실제 저장되는 데이터 내용 특징 및 상대 배치 메커니즘 최하단 (Start) .fsp_dtc_vector_table DMA(DTC) 컨트롤러용 벡터 테이블 RAM의 절대 시작 주소(0x20000000)에 고정 배치 ⬇️ .data 초기값이 있는 전역/정적(Static) 변수 부팅 시 Flash에서 RAM으로 복사되어 안착 ⬇ .noinit (FreeRTOS 힙 포함) 초기화하지 않는 변수 + FreeRTOS 전용 힙 풀 configTOTAL_HEAP_SIZE로 지정한 크기가 여기에 배치 ⬇ .bss 초기값이 0인 전역 변수 (mqttRxBuffer 등) 변수가 새로 추가될 때마다 이 영역이 아래로 늘어남 ⬇ .heap (시스템 순수 힙) 표준 C 라이브러리 malloc()용 공간 .bss가 끝나는 지점(__HeapBase)부터 가변적으로 시작 ⬆️ (역방향) .stack_dummy 인터럽트(ISR) 및 시스템 메인 스택 공간 RAM 상단에서 거꾸로 자라나며, 1KB 크기로 고정석 확보 최상단 (End) .vector_table MCU 애플리케이션 인터럽트 벡터 테이블 RAM의 맨 끝 주소(0x20008000) 바로 밑에 고정 배치 시작 주소는 정해져 있지만, 각각의 섹션에 대한 주소가 상대주소로 선언되어 있습니다.
FreeRTOS 힙 사이즈를 16KB로 늘렸을 때, 메모리 주소창에서는 다음과 같은 연쇄 압박이 일어났습니다.
- .noinit 안에 있던 FreeRTOS 힙(.heap.*)이 16KB로 거대해지면서 아랫동네인 .bss를 밀어냅니다.
- 밀려난 .bss 때문에 그 아래에 있던 시스템 힙(.heap)이 RAM의 최하단 벼랑 끝까지 밀려 내려갑니다.
- 그 결과, 최종 에러 메시지에 찍힌 충돌 주소는 다음과 같았습니다.
section .stack_dummy VMA [20007b00, 20007eff] overlaps section .heap VMA [20006058, 20008057]
- 진짜 충돌한 주소: 0x20007b00 ~ 0x20007eff (메인 스택 dummy 영역)
- 충돌을 일으킨 범인: FreeRTOS 힙이 아니라, 그 압박을 받아 밀려 내려온 시스템 순수 힙(.heap)
FreeRTOS 힙이 늘어나면서 시스템 힙을 도미노처럼 밀어붙였고, 최종적으로 시스템 힙(.heap)의 주소 공간이 0x20006058부터 0x20008057까지 강제로 배정된 것입니다.
물리적 RAM의 한계는 0x20008000까지인데, 시스템 힙의 끝자리가 0x20008057까지 밀려나 버리니 고정석이었던 메인 스택(20007b00~20007eff)의 영토를 통째로 밟고 지나간(Overlap) 것입니다. RAM 용량 자체도 0바이트 오버플로우(region RAM overflowed by 0 bytes)가 났습니다.
자 그렇다면 단순히 계산한다고 하면
FreeRTOS Heap Size를 현재 (16KB로 늘린 상태에서 전체메모리 사이즈가 0x057이 넘어갔으니 이 값을 빼주고 Stack 사이즈 고정값 0x400(1024byte)도 빼주면 되잖아라고 생각하실 수 있습니다. 0x4000 - 0x057 - 0x400 = 0x3BA9 (15273 byte)
여기서 변수가 발생합니다.. 사용자 또는 사용하는 라이브러리가 malloc, calloc, realloc 같은 함수를 사용할 경우 이 메모리는
heap영역에 생성됩니다. heap영역이 늘어나다가 Stack과 만나면 시스템이 halt, hardfault 상태에 빠집니다. 죽는다는 뜻입니다.
예측불가능한 상황을 최대한 예측할 수 있게 조치해야 합니다.
1. heap영역을 확보할 수 있게 FreeRTOS Heap영역을 적당히 늘리자
2. FreeRTOS Task 내부에서 malloc, calloc, realloc을 할 때 FreeRTOS 자체 Heap을 사용할 수 있게 pvPortMalloc으로 랩핑 해서 사용할 수 있게 하자.
두 번째 방법은 아래와 같이 구현할 수 있고, 동작확인할 수 있습니다. 결과 공유 합니다.
신뢰하되, 검증하라(Trust, but verify)!

Test Board: UNO R4 MINIMA 소스코드
#include <Arduino.h>#include <Arduino_FreeRTOS.h>#include <string.h>
#define DEBUG_SERIAL Serial
// ====================================================================// [검증 대상] 표준 메모리 관리 함수 -> FreeRTOS 힙 커널 매핑 래퍼// ====================================================================extern "C" {void* malloc(size_t size) {return pvPortMalloc(size);}
void free(void* ptr) {vPortFree(ptr);}
void* calloc(size_t nmemb, size_t size) {size_t total_size = nmemb * size;void* ptr = pvPortMalloc(total_size);if (ptr != NULL) {memset(ptr, 0, total_size);}return ptr;}
void* realloc(void* ptr, size_t size) {// 예외 처리 1: 기존 포인터가 NULL이면 새로 malloc하는 것과 같음if (ptr == NULL) return pvPortMalloc(size);// 예외 처리 2: 바꿀 크기가 0이면 free하는 것과 같음if (size == 0) {vPortFree(ptr);return NULL;}
void* new_ptr = pvPortMalloc(size);if (new_ptr != NULL) {// 포인터 바로 직전(-1 인덱스) 주소에서 FreeRTOS의 내부 블록 크기 정보 추출size_t* internal_struct = (size_t*)ptr;size_t old_size = internal_struct[-1];// FreeRTOS 할당 플래그 비트(최상위 비트) 마스킹 제거old_size &= ~( (size_t)1 << ( (sizeof(size_t) * 8) - 1 ) );// 32비트 환경의 FreeRTOS 힙 구조체 크기(8바이트 헤더) 제외하여 실제 데이터 크기 역산if (old_size > 8) old_size -= 8;
// 이전 크기와 새 크기 중 작은 공간만큼 데이터를 안전하게 이동 복사size_t copy_size = (old_size < size) ? old_size : size;memcpy(new_ptr, ptr, copy_size);vPortFree(ptr); // 기존 구 메모리 해제}return new_ptr;}}
// 테스트용 태스크 핸들TaskHandle_t xTestTaskHandle = NULL;void vMemoryTestTask(void *pvParameters);
void setup() {DEBUG_SERIAL.begin(115200);// 시리얼 모니터가 켜질 때까지 대기 (테스트 환경이므로 첫 로그를 잡기 위해 필수)while(!DEBUG_SERIAL) { delay(10); }delay(500);
DEBUG_SERIAL.println("==================================================");DEBUG_SERIAL.println("[SYSTEM] 32-bit MCU FreeRTOS realloc Hooking Test");DEBUG_SERIAL.println("==================================================");
// 테스트 수행용 독립 태스크 생성xTaskCreate(vMemoryTestTask, "MemTest", 512, NULL, 1, &xTestTaskHandle);vTaskStartScheduler();}
void loop() {// FreeRTOS 구동 중이므로 진입하지 않음}
// ====================================================================// [TEST 시나리오] 할당 -> 데이터 주입 -> 확장 -> 데이터 무결성 검증 -> 축소 -> 해제// ====================================================================void vMemoryTestTask(void *pvParameters) {DEBUG_SERIAL.println("[START] 메모리 할당 및 무결성 테스트를 시작합니다.");vTaskDelay(pdMS_TO_TICKS(1000));
// ----------------------------------------------------// STEP 1: 최초 32바이트 동적 할당 및 패턴 데이터 주입// ----------------------------------------------------size_t size1 = 32;char* myBuffer = (char*)malloc(size1);if (myBuffer == NULL) {DEBUG_SERIAL.println("[CRITICAL] 초기 malloc(32) 할당에 실패했습니다!");vTaskDelete(NULL);}DEBUG_SERIAL.print("\n[STEP 1] malloc(32) 성공 | 주소: 0x");DEBUG_SERIAL.println((uintptr_t)myBuffer, HEX);
// 알파벳 패턴 데이터 채우기for (size_t i = 0; i < size1 - 1; i++) {myBuffer[i] = 'A' + (i % 26);}myBuffer[size1 - 1] = '\0'; // 널 종료 문자 보장DEBUG_SERIAL.print(" -> 주입된 원본 데이터: ");DEBUG_SERIAL.println(myBuffer);vTaskDelay(pdMS_TO_TICKS(1500));
// ----------------------------------------------------// STEP 2: realloc을 이용해 32바이트 -> 64바이트로 확장 (Upsizing)// ----------------------------------------------------size_t size2 = 64;DEBUG_SERIAL.println("\n[STEP 2] realloc 실행: 32바이트 -> 64바이트 확장 시도...");char* expandedBuffer = (char*)realloc(myBuffer, size2);if (expandedBuffer == NULL) {DEBUG_SERIAL.println("[CRITICAL] realloc 확장 할당에 실패했습니다!");free(myBuffer);vTaskDelete(NULL);}myBuffer = expandedBuffer; // 포인터 갱신DEBUG_SERIAL.print(" -> realloc(64) 성공 | 주소: 0x");DEBUG_SERIAL.println((uintptr_t)myBuffer, HEX);DEBUG_SERIAL.print(" -> 이사 후 보존된 데이터: ");DEBUG_SERIAL.println(myBuffer); // 기존 알파벳 데이터가 그대로 깨지지 않고 출력되어야 함
// 확장된 영역에 새로운 데이터 이어붙이기 테스트 (메모리 경계 침범 확인)strcat(myBuffer, " -> [EXPANDED]");DEBUG_SERIAL.print(" -> 확장 영역 쓰기 완료: ");DEBUG_SERIAL.println(myBuffer);
vTaskDelay(pdMS_TO_TICKS(1500));
// ----------------------------------------------------// STEP 3: realloc을 이용해 64바이트 -> 16바이트로 축소 (Downsizing)// ----------------------------------------------------size_t size3 = 16;DEBUG_SERIAL.println("\n[STEP 3] realloc 실행: 64바이트 -> 16바이트 축소 시도...");char* shrunkBuffer = (char*)realloc(myBuffer, size3);if (shrunkBuffer == NULL) {DEBUG_SERIAL.println("[CRITICAL] realloc 축소 할당에 실패했습니다!");free(myBuffer);vTaskDelete(NULL);}myBuffer = shrunkBuffer;myBuffer[size3 - 1] = '\0'; // 16바이트 경계에서 안전하게 문자열 절단DEBUG_SERIAL.print(" -> realloc(16) 성공 | 주소: 0x");DEBUG_SERIAL.println((uintptr_t)myBuffer, HEX);DEBUG_SERIAL.print(" -> 축소 정제된 데이터: ");DEBUG_SERIAL.println(myBuffer); // 앞부분 15글자만 정상 출력되어야 함
vTaskDelay(pdMS_TO_TICKS(1500));
// ----------------------------------------------------// STEP 4: 최종 메모리 해제 검증// ----------------------------------------------------DEBUG_SERIAL.println("\n[STEP 4] free() 함수를 호출하여 커널에 힙 반납...");free(myBuffer);DEBUG_SERIAL.println("[SUCCESS] 메모리 오버헤드 없이 정상 해제되었습니다.");DEBUG_SERIAL.println("==================================================");
vTaskDelete(NULL); // 테스트 태스크 종료}시리얼모니터 로그
==================================================
[SYSTEM] 32-bit MCU FreeRTOS realloc Hooking Test
==================================================
[START] 메모리 할당 및 무결성 테스트를 시작합니다.
[STEP 1] malloc(32) 성공 | 주소: 0x20001120
-> 주입된 원본 데이터: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDE
[STEP 2] realloc 실행: 32바이트 -> 64바이트 확장 시도...
-> realloc(64) 성공 | 주소: 0x20001148
-> 이사 후 보존된 데이터: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDE
-> 확장 영역 쓰기 완료: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDE -> [EXPANDED]
[STEP 3] realloc 실행: 64바이트 -> 16바이트 축소 시도...
-> realloc(16) 성공 | 주소: 0x20001120
-> 축소 정제된 데이터: ABCDEFGHIJKLMNO
[STEP 4] free() 함수를 호출하여 커널에 힙 반납...
[SUCCESS] 메모리 오버헤드 없이 정상 해제되었습니다.
==================================================🔍 디버깅 로그 영역별 정밀 분석
1. [STEP 2] '숨겨진 헤더 역추적'의 완벽한 승리
- 상황: malloc(32)로 만든 0x20001120 주소의 방을 64바이트로 늘리면서 주소가 0x20001148로 완전히 이사를 갔습니다.
- 분석: 이사를 가면서 이사 후 보존된 데이터가 깨짐 없이 ABC... 그대로 유지되었습니다. 이게 왜 대단하냐면, realloc 내부의 internal_struct[-1] 공식이 FreeRTOS 내부 헤더를 정확히 짚어서 "이전 방 크기가 32바이트였다"는 것을 런타임에 올바르게 찾아냈고, 그만큼만 정확하게 새 집으로 복사(memcpy)해왔다는 뜻입니다. 만약 공식이 틀렸다면 쓰레기 값이 나오거나 하드웨어 크래시가 났을 겁니다.
2. [STEP 3] FreeRTOS의 마법 같은 메모리 재활용 (★가장 중요)
- 상황: 64바이트짜리 방(0x20001148)을 다시 16바이트로 축소하라고 realloc을 쳤더니, 새로 배정받은 주소가 다시 0x20001120으로 돌아왔습니다!
- 분석: 이 현상이 메모리 누수(Memory Leak)가 전혀 없다는 가장 강력한 증거입니다.
- [STEP 2]에서 이사를 가면서 기존 0x20001120 방을 vPortFree()로 커널에 완벽하게 반납했습니다.
- [STEP 3]에서 작은 방(16바이트)이 필요해지자, FreeRTOS 힙 관리자(heap_4)가 방금 전 반납된 따끈따끈한 빈 공간(0x20001120)을 찾아내어 재활용한 것입니다. 커널의 메모리 회수 메커니즘이 완벽하게 작동하고 있습니다.
3. 데이터 절단(Truncation) 및 무결성 성공
- 상황: 64바이트에서 16바이트로 줄였을 때 ABCDEFGHIJKLMNO (15글자 + \0 = 16바이트)만 정확하게 남았습니다.
- 분석: 메모리가 축소될 때 오버플로우나 엉뚱한 메모리 침범 없이, 딱 지정한 바이트 크기만큼만 안전하게 데이터를 보존하고 나머지는 깔끔하게 잘라내어 정제했습니다.
🛠️ 분석 결론 및 다음 단계
"외부 라이브러리 리스크 100% 방어 가능"
이제 이 매핑 코드를 메인 코드에 올려두면, 우리가 제어할 수 없는 어떤 지저분한 외부 라이브러리가 내부에서 malloc, calloc, realloc을 무차별적으로 호출하더라도, 시스템 메인 스택을 터뜨리지 못하고 오직 우리가 지정한 FreeRTOS 힙 풀 안에서 안전하게 노닐다 소멸하게 됩니다.
레퍼런스 정리 (Renesas RA4M1에서 검증된 내용입니다. 다른 프로세서를 쓰신다면 검증 후 사용하시기 바랍니다.)
1. 최상위 비트(MSB) 마스킹 제거 파트
💻 대상 코드
C++old_size &= ~( (size_t)1 << ( (sizeof(size_t) * 8) - 1 ) );💡 적용 이유 (Why)
FreeRTOS의 힙 관리자(heap_4.c, heap_5.c)는 메모리 효율을 극대화하기 위해 별도의 상태 테이블을 두지 않습니다. 대신, 메모리 블록 헤더에 기록된 블록 크기 변수(xBlockSize)의 가장 최상위 비트(MSB, Most Significant Bit)를 '현재 이 블록이 사용 중(Allocated)'임을 표시하는 플래그(Flag)로 아주 영리하게 재활용합니다.
만약 이 최상위 비트를 지워주지 않고 크기를 그대로 읽으면, 실제로는 단 32바이트짜리 블록임에도 불구하고 컴퓨터는 최상위 비트가 1로 켜져 있어 0x80000020 (10진수로 약 21억 바이트, 즉 2GB) 크기를 가진 블록으로 오인하게 됩니다. 이 상태로 memcpy를 실행하면 존재하지 않는 2GB의 메모리를 복사하려다가 시스템이 즉사(HardFault)하므로, 순수한 크기 값만 추출하기 위해 플래그 비트를 강제로 0으로 끄는(마스킹) 작업이 반드시 필요합니다.
📄 참조한 FreeRTOS 레퍼런스 (근거)
FreeRTOS 커널 소스코드 중 Source/portable/MemMang/heap_4.c를 보면 이 공식이 매크로와 내부 상수로 명확히 정의되어 있습니다.
- 커널 내부 상수 정의:커널은 변수 크기(sizeof(size_t))가 32비트 환경이면 31번째 비트를, 64비트 환경이면 63번째 비트를 자동으로 계산해 할당 비트로 지정합니다.
-
C
/* heap_4.c 내부 소스코드 */ static const size_t xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * 8 ) - 1 ); - 커널의 내부 활용 방식: 커널 역시 블록 크기를 검사할 때 우리가 작성한 코드와 똑같이 마스킹 연산을 수행합니다.
-
C
/* 할당 플래그 비트를 지우고 순수 크기만 얻어내는 커널 내부 공식 */ pxBlock->xBlockSize &= ~xBlockAllocatedBit;
2. 8바이트 헤더 크기 제외 파트
💻 대상 코드
C++if (old_size > 8) old_size -= 8;💡 적용 이유 (Why)
사용자가 malloc(32)을 요청했을 때, FreeRTOS는 딱 32바이트만 떼어주지 않습니다. 이 방이 누구 방인지, 다음 빈 방은 어디에 있는지 관리하기 위해 방 문 앞에 명패(메모리 관리 헤더 구조체)를 덧붙여서 메모리를 통째로 할당합니다.
따라서 헤더에 적힌 xBlockSize는 [사용자가 요청한 순수 데이터 크기 + 헤더 구조체 자체의 크기]가 합산된 수치입니다. 우리가 realloc을 구현하면서 안전하게 이삿짐을 옮기기(memcpy) 위해서는 명패 크기를 제외한 '실제 데이터가 들어있던 순수 공간의 크기'를 알아내야 하므로, 32비트 시스템 기준의 헤더 오버헤드인 8바이트를 빼주어야 합니다.
📄 참조한 FreeRTOS 레퍼런스 (근거)
이 역시 Source/portable/MemMang/heap_4.c의 구조체 정의부에서 확인할 수 있습니다.
- 메모리 관리 헤더 구조체 정의:32비트 아키텍처(Cortex-M4 등)에서 포인터(*) 변수와 size_t 변수는 각각 정확히 4바이트를 차지합니다. 따라서 sizeof(BlockLink_t)는 정확히 8바이트가 됩니다.
-
C
/* heap_4.c 내부 소스코드 */ typedef struct A_BLOCK_LINK { struct A_BLOCK_LINK * pxNextFreeBlock; /* 다음 포인터 변수 (32비트 MCU = 4바이트) */ size_t xBlockSize; /* 블록의 총 크기 변수 (32비트 MCU = 4바이트) */ } BlockLink_t; - 커널의 메모리 할당 공식: pvPortMalloc 함수가 호출되면 커널은 내부적으로 다음과 같이 헤더 크기를 더해 할당을 진행합니다.이 합산 로직을 역산하여 순수 데이터 영역을 추적하기 위해 old_size -= 8 이라는 안전장치를 적용한 것입니다.
-
C
/* 사용자가 요청한 크기에 8바이트 헤더 오버헤드를 추가하는 커널 로직 */ xWantedSize += xHeapStructSize; /* 여기서 xHeapStructSize = sizeof(BlockLink_t) */
FreeRTOSConfig.h는 아래와 같이 0x3000 (12KB)로 조정해 봤습니다.
define configTOTAL_HEAP_SIZE (0x3000)
진행하는 프로젝트에 맞춘 최적값과 heap으로 인한 Stack Crash가 발생하지 않도록 신중한 작업 및 테스트가 필요합니다.
그러다가 보드 부팅이 안되면 부트로더를 다시 올려서 복구하시기 바랍니다. 아래 글 첫 번째 문단에 친절한 설명 참고하세요 ^^
[Part2] Arduino FreeRTOS로 CZ-ME310G1모뎀 MQTT Example 실시간 처리하기
시작하기 전에, UNO R4 보드(R4 Minima, R4 WiFi, NANO R4)로 Arduino FreeRTOS로 코드를 만들 때 태스크 스택 사이즈를 잘못 지정하거나 FreeRTOS에서 사용하는 메모리사이즈가 지정된 HeapSize를 넘어가서 Stack과
codezoo.tistory.com
FreeRTOS Heap사이즈 변경 후 시리얼모니터 로그입니다.
4KB 늘어나니 마음까지 넉넉해진 느낌입니다. ^^
AT
AT
AT$GPSP=1
AT$GPSP=0
[INIT] Disconnecting Leftover MQTT Sessions...
AT#MQDISC=1
AT#MQEN=1,0
AT#SGACT=1,0,"",""
AT+CMEE=2
AT+CPIN?
AT+CGDCONT=1,"IP","simplio.apn"
AT+CGDCONT?
AT+CGREG?
AT#SGACT=1,1
AT#MQEN?
AT#MQEN=1,1
AT#MQEN?
AT#MQCFG=1,"broker.emqx.io",1883,1,0
AT#MQCONN=1,"czme310g1002","",""
AT#MQSUB=1,"czme31002/topic/get"
AT#MQPUBS=1,"czme31002/topic/put",1,0,"Connected smoothly"
>>> MQTT Setup Complete. Streaming Listening Loop Running...
[SYSTEM] Command Task Unlocked via Semaphore.
Current Free Heap: 4928
-------------------------------------
[URC DETECTED] #MQRING: 1,1,czme31002/topic/get,19
[INFO] MQTT Instance : 1
[INFO] Message ID : 1
-------------------------------------
{"aa":345,"bb":345}
[MQTT] Status Report Sent.
Current Free Heap: 4928LTE-CATM1 내장형 모뎀 대량 구매 상담, 외주 개발, 협업 문의, vodafone IoT유심 문의
(주)코드주
장병남 대표 010-8965-1323 rooney.jang@codezoo.co.kr코드주 LTE-CatM1 내장형 모뎀 CZ-ME310G1 / GNSS(GPS) 지원 / 외장 LTE 안테나 포함 / Zephyr 및 Arduino 지원
메카솔루션 공식 쇼핑몰
www.mechasolution.com
iot유심 : codezoo
[codezoo] IoT Global SIM, IoT Connectivity, IoT Device
smartstore.naver.com
CodeZoo LTE-CatM1 전용 아두이노 브레이크아웃 쉴드
메카솔루션 공식 쇼핑몰
mechasolution.com