在STM8L上实现IAP(In Application Programming)

来源:互联网 发布:淘宝千人千面是什么 编辑:程序博客网 时间:2024/06/01 21:27
1.实现将Boot和App下载到FLASH的不同地址上,我们需要对链接脚本进行配置
IAR默认的链接脚本在安装目录下
C:\Program Files (x86)\IAR Systems\Embedded Workbench 7.0\stm8\config
找到对应芯片打开后可以看到的这样的字样:

///////////////////////////////////////////////////////////////////      Example ILINK command file for//      STM8 IAR C/C++ Compiler and Assembler.////      Copyright 2014 IAR Systems AB.///////////////////////////////////////////////////////////////////define memory with size = 16M;define region TinyData = [from 0x00 to 0xFF];define region NearData = [from 0x0000 to 0x0FFF];define region Eeprom = [from 0x1000 to 0x10FF];define region BootROM = [from 0x6000 to 0x67FF];define region NearFuncCode = [from 0x8000 to 0xFFFF];define region FarFuncCode = [from 0x8000 to 0xFFFF]                          | [from 0x10000 to 0x17FFF];define region HugeFuncCode = [from 0x8000 to 0x17FFF];

这里定义了不同区域对应的地址,先将该文件拷贝到工程目录下,我们要对其做相应的修改,
我规划Boot的大小为5k,所以将三个FuncCode的范围改为如下:
define region NearFuncCode = [from 0x8000 to 0x93FF];define region FarFuncCode = [from 0x8000 to 0x93FF];define region HugeFuncCode = [from 0x8000 to 0x93FF];
相应的app的链接脚本我们也做了如下的修改:
define region NearFuncCode = [from 0x9400 to 0xFFFF];define region FarFuncCode = [from 0x9400 to 0xFFFF]                          | [from 0x10000 to 0x17FFF];define region HugeFuncCode = [from 0x9400 to 0x17FFF];
最后我们对配置进行修改,右击工程->Options->Linker->Config->Linker configuration file->选中Override define,
并将链接脚本路径改为工程目录下:$PROJ_DIR$\lnkstm8l052r8.icf
至此Boot和App地址空间划分完毕


2.中断向量表的配置
在stm32中,有一个寄存器保存着中断向量表的起始地址,所以在Boot和App中可以有两个中断向量表,
当从Boot跳转到App时只需要设置一下这个寄存器里的值就行了。
但是STM8l的中断向量位置是固定的,从0x8000处开始。
当中断发生时都是跳转到0x8000开始的中断向量表。那么问题就来了,如果App中发生中断,要是跳到Boot中去了,
那不就GG了,所以我们要对Boot的中断向量表进行修改:
/************************************************** * * System initialization code for the STM8 IAR Compiler. * * Copyright 2010 IAR Systems AB. * * $Revision: 1413 $ * *************************************************** * * To add your own interrupt handler to the table, * give it the label _interrupt_N, where N is the * offset from the RESET vector.  Your label will * override the corresponding weak label declaration * on the unhandled_exception function. * **************************************************/        MODULE   ?interrupt        SECTION __DEFAULT_CODE_SECTION__:CODE/* * The interrupt vector table. */        SECTION `.intvec`:CONST        PUBLIC  __intvec        EXTERN  __iar_program_start                //app start at 0x9000__intvec:        DC8     0x82        DC24    __iar_program_start          ;; RESET    0x8000        DC8     0x82        DC24    0x9404        DC8     0x82        DC24    0x9408        DC8     0x82        DC24    0x940C        DC8     0x82        DC24    0x9410        DC8     0x82        DC24    0x9414        DC8     0x82        DC24    0x9418        DC8     0x82        DC24    0x941C        DC8     0x82        DC24    0x9420        DC8     0x82        DC24    0x9424        DC8     0x82        DC24    0x9428        DC8     0x82        DC24    0x942C        DC8     0x82        DC24    0x9430        DC8     0x82        DC24    0x9434        DC8     0x82        DC24    0x9438        DC8     0x82        DC24    0x943C        DC8     0x82        DC24    0x9440        DC8     0x82        DC24    0x9444        DC8     0x82        DC24    0x9448        DC8     0x82        DC24    0x944C        DC8     0x82        DC24    0x9450        DC8     0x82        DC24    0x9454        DC8     0x82        DC24    0x9458        DC8     0x82        DC24    0x945C        DC8     0x82        DC24    0x9460        DC8     0x82        DC24    0x9464        DC8     0x82        DC24    0x9468        DC8     0x82        DC24    0x946C        DC8     0x82        DC24    0x9470        DC8     0x82        DC24    0x9474        DC8     0x82        DC24    0x9478        DC8     0x82        DC24    0x947C        END

个人理解DCn是开辟一个n bit的汇编指令吧。0x82 为操作码,意思是跳转到后面的地址去执行。
0x94XX表示一个地址,我们会将这个地址里的数据赋值给PC指针。
那么这个中断向量表的意思就是,除了Reset,其他的中断发生时,都跳转到App的中断向量表去执行。
这么做的后果就是,Boot中不能使用中断了。不然就跳转到App中去执行了。
那有的同学头就很铁,我偏要两个地方都是用中断呢?
还真有办法,前面的流程都一样,但是用一个全局变量来表示当前程序是在在哪里运行的,
然后在中断函数里根据这个全局变量来选择执行哪段程序。大致思路就这样,具体没有去实现过。
这里还要说一句:既然写Boot就好好写一个功能专一点的Boot,干嘛非要用中断。这种花里胡哨的搞来搞去,没有用的!


3.执行Boot到App的跳转
比较常用的跳转方法有两种,在C语言里,我们一般使用函数指针的方式,还有一种就是使用汇编直接改变PC指针的值。
stm8l中用的是第二种:
    asm("LDW X,  SP ");    asm("LD  A,  $FF");    asm("LD  XL, A  ");    asm("LDW SP, X  ");    asm("JPF $9400");

我只知道这些是C语言内嵌汇编的写法,对于stm8l的架构是一无所知,大概就是设置了堆栈,然后跳转吧$9400就是App的起始地址。