历史上的今天
返回首页

历史上的今天

今天是: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

推荐阅读

史海拾趣

Ceramics公司的发展小趣事

“全球陶瓷”公司凭借其卓越的产品质量和国际化战略,成功拓展了海外市场。该公司积极参与国际展览和交流活动,与多国电子企业建立了合作关系。同时,全球陶瓷还针对不同国家和地区的市场需求,推出了定制化的陶瓷电子材料解决方案。这一国际化战略不仅提升了公司的品牌影响力,也为其在全球范围内的业务拓展提供了有力支持。

CST Master Electronic Co Ltd公司的发展小趣事

CST Master Electronic Co Ltd的创始人在一次行业会议上看到了电子技术的巨大潜力,决定投身于这一领域。初创时期,公司面临着资金短缺、人才匮乏和技术壁垒等多重困难。然而,创始人凭借对技术的热情和坚定的信念,带领团队日夜钻研,最终成功研发出一款具有竞争力的电子产品,打开了市场的大门。

AEL [AEL Crystals Ltd]公司的发展小趣事

AEL Crystals一直注重技术创新和产品升级。公司拥有一支专业的研发团队,致力于开发具有竞争力的新产品。通过不断引进新技术和新材料,AEL Crystals成功推出了一系列具有高性能和稳定性的频率控制产品。这些产品不仅满足了客户的多样化需求,也进一步巩固了公司在行业内的领先地位。

Crane Co.公司的发展小趣事

随着公司业务的蓬勃发展,Crane Co.在1880年代经营着四家制造工厂,员工人数超过1500名。公司的业务足迹也逐渐延伸到美国西部地区。为了进一步提升产品质量和技术水平,Crane Co.在1890年代成立了旗下第一家冶金实验室,专注于材料研究和开发。这一举措为公司在电子行业的后续发展提供了强大的技术支持。

APC (APC by Schneider Electric)公司的发展小趣事

随着计算机技术的飞速发展,单一的UPS产品已无法满足市场的多样化需求。为此,APC在1989年推出了突破性的电源管理软件(PowerChute®)。这款软件能够智能地管理UPS设备,提供更为精细的电力保护。紧接着,APC又推出了Smart-UPS®系列UPS产品,该产品以其卓越的性能和稳定性,迅速成为评估所有其它网络UPS产品的标准。

DBM REFLEX公司的发展小趣事

DBM REFLEX深知品质是企业的生命线。因此,公司建立了严格的品质管理体系,从原材料采购到生产过程的每一个环节都进行严格的把控。公司还引进了先进的检测设备和技术,确保每一件产品都符合高品质的标准。这种对品质的执着追求,使DBM REFLEX的产品在市场上赢得了客户的信赖和认可。

问答坊 | AI 解惑

加快电源启动的分流稳压器

在特定应用中,设计要求可能  需要系统的开关模式电源比普通电源能更迅速地提供输出。图 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  & ...…

查看全部问答>

在WINCE5中打开串口错误?

我写了一个串口程序,在模拟器PPC2003上调试是可以的,能正常的打开串口并收发数据,但部署到真机(WINCE5)串口都打不开,代码如下:                 try          &n ...…

查看全部问答>

//---------TCPMP如何指定从哪帧开始播放,播放到哪帧停止--------

TCPMP如何指定从哪帧开始播放,播放到哪帧停止. 在我的项目中,使用的视频文件是AVI格式的,打算用TCPMP实现,要准确的定位播放起始帧与结束帧,并播放从起始帧到结束帧之间的视频段。 跪求高人指点。…

查看全部问答>

用pl2303做了一个USB转串口,电脑检测不到。

用pl2303做了一个USB转串口,可是电脑怎么都检测不到。只有当我将万用表接到17脚和地时,电脑才能检测到。查了好几天了,请各位老师帮我看看。D:\\网址\\44.jpg…

查看全部问答>

做逻辑的难点在于系统结构设计和仿真验证

刚去公司的时候BOSS就和我讲,做逻辑的难点不在于RTL级代码的设计,而在于系统结构设计和仿真验证方面。目前国内对可综合的设计强调的比较多,而对系统结构设计和仿真验证方面似乎还没有什么资料,这或许也从一个侧面反映了国内目前的设计水平还比 ...…

查看全部问答>

新手提问,多多帮忙啊!!

我刚接触到TI公司的2000系列DSP,我装好CCS2000后,启动SetUpCCS2000后,在configurition里我选择的是F2812Device Sumilator,保存后启动CCS,可在打开和新建工程的时候都有问题,具体的时在新建工程的对话框里Target一栏里没有可选项,所以就不能建 ...…

查看全部问答>

zstack的时钟

使用cc2530,timer2是mac timer。某些资料上面说周期是320us。但是不明白函数osalTimeUpdate()里边的操作 tmp = (ticks320us * 8) + remUsTicks; 以及osalTimeUpdate()调用的函数 CONVERT_320US_TO_MS_ELAPSED_REMINDER( tmp, elapsedMSec, r ...…

查看全部问答>

新手求助

想用单片机控制800个灯的亮灭,如何用单片机控制,每个灯都是独立的,有思维的大侠们帮忙给个思路,新手刚接触单片机。小弟在这里膜拜了…

查看全部问答>