1. 같은 플래시라도 호출자가 보는 단위가 다르다
Zephyr 3.7.0의 Flash API는 struct device에 대해 flash_read(), flash_write(), flash_erase()를 제공한다. Flash map은 devicetree의 fixed-partitions에서 만들어진 flash_area를 ID로 찾아, 영역 안의 상대 오프셋을 확인한 다음 하위 플래시 드라이버로 보낸다. 범위 검사는 추가되지만 지우기 페이지 크기와 쓰기 블록 크기가 사라지는 것은 아니다.
↔ 좁은 화면에서 오른쪽으로 이동해 각 계층의 입력 단위를 비교하세요.
flash_area_read(fa, rel, ...)자기 영역의 시작을 0으로 센다.fa_off + relfa_size 바깥 요청을 막고 backing device를 고른다.flash_read(dev, absolute, ...)장치 시작점 기준 오프셋으로 드라이버를 부른다.| 호출 | 오프셋의 원점 | 제한 범위 | 주의점 |
|---|---|---|---|
flash_read/write/erase(dev,...) | 플래시 장치 시작 | 장치·드라이버가 허용한 범위 | 호출자가 파티션 경계를 별도로 지켜야 한다. |
flash_area_read/write/erase(fa,...) | 해당 파티션 시작 | fa_size 이내 | 하위 드라이버의 정렬·상태 조건은 그대로 적용된다. |
FIXED_PARTITION_OFFSET(label) | 플래시 장치 시작 | DTS가 선언한 값 | flash_area_*에 넘길 상대 오프셋으로 혼동하면 안 된다. |
근거: 3.7.0 Flash API의 장치 기준 오프셋, 3.7.0 Flash map의 영역 범위 검사와 상대 오프셋.
2. DTS 파티션은 주소 약속이지 독점 잠금이 아니다
fixed-partitions 아래의 각 reg는 플래시 장치 시작점에서 잰 오프셋과 크기다. 아래 가상 장치의 raw 파티션이 0x30000에서 시작한다면 영역 안의 0x100은 장치 기준 0x30100이다. FIXED_PARTITION_ID(app_raw_partition)로 ID를 얻어 flash_area_open()에 넘긴다. 구획 선언만으로 다른 코드가 같은 파티션을 열지 못하게 되거나 지우기 단위에 자동 정렬되는 것은 아니다.
다음은 플래시 장치 노드 아래에 놓일 파티션 선언의 축약 예시다. 이미 파티션 노드가 있는 보드라면 중복 선언하지 않고 기존 지도에 통합해야 한다. 0x30000과 0x10000이 실제 장치의 용량·페이지 경계·부트 영역에 맞는지는 이 조각만으로 알 수 없다.
partitions { /* flash device 노드의 자식 */
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
app_raw_partition: partition@30000 {
label = "app-raw";
reg = <0x30000 0x10000>;
};
};
↔ 가상 숫자 예시입니다. 장치 전체와 선택한 영역의 서로 다른 원점을 확인하세요.
0x00000 →
0x30000 · 크기 0x10000영역 기준 rel = 0x100 → 장치 기준 0x30100flash_read(dev, 0x30100, ...)flash_area_read(fa, 0x100, ...)| 선언·필드 | 뜻 | 검토할 조건 |
|---|---|---|
reg = <offset size> | 장치 기준 시작과 바이트 크기 | 실제 용량, 이웃 파티션, 지우기 페이지 경계가 맞는가? |
FIXED_PARTITION_ID(label) | v3.7.0의 고정 파티션 노드 라벨 → flash map ID | 해당 라벨이 빌드된 DTS에 존재하고 활성화됐는가? |
fa->fa_off / fa->fa_size | 장치 기준 영역 시작 / 영역 크기 | 호출자는 fa_off를 상대 오프셋에 다시 더하지 않는다. |
read-only 속성 | DTS가 영역을 읽기 전용으로 기술 | 별도 정책·드라이버 제약까지 확인한다. 공유 영역 동시 사용을 중재하지 않는다. |
3. 영역 범위와 지우기·쓰기 정렬은 별도로 검사한다
명시적 지우기가 필요한 플래시에서 새 값을 쓰려면 그 매체의 지우기 조건을 먼저 만족해야 한다. flash_area_align(fa)은 최소 쓰기 블록 크기를 알려 주지만 지우기 페이지 크기를 알려 주는 함수는 아니다. 지우기는 드라이버가 지원하는 페이지 정보(CONFIG_FLASH_PAGE_LAYOUT 및 flash_get_page_info_by_offs() 등)와 실제 장치 사양으로 따로 확인한다. 읽기·쓰기·지우기 호출의 성공은 0, 실패는 음수 오류값이며, 쓰기와 지우기는 한 번의 논리적 트랜잭션이 아니다.
↔ 각 칸은 서로 다른 조건입니다. 앞 칸 성공이 뒤 칸 성공을 보장하지 않습니다.
fa_size 안인가?| 동작 | v3.7.0 API 조건 | 이것만으로 보장되지 않는 것 |
|---|---|---|
flash_area_read | 영역 내 상대 범위. 하위 드라이버의 읽기 계약을 따른다. | 데이터의 형식·CRC·최신 버전의 유효성 |
flash_area_write | 영역 범위 + 드라이버의 최소 쓰기 블록 크기·오프셋 정렬 | 지우지 않은 비트를 임의 값으로 변경하는 능력, 원자성 |
flash_area_erase | 영역 범위 + 장치별 지우기 페이지 시작·크기 제약 | 다른 데이터가 같은 페이지에 없다는 보증, 마모 수명 |
flash_area_erased_val | 장치가 보고하는 지워진 바이트 값 | 모든 장치가 항상 0xFF라는 가정 |
지우기와 쓰기를 한 함수처럼 취급하지 않는다. flash_area_*는 영역 밖 요청을 막는 래퍼이며 원자적 레코드 갱신, 쓰기 횟수 분산, 전원 복구 절차는 제공한다고 약속하지 않는다. 이 요구가 있으면 레코드 포맷과 복구 규칙을 설계하거나 적합한 상위 저장소를 선택한다.
근거: 3.7.0 flash area API의 범위·정렬 계약, 3.7.0 flash_write·flash_erase·page info.
4. 먼저 읽기만으로 파티션 좌표를 확인한다
아래 코드는 보드의 DTS에 app_raw_partition 라벨이 존재하고 Flash map이 활성화됐다는 조건의 읽기 전용 예시다. 실제 쓰기 실험 전에는 해당 보드의 파티션 소유권과 지우기 페이지 경계를 따로 확인한다. 범위를 열었다고 곧바로 지우거나 쓰지 않는다.
#include <errno.h>
#include <stdint.h>
#include <zephyr/storage/flash_map.h>
int read_raw_header(uint8_t header[16])
{
const struct flash_area *area;
int rc = flash_area_open(FIXED_PARTITION_ID(app_raw_partition), &area);
if (rc != 0) {
return rc; /* ID 없음, map/driver 문제 등 */
}
if (area->fa_size < 16U) {
flash_area_close(area);
return -ERANGE;
}
rc = flash_area_read(area, 0, header, 16);
flash_area_close(area);
return rc; /* 0 또는 음수 오류값 */
}
flash_area_close()는 v3.7.0 헤더에서 현재 아무 작업도 하지 않는 함수지만, open/close API의 쌍을 코드에 남기면 수명 경계가 분명해진다. flash_area_read()의 성공 반환값은 읽은 바이트 수가 아니라 0이다. 위 함수는 데이터 내용의 유효성을 판정하지 않는다.
근거: v3.7.0 flash_map.h의 ID·open/close·read 선언, 3.7.0 공식 사용 예시와 오류 계약.
5. 파티션의 주인은 한 저장 포맷으로 정한다
같은 영역을 raw 코드와 NVS, LittleFS, MCUboot, flash-disk가 동시에 소유하면 각자의 메타데이터·지우기 단위가 충돌한다. flash_area_open()은 이름에서 영역을 찾는 동작이지 독점 잠금이 아니다. DTS, 빌드 설정, 부트로더 파티션 계획을 함께 검토해야 한다.
| 영역의 주인 | 주로 다루는 단위 | raw 코드가 같은 영역을 쓰면 |
|---|---|---|
| MCUboot 이미지 슬롯 | 이미지·업데이트 상태 | 부팅 가능한 이미지와 업데이트 절차가 깨질 수 있다. |
| NVS / Settings 백엔드 | ID·레코드 / 설정 키 | 메타데이터와 회복 규칙 밖에서 페이지를 지우게 된다. |
| LittleFS 등 파일 시스템 | 파일·디렉터리·내부 블록 | 파일 시스템이 소유한 블록을 덮어쓴다. |
| flash-disk | 에뮬레이션된 디스크 섹터 | 캐시·섹터 이미지와 원시 바이트 쓰기가 불일치한다. |
| 애플리케이션 전용 raw 영역 | 애플리케이션이 정의한 레코드 | 다른 주인이 없다면 자체 유효성·복구·마모 정책이 필요하다. |
보드를 바꿀 때 검사할 것: 부트로더와 애플리케이션이 같은 파티션 지도를 보는가, 예약 영역이 겹치지 않는가, 외부 플래시 장치가 초기화됐는가, 선택한 영역의 시작·끝이 지우기 페이지 경계와 맞는가. DTS의 read-only 속성을 애플리케이션 간 동시 접근을 조정하는 잠금으로 해석하지 않는다.
6. flash-disk는 파티션을 블록 장치로 다시 보여준다
v3.7.0 Disk Access 문서는 zephyr,flash-disk 노드의 partition이 flash map 파티션을 가리키고, disk-name과 cache-size를 설정하는 예시를 보여준다. 이 드라이버는 플래시를 디스크 섹터 인터페이스로 바꿔 상위 소비자에게 제공한다. 따라서 disk_access_read/write()의 start_sector는 섹터 번호이며 flash_area_read/write()의 off 바이트와 같은 값이 아니다.
| 경로 | 호출자가 주는 단위 | 그 경로가 맡는 일 |
|---|---|---|
| Flash API | 장치 기준 바이트 오프셋 | 드라이버의 물리적 read/write/erase |
| Flash map | 영역 기준 바이트 오프셋 | 정해진 파티션 안으로 요청을 제한 |
| flash-disk / Disk Access | 디스크 이름·섹터 번호·섹터 수 | flash 파티션을 block device로 변환 |
| 파일 시스템 | 마운트된 경로·파일 오프셋 | 파일 이름·내용·메타데이터 관리 |
문서의 cache-size = <4096>는 특정 예시 값이다. v3.7.0 Disk Access 문서는 이 캐시 크기를 backing 파티션의 최소 지우기 블록 크기와 같게 잡도록 안내한다. 실제 장치의 페이지 구성과 해당 버전 드라이버·DTS 바인딩 조건을 확인해야 한다. flash-disk를 붙였다고 해서 전원 중단 복구나 플래시 수명이 자동으로 보장되지는 않는다.
근거: 3.7.0 flash-disk DTS 예시와 Disk Access API, v3.7.0 flashdisk 드라이버.
7. 오류값보다 먼저 어느 경계에서 실패했는지 본다
| 관측 | 먼저 볼 경계 | 다음 확인 |
|---|---|---|
flash_area_open 실패 | flash map·ID·드라이버 | 생성된 DTS 라벨과 설정, backing 장치 존재 여부 |
| 영역 바깥 offset/len | flash map 범위 검사 | 상대 오프셋에 fa_off를 중복 가산했는가? |
| 범위 안이지만 write/erase 실패 | 드라이버·장치 정렬 | 쓰기 블록과 지우기 페이지를 혼동했는가? |
| 재부팅 뒤 레코드 불일치 | 애플리케이션 포맷·복구 | 전원이 끊겼을 때의 유효성 표시, 복제본, checksum 규칙이 있는가? |
| 다른 서브시스템 데이터 손상 | 영역 소유권 | 부트/FS/NVS/flash-disk와 파티션이 겹쳤는가? |
정확한 음수 errno는 경계와 드라이버에 따라 달라진다. flash_area_open() 문서는 map 부재, 알 수 없는 ID, 드라이버 부재를 구분한다. 이후 I/O 실패는 하위 플래시 드라이버도 조사해야 한다. 반환값만 보고 데이터가 안전하게 롤백됐다고 가정하지 않는다.
8. 소스와 재현 범위
이 글은 Zephyr 릴리스 v3.7.0의 공식 문서와 같은 태그의 공개 헤더·드라이버를 기준으로 썼다. 숫자 그림은 설명용 가상 주소이고, 실제 보드의 DTS·플래시 지우기 크기·서브시스템 구성은 독자가 고정해야 한다. 보드에서의 소거/쓰기를 실행해 검증했다는 뜻이 아니다.
| 고정 근거 | 확인할 부분 |
|---|---|
| Flash API | 장치 기준 오프셋, 최소 쓰기 블록, 지우기 페이지 제약 |
| Flash map · 공개 헤더 | 고정 파티션 ID, 영역 상대 오프셋, 범위·반환값 |
| Disk Access · flashdisk | flash-disk 노드와 섹터 인터페이스의 경계 |