STM8的IAP在线升级

发布者:冰山火影1977最新更新时间:2020-01-09 来源: eefocus关键字:STM8  IAP  在线升级 手机看文章 扫描二维码
随时随地手机看文章

IAP(In Application Program)在线应用编程


官方资料(STVD开发环境):例程AN2659,


《 AN2659 Application Note.pdf 》


要实现在线升级,MCU代码须分为 : bootloader和 用户代码App 两个部分。

图1.STM8下IAP程序的存储方式


用户启动区域(UBC): (可理解为用户自定义的bootloader的存放区域)


包含有复位和中断向量表,它可用于存储IAP及通讯程序。UBC有一个两级保护结构可保护用户代码及数据在IAP编程中免于无意的擦除或修改。这意味着该区域总是写保护的,而且写保护不能通过使用MASS密钥来解锁。它的大小可通过配置option bytes 设置。


一、中断向量表:


STM8的中断向量表的地址是固定的,位于0x8000~0x8080,即发生中断时,程序将会跳转至0x8000~0x8080的中断向量表中寻找中断入口地址,继而跳转至对应的中断服务函数中执行中断程序。


若是要实现IAP,而0x8000~0x8080的中断向量表将会位于UBC区域,被bootloader所占用。如此一来,UBC区域中的bootloader程序与MAIN PROGRAM区域中的App发生中断时,程序同样都是跳转至UBC区域中的中断向量表中寻找中断入口地址。所以,若App要执行App自己的中断服务函数,则须在App中建立自己的中断向量表,并对bootloader中的中断向量表进行重定向,将程序跳转至App的中断向量表。如图2、图3所示。

          

图2.中断跳转示意图

图3.中断跳转流程图


中断向量表的重定向:(以STVD环境下的官方例程AN2659为例)


以下重定向即可使App程序能够找到自己对应的中断服务函数,但是bootloader的中断将不可使用


原中断向量表为:


struct interrupt_vector const _vectab[] = {

{0x82, (interrupt_handler_t)_stext}, /* reset */

{0x82, NonHandledInterrupt}, /* trap  */

{0x82, NonHandledInterrupt}, /* irq0  */

{0x82, NonHandledInterrupt}, /* irq1  */

{0x82, NonHandledInterrupt}, /* irq2  */

{0x82, NonHandledInterrupt}, /* irq3  */

{0x82, NonHandledInterrupt}, /* irq4  */

{0x82, NonHandledInterrupt}, /* irq5  */

{0x82, NonHandledInterrupt}, /* irq6  */

{0x82, NonHandledInterrupt}, /* irq7  */

{0x82, NonHandledInterrupt}, /* irq8  */

{0x82, NonHandledInterrupt}, /* irq9  */

{0x82, NonHandledInterrupt}, /* irq10 */

{0x82, NonHandledInterrupt}, /* irq11 */

{0x82, NonHandledInterrupt}, /* irq12 */

{0x82, NonHandledInterrupt}, /* irq13 */

{0x82, NonHandledInterrupt}, /* irq14 */

{0x82, NonHandledInterrupt}, /* irq15 */

{0x82, NonHandledInterrupt}, /* irq16 */

{0x82, NonHandledInterrupt}, /* irq17 */

{0x82, NonHandledInterrupt}, /* irq18 */

{0x82, NonHandledInterrupt}, /* irq19 */

{0x82, NonHandledInterrupt}, /* irq20 */

{0x82, NonHandledInterrupt}, /* irq21 */

{0x82, NonHandledInterrupt}, /* irq22 */

{0x82, NonHandledInterrupt}, /* irq23 */

{0x82, NonHandledInterrupt}, /* irq24 */

{0x82, NonHandledInterrupt}, /* irq25 */

{0x82, NonHandledInterrupt}, /* irq26 */

{0x82, NonHandledInterrupt}, /* irq27 */

{0x82, NonHandledInterrupt}, /* irq28 */

{0x82, NonHandledInterrupt}, /* irq29 */

};


改为


struct interrupt_vector const UserISR_IRQ[32] @ MAIN_USER_RESET_ADDR;    //MAIN_USER_RESET_ADDR为主程序区的首地址 的宏定义

 

//redirected interrupt table

struct interrupt_vector const _vectab[] = {

    {0x82, (interrupt_handler_t)_stext}, /* reset */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 1)}, /* trap  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 2)}, /* irq0  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 3)}, /* irq1  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 4)}, /* irq2  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 5)}, /* irq3  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 6)}, /* irq4  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 7)}, /* irq5  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 8)}, /* irq6  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 9)}, /* irq7  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+10)}, /* irq8  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+11)}, /* irq9  */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+12)}, /* irq10 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+13)}, /* irq11 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+14)}, /* irq12 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+15)}, /* irq13 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+16)}, /* irq14 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+17)}, /* irq15 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+18)}, /* irq16 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+19)}, /* irq17 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+20)}, /* irq18 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+21)}, /* irq19 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+22)}, /* irq20 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+23)}, /* irq21 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+24)}, /* irq22 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+25)}, /* irq23 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+26)}, /* irq24 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+27)}, /* irq25 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+28)}, /* irq26 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+29)}, /* irq27 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+30)}, /* irq28 */

    {0x82, (interrupt_handler_t)(UserISR_IRQ+31)}, /* irq29 */

}; 


其中,

typedef void @far (*interrupt_handler_t)(void);  //定义中断函数地址类型


struct interrupt_vector {


  unsigned char            interrupt_instruction;    //指令,其中0x82为跳转指令


  interrupt_handler_t    interrupt_handler;    //函数地址


};


二、FLASH块编程程序的存放:

对于stm8的块编程,代码必须在Ram中运行,因为在块编程时Flash程序将会停止运行。因此,存储在Flash中的代码(与Flash编程相关的代码)必须拷贝至Ram中进行编译、链接、运行。这样,程序将在Ram中执行块编程,块编程时Flash的状态也不会影响到Ram中的程序继续运行。


方法如下:


1、代码的编写:


将Flash编程相关的代码存放至FLASH_CODE段:


#pragma section (FLASH_CODE)    //将代码存放至RAM

void Write_Flash(void)

{

    //....

}

void Erase_Flash(void)

{

    //....

}

#pragma section ()    //代码放置至默认段

 

注意,在调用这些函数之前,必须把这些代码拷贝至RAM中,

STVD的cosmic编译器可以使用内置函数 int  _fctcpy(char name)实现此功能。


int  _fctcpy(char name)    //name为定义的段名首字母


如本例中Flash块编程所在的段名为FLASH_CODE,其首字母为 ‘F’ 故在调用这些函数之前须执行


_fctcpy('F');


2、STVD的设置:在STVD--Settings--Linker选项卡下,选择目录Category下的Input,


在Ram下新建Section,Option填-ic,表示可移至RAM。

三、程序的跳转


若bootloader程序要跳转到app,须将程序跳转至主程序区的首地址。


可使用汇编指令完成:


    //reset stack pointer (lower byte - because compiler decreases SP with some bytes) 

    _asm("LDW X, SP "); 

    _asm("LD A, $FF"); 

    _asm("LD XL, A "); 

    _asm("LDW SP, X "); 

 

    //跳转至App程序 :     

    _asm("JPF $A000");//这里假设app首地址为0x00A000。

    /***或者可以***/

    _asm("JPF [_MainUserApplication]");//跳转至app程序首地址,其中_MainUserApplication的定义在下面有所解释

 

/*****其中:*****/

//typedef @far void (*)(void) TFunction;

typedef @far void (*TFunction)(void);

 

//main application code (user reset) - init user code start - to interrupt table reset jump

const TFunction MainUserApplication = (TFunction)MAIN_USER_RESET_ADDR;


关键字:STM8  IAP  在线升级 引用地址:STM8的IAP在线升级

上一篇:STM8做BUS OFF快慢恢复策略
下一篇:STM32系统学习——I2C (读写EEPROM)

推荐阅读最新更新时间:2024-11-12 10:39

基于IAP的STM32程序更新技术
引言 嵌入式系统的开发最终需要将编译好的代码下载到具体的微控制器芯片上,而不同厂家的微控制器芯片有不同的下载方式。随着技术的发展和应用需求的更新,用户程序加载趋向于在线编程的方式,越来越多的芯片公司提供和开放了用户更新程序的接口与方式,以提高整个系统的可靠性和可维护性。 ST公司基于CortexM3内核的STM32系列产品得到了广泛应用,在许多基于STM32系列产品的开发过程中不可避免要进行用户程序的加载。本文在介绍IAP技术原理基础上,详细论述使用该技术在STM32F103ZE芯片上实现用户在线更新功能的方法,并具体分析其中可能发生异常的原因。 1背景综述 1.1主要程序更新方式 目前,除了直接通过仿真器或烧
[单片机]
基于<font color='red'>IAP</font>的STM32程序更新技术
STM8 ADC转换模式-------连续扫描模式
STM8单片机ADC支持5种转换模式:单次模式,连续模式,带缓存的连续模式,单次扫描模式,连续扫描模式。 连续扫描模式 该模式和单次扫描模式相近,只是每一次在最后通道转换完成时,一次新的从通道0到通道n扫描转换会自动开始。如果某个数据缓存寄存器在被读走之前被覆盖,OVR标志将置1。 连续扫描模式是在当SCAN位和CONT位已被置时,通过置位ADON位来启动的。 在转换序列正在进行过程中不要清零SCAN位。 连续扫描模式可以通过清零ADON位来立即停止。另外一种选择就是当转换过程中清除CONT位那么转换会在下一次的最后一个通道转换完成时停止。 注意:在扫描模式中,不要使用
[单片机]
STM8问题汇总
1.在STVD上开发,Build提示bad struct/union operand 这是因为工程文件太大的缘故,对提示的没有使用到的头文件,源文件进行删减即可解决问题 2.DEBUG按钮点击后提示 ERROR:before starting debug session,please,select a target 如图所示,选swim ST-LINK然后确认即可 3.在IAR上函数输入的参数有错,参数实际值不对或为0 有一个函数的参数类型有多个使用uint8_t作为参数类型声明时候,出现传入的参数不对的情况,uint8的声明在其他文件内,后改为int暂时解决。该问题与多地方定义了uint8_t声明有关系,有
[单片机]
<font color='red'>STM8</font>问题汇总
stm8触摸按键调试笔记
默认状态下触摸按键所有键的灵敏度是一样的,但是实际应用不是这样的。各个键都有可能不一样。 实现不同灵敏度的方法如下: TSL_SCKey_Init()函数里面初始化了灵敏度 pKeyStruct- DetectThreshold = SCKEY_DETECTTHRESHOLD_DEFAULT; 我们增加一个数组,保存各个按键的灵敏度: const u8 SCKEY_DETECTTHRESHOLD = { SCKEY_DETECTTHRESHOLD_DEFAULT, // for TS1 SCKEY_DETECTTHRESHOLD_DEFAULT - 5 // for TS2, TS2 sensitivity is low
[单片机]
stm8编程tips(stvd)
编译完成时显示程序占用的flash和ram大小 将附件压缩包中的mapinfo.exe解压到stvd的安装路径stvd中 在工程上点右键选settings 右侧的选项卡选择Linker,将category的下拉框选成output,然后在Generate Map file前打勾 再将选项卡上选择到Post-Build,在下方文本框中新粘贴一行内容mapinfo $(OutputPath)$(TargetSName).map 点OK按键确定,菜单File- save workspace,保存工程 重新编译下,你就能看到flash,ram,eeprom占用字节数了 修改工程选用的MCU Settings- MCU Select
[单片机]
STM8 选项字节的写入
STM8的EEPROM在复位后,要想要写入数据,必须先解锁,必然无法写入数据。解锁就是向 FLASH_DUKR 中先后写入: 第一个硬件秘钥:0xAE 第二个硬件秘钥:0x56 两个字节的数据。 此时 FLASH_IAPSR 中的 DUL 位将会变为1,表示 EEPROM 已经成功解锁,可以进行写入操作了。如果发现 DUL 位不为 1 ,是可以按顺序重复写入秘钥的,直到 DUL 位为 1 为止。 但手册上是这么说的: 中文手册: 2. 如果密钥输入错误,应用程序可以尝试重新输入这两个MASS密钥来对DATA区域进行解 锁。 4. 如果密钥输入错误,DATA EEPROM区域在下一次系统复位之前将一直保持写保护状态。 在下一次复位
[单片机]
STR912--IAP问题
默认情况下,bank0是映射到地址0x00.考虑到,IAP程序需存储在bank1,而用户程序需存储在bank0.因此须使用CAPS工具,将bank1映射到地址0x00.另外,在IAP程序运行期间,必须在执行用户程序跳转之前,通过程序将bank0重映射到地址0x00(注:IAP程序已经实现了bank0重映射到地址0x00,用户不需要自己来编写代码). ARM处理器产生的地址叫虚拟地址,把这个地址按照某种规则转换到另一个物理地址去的方法称为地址映射。 banko,bank1就是物理地址,而ARM处理器(例如KEIL下就是虚拟地址), 通过CAP可以将bank1物理地址映射到虚拟地址0x00, 然后通过软件设置将bank0物理
[单片机]
STR912--<font color='red'>IAP</font>问题
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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