- esp32 c3 supermini oled 보드로 수행해봤음.
파티션 이름 (Name) | 타입 (Type) | 서브타입 (SubType) | 오프셋 (Offset) | 크기 (Size) (예시) | 용도 (Purpose) |
---|---|---|---|---|---|
Bootloader | (숨김) | (숨김) | 0x1000 | 0x7000 (28KB) | 칩 부팅 시 가장 먼저 실행되는 2단계 부트 로더 코드 저장 |
Partition Table | (숨김) | (숨김) | 0x8000 | 0x1000 (4KB) | 플래시 내의 모든 파티션 정보(이름, 타입, 오프셋, 크기)를 정의 |
nvs | data | nvs | 0x9000 | 0x5000 (20KB) | Wi-Fi 설정, Bluetooth 페어링 정보, 장치 보정 데이터 등 비휘발성 데이터 저장 (NVS 라이브러리 사용) |
otadata | data | ota | 0xE000 | 0x2000 (8KB) | OTA(Over-The-Air) 업데이트를 위한 데이터 저장 (현재 활성 앱 슬롯 정보 등) |
factory | app | factory | 0x10000 | 0x140000 (1.25MB) | 기본 공장 펌웨어 또는 단일 애플리케이션 펌웨어 저장 |
ota_0 | app | ota_0 | 0x150000 | 0x140000 (1.25MB) | OTA 업데이트 시 새 펌웨어를 저장하는 공간 (첫 번째 OTA 슬롯) |
ota_1 | app | ota_1 | 0x290000 | 0x140000 (1.25MB) | OTA 업데이트 시 새 펌웨어를 저장하는 공간 (두 번째 OTA 슬롯) |
spiffs | data | spiffs | 0x3D0000 | 0x190000 (1.5MB) | 파일 시스템 (SPIFFS, LittleFS 또는 FATFS) 데이터 저장 (웹 페이지, 이미지 등) |
#include // ESP-IDF 파티션 관련 API 헤더
// #include // Not needed if using ESP.getFlashChipSize()
#include // For esp_ota_get_running_partition()
#include // For ESP.getFlashChipSize()
// **NOTE**: The Wi-Fi and OTA update related code from previous examples
// is not included here to keep this snippet focused on the partition info.
// If you're combining, ensure you include WiFi.h, HTTPClient.h, and Update.h
// in your main sketch.
/**
* @brief 현재 ESP32 장치의 플래시 파티션 정보를 조회하여 출력합니다.
* 주로 4MB 플래시 보드에서 사용되는 파티션 스키마를 가정하고 있습니다.
*/
void printFlashPartitionInfo() {
Serial.println("n--- ESP32 Flash Partition Info ---");
// 플래시 칩 크기 조회
// CORRECTED: Use ESP.getFlashChipSize()
uint32_t flash_chip_size = ESP.getFlashChipSize();
Serial.printf("Flash Chip Size: %u MBn", flash_chip_size / (1024 * 1024));
Serial.println("------------------------------------");
// 모든 파티션을 찾기 위한 이터레이터
esp_partition_iterator_t it;
// 'app' (애플리케이션) 타입 파티션 조회
it = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL);
if (it) {
Serial.println("### Application Partitions (APP) ###");
do {
const esp_partition_t* part = esp_partition_get(it);
Serial.printf(" Label: %-15s, Type: %2d, SubType: %2d, Address: 0x%06x, Size: %6u KBn",
part->label,
part->type,
part->subtype,
part->address,
part->size / 1024);
it = esp_partition_next(it);
} while (it != NULL);
esp_partition_iterator_release(it); // 이터레이터 해제
} else {
Serial.println(" No APP partitions found.");
}
Serial.println("------------------------------------");
// 'data' 타입 파티션 조회 (NVS, OTA Data, SPIFFS/LittleFS 등)
it = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);
if (it) {
Serial.println("### Data Partitions ###");
do {
const esp_partition_t* part = esp_partition_get(it);
// 서브타입에 따라 더 구체적인 이름 출력
const char* subTypeStr;
if (part->subtype == ESP_PARTITION_SUBTYPE_DATA_NVS) {
subTypeStr = "NVS";
} else if (part->subtype == ESP_PARTITION_SUBTYPE_DATA_OTA) {
subTypeStr = "OTA_DATA";
} else if (part->subtype == ESP_PARTITION_SUBTYPE_DATA_PHY) {
subTypeStr = "PHY_INIT";
} else if (part->subtype == ESP_PARTITION_SUBTYPE_DATA_SPIFFS) {
subTypeStr = "SPIFFS";
} else if (part->subtype == ESP_PARTITION_SUBTYPE_DATA_FAT) {
subTypeStr = "FATFS";
} else {
subTypeStr = "UNKNOWN";
}
Serial.printf(" Label: %-15s, Type: %2d, SubType: %-10s, Address: 0x%06x, Size: %6u KBn",
part->label,
part->type,
subTypeStr, // 문자열 서브타입 사용
part->address,
part->size / 1024);
it = esp_partition_next(it);
} while (it != NULL);
esp_partition_iterator_release(it); // 이터레이터 해제
} else {
Serial.println(" No Data partitions found.");
}
Serial.println("------------------------------------");
// 현재 실행 중인 애플리케이션 파티션 정보
const esp_partition_t* running_partition = esp_ota_get_running_partition();
if (running_partition) {
Serial.printf("Currently Running App: %s (Address: 0x%06x)n",
running_partition->label, running_partition->address);
}
Serial.println("------------------------------------");
}
void setup() {
Serial.begin(115200);
delay(100); // 시리얼 초기화 대기
printFlashPartitionInfo(); // 파티션 정보 출력 함수 호출
}
void loop() {
// Simple serial command handler for demonstration
if (Serial.available()) {
String command = Serial.readStringUntil('n');
command.trim();
if (command.equalsIgnoreCase("info") || command.startsWith("table")) {
Serial.println("Executing printFlashPartitionInfo...");
printFlashPartitionInfo();
} else {
Serial.println("Unknown command. Type 'info' or 'table' for partition info.");
}
}
delay(100);
}
17:06:52.917 -> ### Application Partitions (APP) ###
17:06:52.917 -> Label: app0 , Type: 0, SubType: 16, Address: 0x010000, Size: 1920 KB
17:06:52.917 -> Label: app1 , Type: 0, SubType: 17, Address: 0x1f0000, Size: 1920 KB
17:06:52.917 -> ------------------------------------
17:06:52.917 -> ### Data Partitions ###
17:06:52.917 -> Label: nvs , Type: 1, SubType: NVS , Address: 0x009000, Size: 20 KB
17:06:52.917 -> Label: otadata , Type: 1, SubType: OTA_DATA , Address: 0x00e000, Size: 8 KB
17:06:52.917 -> Label: spiffs , Type: 1, SubType: SPIFFS , Address: 0x3d0000, Size: 128 KB
17:06:52.917 -> Label: coredump , Type: 1, SubType: UNKNOWN , Address: 0x3f0000, Size: 64 KB
모두 합하면 4M 가 아니다
시리얼 출력에서 각 파티션의 크기를 합산해보면:
- APP 파티션:
app0
: 1920 KBapp1
: 1920 KB
- Data 파티션:
nvs
: 20 KBotadata
: 8 KBspiffs
: 128 KBcoredump
: 64 KB
이들을 모두 더하면:
1920 + 1920 + 20 + 8 + 128 + 64 = 4060 KB
1MB = 1024KB이므로, 4060 KB는 약 3.965 MB입니다. 실제로 4MB보다 작습니다.
왜 합이 정확히 4MB가 아닐까요? 🧐
리스트에 나온 파티션들의 합이 플래시 전체 크기(예: 4MB)와 정확히 일치하지 않는 데에는 몇 가지 주요 이유가 있습니다.
-
숨겨진/예약된 영역: 파티션 테이블 자체와 2차 부트로더(ESP32가 부팅하는 데 필수)는 플래시 맨 앞부분에 별도의 공간을 차지합니다.
- 2차 부트로더: 일반적으로
0x1000
(4KB 오프셋)에 위치하며 약0x7000
(28KB) 정도를 사용합니다. - 파티션 테이블:
0x8000
(32KB 오프셋)에 위치하며 보통0x1000
(4KB) 크기입니다.
이 영역들은 전체 플래시 메모리의 일부이지만,esp_partition_find
로 나오는 사용자 정의 파티션 목록에는 나타나지 않습니다. 이들은 고정된 역할을 가지며, 사용자가 임의로 조정할 수 없습니다.
- 2차 부트로더: 일반적으로
-
할당되지 않은 공간/패딩: 파티션 사이 또는 플래시 끝에 작은 빈 공간이 남아 있을 수 있습니다. 이는 정렬(alignment) 목적이거나, 단순히 명시적으로 정의되지 않은 미사용 공간일 수 있습니다.
-
플래시 칩 크기 vs. 실제 사용 가능 공간: 플래시 칩이 "4MB"라고 해도, 내부 구조나 주소 지정 방식에 따라 실제 사용 가능한 공간에 약간의 차이가 있을 수 있습니다.
제공하신 주소를 바탕으로 숨겨진 영역을 계산해보면:
- 첫 번째 APP 파티션(
app0
)은0x010000
(64KB)에서 시작합니다. -
그 전에는:
- 부트로더:
0x1000
(4KB)에서 시작해0x8000
(32KB)까지, 약 28KB 사용 - 파티션 테이블:
0x8000
(32KB)에서 시작해0x9000
(36KB)까지, 4KB 사용 - NVS:
0x9000
(36KB)에서 시작해 20KB,0x0E000
(56KB)까지 - OTA Data:
0x0E000
(56KB)에서 시작해 8KB,0x10000
(64KB)까지
따라서,
app0
가 시작되는 이전 공간(0x10000
)은:
0x10000
(app0 시작) -0x0
(플래시 시작) =65536
바이트 = 64 KB입니다.여러분이 나열한 파티션들(NVS, OTA Data)은 20KB + 8KB = 28KB를 차지합니다.
즉, 부트로더와 파티션 테이블이 암묵적으로64 KB - 28 KB = 36 KB
를 사용하고 있다는 뜻입니다. 이 값은 실제로 이 구성요소들의 일반적인 크기와 잘 일치합니다.이렇게 "숨겨진" 또는 암묵적으로 사용되는 부분을 더해보면:
4060 KB(나열된 파티션 합) + 36 KB(부트로더 + 파티션 테이블) = 4096 KB가 됩니다.그리고 4096 KB = 4 MB! 🎉
즉, "사라진" 공간은 바로 ESP32의 동작에 필수적인 부트로더와 파티션 테이블이 차지하고 있으며, 이들은 사용자 관리 파티션 목록에는 나타나지 않는다는 점을 알 수 있습니다.
- 부트로더: