历史上的今天

今天是:2024年09月29日(星期日)

正在发生

2021年09月29日 | STM8S(207)BootLoader制作(在BootLoader和App中都可以使用中断)

发布者:Radiant777 来源: eefocus关键字:STM8S  BootLoader  中断 手机看文章 扫描二维码
随时随地手机看文章

最近这段时间使用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 SystemsEmbedded Workbench 8.0stm8config文件夹中。找到相应的.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]); //把中断向量的值写入EEPROM 这个函数是stm8s的库函数

        }

        

        if(data[Index] == (0X82000000+MIN_USER_Start_ADDR+Index*4)) //判断中断向量的值是否为APP的值,如果

        {                                                           //如果是APP的值,则改为BootLoader的中断向量值

            data[Index] = FLASH_ReadWord(0X4100+4*Index);

            FLASH_ProgramWord(0X8000+4*Index, data[Index]);

        }

    }

    FLASH_Lock(FLASH_MEMTYPE_DATA);

    FLASH_Lock(FLASH_MEMTYPE_PROG);

}


下面是跳转到App时的代码:


void STM8_AppHanderIqr_Init(void)

{

disableInterrupts();   //关闭中断  

uint8_t Index;

FLASH_Unlock(FLASH_MEMTYPE_PROG);

for(Index = 1; Index < 0X20;Index++)

{

if(FLASH_ReadWord(0X8000+4*Index)!=(0X82000000+MIN_USER_Start_ADDR+Index*4))

{

FLASH_ProgramWord(0X8000+4*Index,0X82000000+MIN_USER_Start_ADDR+Index*4);

}

}

  FLASH_Lock(FLASH_MEMTYPE_PROG);

  platform_peripherals_deinit(); //去除外设初始化,你在BootLoader中初始化了什么外设,可以给它去初始化一下,防止进入App外设还在运行出现错误

asm("LDW X,  SP ");

asm("LD  A,  $FF");

asm("LD  XL, A  ");

asm("LDW SP, X  ");

asm("JPF $A000");

}


PS:

上面这种方式虽然可以BootLoader和App都同时使用中断,但是需要每次运行的时候改变两次0x8000~0x807F的地址处的数据,这样频繁的擦写flash会对单片机的寿命产生影响,因为一般flash的擦写次数为10万次左右,一旦flash不能使用了,那单片机也就损坏了。所以有了下面这种方式


思路2:

上面的思路1用的是改变0x8000 ~0x807F处的数据来切换两个中断向量表,但是0x8000 ~0x807F是flash的位置,不能频繁的擦写,那能不能换成一个可以频繁擦写的地方呢?


RAM是可以频繁改变的,那么我们把中断向量表存储在RAM里面就可以解决问题了,下面是怎么把BootLoader和App的中断向量表存储在RAM里面。

因为stm8s207的RAM的地址是0x0000 ~0x17FF,所以我这里选择0x1000 ~0x107F位置来存储BootLoader和App的中断向量表,然后在0x8000 ~0x807F的地址处存储0x1000 ~0x107F的地址。这样产生的时候,就可以如下如图所示跳转

有了跳转方式,剩下的问题就是怎么在0x8000 ~0x807F处放置0x1000 ~0x107F的地址,和怎么把BootLoader和App的中断向量表放在0x1000 ~0x107F处了


1、在0x8000 ~0x807F处放置0x1000 ~0x107F的地址

有一个中断地址配置文件stm8s_interrupt.s(如果你没有这个文件可以直接复制粘贴下面就可以了),可以直接在编译阶段就直接把0x8000 ~0x807F地址处(stm8真正的中断向量表的位置)存储的数据变为自己需要的0x1000 ~0x107F


        MODULE   ?interrupt


        SECTION __DEFAULT_CODE_SECTION__:CODE:NOROOT


declare_label MACRO

        PUBWEAK _interrupt_1

_interrupt_1:

        ENDM


unhandled_exception:


        declare_label 1

        declare_label 2

        declare_label 3

        declare_label 4

        declare_label 5

        declare_label 6

        declare_label 7

        declare_label 8

        declare_label 9

        declare_label 10

        declare_label 11

        declare_label 12

        declare_label 13

        declare_label 14

        declare_label 15

        declare_label 16

        declare_label 17

        declare_label 18

        declare_label 19

        declare_label 20

        declare_label 21

        declare_label 22

        declare_label 23

        declare_label 24

        declare_label 25

        declare_label 26

        declare_label 27

        declare_label 28

        declare_label 29

        declare_label 30

        declare_label 31


        NOP                                   ;; put a breakpoint here

        JRA    unhandled_exception



/*

 * The interrupt vector table.

 */



        SECTION `.intvec`:CONST


define_vector MACRO

        DC8     0x82

        DC24    _interrupt_1

        ENDM


        PUBLIC  __intvec

        EXTERN   __iar_program_start

        



__intvec:

        DC8     0x82

        DC24    __iar_program_start          ;; RESET    0x8000

        DC8     0x82

        DC24    0x1004

        DC8     0x82

        DC24    0x1008

        DC8     0x82

        DC24    0x100C

        DC8     0x82

        DC24    0x1010

        DC8     0x82

        DC24    0x1014

        DC8     0x82

        DC24    0x1018

        DC8     0x82

        DC24    0x101C

        DC8     0x82

        DC24    0x1020

        DC8     0x82

        DC24    0x1024

        DC8     0x82

        DC24    0x1028

        DC8     0x82

        DC24    0x102C

        DC8     0x82

        DC24    0x1030

        DC8     0x82

        DC24    0x1034

        DC8     0x82

        DC24    0x1038

        DC8     0x82

        DC24    0x103C

        DC8     0x82

        DC24    0x1040

        DC8     0x82

[1] [2]
关键字:STM8S  BootLoader  中断 引用地址:STM8S(207)BootLoader制作(在BootLoader和App中都可以使用中断)

上一篇:关于STM8S105写EEPROM时产生的TIM中断问题
下一篇:STM8 Bootloader和APP设计(都可以使用中断)

推荐阅读

历经千年,中国门锁行业在随着物联网技术飞速发展,在用户对安全和便利的需求增长等趋势下,走向了智能互联升级阶段。智能门锁有着可以满足不同用户的开锁方式,以及无需携带钥匙、更高级别的安防监控、场景联动等特色功能和优势。作为家庭安全的第一关卡,也是日常生活使用的高频终端产品,智能门锁领域无疑是智能行业的一大关键切入点,吸引了各行业巨头...
在2019年杭州云栖大会上,英特尔与阿里云签署战略合作备忘录并宣布:将面向2020年东京奥运会和2022年北京冬奥会,在360 8K VR、3D数字孪生、云转播等领域展开密切合作;双方还将面向2020年东京奥运会,在人工智能3D运动员追踪领域展开合作。在这些创新领域,英特尔将提供高性能处理器和AI技术平台的支持,阿里云将在云基础设施和服务上发挥特长。 英特尔...
今天,小米发布新品小米电视大师82英寸,采用4K超高清屏幕,售价9999元。小米电视大师采用82英寸4K超高清屏幕,分辨率高达4320x2160,178°可视角度,DCI-P3 93%广色域覆盖范围,120Hz刷新率,10bit面板,10.7亿色。采用星幕锐影背光系统,具备240个控光分区,1000nits亮度,140000:1对比度,锐影光控技术使得每块分区可呈现4096级明暗变化, 赋予光线千...
一、CPSR概述ARM处理器共有37个寄存器。这37个寄存器按其在用户编程中的功能划分,可分为2类寄存器,即31个通用寄存器和6个状态寄存器。这6个状态寄存器在ARM公司文件中其名称分别为:CPSR、SPSR_svc、SPSR_abt、SPSR_und、SPSR_irq和SPSR_fig。这12的作用分别如图1所示:所有处理器模式下都可访问当前程序状态寄存器CPSR。CPSR中包含条件码标志、中断禁止...

史海拾趣

问答坊 | AI 解惑

看看你是不是安防达人,从图像辨故障

今天看到了一个关于“从图像判断故障”的文章,觉得写的非常具体, 大家在实际应用中,怎么去判断呢,不妨来交流下。 文章如下: 监视器上无图像 1、监控主机等设备及其连接引起无图像显示的原因及解决法 ·微机切换主机输出至监视器的同轴 ...…

查看全部问答∨

求助。。。STC下载器的制作资料

哪位朋友有STC单片机的下载器资料。我想制作一个下载器啊。谢谢啦 急急。。。。。。。。有的话 希望大家传个电路图上来看看 [ 本帖最后由 08221034 于 2010-6-1 20:54 编辑 ]…

查看全部问答∨

6年LED灯珠生产技术工程师经验(LED生产过程漏电的原因分析供工程师讨论)原创

一  选好芯片芯片的抗静电能力要好一点。 二  主要是双线双电极会漏点也就是说白光蓝光和绿光,红的黄的单电极的不怎么会漏电      如果芯片的抗静电能力很好的话,做出的产品还会有漏电的话,那主要原 ...…

查看全部问答∨

89C51\52入门请教

本人想比较快速掌握89C51\\52的程序设计,请各位高手赐招.汇编和C语言我已学过了,还可以. 推荐几本书,什么的.....…

查看全部问答∨

电压跳动导致电池读数变动的问题

现在发现一个问题,由于电池端的电压在不同负载的时候会有所跳动,因此计算出的电池电量也会变化。 比如说,我再正常使用的时候电池电量显示75%,这个时候在播放MP3。不做其他操作,过了一分钟,背光会自动变暗,这是电量显示就变成80%,再过一分 ...…

查看全部问答∨

请仙人指路! LPC1114 与外部flash SST25配置的相关问题

我是这样配置SPI的: void SPIInit() {   uint8 i;   //LPC_SYSCON->PRESETCTRL &= (0x01<<0);   //for(i=0; i<100; i++);   LPC_SYSCON->PRESETCTRL      |= (0X ...…

查看全部问答∨

我的STLINK好像烧了

                                 今天中午用STLINK调试PS2接口,这个PS2键盘好像有问题,所以中间把四根线和目标板分离了一次,然后再调试,发现读 ...…

查看全部问答∨

请教斑竹和大虾怎么看HEX文件?

@FFFE B2 F3 @FFE4 E6 F7 @FFF0 02 F9 2A F7 q 在HEX文件的最后中断向量表中,怎么能够看出具体的程序入口在哪里?比如说上电复位的程序入口是b2f3…

查看全部问答∨

模拟量采集模块模拟量输入输出模块模拟量检测模块

一、JMDM-10DIO10AIO串口控制模拟量数字量系统简介  JMDM-10DIO10AIO串口控制模拟量数字量输入输出控制系统,是深圳市精敏数字机器有限公司自主研发的工业级高可靠性单片机控制系统,采用JMDM-10DIO10AIO工业控制器,以模拟量控制为主要特征, ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved