2020 * Lock on error: the flash controller is locked (best-effort) even when an
2121 * intermediate step fails, to leave the target in a safe state.
2222 *
23+ * Note on naming: all macros describing the N32G031 flash controller use the
24+ * N32_ prefix to avoid collisions with STM32WB CMSIS definitions (which
25+ * define their own FLASH_BASE, FLASH_KEY1, FLASH_KEY2, etc.) pulled in
26+ * transitively through furi_hal.h.
27+ *
2328 * Author: generated for the Flipper Zero RAZ DC25000 vape-reflash project.
2429 */
2530
3136#include <string.h>
3237
3338/* ============================================================================
34- * Flash controller register addresses
39+ * Flash controller register addresses (N32G031 peripheral space)
3540 * ========================================================================= */
3641
37- #define FLASH_BASE 0x40022000UL
38- #define FLASH_AC (FLASH_BASE + 0x00U) /* Access control (wait states) */
39- #define FLASH_KEY (FLASH_BASE + 0x04U) /* Unlock key register */
40- #define FLASH_OPTKEY (FLASH_BASE + 0x08U) /* Option byte unlock key */
41- #define FLASH_STS (FLASH_BASE + 0x0CU) /* Status register */
42- #define FLASH_CTRL (FLASH_BASE + 0x10U) /* Control register */
43- #define FLASH_ADD (FLASH_BASE + 0x14U) /* Page-erase address register */
44-
45- /* FLASH_CTRL bits */
46- #define FLASH_CTRL_PG (1UL << 0) /* Program enable */
47- #define FLASH_CTRL_PER (1UL << 1) /* Page erase */
48- #define FLASH_CTRL_MER (1UL << 2) /* Mass erase */
49- #define FLASH_CTRL_STRT (1UL << 6) /* Start (trigger erase) */
50- #define FLASH_CTRL_LOCK (1UL << 7) /* Lock bit (1 = locked; clear via keys) */
51-
52- /* FLASH_STS bits */
53- #define FLASH_STS_BSY (1UL << 0) /* Controller busy */
54- #define FLASH_STS_PGERR (1UL << 2) /* Program error */
55- #define FLASH_STS_WRPERR (1UL << 4) /* Write-protection error */
56- #define FLASH_STS_EOP (1UL << 5) /* End of operation (write 1 to clear) */
42+ #define N32_FLASH_BASE 0x40022000UL
43+ #define N32_FLASH_AC (N32_FLASH_BASE + 0x00U) /* Access control (wait states) */
44+ #define N32_FLASH_KEY (N32_FLASH_BASE + 0x04U) /* Unlock key register */
45+ #define N32_FLASH_OPTKEY (N32_FLASH_BASE + 0x08U) /* Option byte unlock key */
46+ #define N32_FLASH_STS (N32_FLASH_BASE + 0x0CU) /* Status register */
47+ #define N32_FLASH_CTRL (N32_FLASH_BASE + 0x10U) /* Control register */
48+ #define N32_FLASH_ADD (N32_FLASH_BASE + 0x14U) /* Page-erase address register */
49+
50+ /* N32_FLASH_CTRL bits */
51+ #define N32_CTRL_PG (1UL << 0) /* Program enable */
52+ #define N32_CTRL_PER (1UL << 1) /* Page erase */
53+ #define N32_CTRL_MER (1UL << 2) /* Mass erase */
54+ #define N32_CTRL_STRT (1UL << 6) /* Start (trigger erase) */
55+ #define N32_CTRL_LOCK (1UL << 7) /* Lock bit (1 = locked; clear via keys) */
56+
57+ /* N32_FLASH_STS bits */
58+ #define N32_STS_BSY (1UL << 0) /* Controller busy */
59+ #define N32_STS_PGERR (1UL << 2) /* Program error */
60+ #define N32_STS_WRPERR (1UL << 4) /* Write-protection error */
61+ #define N32_STS_EOP (1UL << 5) /* End of operation (write 1 to clear) */
5762
5863/* Unlock key sequence */
59- #define FLASH_KEY1 0x45670123UL
60- #define FLASH_KEY2 0xCDEF89ABUL
64+ #define N32_KEY1 0x45670123UL
65+ #define N32_KEY2 0xCDEF89ABUL
6166
6267/* ============================================================================
6368 * Flash geometry
6469 * ========================================================================= */
6570
66- #define FLASH_ORIGIN 0x08000000UL /* First byte of flash in address space */
67- #define FLASH_PAGE_SIZE 1024U /* 1 KB per page */
68- #define FLASH_TOTAL_PAGES 64U /* 64 pages = 64 KB */
71+ #define N32_FLASH_ORIGIN 0x08000000UL /* First byte of flash in target space */
72+ #define N32_PAGE_SIZE 1024U /* 1 KB per page */
73+ #define N32_TOTAL_PAGES 64U /* 64 pages = 64 KB */
6974
7075/* NV region: pages 60-63 are reserved and must not be erased/written */
71- #define FLASH_NV_FIRST_PAGE 60U /* First NV page (inclusive) */
72- #define FLASH_MAX_USER_PAGES 60U /* Pages 0-59 are user-writable */
73- #define FLASH_MAX_BYTES (FLASH_MAX_USER_PAGES * FLASH_PAGE_SIZE ) /* 61440 */
76+ #define N32_NV_FIRST_PAGE 60U /* First NV page (inclusive) */
77+ #define N32_MAX_USER_PAGES 60U /* Pages 0-59 are user-writable */
78+ #define N32_MAX_BYTES (N32_MAX_USER_PAGES * N32_PAGE_SIZE ) /* 61440 */
7479
7580/* ============================================================================
7681 * Polling timeouts
@@ -120,17 +125,17 @@ static inline FlashResult flash_read32(uint32_t addr, uint32_t* out) {
120125}
121126
122127/**
123- * flash_poll_bsy() — spin until FLASH_STS_BSY clears or timeout expires.
128+ * flash_poll_bsy() — spin until N32_FLASH_STS BSY clears or timeout expires.
124129 *
125130 * @param max_iters Maximum number of 100-µs polling iterations.
126131 * @return FLASH_OK, FLASH_ERR_TIMEOUT, or FLASH_ERR_SWD.
127132 */
128133static FlashResult flash_poll_bsy (uint32_t max_iters ) {
129134 for (uint32_t i = 0 ; i < max_iters ; i ++ ) {
130135 uint32_t sts = 0 ;
131- FlashResult r = flash_read32 (FLASH_STS , & sts );
136+ FlashResult r = flash_read32 (N32_FLASH_STS , & sts );
132137 if (r != FLASH_OK ) return FLASH_ERR_SWD ;
133- if (!(sts & FLASH_STS_BSY )) return FLASH_OK ;
138+ if (!(sts & N32_STS_BSY )) return FLASH_OK ;
134139 furi_delay_us (POLL_DELAY_US );
135140 }
136141 return FLASH_ERR_TIMEOUT ;
@@ -146,47 +151,47 @@ static FlashResult flash_poll_bsy(uint32_t max_iters) {
146151 */
147152static FlashResult flash_check_errors (FlashResult err_code ) {
148153 uint32_t sts = 0 ;
149- FlashResult r = flash_read32 (FLASH_STS , & sts );
154+ FlashResult r = flash_read32 (N32_FLASH_STS , & sts );
150155 if (r != FLASH_OK ) return FLASH_ERR_SWD ;
151156
152- if (sts & FLASH_STS_WRPERR ) return FLASH_ERR_PROTECTED ;
153- if (sts & FLASH_STS_PGERR ) return err_code ;
157+ if (sts & N32_STS_WRPERR ) return FLASH_ERR_PROTECTED ;
158+ if (sts & N32_STS_PGERR ) return err_code ;
154159 return FLASH_OK ;
155160}
156161
157162/**
158- * flash_clear_eop() — write 1 to FLASH_STS_EOP to acknowledge end-of-op.
163+ * flash_clear_eop() — write 1 to N32_STS_EOP to acknowledge end-of-op.
159164 *
160165 * This is a write-1-to-clear bit; writing EOP does not disturb other bits
161166 * because PGERR/WRPERR are also write-1-to-clear and we write only EOP.
162167 */
163168static FlashResult flash_clear_eop (void ) {
164- return flash_write32 (FLASH_STS , FLASH_STS_EOP );
169+ return flash_write32 (N32_FLASH_STS , N32_STS_EOP );
165170}
166171
167172/**
168173 * flash_unlock() — perform the two-key unlock sequence.
169174 *
170- * After writing both keys, reads back FLASH_CTRL to verify the LOCK bit is
171- * clear. Returns FLASH_ERR_UNLOCK if CTRL cannot be read or LOCK is still
175+ * After writing both keys, reads back N32_FLASH_CTRL to verify the LOCK bit
176+ * is clear. Returns FLASH_ERR_UNLOCK if CTRL cannot be read or LOCK is still
172177 * set (e.g. wrong key order, or controller already in an error state).
173178 *
174179 * @return FLASH_OK on success.
175180 */
176181static FlashResult flash_unlock (void ) {
177182 FlashResult r ;
178183
179- r = flash_write32 (FLASH_KEY , FLASH_KEY1 );
184+ r = flash_write32 (N32_FLASH_KEY , N32_KEY1 );
180185 if (r != FLASH_OK ) return FLASH_ERR_UNLOCK ;
181186
182- r = flash_write32 (FLASH_KEY , FLASH_KEY2 );
187+ r = flash_write32 (N32_FLASH_KEY , N32_KEY2 );
183188 if (r != FLASH_OK ) return FLASH_ERR_UNLOCK ;
184189
185190 /* Verify LOCK bit cleared */
186191 uint32_t ctrl = 0 ;
187- r = flash_read32 (FLASH_CTRL , & ctrl );
192+ r = flash_read32 (N32_FLASH_CTRL , & ctrl );
188193 if (r != FLASH_OK ) return FLASH_ERR_UNLOCK ;
189- if (ctrl & FLASH_CTRL_LOCK ) return FLASH_ERR_UNLOCK ;
194+ if (ctrl & N32_CTRL_LOCK ) return FLASH_ERR_UNLOCK ;
190195
191196 return FLASH_OK ;
192197}
@@ -200,11 +205,11 @@ static FlashResult flash_unlock(void) {
200205 */
201206static FlashResult flash_lock (void ) {
202207 uint32_t ctrl = 0 ;
203- FlashResult r = flash_read32 (FLASH_CTRL , & ctrl );
208+ FlashResult r = flash_read32 (N32_FLASH_CTRL , & ctrl );
204209 if (r != FLASH_OK ) return FLASH_ERR_SWD ;
205210
206- ctrl |= FLASH_CTRL_LOCK ;
207- return flash_write32 (FLASH_CTRL , ctrl );
211+ ctrl |= N32_CTRL_LOCK ;
212+ return flash_write32 (N32_FLASH_CTRL , ctrl );
208213}
209214
210215/**
@@ -218,24 +223,24 @@ static FlashResult flash_lock(void) {
218223 * 5. Clear EOP.
219224 * 6. Check PGERR / WRPERR.
220225 *
221- * @param page_index 0-based page number; must be < FLASH_NV_FIRST_PAGE .
226+ * @param page_index 0-based page number; must be < N32_NV_FIRST_PAGE .
222227 * @return FLASH_OK, FLASH_ERR_ERASE, FLASH_ERR_PROTECTED, FLASH_ERR_SWD,
223228 * or FLASH_ERR_TIMEOUT.
224229 */
225230static FlashResult flash_erase_page (uint32_t page_index ) {
226231 FlashResult r ;
227- uint32_t page_addr = FLASH_ORIGIN + (page_index * FLASH_PAGE_SIZE );
232+ uint32_t page_addr = N32_FLASH_ORIGIN + (page_index * N32_PAGE_SIZE );
228233
229234 /* Step 1: set PER mode */
230- r = flash_write32 (FLASH_CTRL , FLASH_CTRL_PER );
235+ r = flash_write32 (N32_FLASH_CTRL , N32_CTRL_PER );
231236 if (r != FLASH_OK ) return r ;
232237
233238 /* Step 2: write the page address to ADD */
234- r = flash_write32 (FLASH_ADD , page_addr );
239+ r = flash_write32 (N32_FLASH_ADD , page_addr );
235240 if (r != FLASH_OK ) return r ;
236241
237242 /* Step 3: trigger erase */
238- r = flash_write32 (FLASH_CTRL , FLASH_CTRL_PER | FLASH_CTRL_STRT );
243+ r = flash_write32 (N32_FLASH_CTRL , N32_CTRL_PER | N32_CTRL_STRT );
239244 if (r != FLASH_OK ) return r ;
240245
241246 /* Step 4: poll busy */
@@ -269,7 +274,7 @@ static FlashResult flash_write_word(uint32_t flash_addr, uint32_t word) {
269274 FlashResult r ;
270275
271276 /* Step 1: set PG mode */
272- r = flash_write32 (FLASH_CTRL , FLASH_CTRL_PG );
277+ r = flash_write32 (N32_FLASH_CTRL , N32_CTRL_PG );
273278 if (r != FLASH_OK ) return r ;
274279
275280 /* Step 2: write word directly to flash address */
@@ -317,16 +322,16 @@ FlashResult n32_flash_program(
317322 /* ------------------------------------------------------------------
318323 * Parameter validation
319324 * ------------------------------------------------------------------ */
320- if (len == 0 || len > FLASH_MAX_BYTES ) {
325+ if (len == 0 || len > N32_MAX_BYTES ) {
321326 return FLASH_ERR_SIZE ;
322327 }
323328
324329 /* Number of pages that need to be erased to cover 'len' bytes */
325- uint32_t pages_needed = (len + FLASH_PAGE_SIZE - 1 ) / FLASH_PAGE_SIZE ;
330+ uint32_t pages_needed = (len + N32_PAGE_SIZE - 1 ) / N32_PAGE_SIZE ;
326331 /* Clamp to the writable region — the size check above already ensures
327- * pages_needed <= FLASH_MAX_USER_PAGES , but be explicit. */
328- if (pages_needed > FLASH_MAX_USER_PAGES ) {
329- pages_needed = FLASH_MAX_USER_PAGES ;
332+ * pages_needed <= N32_MAX_USER_PAGES , but be explicit. */
333+ if (pages_needed > N32_MAX_USER_PAGES ) {
334+ pages_needed = N32_MAX_USER_PAGES ;
330335 }
331336
332337 /* Number of 32-bit words to write (ceiling division).
@@ -346,7 +351,7 @@ FlashResult n32_flash_program(
346351 /* ------------------------------------------------------------------
347352 * Step 2: Page erase (pages 0 .. pages_needed-1)
348353 * ------------------------------------------------------------------ */
349- uint32_t erase_total = pages_needed * FLASH_PAGE_SIZE ;
354+ uint32_t erase_total = pages_needed * N32_PAGE_SIZE ;
350355
351356 for (uint32_t page = 0 ; page < pages_needed ; page ++ ) {
352357 r = flash_erase_page (page );
@@ -355,14 +360,14 @@ FlashResult n32_flash_program(
355360 return r ;
356361 }
357362 report_progress (cb , cb_ctx , "Erasing" ,
358- (page + 1U ) * FLASH_PAGE_SIZE ,
363+ (page + 1U ) * N32_PAGE_SIZE ,
359364 erase_total );
360365 }
361366
362367 /* ------------------------------------------------------------------
363368 * Step 3: Program words
364369 * ------------------------------------------------------------------ */
365- uint32_t progress_cb_threshold = FLASH_PAGE_SIZE ; /* report every 1 KB */
370+ uint32_t progress_cb_threshold = N32_PAGE_SIZE ; /* report every 1 KB */
366371 uint32_t bytes_since_last_cb = 0 ;
367372
368373 for (uint32_t i = 0 ; i < words_to_write ; i ++ ) {
@@ -377,7 +382,7 @@ FlashResult n32_flash_program(
377382 memcpy (& word , data + byte_offset , copy_bytes );
378383 /* Any remaining bytes in 'word' are already 0 (zero-initialised) */
379384
380- uint32_t flash_addr = FLASH_ORIGIN + byte_offset ;
385+ uint32_t flash_addr = N32_FLASH_ORIGIN + byte_offset ;
381386 r = flash_write_word (flash_addr , word );
382387 if (r != FLASH_OK ) {
383388 flash_lock (); /* best-effort */
@@ -396,7 +401,7 @@ FlashResult n32_flash_program(
396401 report_progress (cb , cb_ctx , "Flashing" , prog_total , prog_total );
397402
398403 /* Clear PG mode before verify reads */
399- r = flash_write32 (FLASH_CTRL , 0UL );
404+ r = flash_write32 (N32_FLASH_CTRL , 0UL );
400405 if (r != FLASH_OK ) {
401406 flash_lock ();
402407 return r ;
@@ -416,7 +421,7 @@ FlashResult n32_flash_program(
416421 uint32_t copy_bytes = (bytes_left >= 4U ) ? 4U : bytes_left ;
417422 memcpy (& expected , data + byte_offset , copy_bytes );
418423
419- uint32_t flash_addr = FLASH_ORIGIN + byte_offset ;
424+ uint32_t flash_addr = N32_FLASH_ORIGIN + byte_offset ;
420425 uint32_t actual = 0 ;
421426 r = flash_read32 (flash_addr , & actual );
422427 if (r != FLASH_OK ) {
0 commit comments