/** * @file flash.c * @author xxx * @date 2024-02-07 11:49:34 * @brief * @copyright Copyright (c) 2024 by xxx, All Rights Reserved. * @attention * * ST 的官方驱动 LL 库并没有 flash 驱动。这里自己实现。 * * 1. 由于在 stm32l4xx_ll_system.h 中存在部分 FLASH 操作函数(ACR寄存器的处理)且不全面 * 因此这里需要额外处理(重命名) * * 2. Main memory * (1) FLASH_ACR 完成 * (2) FLASH_PDKEYR 完成 * (3) FLASH_KEYR 完成 * (4) FLASH_OPTKEYR 完成 * (5) FLASH_SR 完成 * (6) FLASH_CR 完成 * (7) FLASH_ECCR 完成 * (8) FLASH_OPTR 未完成 * (9) FLASH_PCROP1SR 未完成 * 后续寄存器 均未完成 * 3. Information block * - System memory * - OTP area * - Option bytes * 4. 根据 HAL 库的实现,相比于与手册的推荐流程,擦写的执行序列还有其他操作。 * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "flash.h" #include "stm32l4xx_ll_rcc.h" #include "stm32l4xx_ll_system.h" #include "stm32l4xx_ll_pwr.h" #ifdef USE_FULL_ASSERT #include "stm32_assert.h" #else #define assert_param(expr) ((void)0U) #endif /* USE_FULL_ASSERT */ #define WHILE_MAX 10000U /** @addtogroup STM32L4xx_LL_Driver * @{ */ /** @addtogroup FLASH_LL * @{ */ /* Private types -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private constants ---------------------------------------------------------*/ /** @addtogroup FLASH_LL_Private_Constants * @{ */ /** * @} */ /* Private macros ------------------------------------------------------------*/ /** @addtogroup FLASH_LL_Private_Macros * @{ */ #define IS_LL_FLASH_WRITE_ADDR(__ADDR__) ((__ADDR__) % LL_FLASH_ALIGNMENT_MIN_SIZE == 0) /** * @} */ /* Private function prototypes -----------------------------------------------*/ /** @defgroup FLASH_LL_Private_Functions FLASH Private functions * @{ */ /** * @} */ /* Exported functions --------------------------------------------------------*/ /** @addtogroup FLASH_LL_Exported_Functions * @{ */ /** * @brief Clear All Error in SR * @param FLASHx FLASH Instance * @retval None */ void LL_FLASH_ClearAllErrorFlag(void) { LL_FLASH_ClearFlag_OPTVERR(FLASH); LL_FLASH_ClearFlag_RDERR(FLASH); LL_FLASH_ClearFlag_FASTERR(FLASH); LL_FLASH_ClearFlag_MISERR(FLASH); LL_FLASH_ClearFlag_PGSERR(FLASH); LL_FLASH_ClearFlag_SIZERR(FLASH); LL_FLASH_ClearFlag_PGAERR(FLASH); LL_FLASH_ClearFlag_WRPERR(FLASH); LL_FLASH_ClearFlag_PROGERR(FLASH); LL_FLASH_ClearFlag_OPERR(FLASH); } /** * @brief Flush the instruction and data caches. * @retval None */ void LL_FLASH_FlushCaches(void) { /* Flush instruction cache */ if (LL_FLASH_IsEnabledInstructionCache(FLASH)) { LL_FLASH_DisableInstructionCache(FLASH); /* Reset instruction cache */ LL_FLASH_InstructionCacheReset(FLASH); /* Enable instruction cache */ LL_FLASH_EnableInstructionCache(FLASH); } /* Flush data cache */ if (LL_FLASH_IsEnabledDataCache(FLASH)) { LL_FLASH_ZCS_DisableDataCache(FLASH); /* Reset data cache */ LL_FLASH_DataCacheReset(FLASH); /* Enable data cache */ LL_FLASH_ZCS_EnableDataCache(FLASH); } } /** * @brief Erase Page * @param pageno Page number * @retval None */ ErrorStatus LL_FLASH_ErasePage(uint32_t pageno) { uint16_t count = 0; /* Check that no Flash memory operation is ongoing by checking the BSY bit */ while (LL_FLASH_IsActiveFlag_BSY(FLASH)) { if (count++ > WHILE_MAX) { return ERROR; } } count = 0; /* Check and clear all error programming flags due to a previous programming. If not, PGSERR is set. */ LL_FLASH_ClearAllErrorFlag(); /* Set the PER bit and select the page you wish to erase (PNB) with the associated bank (BKER) in the Flash control register (FLASH_CR). */ LL_FLASH_EnablePageErase(FLASH); if (pageno >= LL_FLASH_BANK1_PAGE_NUM) { pageno -= LL_FLASH_BANK1_PAGE_NUM; LL_FLASH_SetErasePageBank(FLASH, LL_FLASH_BANK2); } else { LL_FLASH_SetErasePageBank(FLASH, LL_FLASH_BANK1); } LL_FLASH_SetErasePageNo(FLASH, pageno); /* Set the STRT bit in the FLASH_CR register. */ LL_FLASH_EraseStart(FLASH); /* Wait for the BSY bit to be cleared in the FLASH_SR register. */ while (LL_FLASH_IsActiveFlag_BSY(FLASH)) { if (count++ > WHILE_MAX) { return ERROR; } } count = 0; /* 完成只有需要清除擦除标志. */ LL_FLASH_DisablePageErase(FLASH); /* Flush the caches to be sure of the data consistency */ LL_FLASH_FlushCaches(); return SUCCESS; } /** * @brief Erase bank * @param bank This parameter can be one of the following values: * @arg @ref LL_FLASH_BANK1 * @arg @ref LL_FLASH_BANK2 * @retval None */ ErrorStatus LL_FLASH_EraseBank(uint32_t bank) { uint16_t count = 0; /* Check that no Flash memory operation is ongoing by checking the BSY bit */ while (LL_FLASH_IsActiveFlag_BSY(FLASH)) { if (count++ > WHILE_MAX) { return ERROR; } } count = 0; /* Check and clear all error programming flags due to a previous programming. If not, PGSERR is set. */ LL_FLASH_ClearAllErrorFlag(); /* Set the MER1 bit or/and MER2 (depending on the bank) in the Flash control register (FLASH_CR). Both banks can be selected in the same operation. */ if (bank == LL_FLASH_BANK1) { LL_FLASH_EnableBank1Erase(FLASH); } else { LL_FLASH_EnableBank2Erase(FLASH); } /* Set the STRT bit in the FLASH_CR register. */ LL_FLASH_EraseStart(FLASH); /* Wait for the BSY bit to be cleared in the FLASH_SR register. */ while (LL_FLASH_IsActiveFlag_BSY(FLASH)) { if (count++ > WHILE_MAX) { return ERROR; } } count = 0; /* 完成只有需要清除擦除标志. */ LL_FLASH_DisableBank1Erase(FLASH); LL_FLASH_DisableBank2Erase(FLASH); /* Flush the caches to be sure of the data consistency */ LL_FLASH_FlushCaches(); return SUCCESS; } /** * @brief Erase Chip * @param None * @retval None */ ErrorStatus LL_FLASH_EraseChip(void) { uint16_t count = 0; /* Check that no Flash memory operation is ongoing by checking the BSY bit */ while (LL_FLASH_IsActiveFlag_BSY(FLASH)) { if (count++ > WHILE_MAX) { return ERROR; } } count = 0; /* Check and clear all error programming flags due to a previous programming. If not, PGSERR is set. */ LL_FLASH_ClearAllErrorFlag(); /* Set the MER1 bit or/and MER2 (depending on the bank) in the Flash control register (FLASH_CR). Both banks can be selected in the same operation. */ LL_FLASH_EnableBank1Erase(FLASH); LL_FLASH_EnableBank2Erase(FLASH); /* Set the STRT bit in the FLASH_CR register. */ LL_FLASH_EraseStart(FLASH); /* Wait for the BSY bit to be cleared in the FLASH_SR register. */ while (LL_FLASH_IsActiveFlag_BSY(FLASH)) { if (count++ > WHILE_MAX) { return ERROR; } } count = 0; /* 完成只有需要清除擦除标志. */ LL_FLASH_DisableBank1Erase(FLASH); LL_FLASH_DisableBank2Erase(FLASH); /* Flush the caches to be sure of the data consistency */ LL_FLASH_FlushCaches(); return SUCCESS; } /** * @brief Program Double Word * @param address specifies the address to be programmed. * @param data specifies the data to be programmed. * @retval An ErrorStatus enumeration value: * - SUCCESS: Write successfully * - ERROR: error */ ErrorStatus LL_FLASH_ProgramDoubleWord(uint32_t address, uint64_t data) { assert_param(!IS_LL_FLASH_WRITE_ADDR(address)); uint16_t count = 0; /* Check that no Flash memory operation is ongoing by checking the BSY bit */ while (LL_FLASH_IsActiveFlag_BSY(FLASH)) { if (count++ > WHILE_MAX) { return ERROR; } } count = 0; /* Check and clear all error programming flags due to a previous programming. If not, PGSERR is set. */ LL_FLASH_ClearAllErrorFlag(); /* Set the PG bit in the Flash control register (FLASH_CR). */ LL_FLASH_EnableProgram(FLASH); /* Perform the data write operation at the desired memory address, inside main memory block or OTP area. Only double word can be programmed. */ /* Program the double word */ *(__IO uint32_t *)address = (uint32_t)data; *(__IO uint32_t *)(address + 4U) = (uint32_t)(data >> 32); /* Check that no Flash memory operation is ongoing by checking the BSY bit */ while (LL_FLASH_IsActiveFlag_BSY(FLASH)) { if (count++ > WHILE_MAX) { return ERROR; } } count = 0; /* Check that EOP flag is set in the FLASH_SR register (meaning that the programming operation has succeed), and clear it by software. */ if (LL_FLASH_IsActiveFlag_EOP(FLASH)) { LL_FLASH_ClearFlag_EOP(FLASH); } /* Clear the PG bit in the FLASH_CR register if there no more programming request anymore. */ LL_FLASH_DisableProgram(FLASH); /* Flush the caches to be sure of the data consistency */ LL_FLASH_FlushCaches(); return SUCCESS; } /** * @brief Program * @param address specifies the address to be programmed. * @param data specifies the data to be programmed. * @param num specifies the data number * @retval An ErrorStatus enumeration value: * - SUCCESS: Write successfully * - ERROR: error */ ErrorStatus LL_FLASH_Program(uint32_t address, uint8_t data[], uint32_t num) { static uint64_t DataT = 0; uint32_t T = 0, S = 0; uint16_t count = 0; assert_param(!IS_LL_FLASH_WRITE_ADDR(address)); if (num == 0) { return SUCCESS; } /* Check that no Flash memory operation is ongoing by checking the BSY bit */ while (LL_FLASH_IsActiveFlag_BSY(FLASH)) { if (count++ > WHILE_MAX) { return ERROR; } } count = 0; /* Check and clear all error programming flags due to a previous programming. If not, PGSERR is set. */ LL_FLASH_ClearAllErrorFlag(); /* Set the PG bit in the Flash control register (FLASH_CR). */ LL_FLASH_EnableProgram(FLASH); /* Perform the data write operation at the desired memory address, inside main memory block or OTP area. Only double word can be programmed. */ T = num; while (num > 0) { DataT = 0; if (num >= 8) { for (int i = 0; i < LL_FLASH_ALIGNMENT_MIN_SIZE; i++) { DataT = DataT << 8; DataT |= data[S + 7 - i]; } S += LL_FLASH_ALIGNMENT_MIN_SIZE; num -= LL_FLASH_ALIGNMENT_MIN_SIZE; } else { for (int i = 0; i < num; i++) { DataT = DataT << 8; DataT |= data[T - 1 - i]; } num = 0; } /* Program the double word */ *(__IO uint32_t *)address = (uint32_t)DataT; *(__IO uint32_t *)(address + 4U) = (uint32_t)(DataT >> 32); /* Check that no Flash memory operation is ongoing by checking the BSY bit */ while (LL_FLASH_IsActiveFlag_BSY(FLASH)) { if (count++ > WHILE_MAX) { return ERROR; } } count = 0; /* Check that EOP flag is set in the FLASH_SR register (meaning that the programming operation has succeed), and clear it by software. */ if (LL_FLASH_IsActiveFlag_EOP(FLASH)) { LL_FLASH_ClearFlag_EOP(FLASH); } address += LL_FLASH_ALIGNMENT_MIN_SIZE; } /* Clear the PG bit in the FLASH_CR register if there no more programming request anymore. */ LL_FLASH_DisableProgram(FLASH); /* Flush the caches to be sure of the data consistency */ LL_FLASH_FlushCaches(); return SUCCESS; } /** * @} */ /** @addtogroup FLASH_LL_Private_Functions * @{ */ /** * @brief Fast program a row double-word (64-bit) at a specified address. * @param address: specifies the address to be programmed. * @param DataAddress: specifies the address where the data are stored. * @retval None */ void LL_FLASH_ProgramFast(uint32_t address, uint32_t DataAddress) { uint8_t row_index = (2 * LL_FLASH_ROW_SIZE); __IO uint32_t *dest_addr = (__IO uint32_t *)address; __IO uint32_t *src_addr = (__IO uint32_t *)DataAddress; /* Check the parameters */ assert_param(IS_FLASH_MAIN_MEM_ADDRESS(address)); /* Set FSTPG bit */ LL_FLASH_EnableFastProgram(FLASH); /* Disable interrupts to avoid any interruption during the loop */ __disable_irq(); /* Program the double word of the row */ do { *dest_addr = *src_addr; dest_addr++; src_addr++; row_index--; } while (row_index != 0U); /* Re-enable the interrupts */ __enable_irq(); LL_FLASH_DisableFastProgram(FLASH); } /** * @brief Fast program a row double-word (64-bit) at a specified address. * @param address: specifies the address to be programmed. * @param data: specifies the data to be programmed. * @retval None */ ErrorStatus LL_FLASH_Read(uint32_t address, uint8_t data[], uint32_t num) { if (num == 0) { return SUCCESS; } for (uint32_t i = 0; i < num; i++) { data[i] = *(__IO uint8_t *)(address + i); } return SUCCESS; } /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/