STM8S(207)BootLoader制作(在BootLoader和App中都可以使用中断)

本文详述了STM8 BootLoader的制作过程,重点在于内存分布和中断向量表的重定向,以确保BootLoader和应用程序都能使用中断。通过分析STM8的内存布局,介绍了如何在BootLoader和App中分别存放代码,并提供了两种中断向量表的重定向思路,以实现在多次复位后仍能保持中断功能。
摘要由CSDN通过智能技术生成

最近这段时间使用stm8,要在项目中用到IAP升级,同时还要在BootLoader和App中同时使用中断,花了一些时间查找了很多博客,集合大家的知识,写了一篇文章来总结一下自己的成果。这是我第一次写文章,有错误的地方欢迎大家指出

BootLoader制作分析

1、单片机需要有一个对外的通信接口,一般使用的是单片机自带的串口

2、网上寻找一个稳定的通信协议,保证你的单片机在IAP升级的时,能正确稳定的传输数据。我使用的是
Ymodem协议(如果不知道的可以度娘去了解一下),因为网上有编写好的上位机,比较方便

3、了解stm8的内存分布情况,使用flash读写函数把升级的数据写入单片机的ROM里面

4、重定向中断向量表。这是BootLoader和App都可以使用中断的重点

5、程序跳转

这篇文章的重点是讲解内存和中断重定向的,所以略过1和2

**

STM8的内存分布

从stm8s的数据手册中可以看出stm8s的内存分布情况
stm8s207-208的内存分布
前面的我们不用管,因为程序代码的存放是从0x8000开始的,0x8000~0x8080存放的是中断向量表。
所以我们制作BootLoader的思路如下:

根据自己的BootLoader的大小来确定App的存放位置,我这里选择的是0x8000~0x9FFF(8k)部分存放BootLoader的程序代码,0xA000之后的放App的程序代码,当然你也可以选择其他的地址。

在BootLoader里面编写好串口传输和接受函数,然后使用一个标志位来判断是否进入App或者等待接受数据升级程序,如果进入升级状态上位机或其他的设备可以通过USB转串口、蓝牙转串口等传输升级程序代码给单片机,然后BootLoader把数据写入0xA000之后的位置。

怎么把程序代码存入相应的位置呢?我是用的是IAR,可以在软件中进行如下设置:

我用的是stm8s207RB型号的mcu,大家可以根据自己的mcu选择相应的.icf文件。.icf文件可以在IAR的安装目录下找到,我的是在C:\Program Files (x86)\IAR Systems\Embedded Workbench 8.0\stm8\config文件夹中。找到相应的.icf文件之后复制到你的工程文件夹中,给App的.icf进行如下修改,就可以把App的程序位置放在0xA000处。
在这里插入图片描述
BootLoader的位置不用改变了,因为程序默认存储的位置就是从0x8000开始的,不过你要保证你的BootLoader程序的大小不能超过你留给它的空间(我这里预留的是8k(0x8000~0x9FFF),足够存储我的BootLoader程序),超过会占用App的位置,就会导致程序崩溃。

PS:
1、我这里使用的升级判断标志是在0x4050位置保存一个字符’U’,升级完成就把它改为’O’。你们也可以使用其他的标志。我这里之所以使用它是因为0x4000~0x47FFF这一段EEPROM在程序运行时没有使用到,当然你也可以使用其他的标志来判断。

2、BootLoader中接收到数据,需要写入flash,这就需要掌握stm8的flash读写函数,这里不做说明,不会的去问度娘。

3、BootLoader跳转到App的代码如下:

	asm("LDW X,  SP ");
    asm("LD  A,  $FF");
    asm("LD  XL, A  ");
    asm("LDW SP, X  ");
    asm("JPF $A000"); //可以根据自己的App的位置选择

重定向中断向量表——这是这篇文章的重点

不像stm32有NVIC之类的中断控制器管理中断向量的地址,stm8的中断向量的地址是固定的,它的中断向量表被固定在0x8000~0x8080位置,最多可以有32个中断,有些单片机32个都使用了,有些只是使用其中的部分,我用的stm8s207rb就是只使用部分的。

既然它是固定的,那要怎么才能在BootLoader和App中都使用中断呢?

思路1:


mcu在BootLoader中运行的时候,0x8000~0x807F存储的是BootLoader的中断服务函数的地址(如下图)。因为0x8000 ~0x807F有128个字节,4个字节存储一个中断向量,最多有32个中断。如0x8004 ~0x8007这4个字节存储的是第二个中断向量为820099A1,82为操作数,后面的3个字节为中断服务函数的地址0x0099A1

mcu从BootLoader跳转到App中运行的时候,把0x8000~0x807F存储的地址改为App的中断地址0xA000 ~0xA07F(如下图)。

0x8004 ~0x8007这4个字节存储的数据变为8200A004,当第二个中断产生时,mcu跳转到0x8004位置,然后继续跳转到0xA004的位置执行0xA004地址处的操作。0xA000 ~0xA07F存储的是App的中断服务函数的地址。

App产生中断,由①跳转到固定的中断向量地方,然后②跳转到App的中断向量表的位置,③跳转到App的中断服务函数处,执行相应的操作。

这种方式第一次用的时候,BootLoader和App都可以使用中断,但是当单片机复位之后,再次从BootLoader运行时,BootLoader中就不能使用中断了,因为flash里面的数据是不会随着复位改变的,0x8000~0x807F存储的内容被上一次跳转进入App时改变了,没有存储BootLoader的中断服务函数的地址,这时候当然在BootLoader中就不能使用中断了。

所以我们可以在BootLoader最开始运行没有开启中断的时候,再把0x8000~0x807F的数据改变为BootLoader的中断服务函数的地址,然后再开启中断,这样BootLoader就可以正常使用中断了。

不过这里又存在一个问题,在BootLoader运行时,怎么知道BootLoader的中断服务函数的地址呢?

我这里用了一种比较简单的方法(不过肯定不只这一种方法):

第一次运行BootLoader的时候,读取出0x8000~0x807F的存储的数据,保存到0x4100 ~0x417F处(0x4000 ~0x47FFF这一段EEPROM在程序运行时没有使用到),单片机复位第二次、第三次或更多次重新从BootLoader运行时,又读取0x4100 ~0x417F处的数据,改变0x8000 ~0x807F处的数据。代码如下:

#define MIN_USER_Start_ADDR     0xA000//用户代码(App)的起始地址 字节偏移5个字节
uint32_t FLASH_ReadWord(uint32_t Address)
{
   
 return(*(PointerAttr uint32_t *) (uint16_t)Address);       
}
void STM8_HanderIqr_Default(void)
{
   
    uint32_t data[0x20] = {
   0};
    uint8_t Index;	
    FLASH_Unlock(FLASH_MEMTYPE_PROG);
    FLASH_Unlock(FLASH_MEMTYPE_DATA);
    for(Index = 1; Index < 0X20;Index++) //从1开始,是因为0x8000处存放的是复位中断,不需要重定向
    {
   
        data[Index] = FLASH_ReadWord(0X8000+4*Index); //读取初始中断向量值,也就是BootLoader的中断向量值
        if(FLASH_ReadByte(0X4060) != 'R') //判断是否把中断向量的值写入EEPROM 这个函数是stm8s的库函数
        {
   								//'R'是用来表示0x4100 ~0x417F处是否有数据
            FLASH_ProgramWord(0X4100+4*Index, data[Index
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值