历史上的今天
返回首页

历史上的今天

今天是:2025年01月09日(星期四)

正在发生

2020年01月09日 | STM8的IAP在线升级

2020-01-09 来源:eefocus

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;


推荐阅读

史海拾趣

Defense Logistics Agency公司的发展小趣事

在全球化和信息化的大背景下,DLA面临着诸多挑战,如跨国采购的风险、网络安全威胁等。然而,DLA始终坚持创新驱动、持续发展的理念,通过加强国际合作、完善法律法规等方式积极应对挑战。同时,DLA还注重人才培养和团队建设,打造了一支高素质、专业化的后勤保障队伍。这些努力为DLA的持续发展提供了有力保障。

CTC Coils Ltd公司的发展小趣事

随着国内市场的逐渐饱和,CTC Coils Ltd公司开始将目光投向海外市场。公司首先在欧洲设立了销售分支机构,通过参加国际电子展会、与当地企业建立合作关系等方式,逐步打开了欧洲市场。随后,公司又进一步拓展到北美和亚洲其他地区,实现了业务的国际化布局。

Deutron Electronics Corp公司的发展小趣事

在技术优势的基础上,Deutron Electronics Corp开始了积极的市场拓展和品牌建设工作。公司参加了多个国际电子展会,展示了其创新产品和技术实力,成功吸引了众多潜在客户的关注。同时,公司还加大了对品牌宣传的投入,通过广告、公关等手段提升了品牌知名度和美誉度。这些努力使得Deutron Electronics Corp的产品逐渐在市场上占据了一席之地。

BENCENT公司的发展小趣事

在取得一系列成绩的同时,BENCENT公司也始终关注可持续发展。公司注重环保和节能技术的研发和应用,致力于为客户提供更加环保、高效的电子产品。同时,公司还积极参与社会公益事业,回馈社会。展望未来,BENCENT公司将继续坚持创新驱动、质量为本的发展理念,不断推动电子行业的进步和发展。


请注意,这些故事仅为框架性的描述,并未包含具体的细节和数据。您可以根据BENCENT公司的实际情况和发展历程,对这些故事进行进一步的丰富和完善。同时,确保在描述事实时保持客观公正的态度,避免加入主观评价。

Empro Technology Corp公司的发展小趣事

为了进一步提升市场竞争力,Empro Technology Corp开始实施国际化战略,积极开拓海外市场。公司设立了多个海外分支机构,与当地企业建立了合作关系,共同开拓市场。同时,公司还积极参加国际电子展等交流活动,与国际同行进行深入交流与合作。

请注意,以上故事均为虚构内容,不代表Empro Technology Corp公司的实际发展情况。如需了解该公司的真实信息,请查阅相关公开资料或联系公司官方渠道。

ADATA公司的发展小趣事

Empro Technology Corp成立于2005年,由一群热衷于电子技术的工程师创立。在初创阶段,公司专注于研发高效能、低功耗的半导体芯片。经过数年的不懈努力,公司成功推出了一款具有颠覆性技术的芯片产品,其性能远超当时市场上的同类产品,迅速获得了市场的认可。

问答坊 | AI 解惑

JJG49-1999精密压力表检定规程

JJG49-1999精密压力表检定规程…

查看全部问答>

电流控制技术的斜坡补偿分析

电流控制技术的斜坡补偿分析…

查看全部问答>

vs2005 用VC++建立一个MFC智能设备工程的问题

vs2005 在VC++建立一个MFC智能设备工程,我以为和evc4是一样的.但不知为什么有些类总是提示找不到.比如:CCeDBDatabase类等.难道vs2005 在VC++不支持evc4的东西?…

查看全部问答>

求助:各位大哥帮我看看这个串口问题啊?谢谢2!

请教: 当单片机向 PC 串口发串数据 windows 系统怎么知道单片机 向它发了数据呢? 是有消息触发, 还是 windows 每一定的时间去扫描串口? 谢谢!…

查看全部问答>

急问:VS2005, CPP, 如何实现拨打电话和访问网页

如题,请大家帮帮忙,最好有源码,或者告诉我在哪里可以找到范例,谢谢大家了。…

查看全部问答>

分享几个zigbee开源代码的网址

http://www.tinyos.net/ Tinyos是一个传感网络操作系统,最近发展较快,采用nesC语言、支持多种编译器。 http://freaklabs.org/index.php/FreakZ-Open-Source-Zigbee-Stack.html 也是一个不错的zigbee协议栈,不过作者似乎忙于其他项目 ...…

查看全部问答>

第12章 高级I/O

12.1   引言 27312.2   非阻塞I/O 27312.3   记录锁 27512.3.1   历史 27612.3.2   fcntl记录锁 27612.3.3   锁的隐含继承和释放 28012.3.4 &nbs ...…

查看全部问答>

遥控开关电路如何设计?

红外遥控、射频遥控、超声波遥控、电力载波遥控,甚至拍一下手掌开,在拍一下就关的声控开关等等,…

查看全部问答>

怎样向2530中烧程序

各位,怎样向2530中烧程序啊?是通过DD/DC?还是SPI烧写程序呢?…

查看全部问答>

MSP430 串口

void init_uart1(void){  P5SEL |= 0xC0;                             // P5.6,7 = USCI_A ...…

查看全部问答>