历史上的今天
返回首页

历史上的今天

今天是:2025年01月08日(星期三)

正在发生

2020年01月08日 | STM8的IAP与APP

2020-01-08 来源:eefocus

最近项目需要,开发STM8的升级系统,也就是通过IAP进行升级APP。


MCU:STM8S207M8(不同的型号只要修改相应的接口即可)


IAP:bootloader v1.1(AN2659code)


APP:项目应用程序


开发环境:STVD+Cosmic


升级软件:官方的Flash Loader Demonstrator(后期根据协议自定义实现)


原理:MCU上电后,从0x8000地址执行,也就是bootloader的起始代码,当收到同步码时,进入升级状态,


等待命令,升级软件通过协议进行flash烧写。完成后,跳转到代码APP的起始地址,MCU开始执行APP程序。


在APP状态下,如果收到升级固件命令,跳转到IAP所在起始地址0x8000,进入升级状态。


PS:STM8内部固化了一个bootloader,可以通过配置字OPTBL打开。该bootloader支持iap uart下载程序。


由于硬件的情况,这里就不用内置bootloader,这里所讲的bootlader是指IAP。


1、由于bootloader代码并不是基于STM8S207M8的,所以需要移植,主要问题是段定义问题。


根据代码的段使用情况,在setting->Linker->Input中定义相应的段,尤其是FLASH_CODE段,


因为该段是定义在RAM中,意义是指FLASH操作全部是在RAM中运行的。


注意,设置中断向量地址为0x8000,代码段的起始地址为0x8080(向量表占0x80个字节)。


注意设置C编译优化,因为代码太大的话,APP的起始地址要向后移动,不要重叠了。


另外,还要根据FLASH、EEPROM、RAM等大小在main.h文件中进行一些配置:


#define  BLOCK_BYTES          128

#define  ADDRESS_BLOCK_MASK   (BLOCK_BYTES - 1)

 

//memory boundaries

#define  RAM_START            0x000000ul

#define  RAM_END              0x0017FFul

 

#define  EEPROM_START         0x004000ul

#define  EEPROM_END           0x0047FFul

 

#define  OPTION_START         0x004800ul

#define  OPTION_END           0x00487Ful

#define  UBC_OPTION_LOCATION  0x004801

 

#define  FLASH_START          0x008000ul

#define  FLASH_END            0x017FFFul

 

#define  BLOCK_SIZE           0x80

#define  BLOCK_PER_SECTOR     0x08


2、编译好的IAP通过SWIM工具下载到flash起始地址0x8000中。


3、根据通信协议《STM8 bootloader.pdf》,调通升级软件与IAP之间的串口通信操作。


4、这里自定义APP的起始地址为0xa000,那么在APP的工程里,设置中断向量地址为0xa000,代码段的起始地址为0xa080。


5、APP中跳转到IAP,使用汇编_asm("jp $0x8000")即可。


APP的中断执行流程:


由于STM8的中断向量表是固定的,当STM8产生中断异常后,会跳转到0x8000,执行相应的中断服务程序。但是APP的中断向量起始地址是0xa000。


那么要执行真正的中断服务程序就必须在IAP的中断向量进行定重向。一般的处理方面就是从IAP的向量表中跳转到APP的中断向量表中。


先来看IAP的中断向量表:


extern void _stext();     /* startup routine */

struct interrupt_vector const UserISR_IRQ[32] @ 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 */

};

注意到MAIN_USER_RESET_ADDR的定义:

#define MAIN_USER_RESET_ADDR 0xA000ul


MAIN_USER_RESET_ADDR就是APP的起始地址,同时也是APP的中断向量表的地址。

从IAP的中断向量表中,可以看到,当APP产生中断时,就会先跳转到IAP的中断向量表,再从IAP的中断向量表跳转到APP的中断向量表。


关于时钟的配置:


当MCU是由内部时钟启动的,启动后往往需要切换到外部高速时钟HSE,一般的代码操作是:


CLK_DeInit(); 

CLK_HSECmd(ENABLE);                                  

while(SET != CLK_GetFlagStatus(CLK_FLAG_HSERDY));

CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);

CLK_ClockSwitchCmd(ENABLE); 

CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO , CLK_SOURCE_HSE , DISABLE , CLK_CURRENTCLOCKSTATE_ENABLE);

这里本来没有什么问题,但需要注意的是,如果在IAP和APP都进行时钟切换到HSE的时候,就可能代码一直在这个循环里:

while(SET != CLK_GetFlagStatus(CLK_FLAG_HSERDY));

所以在bootloader中切换时钟后,在APP里就不要再重复操作了。


关于该版本IAP的BUG:


void ProcessCommands(void)

{

  u8 result;

  

  do

  {

    //init pointer

    ReceivedData = DataBuffer;

  

    //receive data 1-st byte

    if(!Receive(ReceivedData++))

      continue;

  

    //receive data 2-nd byte

    if(!Receive(ReceivedData++))

      continue;

  

    //check if command bytes are complements

    if(DataBuffer[N_COMMAND] != (u8)(~DataBuffer[N_NEG_COMMAND]))

    {

      Transmit(NACK);

      continue;

    }

  

    //parse commands

    Transmit(ACK);

    switch(DataBuffer[0])

    {

      case (GT_Command): result = GT_Command_Process(); break;

      case (RM_Command): result = RM_Command_Process(); break;

      case (GO_Command): result = GO_Command_Process(); break;

      case (WM_Command): result = WM_Command_Process(); break;

      case (EM_Command): result = EM_Command_Process(); break;

    }

  }while( (!result) || (DataBuffer[0] != GO_Command) ); //until GO command received

其中,DataBuffer为全局数组:

//input buffer

u8 DataBuffer[130];

从ProcessCommands函数看到,在switch中判断DataBuffer[0]值,在循环中仍然用DataBuffer[0] != GO_Command来判断。

由于在执行XX_Command_Process中,通信缓冲区是用DataBuffer,所以有可能会改变DataBuffer[0]的值,当DataBuffer[0]的


值被改变为GO_Command时,就可能跳出循环,导致函数ProcessCommands返回,无法继续执行下一条命令,从而出错。


笔者遇到该问题,在升级过程中,需要写181页的数据,刚好在第61页的数据中接收到的第一个数据为0x21,也就是GO_Command的值,


从而导致无法继续升级。所以需要改为:


    u8 cmd;

    ... ...

    cmd = DataBuffer[0];

    switch(cmd)

    {

      case (GT_Command): result = GT_Command_Process(); break;

      case (RM_Command): result = RM_Command_Process(); break;

      case (GO_Command): result = GO_Command_Process(); break;

      case (WM_Command): result = WM_Command_Process(); break;

      case (EM_Command): result = EM_Command_Process(); break;

    }

  }while( (!result) || (cmd != GO_Command) ); //until GO command received

推荐阅读

史海拾趣

ASPEED Technology公司的发展小趣事

自成立以来,ASPEED Technology一直致力于自主创新技术的研发与客户需求的快速响应。公司拥有一支专业的研发团队,不断推出具有竞争力的新产品和解决方案。同时,ASPEED还积极拓展全球市场,与众多知名企业和机构建立了合作关系,为公司的发展奠定了坚实的基础。正是这种持续的创新与研发精神,使得ASPEED在电子行业中不断发展壮大,成为了一家备受瞩目的企业。

以上五个故事均基于ASPEED Technology公司发展起来的相关事实,展现了公司在并购、产品创新、合作研发等方面的努力和成果。这些故事不仅反映了ASPEED在电子行业中的成长轨迹,也展示了其不断追求卓越、推动行业发展的决心和实力。

广芯电子(BROADCHIP)公司的发展小趣事

2018年,ASPEED正式推出Cupola360 360度影像拼接处理芯片暨解决方案。这一创新产品的推出,标志着ASPEED将产品线成功扩展至图像处理相关领域。Cupola360芯片的高性能与广泛应用场景,使其在安防监控、虚拟现实等领域受到广泛关注,为ASPEED带来了新的增长点。

Arctic Silicon Devices公司的发展小趣事

在电子行业的发展过程中,创新合作是推动产业进步的重要动力。Arctic Silicon Devices积极与高校、科研机构等合作,共同开展技术研发和人才培养。通过共享资源、互通有无,公司不仅获得了更多的创新灵感和技术支持,还推动了整个电子行业的技术进步和产业升级。

HP(Keysight)公司的发展小趣事

随着企业规模的不断扩大,Arctic Silicon Devices逐渐意识到承担社会责任的重要性。公司积极参与公益事业,通过捐款、捐物等方式支持教育、环保等领域的发展。同时,公司还加强了对员工福利的关注和投入,为员工提供了良好的工作环境和发展空间。这些举措不仅提升了公司的社会形象,也增强了员工的归属感和忠诚度。

以上五个故事虽然基于虚构的Arctic Silicon Devices公司,但它们反映了电子行业中企业发展的常见路径和关键要素。通过技术突破、国际化战略、品质管理、创新合作和社会责任等方面的努力,一个电子企业可以在竞争激烈的市场中脱颖而出,实现可持续发展。

Grayhill公司的发展小趣事
使用万用表等工具测量电路的输出电压和电流,确保它们符合设计要求。
Advanced Optoelectronic Technology Corp公司的发展小趣事

在光电技术领域,AOTC始终保持领先地位。公司不断推出创新产品,如高效能的光电传感器、智能照明系统等,这些产品不仅提升了人们的生活品质,还推动了整个电子行业的变革。AOTC的技术创新得到了业界的广泛认可,公司逐渐成为了行业的领军企业。

问答坊 | AI 解惑

设计者必看,因为你可以搞明白很多

学设计第一个要认识到的就是设计不是艺术。我就是一开始没有分清这个概念,在第一次上设计课时可苦大了。设计是沟通,是传达,而艺术是表现,是创作。这并不是说设计里没有表现的成份,更不是说艺术是不在乎沟通的。但是两者放在这两项上的重视是有 ...…

查看全部问答>

有谁用过L293B的

用L293B 驱动一个电机, 要求:电机可以正反转,有快慢。 都是自动控治的。 程序里不用写电机快慢程序, 只是通过对L293B的输入脚来控治电机这我不会接了, …

查看全部问答>

请教PB->Platform->Settings->Enable full Kernel Mode

如题:PB->Platform->Settings->Enable full Kernel Mode(no IMGNOTALLKMODE=1) 以前的工程一直选择这个选项,从来没想过是做什么的 前两天新做个工程,忘记加这个选项,编译后系统不报错,但是下到板子上,系统好象缺少explore.exe一样 后来 ...…

查看全部问答>

关于nk.bin :error opening file -no such file or directory问题

大家好。我现在在虚拟机上建立Wince系统。建立了虚拟机以后。使用USBoot将U盘以HDD(ZIP也试过)模式格式化为引导盘,将C:\\Program Files\\Microsoft Platform Builder\\6.00\\cepb\\utilities下的CepcBoot.144文件放入WinImage软件中并选择U盘,利 ...…

查看全部问答>

谁有51内核无线模块NRF905或NRF2401 C程序

谁有51内核无线模块NRF905或NRF2401 C程序…

查看全部问答>

门禁系统技术与应用浅析

禁产品在远古时代就已经存在,它作为人身财产安全防范的首道防线,是人们生活、工作的必备品。从一把锁、一道门等机械产品发展到网络化、集成化、智能化的现代门禁产品,可谓经历了千锤百炼,才练就出如今的本领。   今天的门禁产品,已经从单纯 ...…

查看全部问答>

uboot-2009.08.tar.bz2移植到TQ2440

依据上几次搭建的环境进行uboot的移植,出现了一些错误,我特此做出一些总结,已经将编译器转换到旧一点的arm-linux-gcc-4.3.2,具体的原因是为什么,我查找了天嵌的网站说需要转换到3.4版本的编译器,因此我改用了友善之臂的uboot-2009.08.tar.bz2 ...…

查看全部问答>

11.06【每周讨论】软文——春风化雨、润物无声

您知道“软文”的含义吗?什么,不知道。赶紧百度一下吧,别被OUT了 [ 本帖最后由 longxtianya 于 2011-11-6 20:19 编辑 ]…

查看全部问答>

ALTERA Cyclone Ⅲ板子上能否将输入变成输出??

现在手里有一个 板子 上面有5*8个按键开关 请问下 是否能将开关焊下 接上LED灯 如果可以 能在Quartus 软件上改么 ?…

查看全部问答>

LED照明调光器

这LED调光器一般是调电流还是电压也,是一个什么过程或是原理也。…

查看全部问答>