历史上的今天
今天是:2024年08月23日(星期五)
2019年08月23日 | 一步一步实现STM32-FOTA系列教程之FLASH静态区读写
2019-08-23 来源:eefocus
前言
在上一篇文章《一步一步实现STM32-FOTA系列教程之STM32-FLASH分区说明》中,对STM32的FLASH进行了人为了分区,分成了 Bootloader分区、主分区、备份分区和静态区四个区域。其中静态区是用来存放系统一些参数信息的,该分区的内容可以通过编程进行读写,如果不人为的破坏该分区,分区里面的信息会一直保存,掉电不丢失,也就是所谓的FLASH模拟EEPROM的功能。
这篇文章就来说说如何在程序中进行FLASH静态区的读写操作,以方便后续的使用。
FLASH静态区使用
我们在FLASH中给静态区分配了32KB大小的空间,即从0x0803 8000 ~ 0x0804 0000 一共 32 * 1024 字节。
对于单片机而言,能够拥有这么大静态区存储空间已经非常大了,当然我们也不能浪费了。但从Bootloder的分区启动选择而言,利用一个字节的空间用来存储启动分区标志位就已经足够了。考虑到在应用程序中还要公用这一块FLASH静态区,我们还是将这块区域进行结构化定义,才能更为方便的使用。
这里,我们就根据自己的项目实际需求,定义一个静态区变量存储的结构体,用于进行参数读写。
#pragma pack(1)
//静态区参数 配置信息
typedef struct STM32_STATIC_FLASH_SAVE
{
char firmware_info[64]; //固件信息
char hardwareversion[32]; //硬件版本
char softwareversion[64]; //软件版本
char device_sn[20]; //设备SN
char device_imei[20]; //设备IMEI
char updateflag; //flash信息更新标志
unsigned int runcounts; //运行次数
char bootinfo[32];//系统启动相关参数信息
}STM32_SFS;
#pragma pack()
定义完成FLASH 静态区参数结构体后,每一次进行的 FLASH 静态区操作,都利用该结构体进行编解码,即可对我们代码中的参数进行实时的读取写入,非常方便。
该结构体中定义的 updateflag 即为系统启动分区标志位,Bootloader 启动之后,读取完静态区FLASH信息,就会判断该标志位的值,如果该标志位为1,则会从主分区启动程序,如果为2,则会从备份分区启动程序,如果为0,则代表主分区和备份分区还没有烧写软件,需要先进行烧写。
STM32-FLASH的编程接口
有关 STM32 中 FLASH 的编程接口,在STM32的库函数中,已经为我们提供了 stm32f10x_flash.c 和 stm32f10x_flash.h 两个 FLASH 操作的库文件,如果要在程序中对FLASH进行操作,需要在工程中引入这两个库文件。
除此之外,原子大哥也将 STM32 FLASH 的读写操作流程编写出来一份C文件,我们在使用的时候,可以直接移植到自己的工程中来 即stmflash.c 和 stmflash.h 两个文件。
为了更为快速的实现Bootloader功能,这里就直接使用这几份 FLASH 操作的函数库来对FLASH进行操作。
FLASH 静态区参数读写实现
首先定义一个 FLASH 静态区参数的全局结构体。
// FLASH 静态区参数信息
STM32_SFS nbdevice_sfs;
然后编写一个获取FLASH静态区参数的函数。
//得到设备信息
void GetDeviceInfo(void)
{
u8 i=0;
STM32_SFS *nbsfs = &nbdevice_sfs;
memset(&nbdevice_sfs,0,sizeof(STM32_SFS));
printf("Static Params Address :0x%08Xrn",CONFIG_PARAM_START_ADDR);
//STMFLASH_Read(CONFIG_PARAM_ADDR, &buf, 1);
STMFLASH_Read(CONFIG_PARAM_START_ADDR, (u16*)&nbdevice_sfs, sizeof(STM32_SFS));
//静态区没有初始化
if(NULL==strstr(nbdevice_sfs.firmware_info,"NBIOT_SMART_STREET_V2.0"))
{
printf("static flash not initrn");
printf("start to init flashrn");
memset(&nbdevice_sfs,0,sizeof(STM32_SFS));
STMFLASH_Write(CONFIG_PARAM_START_ADDR,(u16*)&nbdevice_sfs,sizeof(STM32_SFS));
}
memset(&nbdevice_sfs,0,sizeof(STM32_SFS));
STMFLASH_Read(CONFIG_PARAM_START_ADDR, (u16*)&nbdevice_sfs, sizeof(STM32_SFS));
if(nbdevice_sfs.updateflag ==0)
{
sprintf(nbsfs->firmware_info,"%s","NBIOT_SMART_STREET_V2.0");
nbdevice_sfs.updateflag = 1;
printf("please upload firmware to stm32rn");
STMFLASH_Write(CONFIG_PARAM_START_ADDR, (u16*)&nbdevice_sfs, sizeof(STM32_SFS));
}
else if(nbdevice_sfs.updateflag ==1)
{
bootflag=nbdevice_sfs.updateflag;
printf("start to boot firmware onern");
printf("Testing...rn");
printf("set updateflag 2rn");
nbdevice_sfs.updateflag = 2;
STMFLASH_Write(CONFIG_PARAM_START_ADDR, (u16*)&nbdevice_sfs, sizeof(STM32_SFS));
}
else if(nbdevice_sfs.updateflag ==2)
{
bootflag=nbdevice_sfs.updateflag;
printf("start to boot firmware tworn");
printf("Testing...rn");
printf("set updateflag 1rn");
nbdevice_sfs.updateflag = 1;
STMFLASH_Write(CONFIG_PARAM_START_ADDR, (u16*)&nbdevice_sfs, sizeof(STM32_SFS));
}
}
该函数实现非常简单,就是读取FLASH静态区信息,然后判断程序启动分区标志位,如果启动分区标志位为1,则将其改写为2,如果为2,怎将其改写为1,如果为0,则打印出下载固件的提示信息,如此以来,该函数能够实现两个分区的程序交替运行。
主函数实现
int main()
{
ledInit();
uart1_init(9600);
delay_init();
printf("-----------------------------------rn");
printf("------------Bootloader-------------rn");
printf("-----------------------------------rn");
LOG_COMPILE();
printf("Version: V1.0rn");
LED0_Blink(100);
GetDeviceInfo();
}
日志打印
这里我重启了3次,分别打印出来3次 bootloader 的打印信息,请参考。
-----------------------------------
------------Bootloader-------------
-----------------------------------
Compile Time: Nov 13 2018,11:37:15
Version: V1.0
Static Params Address :0x08038000
static flash not init
start to init flash
please upload firmware to stm32
-----------------------------------
------------Bootloader-------------
-----------------------------------
Compile Time: Nov 13 2018,11:37:15
Version: V1.0
Static Params Address :0x08038000
start to boot firmware one
Testing...
set updateflag 2
-----------------------------------
------------Bootloader-------------
-----------------------------------
Compile Time: Nov 13 2018,11:37:15
Version: V1.0
Static Params Address :0x08038000
start to boot firmware two
Testing...
set updateflag 1
史海拾趣
|
在特定应用中,设计要求可能 需要系统的开关模式电源比普通电源能更迅速地提供输出。图 1 显示了这种电源的自举(或称启动)电路。在开关模式电源的 PFC(功率因数校正)预稳压器中,电路的 PWM(脉宽调制器),即 IC1,从辅助绕组 L1 ...… 查看全部问答> |
|
ARM9 2440读取SHT11失败,全是0XFF,原因会有哪些呢? ARM9 2440读取SHT11失败,全是0XFF;2440发送命令后,在第九个时钟没有检测到ACK信号。 硬件上应该是没有问题的,同一个传感器在其他处理器平台上正常运行。 软件上哪些地方容易出问题? 现在打算从头开始检查,我怎么样来测SHT11已经对处理器的 ...… 查看全部问答> |
|
STACK SEGMENT STACK DB 1024 DUP(0) STACK ENDS DATA SEGMENT TABF DW 262,350,352,350,441,393,350,393,441 DW & ...… 查看全部问答> |
|
我写了一个串口程序,在模拟器PPC2003上调试是可以的,能正常的打开串口并收发数据,但部署到真机(WINCE5)串口都打不开,代码如下: try &n ...… 查看全部问答> |
|
//---------TCPMP如何指定从哪帧开始播放,播放到哪帧停止-------- TCPMP如何指定从哪帧开始播放,播放到哪帧停止. 在我的项目中,使用的视频文件是AVI格式的,打算用TCPMP实现,要准确的定位播放起始帧与结束帧,并播放从起始帧到结束帧之间的视频段。 跪求高人指点。… 查看全部问答> |
|
用pl2303做了一个USB转串口,可是电脑怎么都检测不到。只有当我将万用表接到17脚和地时,电脑才能检测到。查了好几天了,请各位老师帮我看看。D:\\网址\\44.jpg… 查看全部问答> |
|
刚去公司的时候BOSS就和我讲,做逻辑的难点不在于RTL级代码的设计,而在于系统结构设计和仿真验证方面。目前国内对可综合的设计强调的比较多,而对系统结构设计和仿真验证方面似乎还没有什么资料,这或许也从一个侧面反映了国内目前的设计水平还比 ...… 查看全部问答> |
|
我刚接触到TI公司的2000系列DSP,我装好CCS2000后,启动SetUpCCS2000后,在configurition里我选择的是F2812Device Sumilator,保存后启动CCS,可在打开和新建工程的时候都有问题,具体的时在新建工程的对话框里Target一栏里没有可选项,所以就不能建 ...… 查看全部问答> |




