国民技术N32G031系列Flash数据存储

编程入门 行业动态 更新时间:2024-10-19 10:20:31

国民技术N32G031系列Flash<a href=https://www.elefans.com/category/jswz/34/1770253.html style=数据存储"/>

国民技术N32G031系列Flash数据存储

最近在做一个电源项目软件,客户要求能够在掉电后保存一些数据,重新上电后能加载这些数据。数据内容只有一个字节,但每次写入时是4个字节。

具体的内容如下:

电源带有4路输出,上位机通过RS485能够控制这4路的通断,1:导通,0:断开,当上位机执行一次导通或关断操作时都要保存输出状态到Flash,如果相同的操作执行多次则只保存一次,例如:多次发送导通操作被视为是导通一次操作。

具体思路如下:

1、由于N32G031系列没有EEPROM,也没有其他外部存储器,只能使用ROM的一部分。N32G031总共有64K字节ROM,运行的程序只有十多K,空间还有很多;

2、使用片内Flash的一页来动态存储数据。Flash每页有512个字节,每4个字节写一次,则一页可以写入128次,整页写完,继续再写时才擦除页,重新从页的起始位置写入数据,如此反复,这样可以大大减小Flash页的擦除次数;

3、初始时从Flash页的指定位置读取数据(位置根据计算得到,就是找到第一个连续4个0xFF的位置),并存储在两个变量中A和B中,此时A和B中保存的数据是相同的,运行时如果上位机执行了导通和断开操作会改变B变量相关成员值,当while大循环检测到A和B的值不同时,则用B的值设置A变量,并根据计算的地址写入Flash页中。

程序主要代码如下:

结构体和联合体定义

struct STRUCT_OUTPUT_STATE{unsigned P1		:1;unsigned P2		:1;unsigned P3		:1;unsigned P4		:1;unsigned AUX	:1;unsigned 		:1;unsigned 		:1;unsigned 		:1;
};//used to save states of all the four channels
union OUTPUT_UNION{struct STRUCT_OUTPUT_STATE port_state;uint8_t allbits;//uint8_t P1;//uint8_t P2;//uint8_t P3;//uint8_t P4;//uint32_t allbits;
};typedef union OUTPUT_UNION Output_State;

结构体STRUCT_OUTPUT_STATE的成员P1-P4分别保存1-4路输出状态,AUX成员默认设置为0,是个辅助标志位,用于区别当所有输出都打开时(P1-P4都为1)和从Flash读取的连续4字节都是0xFF的情况。

主程序初始时读取逻辑:

page_offset = Find_Empty_Data();if(page_offset <= 128){if(page_offset > 0){_OutputState_Old.allbits = (*(__IO uint32_t*)(FLASH_WRITE_START_ADDR + (page_offset - 1) * 4));//get the status_OutputState_New.allbits = _OutputState_Old.allbits;_OutputState_Old.port_state.AUX = 0;_OutputState_New.port_state.AUX = 0;}else{_OutputState_Old.allbits = (*(__IO uint32_t*)(FLASH_WRITE_START_ADDR));//get the status_OutputState_New.allbits = _OutputState_Old.allbits;_OutputState_Old.port_state.AUX = 0;_OutputState_New.port_state.AUX = 0;}}else //can't find the address that contains the valid data{_OutputState_Old.allbits = (*(__IO uint32_t*)(FLASH_WRITE_START_ADDR));//get the status_OutputState_New.allbits = _OutputState_Old.allbits;_OutputState_Old.port_state.AUX = 0;_OutputState_New.port_state.AUX = 0;}

两个全局变量及Flash页起始地址定义如下:

//Flash information
#define 	FLASH_PAGE_SIZE        ((uint16_t)0x200)
#define 	FLASH_WRITE_START_ADDR ((uint32_t)0x08008000)
#define 	FLASH_WRITE_END_ADDR   ((uint32_t)0x08010000)volatile	Output_State _OutputState_Old;
volatile	Output_State _OutputState_New;
//uint32_t 	flash_rw_delay = 0;
volatile	uint16_t off_set = 0;

Find_Empty_Data函数用于查找Flash页中连续4字节都为0xFF的位置,也就是我们下一个要写入数据的位置。函数如下:

/**
*@name: Find_Empty_Data
*@description: Find the location that has not been written.The reason why we do this is because we need to avoid erasing flash.
*@params: none
*@return: none
*/
uint16_t Find_Empty_Data(void)
{uint16_t page_offset;for (page_offset = 0; page_offset < 128;/*(FLASH_PAGE_SIZE/4)*/ page_offset++){if (*((uint32_t*)FLASH_WRITE_START_ADDR + page_offset) == 0xFFFFFFFF) break;}return page_offset;
}

当变量A和B的值不同时,执行以下代码,将更新后的数据写入Flash页中指定位置:

/**
*@name: Save_Output_State
*@description: If any of the output state has been changed, we write the new value to the flash.
*@params: none
*@return: none
*/
void Save_Output_State(void)
{if(_OutputState_Old.allbits != _OutputState_New.allbits){uint32_t write_addr = 0;off_set = Find_Empty_Data();		FLASH_Unlock();//if(off_set>=127 && buf32 != 0xFFFFFFFF)//the last four bytes of the current pageif(off_set <= 127){			write_addr = FLASH_WRITE_START_ADDR + off_set * 4;}else	//We can't find the four bytes that are all 0xFF, which means the whole page is programmed.{//Eraseif(FLASH_COMPL != FLASH_EraseOnePage(FLASH_WRITE_START_ADDR)){//TODO}write_addr = FLASH_WRITE_START_ADDR;}//flash_rw_delay = 480000;//about 10ms if FOSC = 48MHz_OutputState_Old.allbits = _OutputState_New.allbits;//Programif (FLASH_COMPL != FLASH_ProgramWord(write_addr, _OutputState_New.allbits)){//TODO}		/* Locks the FLASH Program Erase Controller */FLASH_Lock();//GPIO_WriteBit(GPIOF, GPIO_PIN_7, (Bit_OperateType)(1 - GPIO_ReadOutputDataBit(GPIOF, GPIO_PIN_7)));}
}

这样从理论上可以支持输出状态1280万次以上的更改(Flash擦除次数以10万次计算),可以大大减少Flash页擦除的次数,延长Flash使用寿命。客户那边也说过,用上位机导通和断开输出的次数不会很频繁,所以是够用的。

之前也考虑过连续高频率执行导通和关断操作的问题,例如:如果在一段时间内连续导通和关断很多次则忽略这次操作,等稳定后才执行写入操作,后经客户沟通不用担心这个问题,所以也没有写入这个机制了。

欢迎大家发表你们的看法,还有什么更好的方案大家一起分享。

更多推荐

国民技术N32G031系列Flash数据存储

本文发布于:2023-11-17 03:11:14,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1637198.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:数据存储   国民   系列   技术   Flash

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!