/** **************************************************************************************************** * @file fm33lg0xx_fl_flash.c * @author FMSH Application Team * @brief Src file of FLASH FL Module **************************************************************************************************** * @attention * * Copyright (c) [2021] [Fudan Microelectronics] * THIS SOFTWARE is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * **************************************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "fm33lg0xx_fl.h" /** @addtogroup FM33LG0XX_FL_Driver * @{ */ /** @addtogroup FLASH * @{ */ #ifdef FL_FLASH_DRIVER_ENABLED /* Private macros ------------------------------------------------------------*/ /** @addtogroup GPIO_FL_Private_Macros * @{ */ #define IS_FLASH_ALL_INSTANCE(INTENCE) (((INTENCE) == FLASH)) #define IS_FL_FLASH_PAGE_NUM(__VALUE__) ((uint32_t)(__VALUE__) < FL_FLASH_MAX_PAGE_NUM) #define IS_FL_FLASH_SECTOR_NUM(__VALUE__) ((uint32_t)(__VALUE__) < FL_FLASH_MAX_SECTOR_NUM) #define IS_FL_FLASH_MAX_ADDR(__VALUE__) ((uint32_t)(__VALUE__) <= FL_FLASH_ADDR_MAXPROGRAM) #define IS_FL_FLASH_MAX_PAGE(__VALUE__) ((uint32_t)(__VALUE__) < FL_FLASH_MAX_PAGE_NUM) #define IS_FL_FLASH_MAX_SECTOR(__VALUE__) ((uint32_t)(__VALUE__) < FL_FLASH_MAX_SECTOR_NUM) /** * @} */ /* Exported functions --------------------------------------------------------*/ /** @addtogroup FLASH_FL_EF_Init * @{ */ /** * @brief Flash 页擦除函数,一个页为512byte. * @param FLASHx FLASH Port * @param address 为需要擦除的页内任意地址,推荐使用页开始的首地址(字对齐) * . * @retval ErrorStatus枚举值 * -FL_FAIL 擦写发生错误 * -FL_PASS 擦写成功 */ FL_ErrorStatus FL_FLASH_PageErase(FLASH_Type *FLASHx, uint32_t address) { uint32_t timeout = 0; uint32_t primask; FL_ErrorStatus ret = FL_PASS; /* 入口参数检查 */ assert_param(IS_FLASH_ALL_INSTANCE(FLASHx)); assert_param(IS_FL_FLASH_MAX_ADDR((uint32_t)address)); /*时钟使能*/ FL_CMU_EnableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); if((address % FL_FLASH_ADDRS_ALIGN) != 0) { /*地址未对齐*/ return FL_FAIL; } if(FL_FLASH_GetFlashLockStatus(FLASHx) == FL_FLASH_KEY_STATUS_ERROR) { /*Flash 已经锁定,复位前无法操作*/ return FL_FAIL; } FL_CMU_EnableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); /*配置擦写类型*/ FL_FLASH_SetFlashEraseType(FLASHx, FL_FLASH_ERASE_TYPE_PAGE); /* 开始擦除页*/ FL_FLASH_EnableErase(FLASHx); /* Key 序列*/ primask = __get_PRIMASK(); __disable_irq(); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_ERASE_KEY); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_PGAE_ERASE_KEY); __set_PRIMASK(primask); FL_FLASH_ClearFlag_EraseComplete(FLASHx); FL_FLASH_ClearFlag_ClockError(FLASHx); FL_FLASH_ClearFlag_AuthenticationError(FLASHx); /* 擦请求 */ *((uint32_t *)address) = FL_FLASH_ERASE_REQUEST; while(1) { timeout++; if((timeout > FL_FLASH_ERASE_TIMEOUT)\ || (FL_FLASH_IsActiveFlag_ClockError(FLASHx))\ || (FL_FLASH_IsActiveFlag_KeyError(FLASHx))\ || (FL_FLASH_IsActiveFlag_AuthenticationError(FLASHx))) { /* 超时或出现错误 */ ret = FL_FAIL; break; } else if(FL_FLASH_IsActiveFlag_EraseComplete(FLASHx)) { /*编程成功*/ FL_FLASH_ClearFlag_EraseComplete(FLASHx); ret = FL_PASS; break; } } FL_FLASH_LockFlash(FLASHx); FL_CMU_DisableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); FL_CMU_DisableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); return ret; } /** * @brief Flash 扇区擦除函数,一个扇区为2k byte. * @param FLASHx FLASH Port * @param address 为需要擦除的扇区内任意地址,推荐使用扇区开始的首地址(字对齐) * . * @retval ErrorStatus枚举值 * -FL_FAIL 擦写发生错误 * -FL_PASS 擦写成功 */ FL_ErrorStatus FL_FLASH_SectorErase(FLASH_Type *FLASHx, uint32_t address) { uint32_t timeout = 0; uint32_t primask; FL_ErrorStatus ret = FL_PASS; /* 入口参数检查 */ assert_param(IS_FLASH_ALL_INSTANCE(FLASHx)); assert_param(IS_FL_FLASH_MAX_ADDR((uint32_t)address)); /*时钟使能*/ FL_CMU_EnableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); if((address % FL_FLASH_ADDRS_ALIGN) != 0) { /*地址未对齐*/ return FL_FAIL; } if(FL_FLASH_GetFlashLockStatus(FLASHx) == FL_FLASH_KEY_STATUS_ERROR) { /*Flash 已经锁定,复位前无法操作*/ return FL_FAIL; } FL_CMU_EnableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); /*配置擦写类型*/ FL_FLASH_SetFlashEraseType(FLASHx, FL_FLASH_ERASE_TYPE_SECTOR); /* 开始擦除扇区*/ FL_FLASH_EnableErase(FLASHx); /* Key 序列*/ primask = __get_PRIMASK(); __disable_irq(); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_ERASE_KEY); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_SECTOR_ERASE_KEY); __set_PRIMASK(primask); FL_FLASH_ClearFlag_EraseComplete(FLASHx); FL_FLASH_ClearFlag_ClockError(FLASHx); FL_FLASH_ClearFlag_AuthenticationError(FLASHx); /* 擦请求 */ *((uint32_t *)address) = FL_FLASH_ERASE_REQUEST; while(1) { timeout++; if((timeout > FL_FLASH_ERASE_TIMEOUT)\ || (FL_FLASH_IsActiveFlag_ClockError(FLASHx))\ || (FL_FLASH_IsActiveFlag_KeyError(FLASHx))\ || (FL_FLASH_IsActiveFlag_AuthenticationError(FLASHx))) { /* 超时或出现错误 */ ret = FL_FAIL; break; } else if(FL_FLASH_IsActiveFlag_EraseComplete(FLASHx)) { /*编程成功*/ FL_FLASH_ClearFlag_EraseComplete(FLASHx); ret = FL_PASS; break; } } FL_FLASH_LockFlash(FLASHx); FL_CMU_DisableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); FL_CMU_DisableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); return ret; } /** * @brief 单次编程函数,编程地址必须对齐到Word边界. * @param FLASHx FLASH Port * @param address 为需要编程的已经擦除过的扇区内任意地址,非对齐地址编程将触发fault。 * * @retval ErrorStatus枚举值 * -FL_FAIL 擦写发生错误 * -FL_PASS 擦写成功 */ FL_ErrorStatus FL_FLASH_Program_Word(FLASH_Type *FLASHx, uint32_t address, uint32_t data) { uint32_t timeout = 0; uint32_t primask; FL_ErrorStatus ret = FL_PASS; /* 入口参数检查 */ assert_param(IS_FLASH_ALL_INSTANCE(FLASHx)); assert_param(IS_FL_FLASH_MAX_ADDR((uint32_t)address)); /*时钟使能*/ FL_CMU_EnableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); if((address % FL_FLASH_ADDRS_ALIGN) != 0) { /*地址未对齐*/ return FL_FAIL; } if(FL_FLASH_GetFlashLockStatus(FLASHx) == FL_FLASH_KEY_STATUS_ERROR) { /*Flash 已经锁定,复位前无法操作*/ return FL_FAIL; } FL_CMU_EnableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); /* 开始编程*/ FL_FLASH_EnableProgram(FLASHx); /* Key 序列*/ primask = __get_PRIMASK(); __disable_irq(); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_PROGRAM_KEY1); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_PROGRAM_KEY2); __set_PRIMASK(primask); FL_FLASH_ClearFlag_ClockError(FLASHx); FL_FLASH_ClearFlag_AuthenticationError(FLASHx); *((uint32_t *)address) = data; while(1) { timeout++; if((timeout > FL_FLASH_ERASE_TIMEOUT)\ || (FL_FLASH_IsActiveFlag_ClockError(FLASHx))\ || (FL_FLASH_IsActiveFlag_KeyError(FLASHx))\ || (FL_FLASH_IsActiveFlag_AuthenticationError(FLASHx))) { /* 超时或出现错误 */ ret = FL_FAIL; break; } else if(FL_FLASH_IsActiveFlag_ProgramComplete(FLASHx)) { /*编程成功*/ FL_FLASH_ClearFlag_ProgramComplete(FLASHx); ret = FL_PASS; break; } } FL_FLASH_LockFlash(FLASHx); FL_CMU_DisableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); FL_CMU_DisableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); return ret; } /** * @brief 页编程函数,编程地址必须对齐到Page边界. * @param FLASHx FLASH Port * @param PageNum 为需要编程的已经擦除过的扇区号,FM33LG04最大为256,非对齐地址编程将触发fault。 * * @retval ErrorStatus枚举值 * -FL_FAIL 擦写发生错误 * -FL_PASS 擦写成功 */ FL_ErrorStatus FL_FLASH_Program_Page(FLASH_Type *FLASHx, uint32_t pageNum, uint32_t *data) { uint32_t count; uint32_t primask; uint32_t address; uint32_t timeout; FL_ErrorStatus ret = FL_PASS; /* 入口参数检查 */ assert_param(IS_FLASH_ALL_INSTANCE(FLASHx)); assert_param(IS_FL_FLASH_MAX_PAGE((uint32_t)pageNum)); address = pageNum * FL_FLASH_PGAE_SIZE_BYTE; /* 页对齐*/ if((address % FL_FLASH_PGAE_SIZE_BYTE) != 0) { /*地址未对齐*/ return FL_FAIL; } FL_CMU_EnableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); FL_CMU_EnableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); FL_FLASH_EnableProgram(FLASHx); /* Key 序列*/ primask = __get_PRIMASK(); __disable_irq(); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_PROGRAM_KEY1); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_PROGRAM_KEY2); __set_PRIMASK(primask); FL_FLASH_ClearFlag_ClockError(FLASHx); FL_FLASH_ClearFlag_AuthenticationError(FLASHx); for(count = 0; count < FL_FLASH_PGAE_SIZE_BYTE; count += 4) { timeout = 0; FL_FLASH_EnableProgram(FLASHx); *((uint32_t *)address) = *data; address += 4; data++; while(1) { timeout++; if((timeout > FL_FLASH_ERASE_TIMEOUT)\ || (FL_FLASH_IsActiveFlag_ClockError(FLASHx))\ || (FL_FLASH_IsActiveFlag_KeyError(FLASHx))\ || (FL_FLASH_IsActiveFlag_AuthenticationError(FLASHx))) { /* 超时或出现错误 */ ret = FL_FAIL; break; } if(FL_FLASH_IsActiveFlag_ProgramComplete(FLASHx)) { /*编程成功*/ FL_FLASH_ClearFlag_ProgramComplete(FLASHx); ret = FL_PASS; break; } } if(ret == FL_FAIL) { break; } } FL_FLASH_LockFlash(FLASHx); FL_CMU_DisableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); FL_CMU_DisableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); return ret; } /** * @brief 扇区编程函数,编程地址必须对齐到Sector边界. * @param FLASHx FLASH Port * @param sectorNum 为需要编程的已经擦除过的扇区号,最大为128,非对齐地址编程将触发fault。 * * @retval ErrorStatus枚举值 * -FL_FAIL 擦写发生错误 * -FL_PASS 擦写成功 */ FL_ErrorStatus FL_FLASH_Program_Sector(FLASH_Type *FLASHx, uint32_t sectorNum, uint32_t *data) { uint32_t count; uint32_t primask; uint32_t address; uint32_t timeout; FL_ErrorStatus ret = FL_PASS; /* 入口参数检查 */ assert_param(IS_FLASH_ALL_INSTANCE(FLASHx)); assert_param(IS_FL_FLASH_MAX_SECTOR((uint32_t)sectorNum)); address = sectorNum * FL_FLASH_SECTOR_SIZE_BYTE; /* Sector对齐*/ if((address % FL_FLASH_SECTOR_SIZE_BYTE) != 0) { /*地址未对齐*/ return FL_FAIL; } FL_CMU_EnableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); FL_CMU_EnableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); FL_FLASH_EnableProgram(FLASHx); /* Key 序列*/ primask = __get_PRIMASK(); __disable_irq(); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_PROGRAM_KEY1); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_PROGRAM_KEY2); __set_PRIMASK(primask); FL_FLASH_ClearFlag_ClockError(FLASHx); FL_FLASH_ClearFlag_AuthenticationError(FLASHx); for(count = 0; count < FL_FLASH_SECTOR_SIZE_BYTE; count += 4) { timeout = 0; FL_FLASH_EnableProgram(FLASHx); *((uint32_t *)address) = *data; address += 4; data++; while(1) { timeout++; if((timeout > FL_FLASH_ERASE_TIMEOUT)\ || (FL_FLASH_IsActiveFlag_ClockError(FLASHx))\ || (FL_FLASH_IsActiveFlag_KeyError(FLASHx))\ || (FL_FLASH_IsActiveFlag_AuthenticationError(FLASHx))) { /* 超时或出现错误 */ ret = FL_FAIL; break; } if(FL_FLASH_IsActiveFlag_ProgramComplete(FLASHx)) { /*编程成功*/ FL_FLASH_ClearFlag_ProgramComplete(FLASHx); ret = FL_PASS; break; } } if(ret == FL_FAIL) { break; } } FL_FLASH_LockFlash(FLASHx); FL_CMU_DisableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); FL_CMU_DisableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); return ret; } /** * @brief DMA编程函数,编程地址必须对齐到half-page,长度固定为64字. * @param FLASHx FLASH Port * @param address 待编程Flash地址 * @param *data 待写入Flash数据 * * @retval ErrorStatus枚举值 * -FL_FAIL 擦写发生错误 * -FL_PASS 擦写成功 */ FL_ErrorStatus FL_FLASH_Write_Dma(FLASH_Type *FLASHx, uint32_t address, uint32_t *data) { FL_ErrorStatus ret = FL_PASS; uint32_t primask; uint32_t timeout; FL_DMA_InitTypeDef DMA_InitStruct = {0}; /* 入口参数检查 */ assert_param(IS_FLASH_ALL_INSTANCE(FLASHx)); assert_param(IS_FL_FLASH_MAX_ADDR(address)); /* 半页对齐*/ if((address % (FL_FLASH_PGAE_SIZE_BYTE / 2)) != 0) { /*地址未对齐*/ return FL_FAIL; } FL_CMU_EnableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); FL_CMU_EnableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); FL_FLASH_EnableProgram(FLASHx); /* Key 序列*/ primask = __get_PRIMASK(); __disable_irq(); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_PROGRAM_KEY1); FL_FLASH_UnlockFlash(FLASHx, FL_FLASH_PROGRAM_KEY2); __set_PRIMASK(primask); FL_FLASH_EnableProgram(FLASHx); DMA_InitStruct.circMode = FL_DISABLE; DMA_InitStruct.direction = FL_DMA_DIR_RAM_TO_FLASH; DMA_InitStruct.memoryAddressIncMode = FL_DMA_CH7_RAM_INC_MODE_INCREASE; DMA_InitStruct.flashAddressIncMode = FL_DMA_CH7_FLASH_INC_MODE_INCREASE; DMA_InitStruct.priority = FL_DMA_PRIORITY_HIGH; FL_DMA_Init(DMA, &DMA_InitStruct, FL_DMA_CHANNEL_7); /* Channel7 Flash 指针地址为(word 地址) */ FL_DMA_WriteFlashAddress(DMA, address >> 2); /* Channel7 RAM 指针地址为(word 地址)*/ FL_DMA_WriteMemoryAddress(DMA, (uint32_t)data >> 2, FL_DMA_CHANNEL_7); FL_DMA_WriteTransmissionSize(DMA, 64 - 1, FL_DMA_CHANNEL_7); FL_DMA_ClearFlag_TransferComplete(DMA, FL_DMA_CHANNEL_7); FL_DMA_EnableChannel(DMA, FL_DMA_CHANNEL_7); timeout = 0; while(1) { timeout++; if(timeout > FL_FLASH_ERASE_TIMEOUT) { ret = FL_FAIL; break; } if(FL_DMA_IsActiveFlag_TransferComplete(DMA, FL_DMA_CHANNEL_7) == FL_SET) { ret = FL_PASS; break; } } FL_FLASH_LockFlash(FLASHx); FL_CMU_DisableGroup3OperationClock(FL_CMU_GROUP3_OPCLK_FLASH); FL_CMU_DisableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_FLASH); return ret; } /** * @brief DMA读取函数,编程地址必须对齐到Word边界. * @param FLASHx FLASH Port * @param address 读取数据Flash地址 * @param *data 读出数据存储区 * @param length 读出数据的字长度 * * @retval ErrorStatus枚举值 * -FL_FAIL 擦写发生错误 * -FL_PASS 擦写成功 */ FL_ErrorStatus FL_FLASH_Read_Dma(FLASH_Type *FLASHx, uint32_t address, uint32_t *data, uint16_t length) { FL_ErrorStatus ret = FL_PASS; uint32_t Timeout; FL_DMA_InitTypeDef DMA_InitStruct = {0}; /* 入口参数检查 */ assert_param(IS_FLASH_ALL_INSTANCE(FLASHx)); assert_param(IS_FL_FLASH_MAX_ADDR(address)); /* 字对齐*/ if((address % FL_FLASH_ADDRS_ALIGN) != 0) { /*地址未对齐*/ return FL_FAIL; } DMA_InitStruct.circMode = FL_DISABLE; DMA_InitStruct.direction = FL_DMA_DIR_FLASH_TO_RAM; DMA_InitStruct.memoryAddressIncMode = FL_DMA_CH7_RAM_INC_MODE_INCREASE; DMA_InitStruct.flashAddressIncMode = FL_DMA_CH7_FLASH_INC_MODE_INCREASE; DMA_InitStruct.priority = FL_DMA_PRIORITY_HIGH; FL_DMA_Init(DMA, &DMA_InitStruct, FL_DMA_CHANNEL_7); /* Channel7 Flash 指针地址为(word 地址) */ FL_DMA_WriteFlashAddress(DMA, address >> 2); /* Channel7 RAM 指针地址为(word 地址)*/ FL_DMA_WriteMemoryAddress(DMA, (uint32_t)data >> 2, FL_DMA_CHANNEL_7); FL_DMA_WriteTransmissionSize(DMA, length - 1, FL_DMA_CHANNEL_7); FL_DMA_ClearFlag_TransferComplete(DMA, FL_DMA_CHANNEL_7); FL_DMA_EnableChannel(DMA, FL_DMA_CHANNEL_7); Timeout = 0; while(1) { Timeout++; if(Timeout > FL_FLASH_ERASE_TIMEOUT) { ret = FL_FAIL; break; } if(FL_DMA_IsActiveFlag_TransferComplete(DMA, FL_DMA_CHANNEL_7) == FL_SET) { ret = FL_PASS; break; } } return ret; } /** * @} */ #endif /* FL_FLASH_DRIVER_ENABLED */ /** * @} */ /** * @} */ /********************** (C) COPYRIGHT Fudan Microelectronics **** END OF FILE ***********************/