STM32F4,Flash,ROM,RAM,IAP升级,ISP下载

1、STM32F405RGT6芯片结构

ARM Cortex-M4 MCU,具有1 MB Flash、168 MHz CPU和ART加速器
数据手册下载链接:
https://www.st.com/resource/en/datasheet/stm32f405rg.pdf
官方链接:
https://www.st.com/zh/microcontrollers-microprocessors/stm32f405rg.html#tools-software

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G9LeEZ4i-1681536764176)(null#pic_center)]

2、Flash

stm32f405内部flah是1M(1024K)大小,其结构划分如图所示:
在这里插入图片描述

STM32F4 的闪存模块由:主存储器、系统存储器、 OPT 区域和选项字节等 4 部分组成:
主存储器:该部分用来存放代码和数据常数(如 const 类型的数据),分为 12 个大小不同的扇区,主存储器的起始地址是 0X08000000。

系统存储器:这个区主要用来存放 STM32F4 的 bootloader 代码,此代码是出厂的时候就固化在芯片内部了,比例用串口下载程序时的bootload(ISP下载)。

OTP 区域:即一次性可编程区域,一次性的,写完一次,永远不能擦除。

选项字节:用于配置读保护、 BOR 级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位,相当于一些寄存器位。

在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。所以在写的时候有必要写FLASH_DataCacheCmd(DISABLE);来禁止数据缓存,写完后再打开。

flash擦除后每个地址块的数据是0xff,擦除就是将地址内的数据转变为0xff,写入数据就是将有关位置0;

3、RAM, ROM

这里所说的内存,是指RAM,RAM包括SRAM,DRAM等。
这里所说的flash,指的是用作为ROM的存储器,保存代码与常量数据。

栈的生长方向:指的是入栈方向,从高地址向低地址生长叫做向下生长,或逆向生长;反过来就叫向上生长,或正向生长。STM32的栈是向下生长。

(1)栈区(stack):由编译器自动分配和释放,存放函数的参数与返回值、局部变量等,其操作方式类似于数据结构中的栈。
(2)堆区(heap):由程序员分配管理。
(3)全局区与静态区(data):存储全局变量和静态变量,其中初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
(4)文字常量区 [constdata(常量)]:常量字符串存放。
(5)程序代码区 [main()]:存放程序代码。

0X20000000是RAM开始地址。可以看到各段的分布。从低地址到高地址,分别为:data段,bss段,heap段,stack段。包含对应上面所说的(1)(2)(3)。

0X08000000是ROM(flash)开始地址。可以看到constdata(常量),和函数代码,对应上面的(4)(5);

其中,data指的是初始化不为0的全局或静态(static)变量。bss指的是没有初始化,或者初始化为0的全局或静态变量。

全局与静态变量的初始值,是需要保存下来,其基本可以分为三大类,一种是等于0的,一种是不等于0,还有一种是没有初始值的。
这些都是需要记录下来保存在镜像文件里面,再烧录到单片机的flash里(当然非要写到ram也可以)。为了节省空间,就把等于0的变量和没有初始值的变量归为一类,都当做初始值等于0的变量处理。因为这些变量的初始值都为0,所以记录也方便,节省不少空间。比如定义一个500字节的全局数组,要是初始值已经定义,那么镜像文件也需要相应大小的空间记录下来。但是如果全部为0,或者没有定义初始值。那么,从原理上来说,只需记录数组长度,赋予BSS“属性”。
这样分类,可以节省镜像文件中的空间大小。

4、ISP,IAP

ISP(In-System Programming)在系统可编程,指电路板上的空白器件可以写入最终用户代码, 而不需要从电路板上取下器件,已经编程的器件也可以用ISP方式擦除或再编程。
IAP(In-Application Programming) 指MCU可以在系统中获取新代码并对自己重新编程,即可用程序来改变程序。

ISP技术的优势是不需要编程器就可以进行单片机的实验和开发,单片机芯片可以直接焊接到电路板上,调试结束即成成品,免去了调试时由于频繁地插入取出芯片对芯片和电路板带来的不便。比如可以通过串口给32下载程序。

IAP技术是从结构上将Flash存储器映射为两个存储体,当运行一个存储体上的用户程序时,可对另一个存储体重新编程,之后将程序从一个存储体转向另一个。

IAP的编写流程
由Bootloader负责检测SD卡中是否有固件更新所需的BIN文件,或者通过SPI、CAN、以太网等方式获取BIN文件。
如果获取到所需要的BIN文件,则开始复制文件更新固件,更新结束后跳转到指定的地址开始执行最新的程序。

#define FLASH_OLDAPP_ADDR    0x08010000//FLASH_Sector_4
#define FLASH_APP_ADDR       0x08080000//应用程序起始地址128Kb
typedef  void (*pFunction)(void);
pFunction Jump_To_Application;
void execute_app()
{
    uint32_t JumpAddress = 0;
	uint32_t Jumpadd = FLASH_OLDAPP_ADDR;
	USART_DeInit(USART1);
	if (upgrade_flag == 1)//1111-升级完成
	{
		Jumpadd = FLASH_APP_ADDR;
	}		
	JumpAddress = *(__IO uint32_t *)(Jumpadd + 4);//用户代码区第二个字存储维新程序起始地址
	Jump_To_Application = (pFunction)JumpAddress;
	__set_MSP(*(__IO uint32_t *)Jumpadd); //初始化APP堆栈指针(用户代码区的第一个字用于存储栈顶地址)
	Jump_To_Application();  //设置PC指针为新程序复位中断函数的地址
}

RAM:随机存取器,内存
ROM :只读存储器,flash,保存代码,立即数,常数,常数字符串。
1024 kB ROM (flash), 4 kB、192 kB RAM
静态存储区的大小是,192k

程序启动

程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,当复位中断程序运行完成后才跳转到main函数。由此可见,在最后一步的设计中需要根据存放APP程序的起始地址以及中断向量表来设置栈顶地址,并获取复位中断地址跳转到复位中断程序。

内置Flash的分配情况大致如下:
在这里插入图片描述
在这里插入图片描述
STM32Fx有一个中断向量表,这个中断向量表存放代码开始部分的后4个字节处(即0x08000004),代码开始的4个字节存放的是栈顶地址。
当发生中断后程序通过查找该表得到相应的中断服务程序入口,然后跳到相应的中断服务程序中执行。

1)上电后从0x08000004处取出复位中断向量的地址,然后跳转到复位中断程序入口。
2)执行结束后跳转到main函数。
3)在执行main函数的过程中发生中断,则STM32强制将PC指针指回中断向量表处。
4)从中断向量表中找到相应的中断函数入口地址,跳转到相应的中断服务函数
5)执行完中断服务函数后再返回到main函数中来。

IAP方案,程序启动

在这里插入图片描述
在内置的Flash里面添加一个BootLoader程序,BootLoader程序和user application各有一个中断向量表,假设BootLoader程序占用的空间为N+M字节,则程序的走向应该如下图所示:
链接

#define

#define 是个宏,宏本质就是个定义一个符号

宏与定义变量没有关系,更说不上是放在ROM还是RAM 中了。
#define a 0 的意思是:用符号a表示0。

宏定义 #define只是在预编译时简单的文字替换,其实并没有定义任何的变量。
#define a 1
uchar i;
main()
{i=a;}
其实在预编译以后,程序就成了{i=1;}程序里面根本就没有a。
猜测sizeof得到的并不是a,是宏定义下的那个东西的长度。因为sizeof(a),预编译后就是sizeof(1)。

typedef

在编程中使用typedef目的一般有两个:
1) 一个是给变量一个易记且意义明确的新名字

typedef   long           byte_4;//给已知数据类型long起个新名字,叫byte_4。
typedef   signed         char int8_t;
typedef   signed short   int int16_t;
typedef   signed         int int32_t;

2) 一个是简化一些比较复杂的类型声明

typedef struct tagStruct
{
 int iNum;
 long Length;
} Struct;

这个typedef和结构体,结合使用的方法,有以下两个操作:

  1. 定义一个新的结构类型
struct tagMyStruct
{
 int iNum;
 long lLength;
};
  1. typedef为这个新的结构起了一个名字,叫MyStruct。
typedef struct tagMyStruct MyStruct;

定义结构体指针,使用以下方式:

struct tagNode
{
 char *pItem;
 struct tagNode *pNext;
};
typedef struct tagNode *pNode;
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值