LV050-STM32地址重映射
一、地址重映射
这一部分还是以STM42F429为例。F429的中文手册可以看这里:RM0090_STM32F40xxx、STM32F41xxx、STM32F42xxx、STM32F43xx参考手册
1. 自举的概念
自举(bootstrap)计算机设备使用硬件加载的程序,用于初始化足够的软件来查找并加载功能完整的操作系统。也用来描述加载自举程序的过程。什么是单片机的自举?单片机的自举就是单片机的启动。
我们说,单片机程序基本都是从0地址出开始运行的,F429的0x00000000~0x001FFFFF地址映射了到什么存储器上,那么就从该存储器上读取指令,开始运行。
至于说0x00000000~0x001FFFFF到底映射在了什么存储器上,这个要看F429 芯片 BOOT1、BOOT0这两个引脚的电平值,说白了就是,通过BOOT1和BOOT0 引脚的电平值,可以选择将0x00000000~0x001FFFFF映射到不同的存储器上。

STM32片内的FLASH分成两部分:主存储块、信息块。主存储块(主Flash)用于存储程序,我们写的程序一般存储在这里。信息块又分成两部分:系统存储器(系统FLASH)、选项字节。系统存储器存储用于存放在系统存储器自举模式下的启动程序(BootLoader),当使用ISP方式加载程序时,就是由这个程序执行。这个区域由芯片厂写入BootLoader,然后锁死,用户是无法改变这个区域的。选项字节存储芯片的配置信息及对主存储块的保护信息。
2. 主flash地址
主FLASH地址为0x0800 0000-0x081FFFFF,Jlink下载时的FLASH设置是不是通过Jlink下载到了地址为0x08000000的地方,大小是0x00100000,也就是1MB。我们打开一个STM32F4的keil-MDK工程看一下:

明明代码是下载到0x0800 0000往后的存储空间中,为什么说运行又是从0x0000 0000地址运行的呢?为什么不是从0x0800 0000开始运行的呢?有关这个问题,就是我们说的单片机的自举。
3. 自举配置
这里可以看一下STM32F429的中文参考手册,中文手册可以看这里:RM0090_STM32F40xxx、STM32F41xxx、STM32F42xxx、STM32F43xx参考手册

正常情况下都是映射到主FLASH上,所以都是从主FLASH上启动的,为了从FLASH启动,我们需要将代码下载到主FLASH上。
4. 重映射
如果0x00000000~0x001FFFFF之前是映射在系统存储器或者嵌入式 SRAM上的,现在改变BOOT0、BOOT1 的电平为 0、x。0x00000000~0x001FFFFF就被重新映射在了主FLASH上,这就是单片机的地址重映射。
重映射就是本来是和张三进行映射的的,现在改为了和李四映射。换句话说重映射就是0x00000000 ~0x001FFFFF(1MB)本来映射在系统存储器 0x1FFF 0000~0x1FFF7A0F(30KB)上面,现在映射到了主FLASH 0x08000000 -0x081FFFFF(1MB)上面。

选择从主FLASH启动时,显然FLASH会被映射在了两片地址上。
- 原本映射的地址(1MB):0x08000000~0x081F FFFF,进行Jlink下载时使用这个地址
- 重映射的地址(1MB):0x00000000~0x001F FFFF,启动时CPU就是从重映射的地址读取指令
这两片地址都是有效的,重映射到FLASH上后,CPU从0地址开始运行时,就从FLASH上读取指令,当然前提是我们需要将代码下载FLASH中。
这就解释了为什么我们在keil中设置好程序的下载地址为0x0800 0000,但是单片机上电是确实从0开始执行。是因为我们在硬件上设置了BOOT0=1,BOOT1=X,从而导致了主FLASH区(也叫主闪存,大小1MB)被映射到了0x0000 0000~0x001F FFFF(1MB),故而代码是下载到 0x0800 0000 往后的存储空间中,却说运行又是从0x0000 0000地址运行的。
5. 程序下载地址?
下载时,能不能使用0x0000 0000地址来下载?
这个不行,因为下载时,0x0000 0000~0x001F FFFF还没有被重映射到FLASH上,只能使用0x0800 0000来下载。
上面说的是我们用JLink下载器下载代码,但是有时候我们还听说可以用串口来下载程序,这又是怎么回事?
用串口下载程序,也就是我们说的ISP在系统中编程。从系统存储器启动,即STM32的ISP了。此时硬件电路B00T0=1,B00T1=0。由于串口不能直接把程序下载到主FLASH里面,所以需要使用到ST公司内嵌于系统存储区的Bootloader来引导把程序下载到主FLASH里面。JLink能直接把程序下载到内置的FLASH里面,是因为JLink下载器内部有Bootloader来引导把程序下载到FLASH里面。程序下载完成后还需要配置BOOT引脚为BOOT0=0,BOOT1=X(即从主闪存存储器启动),复位后才能正常启动程序。
如果不修改BOOT引脚的话也就是B00T0=1,B00T1=0,那么0x0000 0000 ~ 0x001FFFFF是不是被重映射到系统存储器上面,而程序代码在主FLASH里面。复位后程序肯定不能正常运行,只有在使用串口下载程序后配置BOOT引脚为BOOT0=0,BOOT1=X,复位后才能正常执行代码。
总的来说,使用JLink下载代码,JLink下载器内部的Bootloader将程序引导下载到主FLASH里面。使用串口下载代码,由于串口没有Bootloader,就要使用ST官方内置在芯片系统存储区的Bootloader代码,将程序引导下载止主FLASH。又因为程序是从0开始执行的,所以我们复位后运行程序时一定要让BOOT0=0,BOOT1=X,将0x00000000~0x001FFFFF是重映射到主FLASH我们代码存在的地方,从0开始执行代码。
下图是使用FlyMcu串口下载程序,这个串口是USB-TTL,下载程序时让BOOT0=0,BOOT1=X即可。**不是说在系统中编程需要将B00T0=1,B00T1=0吗?**这是因为我们使用的是这个软件,这个软件可以通过DTR和RTS改变BOOT的引脚电平,达到不用修改BOOT引脚就可以下载运行代码,实际上是软件替我们做了改变BOOT引脚的操作。

二、 ISP与IAP
先来了解两个概念,后面会具体再学习:
ISP在系统编程,是指直接在目标电路板上对芯片进行编程,一般需要一个自举程序(BootLoader)来执行。ISP也有叫ICP在电路编程、在线编程。
IAP在应用中编程,是指最终产品出厂后,由最终用户在使用中对用户程序部分进行编程,实现在线升级。IAP要求将程序分成两部分:引导程序、用户程序。引导程序总是不变的。IAP也有叫在程序中编程。
ISP与IAP的区别在于,ISP一般是对芯片整片重新编程,用的是芯片厂的自举程序。而IAP只是更新程序的一部分,用的是电器厂开发的IAP引导程序。综合来看,ISP受到的限制更多,而IAP由于是自己开发的程序,更换程序的时候更容易操作。