์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

STM32 QSPI NOR ํ”Œ๋ž˜์‹œ ๊ธฐ๋ฐ˜ LittleFS์˜ ๋Œ๋ฐœ ์ „์› ์ฐจ๋‹จ ์†์ƒ ๋ณต๊ตฌ ๋ฐ ์›จ์–ด ๋ ˆ๋ฒจ๋ง ์ตœ์ ํ™” ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… Guide

๊ฒŒ์ž„๊ต์ˆ˜ 2026. 9. 4. 22:01
๋ฐ˜์‘ํ˜•

๐ŸŒ English Abstract

This article explores technical strategies for recovering from metadata corruption and optimizing wear leveling in LittleFS running on STM32 QSPI NOR flash memory during sudden power-off (SPO) events. It covers the root causes of QSPI write failures, LittleFS metadata pair mechanics, and HAL-level driver optimizations. Embedded software engineers will learn how to fine-tune LittleFS parameters and low-level flash drivers to guarantee high data integrity and extend device lifespan in industrial IoT environments.

์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ(Embedded System) ํ™˜๊ฒฝ์—์„œ ๊ณ ์„ฑ๋Šฅ ๋””๋ฐ”์ด์Šค ์ œ์–ด๋ฅผ ์œ„ํ•ด STM32 ๋งˆ์ดํฌ๋กœ์ปจํŠธ๋กค๋Ÿฌ์™€ ์ฟผ๋“œ SPI(QSPI, Quad Serial Peripheral Interface) NOR ํ”Œ๋ž˜์‹œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์กฐํ•ฉํ•˜๋Š” ์„ค๊ณ„๋Š” ๋งค์šฐ ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ๋ณด์•ˆ์„ฑ๊ณผ ๋ฌด๊ฒฐ์„ฑ์ด ํ•ต์‹ฌ์ธ IoT ๋ฐ ์‚ฐ์—…์šฉ ๊ธฐ๊ธฐ์—์„œ๋Š” ์ „์› ๊ณต๊ธ‰์ด ๋ถˆ์‹œ์— ์ค‘๋‹จ๋˜๋Š” ๋Œ๋ฐœ ์ „์› ์ฐจ๋‹จ(SPO, Sudden Power Off) ์ƒํ™ฉ์—์„œ๋„ ํŒŒ์ผ ์‹œ์Šคํ…œ์ด ํŒŒ์†๋˜์ง€ ์•Š๊ณ  ๋ณต๊ตฌ๋˜๋Š” ์„ฑ๋Šฅ์ด ํ•„์ˆ˜์ ์œผ๋กœ ์š”๊ตฌ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๊ธฐ ์œ„ํ•ด ์ •์ „ ๋Œ€๋น„ ๋‚ด๊ตฌ์„ฑ(Power-loss Resilience)๊ณผ ์ ์€ RAM ์†Œ๋น„๋Ÿ‰์„ ์ž๋ž‘ํ•˜๋Š” LittleFS ํŒŒ์ผ ์‹œ์Šคํ…œ์ด ๋งŽ์ด ์ฑ„ํƒ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ ํ˜„์žฅ์—์„œ STM32์˜ QSPI ๋“œ๋ผ์ด๋ฒ„ ๋ ˆ์ด์–ด์™€ LittleFS๋ฅผ ๊ฒฐํ•ฉํ•˜์—ฌ ์žฅ์‹œ๊ฐ„ ์šด์šฉํ•˜๋‹ค ๋ณด๋ฉด, ํŠน์ • ์—ฃ์ง€ ์ผ€์ด์Šค(Edge Cases)์—์„œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ธ”๋ก(Metadata Block)์ด ์†์ƒ๋˜์–ด ๋งˆ์šดํŠธ ์‹คํŒจ(Mount Failure)๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜, ํŠน์ • ํ”Œ๋ž˜์‹œ ๋ธ”๋ก์— ์“ฐ๊ธฐ ์ž‘์—…์ด ์ง‘์ค‘๋˜์–ด ์ˆ˜๋ช…์ด ๊ธ‰๊ฒฉํžˆ ๋‹จ์ถ•๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ณด๊ณ ๋˜๊ณค ํ•ฉ๋‹ˆ๋‹ค.

๋ณธ ํฌ์ŠคํŒ…์—์„œ๋Š” STM32 ๋งˆ์ดํฌ๋กœ์ปจํŠธ๋กค๋Ÿฌ์™€ QSPI NOR ํ”Œ๋ž˜์‹œ ๋ ˆ์ด์–ด ์ƒ์—์„œ LittleFS ์šด์šฉ ์ค‘ ๋ฐœ์ƒํ•˜๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์†์ƒ ์›์ธ์„ ์‹ฌ์ธต ๋ถ„์„ํ•˜๊ณ , ์ด๋ฅผ ์™„๋ฒฝํžˆ ๋ณต๊ตฌํ•จ๊ณผ ๋™์‹œ์— ์›จ์–ด ๋ ˆ๋ฒจ๋ง(Wear Leveling) ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š” ํ•˜๋“œ์›จ์–ด/์†Œํ”„ํŠธ์›จ์–ด ํ†ตํ•ฉ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ๊ฐ€์ด๋“œ๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.



1. LittleFS ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์™€ QSPI NOR ํ”Œ๋ž˜์‹œ์˜ ๋งค์ปค๋‹ˆ์ฆ˜ ๋ถ„์„

LittleFS๊ฐ€ ๋Œ๋ฐœ ์ „์› ์ฐจ๋‹จ์— ๊ฐ•ํ•œ ์ด์œ ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ CoW(Copy-on-Write) ๋ฐฉ์‹๊ณผ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํŽ˜์–ด(Metadata Pair) ๊ตฌ์กฐ๋ฅผ ์ฑ„ํƒํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ•˜์œ„ ๋ฌผ๋ฆฌ ๋ ˆ์ด์–ด์ธ QSPI NOR ํ”Œ๋ž˜์‹œ ๋ฉ”๋ชจ๋ฆฌ์˜ ํŠน์„ฑ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋ฉด ์ œ์–ด ํƒ€์ด๋ฐ์—์„œ ๊ฒฐํ•จ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ€. ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํŽ˜์–ด(Metadata Pair) ๋™์ž‘ ๋ฐฉ์‹

LittleFS์˜ ๋ชจ๋“  ๋””๋ ‰ํ„ฐ๋ฆฌ์™€ ์‹œ์Šคํ…œ ์ƒํƒœ ์ •๋ณด๋Š” ๋‘ ๊ฐœ์˜ ๋ธ”๋ก์œผ๋กœ ๊ตฌ์„ฑ๋œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํŽ˜์–ด์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๊ธฐ์กด ๋ธ”๋ก์„ ๋ฎ์–ด์“ฐ๋Š” ๋Œ€์‹ , ๋นˆ ๋ธ”๋ก์— ์ƒˆ ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๊ณ  ๋ฆฌ๋น„์ „ ํฌ์ธํ„ฐ(Revision Pointer)์™€ ์ฒดํฌ์„ฌ(CRC32)์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ์—…๋ฐ์ดํŠธ๊ฐ€ ์™„๋ฃŒ๋œ ํ›„ ์ด์ „ ๋ธ”๋ก์„ ์‚ญ์ œ(Erase)ํ•˜๋Š” ์œ ๊ธฐ์ ์ธ ์ˆœ์„œ๋ฅผ ๊ฑฐ์นฉ๋‹ˆ๋‹ค.

๋‚˜. QSPI NOR ํ”Œ๋ž˜์‹œ์˜ ๋ฌผ๋ฆฌ์  ํ•œ๊ณ„

NOR ํ”Œ๋ž˜์‹œ๋Š” ๋น„ํŠธ ๋‹จ์œ„์˜ ์ฝ๊ธฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์“ฐ๊ธฐ(Program)๋Š” ๊ธฐ๋ณธ ๋‹จ์œ„(๋ณดํ†ต 256 Byte Page), ์ง€์šฐ๊ธฐ(Erase)๋Š” ๋” ํฐ ๋‹จ์œ„(๋ณดํ†ต 4KB Sector ๋˜๋Š” 64KB Block)๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. ํŠนํžˆ Erase ์ž‘์—… ๋„์ค‘ ์ „์›์ด ์ฐจ๋‹จ๋˜๋ฉด ํ”Œ๋ž˜์‹œ ์…€์˜ ์ „ํ•˜ ์ƒํƒœ๊ฐ€ ๋ถˆํ™•์‹คํ•œ ๋ฉ”ํƒ€์Šคํ…Œ์ด๋ธ”(Metastable) ์ƒํƒœ๋กœ ๋‚จ์•„, ์ดํ›„ ์ฝ๊ธฐ ์‹œ ๋น„ํŠธ ์—๋Ÿฌ(Bit Flip)๋ฅผ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค.

STM32์˜ QSPI ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ Direct Mode ๋˜๋Š” Memory-Mapped Mode๋กœ ์ž‘๋™ํ•˜๋Š” ๊ณผ์ •์—์„œ, ๋ฒ„ํผ๋ง๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ํ”Œ๋ž˜์‹œ์— ์™„์ „ํžˆ ๊ธฐ๋ก๋˜๊ธฐ ์ „์— ํ•˜๋“œ์›จ์–ด ์ „์›์ด ํ•˜๊ฐ• ์ „์•• ์ž„๊ณ„์น˜(Power-down Threshold) ๋ฐ‘์œผ๋กœ ๋–จ์–ด์ง€๋ฉด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ—ค๋”๋Š” ์ •์ƒ์ฒ˜๋Ÿผ ๋ณด์ด๋‚˜ ๋‚ด์šฉ๋ฌผ์ด ์œ ํšจํ•˜์ง€ ์•Š์€ ์‹ฌ๊ฐํ•œ ์ƒํƒœ์— ๋น ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. ๋Œ๋ฐœ ์ „์› ์ฐจ๋‹จ(SPO) ์‹œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์†์ƒ ์›์ธ ๋ถ„์„

LittleFS ํ™˜๊ฒฝ์—์„œ `lfs_mount()` ํ•จ์ˆ˜๊ฐ€ `LFS_ERR_CORRUPT` ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ทผ๋ณธ ์›์ธ์€ ๋‹จ์ˆœํžˆ ํŒŒ์ผ ์‹œ์Šคํ…œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ๋ผ๊ธฐ๋ณด๋‹ค MCU-ํ”Œ๋ž˜์‹œ ๋ฉ”๋ชจ๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค ๊ฐ„ ํƒ€์ด๋ฐ ๋ถˆ์ผ์น˜์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋Œ€๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

  • QSPI FIFO ๋ฒ„ํผ ๋ฐ ํ”Œ๋ž˜์‹œ ๋‚ด๋ถ€ Program Time ์ง€์—ฐ: NOR ํ”Œ๋ž˜์‹œ์˜ Page Program ๋™์ž‘ ์‹œ๊ฐ„(tPP)์€ ์ŠคํŽ™์ƒ ๋ณดํ†ต 0.2ms~3ms๊ฐ€ ์†Œ์š”๋ฉ๋‹ˆ๋‹ค. MCU๋Š” ์ด๋ฏธ ๋ฐ์ดํ„ฐ ์ „์†ก ๋ช…๋ น์„ ๋งˆ์ณค์œผ๋‚˜, ํ”Œ๋ž˜์‹œ ๋‚ด๋ถ€ ํŽŒ์›จ์–ด๊ฐ€ ๋ฌผ๋ฆฌ ์…€์— ๊ธฐ๋ก์„ ์ง„ํ–‰ํ•˜๋Š” ์ค‘๊ฐ„์— ์ „์›์ด ์ƒ์‹ค๋˜๋ฉด ํ—ค๋”๋งŒ ํŒŒ์†๋˜๊ฑฐ๋‚˜ ์ฒดํฌ์„ฌ ๋ฏธ์Šค๋งค์น˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • WIP(Write In Progress) ๋น„ํŠธ ์ฒดํฌ ๋ฏธํก: STM32 HAL ๋“œ๋ผ์ด๋ฒ„์˜ QSPI ์ „์†ก ์™„๋ฃŒ ์ฝœ๋ฐฑ ์ดํ›„, ํ”Œ๋ž˜์‹œ ๋ฉ”๋ชจ๋ฆฌ์˜ Status Register-1 ๋‚ด WIP ๋น„ํŠธ๊ฐ€ 0(Ready)์ด ๋  ๋•Œ๊นŒ์ง€ ์™„๋ฒฝํ•˜๊ฒŒ ํด๋ง(Polling)ํ•˜์ง€ ์•Š๊ณ  ๋‹ค์Œ ๋ฃจํ‹ด์œผ๋กœ ๋„˜์–ด๊ฐ€๋ฉด ์ „์› ์ฐจ๋‹จ ์‹œ ์ง์ „ ์“ฐ๊ธฐ ์ž‘์—…์ด ์ค‘๊ฐ„์— ๋Š๊ธฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • Lookahead Buffer ๋ถˆ์ผ์น˜: LittleFS๋Š” ๋ธ”๋ก ํ• ๋‹น ์ƒํƒœ๋ฅผ ๋น ๋ฅด๊ฒŒ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด RAM ๋‚ด๋ถ€์— Lookahead Buffer๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. RAM ์ƒ์˜ ๋น„ํŠธ๋งต ์ƒํƒœ์™€ ๋ฌผ๋ฆฌ ํ”Œ๋ž˜์‹œ ๋ฉ”๋ชจ๋ฆฌ์˜ ์‹ค์ œ ์ง€์›Œ์ง„ ์ƒํƒœ(Erased State)๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ์ˆœ๊ฐ„ ์ „์›์ด ๊บผ์ง€๋ฉด, ์žฌ๋ถ€ํŒ… ์‹œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ธ”๋ก ๊ฐ„ ์ฒด์ธ ํฌ์ธํ„ฐ(Chain Pointer)๊ฐ€ ์œ ์‹ค๋˜๋Š” ํ˜„์ƒ์ด ์œ ๋ฐœ๋ฉ๋‹ˆ๋‹ค.


3. ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์†์ƒ ๋ณต๊ตฌ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ๊ธฐ๋ฒ•

๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์†์ƒ์œผ๋กœ ์ธํ•˜์—ฌ ์‹œ์Šคํ…œ์ด ๋ถ€ํŒ… ๋ถˆ๋Šฅ ์ƒํƒœ์— ๋น ์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์†Œํ”„ํŠธ์›จ์–ด ๋ ˆ์ด์–ด์™€ ํ•˜๋“œ์›จ์–ด ๋“œ๋ผ์ด๋ฒ„ ๋ ˆ์ด์–ด ์–‘์ชฝ์—์„œ ์ด์ค‘ ๋ณต๊ตฌ ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€. ํ•˜๋“œ์›จ์–ด ํƒ€์ด๋ฐ ๋ฐ QSPI Polling ๋ณด์™„

์“ฐ๊ธฐ ๋ฐ ์ง€์šฐ๊ธฐ ์ž‘์—… ์งํ›„ ํ”Œ๋ž˜์‹œ ์ƒํƒœ๋ฅผ ๋™๊ธฐ์‹์œผ๋กœ ๊ฒ€์ฆํ•˜๋Š” `QSPI_AutoPolling` ๋ฃจํ‹ด์„ ํ•„์ˆ˜์ ์œผ๋กœ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” STM32 HAL ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ธฐ์ค€ ํ‘œ์ค€ ์ฒ˜๋ฆฌ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


/* QSPI NOR Flash Write In Progress(WIP) Polling function */
HAL_StatusTypeDef QSPI_WaitForReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout) {
    QSPI_CommandTypeDef s_command = {0};
    QSPI_AutoPollingTypeDef s_config = {0};

    s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
    s_command.Instruction       = READ_STATUS_REG1_CMD; // 0x05
    s_command.DataMode          = QSPI_DATA_1_LINE;
    s_command.AddressMode       = QSPI_ADDRESS_NONE;
    s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    s_command.DummyCycles       = 0;

    s_config.Match              = 0x00; // Bit 0 (WIP) must be 0
    s_config.Mask               = 0x01; // Read Status Register Bit 0
    s_config.MatchMode          = QSPI_MATCH_MODE_AND;
    s_config.StatusBytesSize    = 1;
    s_config.Interval           = 0x10;
    s_config.AutomaticStop      = QSPI_AUTOMATIC_STOP_ENABLE;

    return HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, Timeout);
}

๋‚˜. LittleFS mount ์‹คํŒจ ์‹œ ์ž๋™ ๋กค๋ฐฑ ๋ฐ ๋ณต๊ตฌ ๋งค์ปค๋‹ˆ์ฆ˜

`lfs_mount()`๊ฐ€ ์‹คํŒจํ•˜๋Š” ๊ฒฝ์šฐ ๊ณง๋ฐ”๋กœ ์ „์ฒด ํฌ๋งท(`lfs_format()`)์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ๊ธฐ์กด ์ค‘์š” ๋กœ๊ทธ ๋ฐ ํ™˜๊ฒฝ์„ค์ •์ด ๋ชจ๋‘ ๋‚ ์•„๊ฐ‘๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹จ๊ณ„๋ณ„ ๋ณต๊ตฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. 1๋‹จ๊ณ„: `lfs_mount()` ์‹œ๋„. ์‹คํŒจ ์‹œ `LFS_ERR_CORRUPT` ๊ฐ์ง€.
  2. 2๋‹จ๊ณ„: ์ €์ˆ˜์ค€(Low-level) Flash Read๋ฅผ ํ†ตํ•ด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํŽ˜์–ด Block 0๊ณผ Block 1์˜ CRC32๋ฅผ ์ˆ˜๋™ ๊ฒ€์ฆ.
  3. 3๋‹จ๊ณ„: ์†์ƒ๋œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ธ”๋ก์„ ๊ฒฉ๋ฆฌ(Bad Block Marking)ํ•˜๊ณ , ์œ ํšจํ•œ ๋ฆฌ๋น„์ „์„ ๊ฐ€์ง„ ๋‹ค๋ฅธ ๋ธ”๋ก์œผ๋กœ ํŠธ๋ ˆ์ด์‹ฑํ•˜์—ฌ ํฌ์ธํ„ฐ ๊ฐ•์ œ ๋ณต์› ์‹œ๋„.
  4. 4๋‹จ๊ณ„: ์†Œํ”„ํŠธ์›จ์–ด ๋ณต๊ตฌ ๋ถˆ๊ฐ€ ํŒ์ • ์‹œ, ํŠน์ • ๋ฐ์ดํ„ฐ ๊ตฌ์—ญ๋งŒ ๋ฐฑ์—…(RAM ์ž„์‹œ ๋ณต์‚ฌ) ํ›„ ์‹œ์Šคํ…œ ์„ค์ • ์˜์—ญ์„ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ์„นํ„ฐ๋งŒ ๋ถ€๋ถ„ ๋ฆฌ์…‹.

4. ์›จ์–ด ๋ ˆ๋ฒจ๋ง(Wear Leveling) ๋ฐ ์„ฑ๋Šฅ ์ตœ์ ํ™”

LittleFS๋Š” ๋™์  ์›จ์–ด ๋ ˆ๋ฒจ๋ง(Dynamic Wear Leveling) ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜์ง€๋งŒ, ๋ฌผ๋ฆฌ NOR ํ”Œ๋ž˜์‹œ์˜ ๋ธ”๋ก ํฌ๊ธฐ ๋ฐ `block_cycles` ์„ค์ •๊ฐ’์ด ์ตœ์ ํ™”๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํŠน์ • ์„นํ„ฐ์˜ Endurance(์“ฐ๊ธฐ ์ œํ•œ ํšŸ์ˆ˜, ๋ณดํ†ต 10๋งŒ ํšŒ)๊ฐ€ ๋น ๋ฅด๊ฒŒ ์†Œ๋ชจ๋ฉ๋‹ˆ๋‹ค.

๊ฐ€. `struct lfs_config` ํ•ต์‹ฌ ํŒŒ๋ผ๋ฏธํ„ฐ ํŠœ๋‹

STM32 QSPI NOR ํ”Œ๋ž˜์‹œ(์˜ˆ: W25Q128JW, MX25R6435F) ํ™˜๊ฒฝ์—์„œ ์ตœ์ƒ์˜ ์“ฐ๊ธฐ ๋‚ด๊ตฌ์„ฑ๊ณผ ์†๋„๋ฅผ ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•œ ์„ค์ • ๊ธฐ์ค€์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ ํ•ญ๋ชฉ ๊ถŒ์žฅ ์„ค์ • ๊ฐ’ ๊ธฐ์ˆ ์  ๊ทผ๊ฑฐ ๋ฐ ํšจ๊ณผ
read_size 16 ~ 256 Byte QSPI FIFO ๋ฐ DMA ๋ฒ„ํผ ํฌ๊ธฐ์— ๋งž์ถ”์–ด ์ •๋ ฌ. ์ฝ๊ธฐ ์˜ค๋ฒ„ํ—ค๋“œ ์ตœ์†Œํ™”.
prog_size 256 Byte NOR ํ”Œ๋ž˜์‹œ์˜ ๋ฌผ๋ฆฌ์  Page Program ํฌ๊ธฐ์™€ 1:1 ์ •๋ ฌํ•˜์—ฌ ์“ฐ๊ธฐ ํšจ์œจ ์ฆ๋Œ€.
block_size 4096 Byte (4KB) ํ”Œ๋ž˜์‹œ์˜ ์ตœ์†Œ ์‚ญ์ œ ๋‹จ์œ„์ธ Sector Erase ๋‹จ์œ„์™€ ์™„์ „ํžˆ ์ผ์น˜์‹œํ‚ด.
block_cycles 100 ~ 500 ํ•ต์‹ฌ ๊ฐ’: ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ฃผ๊ธฐ. ๊ฐ’์ด ์ž‘์„์ˆ˜๋ก ์›จ์–ด ๋ ˆ๋ฒจ๋ง์€ ๊ณ ๋ฅด๊ฒŒ ๋ถ„์‚ฐ๋˜๋‚˜ ์ง€์šฐ๊ธฐ ํšŸ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•จ. 100~500 ์‚ฌ์ด๊ฐ€ ๊ฐ€์žฅ ์ด์ƒ์ ์ž„.
lookahead_size 64 ~ 128 (Bit ๋‹จ์œ„) RAM ์†Œ๋น„๋Ÿ‰ ์กฐ์ ˆ ๋ฐ ๋นˆ ๋ธ”๋ก ์Šค์บ” ํƒ์ƒ‰ ์†๋„ ์ตœ์ ํ™” (8๋ฐ”์ดํŠธ ๋‹จ์œ„ ์ •๋ ฌ ํ•„์ˆ˜).

๋‚˜. BVD(Brown-Out Reset) ๋ฐ ์ €์ „๋ ฅ ๊ฐ์ง€ ์—ฐ๋™

์†Œํ”„ํŠธ์›จ์–ด์  ๋ณต๊ตฌ ์ „๋žต๊ณผ ๋”๋ถˆ์–ด ์ „์› ํ•˜๊ฐ•์„ ํ•˜๋“œ์›จ์–ด์ ์œผ๋กœ ์ฆ‰๊ฐ ๊ฐ์ง€ํ•˜๋Š” BOR(Brown-Out Reset) ๊ธฐ๋Šฅ ์„ค์ •์ด ๋ณ‘ํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. STM32์˜ Option Byte ์„ค์ •์„ ํ†ตํ•ด BOR Level์„ 2.7V ์ด์ƒ์œผ๋กœ ์ƒํ–ฅ ์กฐ์ •ํ•˜๋ฉด, VDD ์ „์›์ด ๋‹ค์šด๋  ๋•Œ QSPI ์ธํ„ฐํŽ˜์ด์Šค์˜ ์“ฐ๊ธฐ ์ž‘์—…์ด ๋ฌด์ž‘์œ„๋กœ ๊ณ„์† ์ง„ํ–‰๋˜๋Š” ํ˜„์ƒ์„ ํ•˜๋“œ์›จ์–ด ์ฐจ์›์—์„œ ๋ฌด์กฐ๊ฑด ์ค‘๋‹จ์‹œํ‚ต๋‹ˆ๋‹ค.



๊ฒฐ๋ก : ์‹œ์Šคํ…œ ์•ˆ์ •์„ฑ ๊ฒ€์ฆ์„ ์œ„ํ•œ ๊ถŒ์žฅ ์‚ฌํ•ญ

STM32์™€ QSPI NOR ํ”Œ๋ž˜์‹œ ์กฐํ•ฉ์—์„œ LittleFS ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ๋งค์šฐ ๋†’์€ ์‹ ๋ขฐ์„ฑ์œผ๋กœ ์šด์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์†Œํ”„ํŠธ์›จ์–ด, ํŽŒ์›จ์–ด ๋“œ๋ผ์ด๋ฒ„, ํ•˜๋“œ์›จ์–ด ์ „์› ๋ชจ๋‹ˆํ„ฐ๋ง ์‚ผ๋ฐ•์ž๊ฐ€ ์™„๋ฒฝํ•˜๊ฒŒ ๋งž๋ฌผ๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์–‘์‚ฐ ๊ฒ€์ฆ ๋‹จ๊ณ„์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‹ค๋ฌด ํ…Œ์ŠคํŒ… ๊ธฐ๋ฒ•์„ ํ•„์ˆ˜์ ์œผ๋กœ ์ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  • Power-Cut Injection Test: QSPI Page Program ๋ฐ Sector Erase ์ˆ˜ํ–‰ ์ค‘ Relay ๋ชจ๋“ˆ์„ ์ด์šฉํ•˜์—ฌ 1,000ํšŒ ์ด์ƒ์˜ ๋ฌด์ž‘์œ„ ์ „์› ์ฐจ๋‹จ ํ…Œ์ŠคํŠธ ์ง„ํ–‰ ํ›„ Mount ๋ฐ Integrity Check ๊ฒ€์ฆ.
  • Endurance Burn-in Test: `block_cycles` ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ ์šฉ๋œ ์ƒํƒœ์—์„œ ๊ฐ€์ƒ์œผ๋กœ 10๋…„ ์น˜ ์“ฐ๊ธฐ/์ง€์šฐ๊ธฐ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๊ณ ์† ์ˆ˜ํ–‰ํ•˜์—ฌ ํŠน์ • ๋ธ”๋ก์— ํŽธ์ค‘ ์“ฐ๊ธฐ๊ฐ€ ์—†๋Š”์ง€ ๋ชจ๋‹ˆํ„ฐ๋ง.

๋ณธ ๊ฐ€์ด๋“œ์—์„œ ๋‹ค๋ฃฌ QSPI AutoPolling ์ง€์—ฐ ์ฒ˜๋ฆฌ, `lfs_config` ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๋ฌผ๋ฆฌ ์„นํ„ฐ ํฌ๊ธฐ ์ •๋ ฌ, BOR ํ•˜๋“œ์›จ์–ด ์ฐจ๋‹จ ์ „๋žต์„ ์ ์šฉํ•œ๋‹ค๋ฉด, ๊ทนํ•œ์˜ ์‚ฐ์—… ํ˜„์žฅ ํ™˜๊ฒฝ์—์„œ๋„ ๋Œ๋ฐœ ์ „์› ์ฐจ๋‹จ์œผ๋กœ ์ธํ•œ ํŒŒ์ผ ์‹œ์Šคํ…œ ์†์ƒ ์‚ฌ๊ณ ๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•