GD32F103RB或STM32读写内部FLASH,实现配置信息和版本号存储
对32内部的Flash进行读写主要分为两种情况:
第一种情况:对存储信息只做读取操作。这种使用可以理解为是只读的,像版本号,或因为硬件不一样做的区分信息,这些信息是只读的,不修改;attribute的方式,bin文件会很大,我没有再仔细研究了。换一种方式 #define App_Ver "AP:t001",直接定义一个宏
第二种情况:存储到flash的信息可以读取、修改,这种使用是为了让设置不至于掉电就清除了,但是设置又会根据客户需求有不一样;
这两种情况是不能同时兼容的,所谓不能同时兼容,是指在一页的地址区间内,不能有这两种情况(例如一页的范围是0到100的地址,把可以修改信息放在0-50地址,把不能修改的地址放到51-100。这种情况是不允许的)。为什么要区分好这两种情况,因为Flash的写入前必须先擦除(Flash默认是FF,只做写0操作),flash的擦除,是按照一页为单位进行操作。
#define FMC_PAGE_SIZE ((uint16_t)0x400U) //代码是GD32F103RB,一页是1k,0x400大小
//------------------------版本信息,属于只读信息,单独一页放置只读信息,
//------------------------
#define VersionAddr ((uint32_t)0x0801FC00U)
const char Software_Ver[12] __attribute__((at(VersionAddr ))) = "AP:0001";
//-------------------------可读可修改的信息放在0x0801F800U页
//-------------------------
#define FMC_WRITE_START_ADDR ((uint32_t)0x0801F800U)
#define FMC_WRITE_END_ADDR ((uint32_t)0x0801FC00U)
typedef struct _flash_data
{
unsigned char data_valid_flag;
unsigned char detectMode;
unsigned char Otp;
unsigned char O_E;
ColorData baseColor1;
unsigned short thr1;
unsigned int tgTime;
signed short boxID;
ColorData baseColor2;
unsigned char chlNum;
unsigned short thr2;
}flash_data;//共19个字节
typedef union _flash_data_union
{
flash_data flashParms;
uint32_t data[6];
}flash_data_union;
flash_data g_flash_params = {0};
//----------------------------------------------------------读操作
signed char load_config_params()
{
unsigned char *ptr = (unsigned char *)FMC_WRITE_START_ADDR;
if(*ptr == FLASHDataOK)
{
//从Flash中读取到有效的配置数据
memcpy(&g_flash_params, ptr, sizeof(flash_data_union));
return 0;
}
return -1;
}
//-----------------------------------------------------------写操作
int save_config_params(flash_data *params)
{
flash_data_union config_params_union;//联合体其实就是flash_data
if(params == NULL) return -1;
memset(&config_params_union, 0, sizeof(flash_data_union)); //清空数据
memcpy(&config_params_union.flashParms, params, sizeof(flash_data)); //拷贝数据
//擦除FLASH
fmc_erase_pages();
//保存配置数据到Flash中
fmc_program((uint32_t *)&config_params_union, sizeof(flash_data));
return 0;
}
void fmc_erase_pages(void)
{
uint32_t erase_counter;
/* unlock the flash program/erase controller */
fmc_unlock();
/* clear all pending flags */
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
/* erase the flash pages */
for(erase_counter = 0; erase_counter < page_num; erase_counter++){
fmc_page_erase(FMC_WRITE_START_ADDR + (FLASH_SECTOR_SIZE * erase_counter));
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
}
/* lock the main FMC after the erase operation */
fmc_lock();
}
static void fmc_program(uint32_t *data, int data_len)
{
uint32_t address = FMC_WRITE_START_ADDR;//配置信息的地址开始写入
/* unlock the flash program/erase controller */
fmc_unlock();
/* program flash */
while(address <= FMC_WRITE_END_ADDR)
{
if(data_len <= 0) break;
fmc_word_program(address, *data);
address += 4U;
data++;
fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR);
data_len-=4;
}
/* lock the main FMC after the program operation */
fmc_lock();
}
作者:外道幻想