36940db938a8f4a1e919496793ed439850a221c2를 기준으로 한다. Settings API와 NVS backend의 책임 경계만 다룬다. 파일시스템 내부, 암호화 저장, 보드별 플래시 수명 수치와 최신 개발판의 ZMS 선택은 범위 밖이다. 그림은 설명을 위해 새로 그렸다.1. Settings는 이름을 알고, NVS는 저장 공간을 안다
애플리케이션은 app/mode처럼 하위 트리로 나뉜 문자열 키를 Settings에 건넨다. 모듈 handler는 복원한 값을 RAM 상태에 반영하고, backend는 영속 매체에서 읽고 쓴다. 직접 저장인 settings_save_one()은 handler를 거치지 않으며, 전체 저장인 settings_save()는 handler의 h_export를 이용한다. 3.7.0 Settings는 FCB·파일·NVS backend를 제공한다. NVS 자체 API는 16비트 숫자 ID와 데이터를 플래시에 기록한다. 고정 버전의 Settings NVS adapter는 한 설정의 이름과 값을 별도 NVS entry로 관리한다. 따라서 Settings의 키 이름과 NVS의 ID를 동일한 공개 API로 혼동하지 않는다.
↔ 좁은 화면에서는 네 책임 칸과 아래 세 경로를 가로로 이동해 보세요.
| 계층 | 다루는 이름·단위 | 책임 | 오해하기 쉬운 점 |
|---|---|---|---|
| 애플리케이션·Settings API | app/mode 같은 문자열 키 | 로드·저장 요청 | API 호출만으로 RAM 값이 자동 변경된다고 단정하지 않음 |
| 모듈 handler | 등록한 subtree와 값 | h_set·h_commit·h_export 계약 | 값 복원과 실제 기능 적용 시점을 구분 |
| Settings backend | 직렬화한 키·값 | 읽기 source와 쓰기 destination 연결 | source는 여러 개 가능해도 destination은 하나 |
| NVS·flash | 16비트 ID·데이터, sector | 기록·복구·sector 재사용 | NVS의 ID는 애플리케이션의 문자열 키가 아님 |
근거: Settings 개요·backend·handler, NVS ID·데이터·sector, 이름·값을 별도 NVS entry로 읽는 3.7.0 adapter.
2. 로드는 읽기, handler 호출, 적용의 순서로 본다
애플리케이션이 시작할 때 Settings 초기화와 해당 subtree handler 준비가 끝난 뒤 settings_load()를 호출한다. 동적 handler라면 CONFIG_SETTINGS_DYNAMIC_HANDLERS와 등록을 확인하고, 정적 handler는 정의 macro로 포함한다. 등록된 영속 source에서 각 값을 읽으면 맞는 handler의 h_set이 RAM 상태를 구성한다. 전체 로드 뒤 h_commit을 사용하는 handler는 그 시점에 서로 의존하는 값들을 함께 적용할 수 있다. h_set과 h_commit이 모든 모듈에서 반드시 같은 일을 한다는 뜻은 아니다.
↔ 좁은 화면에서는 시간 흐름을 오른쪽으로 이동해 확인하세요.
| 콜백 | 대표 호출 계기 | 모듈이 할 일 | 주의 |
|---|---|---|---|
h_set | 영속 값을 settings_load()로 복원 | 이름·길이를 확인하고 값을 읽어 RAM 상태 구성 | 불완전한 조합을 곧바로 외부에 적용할 필요 없음 |
h_commit | 전체 로드 뒤 | 필요하면 여러 값의 조합을 최종 적용 | handler에 정의하지 않았다면 이 단계의 작업도 없음 |
h_export | settings_save()의 전체 저장 | 현재 RAM 값을 저장 함수에 넘김 | settings_save_one()의 직접 저장과 경로가 다름 |
3.7.0 구현의 반환값 경계. settings_load_subtree()는 source별 csi_load의 반환값을 모으지 않고 마지막 settings_commit_subtree() 결과를 반환한다. handler의 h_set 오류도 로그를 남긴 뒤 무시하는 경로가 있다. 따라서 settings_load() == 0만으로 모든 설정 키의 복원 성공을 인증하지 않는다. 필요한 키의 실제 RAM 값과 오류 로그를 함께 확인한다.
근거: 3.7.0 handler 계약, 로드 절차, settings_load_subtree의 반환, h_set 오류 처리, 공식 Settings 샘플.
3. 한 키를 바로 저장할지, handler 상태를 내보낼지 선택한다
settings_save_one("app/mode", &mode, sizeof(mode))은 지정한 키와 값을 destination backend에 직접 저장한다. 반대로 settings_save()는 등록된 handler의 h_export를 통해 현재 상태를 내보낸다. save_one()으로 저장한 키가 자동으로 h_export의 대상이 되지는 않는다. 전체 저장에 포함하려면 handler 쪽 export 계약을 구현해야 한다. 두 호출 모두 오류 반환을 확인하고, 런타임 RAM 상태 갱신은 애플리케이션의 흐름에서 명시한다.
| 호출 | 값의 출처 | handler 경계 | 적합한 상황 |
|---|---|---|---|
settings_save_one(name, value, len) | 호출자가 넘긴 단일 값 | 전체 h_export 순회가 필요하지 않음 | 한 설정을 바꿀 때 바로 영속화 |
settings_save() | 각 handler가 내보내는 현재 상태 | h_export가 포함한 키를 저장 | 모듈 상태들을 한 번에 내보낼 때 |
settings_load() | 등록된 source에 이미 저장된 값 | h_set 후 필요하면 h_commit | 부팅·재초기화할 때 RAM 상태 복원 |
/* 호출 순서 예시. 동적 handler 옵션·backend·보드 설정은 별도 필요. */
int rc = settings_subsys_init();
if (rc == 0) { rc = settings_register(&app_handler); }
if (rc == 0) { rc = settings_load(); }
if (rc == 0) {
/* 3.7.0에서 rc == 0만으로 모든 키의 복원은 입증되지 않는다. */
/* 필요한 mode의 복원 여부를 앱 상태와 로그로 검증한다. */
mode = new_mode; /* 이 예시의 RAM 상태 갱신 */
rc = settings_save_one("app/mode", &mode, sizeof(mode));
}
/* rc를 확인하고, 오류 시 복구 정책은 애플리케이션이 결정한다. */
예시를 완성된 보드 코드로 복사하지 않는다. CONFIG_SETTINGS_DYNAMIC_HANDLERS, app_handler의 name·h_set 구현, backend Kconfig, 저장 partition과 복원값 검증이 필요하다. 초기화·등록·쓰기 오류와 복원 누락을 분리해서 다룬다.
근거: 3.7.0 save 경로, Settings API 계약.
4. NVS는 먼저 데이터를 쓰고, 나중에 기록 정보를 쓴다
NVS는 플래시 공간을 여러 sector로 나누고 ID·데이터 쌍을 끝에 덧붙인다. 데이터는 sector 앞쪽에서, 해당 기록을 가리키는 metadata는 뒤쪽에서 자란다. 데이터를 먼저, metadata를 나중에 기록하므로 전원 차단으로 metadata가 빠진 데이터는 재시작할 때 유효한 항목으로 취급하지 않는다. 같은 ID·데이터를 다시 쓰려 하면 불필요한 플래시 쓰기를 건너뛴다. 공간이 차면 유효한 최신 항목을 보존하며 sector를 재사용한다.
↔ 좁은 화면에서는 왼쪽 기록과 오른쪽 복구 조건을 모두 확인하세요.
NVS metadata의 CRC는 기록 완료를 살피는 데 사용한다. 값 데이터의 무결성 검사가 항상 켜져 있다는 의미는 아니다. 3.7.0 문서는 데이터 CRC-32를 CONFIG_NVS_DATA_CRC로 별도 활성화하며, 기존에 CRC 없이 기록한 공간에서 이 옵션을 켜면 그 기존 데이터를 무효로 읽게 된다고 설명한다. 실제 제품에서 옵션을 바꾸기 전에는 마이그레이션과 보존 정책을 점검해야 한다.
| 선택·조건 | 3.7.0에서 하는 일 | 검토할 위험 |
|---|---|---|
| Settings FCB / File / NVS | 같은 Settings API 아래 서로 다른 영속 저장 | backend를 바꿔도 기존 형식이 자동 이관되지는 않음 |
| Settings read source·write destination | source 여러 개, destination 하나 | 로드 우선순위·실제 쓰기 대상 확인 |
| NVS metadata CRC | metadata 기록의 유효성 확인 | 데이터 payload CRC와 동일시하지 않음 |
CONFIG_NVS_DATA_CRC | 전체 데이터 읽기에 선택적 CRC-32 검사 | 기존 비CRC 공간과 호환성 문제 |
| sector 여유 공간 | 최신 ID·데이터 보존과 sector 재사용 | 빈 공간이 부족하면 쓰기 실패 가능 |
5. 저장 실패를 API 오류와 플래시 조건으로 나누어 본다
설정이 재부팅 후 사라졌다면 먼저 handler가 해당 키를 받는지, 복원된 RAM 값과 로그를 확인한다. settings_load()의 0 반환만으로 source별 읽기와 h_set 성공을 모두 결론 내리지 않는다. 다음으로 실제 빌드의 backend 선택과 partition, 쓰기 호출 반환값을 확인한다. 3.7.0의 NVS backend는 기본적으로 storage 레이블 고정 partition을 사용하고, devicetree의 zephyr,settings-partition chosen 속성으로 다른 partition을 고를 수 있다. 이름만 맞아도 플래시 장치·크기·쓰기 조건이 맞지 않으면 영속성을 보장할 수 없다.
| 관찰 | 먼저 확인 | 다음 분기 |
|---|---|---|
| 부팅 후 기본값만 남음 | handler 준비 시점, RAM 값·오류 로그 | load() 0이어도 키 이름·h_set·source 확인 |
| 직접 저장은 성공, 전체 저장 뒤 값 누락 | h_export에 그 키를 포함했는가 | save_one()과 save()의 경로 구분 |
| 쓰기 오류·공간 부족 | backend destination·partition·플래시 상태 | NVS sector 크기·개수·여유 공간 |
| CRC 옵션 변경 뒤 옛 값 소실 | 기록 시점의 CONFIG_NVS_DATA_CRC | 기존 데이터 형식의 이관·복구 계획 |
| 민감 설정 저장 | 선택한 backend와 위협 모델 | Settings API 자체를 암호화 저장으로 간주하지 않음 |
이 표는 원인 분리 순서다. 특정 보드에서 플래시 수명, 정전 복구 또는 보안 성질이 충족됐다는 시험 결과가 아니다. NVS 쓰기 수명은 실제 erase 내구도, sector 크기와 갱신 빈도로 따로 계산해야 한다.
6. 고정 버전 자료와 이어 읽기
API·handler·backend·partition의 기준은 Zephyr 3.7.0 Settings 문서, NVS ID·sector·CRC의 기준은 Zephyr 3.7.0 NVS 문서다. 예시 흐름은 공식 Settings API 샘플과 비교할 수 있다. 버전 고정 구현 출발점은 settings_nvs.c, settings_store.c, settings.c와 settings.h다.