> 文档中心 > GD32片内flash读写数据

GD32片内flash读写数据

        GD32现在越来越火,应用也越来越广泛。我们在开发项目的时候,总会有需要掉电存储一些配置信息的时候,但是使用外挂flash、或者EEPROM,或多或少都会占用一些外围接口或增加一定的成本。于是,直接将配置参数存储到片内flash上还是会更香一些。一般flash的擦写次数能够达到10万次,若擦写操作不太频繁,完全是够用的。

        刚好最近做了个项目,用到了这个功能,掉电存储一些必要的参数配置。在GD32中,Flash模块的名称为FMC。

其实要实现的主要功能就只有三个:读取存在flash中的参数信息、报存参数信息到flash中、获取读出来的参数信息。

        而参数信息可以是自行定义的任意结构体,但是值得注意的是Flash是按页(1Kb)擦除的。需要自行修改FLASH写入的开始地址和结束地址。我这款单片机Flash大小是用的64K的,数据存储在最后1KB的位置。

        由于数据写入以四个直接为单位,所以创建了一个联合体,方便通过指针来将参数数据写入。

注意:以下程序只支持大小小于1KB的参数读写,如果超过1KB,需要加入对页的判断,自行修改数据读、写过程。

程序源码示例:

params_manage.h

#ifndef __PARAMS_MANAGE_H__#define __PARAMS_MANAGE_H__#include #ifdef __cplusplusextern "C"{#endif /* __cplusplus */#define FMC_PAGE_SIZE    ((uint16_t)0x400U)#define FMC_WRITE_START_ADDR    ((uint32_t)0x0800FC00U)#define FMC_WRITE_END_ADDR((uint32_t)0x0800FFFFU)/* 需要保存的参数 */typedef struct _CONFIG_PARAMS{unsigned char data_valid_flag;//数据有效标志  0xF1:有效  其它:无效unsigned char sleep_flag;      //是否进入休眠标志  0:不进入 1:进入unsigned char open_direction;//开门方向   0:左开门 1:右开门int16_t x_value;//地磁X轴方向值int16_t y_value;//地磁Y轴方向值int16_t z_value;//地磁Z轴方向值uint32_t tmp_password_flag;//临时密码使用标志unsigned char user_flag[50];//当前有效用户标记unsigned char password_table[50][7];//用户密码数组}CONFIG_PARAMS;/* 系统状态信息 */typedef struct _SYS_STATUS{unsigned char door_state;//门磁状态    0:关门  1:开门unsigned char auto_anti_lock;//自动反锁配置 0:不自动反锁    1:自动反锁unsigned char quiet_flag;//自动反锁配置 0:音频正常播放  1:部分音频静音unsigned char opto1_state;//光耦1状态unsigned char opto2_state;//光耦2状态unsigned char opto3_state;//光耦3状态float battery_volatage;//电池电压0-5V}SYS_STATUS;typedef union _CONFIG_PARAMS_UNION{CONFIG_PARAMS config_params;  // 360字节uint32_t data[104];//用于通过联合体字节对齐,方便数据存储 104*4=416字节}CONFIG_PARAMS_UNION;extern int load_config_params(void);extern CONFIG_PARAMS *get_config_params(void);extern int is_config_params_avaliable(void);extern int save_config_params(CONFIG_PARAMS *params);#ifdef __cplusplus}#endif /* __cplusplus */#endif

params_manage.c

#include #include #include "gd32e230.h"#include "params_manage.h"static CONFIG_PARAMS g_config_params = {0};static void fmc_erase_pages(void){    /* unlock the flash program/erase controller */    fmc_unlock();    /* clear all pending flags */    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);    /* erase the flash pages */    fmc_page_erase(FMC_WRITE_START_ADDR);fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);    /* lock the main FMC after the erase operation */    fmc_lock();}static void fmc_program(uint32_t *data, int data_len){    /* unlock the flash program/erase controller */    fmc_unlock();    uint32_t address = FMC_WRITE_START_ADDR;    /* 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_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR); data_len-=4;    }    /* lock the main FMC after the program operation */    fmc_lock();}//参数是否有效int is_config_params_avaliable(){return (g_config_params.data_valid_flag == 0xF1)?1:0;}//加载配置参数int load_config_params(){CONFIG_PARAMS_UNION config_params_union;  unsigned char *ptr = (unsigned char *)FMC_WRITE_START_ADDR; //将指针指向存储区首地址if(*ptr == 0xF1){//从Flash中读取到有效的配置数据memcpy(&config_params_union, ptr, sizeof(CONFIG_PARAMS_UNION)); memcpy(&g_config_params, &config_params_union.config_params, sizeof(CONFIG_PARAMS)); //拷贝数据return 0;}return -1;}//获取参数配置CONFIG_PARAMS *get_config_params(){return &g_config_params;}//保存配置参数int save_config_params(CONFIG_PARAMS *params){if(params == NULL)return -1;CONFIG_PARAMS_UNION config_params_union;memset(&config_params_union, 0, sizeof(CONFIG_PARAMS_UNION));//清空数据memcpy(&config_params_union.config_params, params, sizeof(CONFIG_PARAMS)); //拷贝数据//擦除FLASHfmc_erase_pages();//保存配置数据到Flash中fmc_program((uint32_t *)&config_params_union, sizeof(CONFIG_PARAMS_UNION));return 0;}

VR资源云