Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Flipper-Zero/STM32CubeWB.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Projects/NUCLEO-WB15CC/Applications/BLE/BLE_Ota/Core/Src/flash_driver.c')
-rw-r--r--Projects/NUCLEO-WB15CC/Applications/BLE/BLE_Ota/Core/Src/flash_driver.c322
1 files changed, 322 insertions, 0 deletions
diff --git a/Projects/NUCLEO-WB15CC/Applications/BLE/BLE_Ota/Core/Src/flash_driver.c b/Projects/NUCLEO-WB15CC/Applications/BLE/BLE_Ota/Core/Src/flash_driver.c
new file mode 100644
index 000000000..dcd415b18
--- /dev/null
+++ b/Projects/NUCLEO-WB15CC/Applications/BLE/BLE_Ota/Core/Src/flash_driver.c
@@ -0,0 +1,322 @@
+/**
+ ******************************************************************************
+ * File Name : flash_driver.c
+ * Description : Dual core Flash driver
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+ * All rights reserved.</center></h2>
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "app_common.h"
+
+#include "flash_driver.h"
+#include "shci.h"
+#include "utilities_conf.h"
+
+/* Private typedef -----------------------------------------------------------*/
+typedef enum
+{
+ SEM_LOCK_SUCCESSFUL,
+ SEM_LOCK_BUSY,
+}SemStatus_t;
+
+typedef enum
+{
+ FLASH_ERASE,
+ FLASH_WRITE,
+}FlashOperationType_t;
+
+/* Private defines -----------------------------------------------------------*/
+/* Private macros ------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/* Global variables ----------------------------------------------------------*/
+/* Private function prototypes -----------------------------------------------*/
+static SingleFlashOperationStatus_t ProcessSingleFlashOperation(FlashOperationType_t FlashOperationType,
+ uint32_t SectorNumberOrDestAddress,
+ uint64_t Data);
+/* Public functions ----------------------------------------------------------*/
+uint32_t FD_EraseSectors(uint32_t FirstSector, uint32_t NbrOfSectors)
+{
+ uint32_t loop_flash;
+ uint32_t return_value;
+ SingleFlashOperationStatus_t single_flash_operation_status;
+
+ single_flash_operation_status = SINGLE_FLASH_OPERATION_DONE;
+
+ /**
+ * Take the semaphore to take ownership of the Flash IP
+ */
+ while(LL_HSEM_1StepLock(HSEM, CFG_HW_FLASH_SEMID));
+
+ HAL_FLASH_Unlock();
+
+ /**
+ * Notify the CPU2 that some flash erase activity may be executed
+ * On reception of this command, the CPU2 enables the BLE timing protection versus flash erase processing
+ * The Erase flash activity will be executed only when the BLE RF is idle for at least 25ms
+ * The CPU2 will prevent all flash activity (write or erase) in all cases when the BL RF Idle is shorter than 25ms.
+ */
+ SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON);
+
+ for(loop_flash = 0; (loop_flash < NbrOfSectors) && (single_flash_operation_status == SINGLE_FLASH_OPERATION_DONE) ; loop_flash++)
+ {
+ single_flash_operation_status = FD_EraseSingleSector(FirstSector+loop_flash);
+ }
+
+ if(single_flash_operation_status != SINGLE_FLASH_OPERATION_DONE)
+ {
+ return_value = NbrOfSectors - loop_flash + 1;
+ }
+ else
+ {
+ /**
+ * Notify the CPU2 there will be no request anymore to erase the flash
+ * On reception of this command, the CPU2 disables the BLE timing protection versus flash erase processing
+ */
+ SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF);
+
+ HAL_FLASH_Lock();
+
+ /**
+ * Release the ownership of the Flash IP
+ */
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_FLASH_SEMID, 0);
+
+ return_value = 0;
+ }
+
+ return return_value;
+}
+
+uint32_t FD_WriteData(uint32_t DestAddress, uint64_t * pSrcBuffer, uint32_t NbrOfData)
+{
+ uint32_t loop_flash;
+ uint32_t return_value;
+ SingleFlashOperationStatus_t single_flash_operation_status;
+
+ single_flash_operation_status = SINGLE_FLASH_OPERATION_DONE;
+
+ /**
+ * Take the semaphore to take ownership of the Flash IP
+ */
+ while(LL_HSEM_1StepLock(HSEM, CFG_HW_FLASH_SEMID));
+
+ HAL_FLASH_Unlock();
+
+ for(loop_flash = 0; (loop_flash < NbrOfData) && (single_flash_operation_status == SINGLE_FLASH_OPERATION_DONE) ; loop_flash++)
+ {
+ single_flash_operation_status = FD_WriteSingleData(DestAddress+(8*loop_flash), *(pSrcBuffer+loop_flash));
+ }
+
+ if(single_flash_operation_status != SINGLE_FLASH_OPERATION_DONE)
+ {
+ return_value = NbrOfData - loop_flash + 1;
+ }
+ else
+ {
+ HAL_FLASH_Lock();
+
+ /**
+ * Release the ownership of the Flash IP
+ */
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_FLASH_SEMID, 0);
+
+ return_value = 0;
+ }
+
+ return return_value;
+}
+
+SingleFlashOperationStatus_t FD_EraseSingleSector(uint32_t SectorNumber)
+{
+ SingleFlashOperationStatus_t return_value;
+
+ /* The last parameter is unused in that case and set to 0 */
+ return_value = ProcessSingleFlashOperation(FLASH_ERASE, SectorNumber, 0);
+
+ return return_value;
+}
+
+SingleFlashOperationStatus_t FD_WriteSingleData(uint32_t DestAddress, uint64_t Data)
+{
+ SingleFlashOperationStatus_t return_value;
+
+ return_value = ProcessSingleFlashOperation(FLASH_WRITE, DestAddress, Data);
+
+ return return_value;
+}
+
+/*************************************************************
+ *
+ * LOCAL FUNCTIONS
+ *
+ *************************************************************/
+static SingleFlashOperationStatus_t ProcessSingleFlashOperation(FlashOperationType_t FlashOperationType,
+ uint32_t SectorNumberOrDestAddress,
+ uint64_t Data)
+{
+ SemStatus_t cpu1_sem_status;
+ SemStatus_t cpu2_sem_status;
+ WaitedSemStatus_t waited_sem_status;
+ SingleFlashOperationStatus_t return_status;
+
+ uint32_t page_error;
+ FLASH_EraseInitTypeDef p_erase_init;
+
+ waited_sem_status = WAITED_SEM_FREE;
+
+ p_erase_init.TypeErase = FLASH_TYPEERASE_PAGES;
+ p_erase_init.NbPages = 1;
+ p_erase_init.Page = SectorNumberOrDestAddress;
+
+ do
+ {
+ /**
+ * When the PESD bit mechanism is used by CPU2 to protect its timing, the PESD bit should be polled here.
+ * If the PESD is set, the CPU1 will be stalled when reading literals from an ISR that may occur after
+ * the flash processing has been requested but suspended due to the PESD bit.
+ *
+ * Note: This code is required only when the PESD mechanism is used to protect the CPU2 timing.
+ * However, keeping that code make it compatible with the two mechanisms.
+ */
+ while(LL_FLASH_IsActiveFlag_OperationSuspended());
+
+ UTILS_ENTER_CRITICAL_SECTION();
+
+ /**
+ * Depending on the application implementation, in case a multitasking is possible with an OS,
+ * it should be checked here if another task in the application disallowed flash processing to protect
+ * some latency in critical code execution
+ * When flash processing is ongoing, the CPU cannot access the flash anymore.
+ * Trying to access the flash during that time stalls the CPU.
+ * The only way for CPU1 to disallow flash processing is to take CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID.
+ */
+ cpu1_sem_status = (SemStatus_t)LL_HSEM_GetStatus(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID);
+ if(cpu1_sem_status == SEM_LOCK_SUCCESSFUL)
+ {
+ /**
+ * Check now if the CPU2 disallows flash processing to protect its timing.
+ * If the semaphore is locked, the CPU2 does not allow flash processing
+ *
+ * Note: By default, the CPU2 uses the PESD mechanism to protect its timing,
+ * therefore, it is useless to get/release the semaphore.
+ *
+ * However, keeping that code make it compatible with the two mechanisms.
+ * The protection by semaphore is enabled on CPU2 side with the command SHCI_C2_SetFlashActivityControl()
+ *
+ */
+ cpu2_sem_status = (SemStatus_t)LL_HSEM_1StepLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID);
+ if(cpu2_sem_status == SEM_LOCK_SUCCESSFUL)
+ {
+ /**
+ * When CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID is taken, it is allowed to only erase one sector or
+ * write one single 64bits data
+ * When either several sectors need to be erased or several 64bits data need to be written,
+ * the application shall first exit from the critical section and try again.
+ */
+ if(FlashOperationType == FLASH_ERASE)
+ {
+ HAL_FLASHEx_Erase(&p_erase_init, &page_error);
+ }
+ else
+ {
+ HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, SectorNumberOrDestAddress, Data);
+ }
+ /**
+ * Release the semaphore to give the opportunity to CPU2 to protect its timing versus the next flash operation
+ * by taking this semaphore.
+ * Note that the CPU2 is polling on this semaphore so CPU1 shall release it as fast as possible.
+ * This is why this code is protected by a critical section.
+ */
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, 0);
+ }
+ }
+
+ UTILS_EXIT_CRITICAL_SECTION();
+
+ if(cpu1_sem_status != SEM_LOCK_SUCCESSFUL)
+ {
+ /**
+ * To avoid looping in ProcessSingleFlashOperation(), FD_WaitForSemAvailable() should implement a mechanism to
+ * continue only when CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID is free
+ */
+ waited_sem_status = FD_WaitForSemAvailable(WAIT_FOR_SEM_BLOCK_FLASH_REQ_BY_CPU1);
+ }
+ else if(cpu2_sem_status != SEM_LOCK_SUCCESSFUL)
+ {
+ /**
+ * To avoid looping in ProcessSingleFlashOperation(), FD_WaitForSemAvailable() should implement a mechanism to
+ * continue only when CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID is free
+ */
+ waited_sem_status = FD_WaitForSemAvailable(WAIT_FOR_SEM_BLOCK_FLASH_REQ_BY_CPU2);
+ }
+ }
+ while( ((cpu2_sem_status != SEM_LOCK_SUCCESSFUL) || (cpu1_sem_status != SEM_LOCK_SUCCESSFUL))
+ && (waited_sem_status != WAITED_SEM_BUSY) );
+
+ /**
+ * In most BLE application, the flash should not be blocked by the CPU2 longer than FLASH_TIMEOUT_VALUE (1000ms)
+ * However, it could be that for some marginal application, this time is longer.
+ * In that case either HAL_FLASHEx_Erase() or HAL_FLASH_Program() will exit with FLASH_TIMEOUT_VALUE value.
+ * This is not a failing case and there is no other way than waiting the operation to be completed.
+ * If for any reason this test is never passed, this means there is a failure in the system and there is no other
+ * way to recover than applying a device reset.
+ *
+ * Note: This code is required only when the PESD mechanism is used to protect the CPU2 timing.
+ * However, keeping that code make it compatible with the two mechanisms.
+ */
+ while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_CFGBSY));
+
+ if(waited_sem_status != WAITED_SEM_BUSY)
+ {
+ /**
+ * The flash processing has been done. It has not been checked whether it has been successful or not.
+ * The only commitment is that it is possible to request a new flash processing
+ */
+ return_status = SINGLE_FLASH_OPERATION_DONE;
+ }
+ else
+ {
+ /**
+ * The flash processing has not been executed due to timing protection from either the CPU1 or the CPU2.
+ * This status is reported up to the user that should retry after checking that each CPU do not
+ * protect its timing anymore.
+ */
+ return_status = SINGLE_FLASH_OPERATION_NOT_EXECUTED;
+ }
+
+ return return_status;
+}
+
+/*************************************************************
+ *
+ * WEAK FUNCTIONS
+ *
+ *************************************************************/
+__WEAK WaitedSemStatus_t FD_WaitForSemAvailable(WaitedSemId_t WaitedSemId)
+{
+ /**
+ * The timing protection is enabled by either CPU1 or CPU2. It should be decided here if the driver shall
+ * keep trying to erase/write the flash until successful or if it shall exit ans report to the user that the action
+ * has not been executed.
+ * WAITED_SEM_BUSY returns to the user
+ * WAITED_SEM_FREE keep looping in the driver until the action is executed. This will result in the current tack looping
+ * until this is done. In a bare metal implementation, only the code within interrupt handler can be executed. With an OS,
+ * only task with higher priority can be processed
+ *
+ */
+ return WAITED_SEM_BUSY;
+}
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/