写这段程序之前参考了NXP官网的《AN5400:KEA bootloader》
源代码可下载我发布的资源。编译器使用S32DS。
1、简述:boot loader的实现可以简单理解为在MCU的程序存储区分为两个部分,BOOT和APP。
上电执行BOOT,如有下载请求就下载程序,没有就跳转到APP程序。在实际编程中应该创建两个工程,APP与BOOT。
2、向量地址。
我们要把FLASH区分为两个部分,那自然要要分配不同的起始地址。由于单片机硬复位后PC指针会默认指向0x0000,所以BOOT部分必须以地址0起始,我这里为BOOT预留的地址空间是0x0000-0x4000.由于使用默认地址,所以LD文件不需要修改。
FLASH_1 (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400
FLASH_CONFIG (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010
FLASH_2 (RX) : ORIGIN = 0x00000410, LENGTH = 0x0001FBF0
APP的工程需修改为
FLASH_1 (RX) : ORIGIN = 0x00004000, LENGTH = 0x00000400
FLASH_CONFIG (RX) : ORIGIN = 0x00004400, LENGTH = 0x00000010
FLASH_2 (RX) : ORIGIN = 0x00004410, LENGTH = 0x0001BBF0
关于LD文件的位置:工程文件夹里
3、FLASH的读写。
KEAZ128的FLASH擦写操作并不会占用总线(见手册),所以不需要将FLASH的操作程序段放在内存中。直接执行即可,但需注意的是,需要在执行操作时关闭中断,且不能操作正在执行程序的扇区。下面介绍下FLASH的读写方法。
3.1设置保护区以防止误操作。
//Flash Protection Operation Enable
FTMRE->FPROT |= FTMRE_FPROT_FPOPEN_MASK;
//Flash Protection Higher Address Range Disable
FTMRE->FPROT |= FTMRE_FPROT_FPHDIS_MASK;
//Flash Protection Lower Address Range Disable
FTMRE->FPROT &= ~FTMRE_FPROT_FPLDIS_MASK;
//Flash Protection Lower Address Size, from 0 to 0x3FFF
FTMRE->FPROT |= FTMRE_FPROT_FPLS_MASK;
3.2初始化
retError |= FLASH_Init(20000000);
3.3擦除扇区 :在向FLASH区写入数据之前要先执行擦除,而擦除是按照扇区执行的,每扇区512字节。
FLASH_EraseSector(add);
FLASH_EraseVerifySection(add, w);
add 扇区的地址
w 要验证的字数。注:此处为长字,即1个字四个字节
例如: FLASH_EraseSector(0x4000);
FLASH_EraseVerifySection(0x4000, 128);
擦除了0x4000-0x41ff的内容。
3.4写入:下面这段的意思是向地址flash_app_addr连续写入512字节,内容为数组hcBuff[]
需注意的是无论擦除还是写入都需关闭中断。
__disable_irq();
int error1=FLASH_Program(flash_app_addr, hcBuff, 512);
__enable_irq();
3.5读值 直接使用uchar型指针指向就可以。
x=*((uint8_t*)(flash_app_addr));
4、如何跳转:在没有请求或者下载完成后需跳转到APP部分。跳转方法为函数指针:
typedef void(*JumpToPtr)(void); //函数指针类型 别名JumpToPtr
#define APP_IMAGE_START 0x4000
for(i=0;i<8;i++)
UART_DisableInterrupt(UART0, i); //跳转前关闭所有打开的外设,这里使用了串口
/*这里禁用所有中断,就不举例了*/
JumpToPtr jump2app; /*定义函数指针*/
jump2app = (JumpToPtr)*(uint32_t*)(APP_IMAGE_START + 4);
jump2app(); //跳转
while(1);
PS:其实”在内存中执行函数“也是利用函数指针,只是把指针指向了存储着函数机器码的数组的首地址。
5、烧写的内容
BOOT接受到下载请求下载程序,将程序烧写0x4000起始的位置。程序信息是由16进制的机器码形式保存的,也是就是用APP工程编译出BIN文件中的内容。
6、关于通信。
BOOT中的通信与正常编程是相同的,只是需要在跳转前关闭在BOOT中打开的外设。
源代码中使用的通讯方式是LIN总线。19200波特率 帧间隔20ms。关于客户协议的部分就不赘述了,我想对于大家来说这都不是难题。
对于刚接触bootloader的工程师来说需要的无非就那么几点,如何在C语言中跳转PC指针、FLASH的操作接口、在哪里设置向量地址、以及总线条件不允许时如何在内存中执行程序等。简单写一下算是抛砖引玉,欢迎交流。