current_v/Drivers/FM33LG0xx_FL_Driver/Src/fm33lg0xx_fl_flash.c
2025-12-31 08:21:43 +08:00

569 lines
18 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
****************************************************************************************************
* @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 ***********************/