5656// Used by CPU2 to prevent CPU1 from writing/erasing data in flash memory.
5757#define SEMID_FLASH_CPU2 (7)
5858
59+ #define SEM_LOCK_SUCCESSFUL (0)
60+ #define SEM_LOCK_BUSY (1)
61+
5962#endif
6063
6164typedef struct {
@@ -242,35 +245,120 @@ int32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *siz
242245 return -1 ;
243246}
244247
248+
249+ #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
250+ static mp_uint_t flash_sync_lock_aquire (void ) {
251+ // Wait for flash interlocks
252+ mp_uint_t atomic_state ;
253+
254+ for (;;) {
255+ // Wait for PES (if it's enabled, no-op if not).
256+ while (LL_FLASH_IsActiveFlag_OperationSuspended ()) {
257+ }
258+
259+ atomic_state = MICROPY_BEGIN_ATOMIC_SECTION ();
260+
261+ // Check the flash hasn't already been locked elsewhere by CPU1
262+ if (LL_HSEM_GetStatus (HSEM , SEMID_FLASH_CPU1 ) == SEM_LOCK_SUCCESSFUL ) {
263+
264+ // Ensure CPU2 isn't already using the flash
265+ if (LL_HSEM_1StepLock (HSEM , SEMID_FLASH_CPU2 ) == SEM_LOCK_SUCCESSFUL ) {
266+ // Got the lock, continue flash operation
267+ break ;
268+ }
269+ // CPU2 Locked, release our semaphore / critical section to try again.
270+ LL_HSEM_ReleaseLock (HSEM , SEMID_FLASH_CPU2 , 0 );
271+ }
272+ MICROPY_END_ATOMIC_SECTION (atomic_state );
273+
274+ MICROPY_EVENT_POLL_HOOK
275+ }
276+ return atomic_state ;
277+ }
278+
279+ static void flash_sync_lock_release (mp_uint_t atomic_state ) {
280+ // Release flash lock.
281+ while (__HAL_FLASH_GET_FLAG (FLASH_FLAG_CFGBSY )) {
282+ }
283+ LL_HSEM_ReleaseLock (HSEM , SEMID_FLASH_CPU2 , 0 );
284+
285+ MICROPY_END_ATOMIC_SECTION (atomic_state );
286+ }
287+
245288int flash_erase (uint32_t flash_dest , uint32_t num_word32 ) {
289+ HAL_StatusTypeDef status = 0 ;
290+
246291 // check there is something to write
247292 if (num_word32 == 0 ) {
248293 return 0 ;
249294 }
250295
251- #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
252296 // Acquire lock on the flash peripheral.
253297 while (LL_HSEM_1StepLock (HSEM , SEMID_FLASH_REGISTERS )) {
254298 }
255- #endif
256299
257300 // Unlock the flash for erase.
258301 HAL_FLASH_Unlock ();
259302
260- #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
261303 // Tell the HCI controller stack we're starting an erase, so it
262304 // avoids radio activity for a while.
263305 rfcore_start_flash_erase ();
264- // Wait for PES.
265- while (LL_FLASH_IsActiveFlag_OperationSuspended ()) {
306+
307+ // On STM32WB only one page shall be erased per semaphore lock
308+ size_t total_pages = (4 * num_word32 + FLASH_PAGE_SIZE - 4 ) / FLASH_PAGE_SIZE ;
309+ for (size_t i = 0 ; i < total_pages && status == 0 ; i ++ ) {
310+ num_word32 = 1024 ; // 1 page
311+
312+ // Wait for flash semaphore locks
313+ mp_uint_t sync_lock = flash_sync_lock_aquire ();
314+
315+ // Clear pending flags (if any) and set up EraseInitStruct.
316+ FLASH_EraseInitTypeDef EraseInitStruct ;
317+ #if defined(STM32WB )
318+ __HAL_FLASH_CLEAR_FLAG (FLASH_FLAG_ALL_ERRORS );
319+ EraseInitStruct .TypeErase = FLASH_TYPEERASE_PAGES ;
320+ EraseInitStruct .Page = get_page (flash_dest );
321+ EraseInitStruct .NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4 ) / FLASH_PAGE_SIZE ;
322+ #else
323+ #error "MICROPY_HW_STM32WB_FLASH_SYNCRONISATION only supported on STM32WB"
324+ #endif
325+
326+ // Erase the sectors.
327+ uint32_t SectorError = 0 ;
328+ status |= HAL_FLASHEx_Erase (& EraseInitStruct , & SectorError );
329+
330+ // Release flash lock.
331+ flash_sync_lock_release (sync_lock );
332+
333+ flash_dest += FLASH_PAGE_SIZE ;
266334 }
267- // Wait for flash lock.
268- while (LL_HSEM_1StepLock (HSEM , SEMID_FLASH_CPU2 )) {
335+
336+ // Tell HCI controller that erase is over.
337+ rfcore_end_flash_erase ();
338+
339+ // Lock the flash after erase.
340+ HAL_FLASH_Lock ();
341+
342+ // Release lock on the flash peripheral.
343+ LL_HSEM_ReleaseLock (HSEM , SEMID_FLASH_REGISTERS , 0 );
344+
345+ return mp_hal_status_to_neg_errno (status );
346+ }
347+
348+ #else // ! MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
349+
350+ int flash_erase (uint32_t flash_dest , uint32_t num_word32 ) {
351+ HAL_StatusTypeDef status = 0 ;
352+
353+ // check there is something to write
354+ if (num_word32 == 0 ) {
355+ return 0 ;
269356 }
270- #endif
271357
272- // Clear pending flags (if any) and set up EraseInitStruct.
358+ // Unlock the flash for erase.
359+ HAL_FLASH_Unlock ();
273360
361+ // Clear pending flags (if any) and set up EraseInitStruct.
274362 FLASH_EraseInitTypeDef EraseInitStruct ;
275363 #if defined(STM32F0 )
276364 __HAL_FLASH_CLEAR_FLAG (FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR );
@@ -333,28 +421,16 @@ int flash_erase(uint32_t flash_dest, uint32_t num_word32) {
333421
334422 // Erase the sectors.
335423 uint32_t SectorError = 0 ;
336- HAL_StatusTypeDef status = HAL_FLASHEx_Erase (& EraseInitStruct , & SectorError );
337-
338- #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
339- // Release flash lock.
340- while (__HAL_FLASH_GET_FLAG (FLASH_FLAG_CFGBSY )) {
341- }
342- LL_HSEM_ReleaseLock (HSEM , SEMID_FLASH_CPU2 , 0 );
343- // Tell HCI controller that erase is over.
344- rfcore_end_flash_erase ();
345- #endif
424+ status = HAL_FLASHEx_Erase (& EraseInitStruct , & SectorError );
346425
347426 // Lock the flash after erase.
348427 HAL_FLASH_Lock ();
349428
350- #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
351- // Release lock on the flash peripheral.
352- LL_HSEM_ReleaseLock (HSEM , SEMID_FLASH_REGISTERS , 0 );
353- #endif
354-
355429 return mp_hal_status_to_neg_errno (status );
356430}
357431
432+ #endif // ! MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
433+
358434/*
359435// erase the sector using an interrupt
360436void flash_erase_it(uint32_t flash_dest, uint32_t num_word32) {
@@ -394,12 +470,6 @@ int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
394470 // Unlock the flash for write.
395471 HAL_FLASH_Unlock ();
396472
397- #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
398- // Wait for PES.
399- while (LL_FLASH_IsActiveFlag_OperationSuspended ()) {
400- }
401- #endif
402-
403473 HAL_StatusTypeDef status = HAL_OK ;
404474
405475 #if defined(STM32G0 ) || defined(STM32G4 ) || defined(STM32L4 ) || defined(STM32WB ) || defined(STM32WL )
@@ -409,18 +479,15 @@ int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
409479 uint64_t val = * (uint64_t * )src ;
410480
411481 #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
412- // Wait for flash lock.
413- while (LL_HSEM_1StepLock (HSEM , SEMID_FLASH_CPU2 )) {
414- }
482+ // Wait for flash interlocks
483+ mp_uint_t sync_lock = flash_sync_lock_aquire ();
415484 #endif
416485
417486 status = HAL_FLASH_Program (FLASH_TYPEPROGRAM_DOUBLEWORD , flash_dest , val );
418487
419488 #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
420489 // Release flash lock.
421- LL_HSEM_ReleaseLock (HSEM , SEMID_FLASH_CPU2 , 0 );
422- while (__HAL_FLASH_GET_FLAG (FLASH_FLAG_CFGBSY )) {
423- }
490+ flash_sync_lock_release (sync_lock );
424491 #endif
425492
426493 if (status != HAL_OK ) {
@@ -435,18 +502,15 @@ int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
435502 val = (val & 0xffffffff00000000uL ) | (* src );
436503
437504 #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
438- // Wait for flash lock.
439- while (LL_HSEM_1StepLock (HSEM , SEMID_FLASH_CPU2 )) {
440- }
505+ // Wait for flash interlocks
506+ mp_uint_t sync_lock = flash_sync_lock_aquire ();
441507 #endif
442508
443509 status = HAL_FLASH_Program (FLASH_TYPEPROGRAM_DOUBLEWORD , flash_dest , val );
444510
445511 #if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
446512 // Release flash lock.
447- LL_HSEM_ReleaseLock (HSEM , SEMID_FLASH_CPU2 , 0 );
448- while (__HAL_FLASH_GET_FLAG (FLASH_FLAG_CFGBSY )) {
449- }
513+ flash_sync_lock_release (sync_lock );
450514 #endif
451515 }
452516
0 commit comments