一 STM8 IAP 原理分析

IAP原理非常简单,首先我们需要设计两个程序,然后在第一个程序(即Bootloader)中接收(通过串口、IIC、SPI等)第二个程序(即App)的代码,并写入Flash中,然后跳转到第二个程序首地址,开始运行第二个程序,也就是说我们需要写两个程序:
1. BootLoader 程序
2. 用户APP

note:整个过程听起来非常简单,但是仍然存在一些问题需要我们去解决。首先我们可以先思考一下,
在之前的程序设计中Flash只有一个App程序的代码,此时程序是怎样运行的呢?关于单片机的启动流程可以
参考文末的链接,这里我们只需要简短的总结一下即可:单片机在上电后一直到准备好
C语言的运行环境并跳转到main函数中执行总共经历了5个步骤:
1.内核初始化;
2.强制PC指针指向中断向量表的复位中断向量执行复位中断函数;
3.在复位中断函数中调用 SystemInit 函数,初始化时钟,配置中断向量表等
4.调用 __main 函数完成全局/静态变量的初始化和重定位工作,初始化堆栈和库函数
5.跳转到main函数中执行

现在我们知道了,单片机在复位时会强制PC指针指向复位中断向量,在复位中断函数中完成一系列的初始化,最后再跳转到用户的main函数中执行我们自己编写的程序。当在做IAP升级时,想要的程序执行顺序应该是先执行Bootloader,然后再跳转执行App。通常理想情况是先通过Bootloader的复位中断跳转到Bootloader中的main函数执行,执行完成后再通过让PC指向App的复位中断向量,使得程序跳转到App的main函数中继续执行。这种情况Bootloader和App发生中断时都能单独跳转到各自的中断向量表中执行自己的中断服务函数。

note:这里可能存在两个问题:第一个问题是程序上电时PC指针是在内核初始化完成后强制指向复位中断向量的,但是这样只能跳转到第
一个程序的用户main函数中去,我们需要知道执行什么样的指令才能从第一个程序的main函数中跳转到第二
个main函数中去。这里我们可以参考一下官方的汇编跳转指令:
void _ASM_JumpTo_App(void)
{asm("LDW X,  SP ");asm("LD  A,  $FF");asm("LD  XL, A  ");asm("LDW SP, X  ");asm("JPF $9000");
}第二个问题是对于STM8而言当发生中断时(不管哪个程序),PC指针总指向Bootloader中断向量表相应
的中断向量(因为STM8中断向量表固定在这里,并且不可以映射到别的地址,这是硬件决定的),当第二个程
序发生了中断时,此时断服务程序肯定是在第二个程序里写的,中断服务函数的入口地址也在第二个程序范围
内,但是发生中断时,PC指针不会指向第二个bin文件的中断向量表,而是指向Bootloader中断向量表的地
址,这样也就无法执行App中的中断服务函数。有什么办法可以让我的程序发生中断时,PC指针指向我的中
断向量表呢?这里我们就需要了解一下STM8的中断机制:在参考手册中一般都会列出单片机系统所有的中
断向量及其对应的地址,每个中断向量都存放着4个字节的数据(8位的跳转指令+24位的跳转地址)在中断
发生时,会强制PC指针指向该中断向量的地址,然后取出该地址中的指令执行。例如: 当USART 的中断发生
时,通过查表知道USART2的中断向量存放在0x008054地址,此硬件会把PC指针强制等于0x008054也就是
从这个地址里取指令执行,而这个地址中存放的内容是0x82+OFFSET_ADDR,0x82是内部指令,意思是跳
转到后面的地址执行,OFFSET_ADDR,就是USART2的中断服务函数的入口地址, 这样最终就跳转到了
USART2 的中断服务函数中去执行。假设此时来了USART2的中断,Bootloader程序USART2中断向量地址是0x008054,APP USART2
中断向量地址是0x9054(假设APP从0x9000开始存放),此时PC指针一定等于0x00 8054,这时候就要
让它跳到0x009054就需要在0x008054这个地址放入:0x82009054,这样PC指针又跳回了APP的中断
向量表,然后再从中断向量表中取出USART2的中断服务函数并执行。这就是中断重定向,重定向之后就能
在APP程序中随意使用中断了。当然中断发生时还会有一些入栈操作,保存程序当前运行的地址,一些变量的值到栈中,当中断服务程序
执行完成后会从栈中恢复到执行中断前程序的运行状态,从而保证主程序的正常运行。另外还有,在STM8
中,0x82后面会跟着24位的地址:PCE + PCH + PCL,CPU最大寻址2^24=16M空间。

注意:对于STM32来说可以设置中断向量表的偏移地址,而STM8却不能设置偏移,只能通过重定向来使得我们的APP程序能够使用中断,但是重定向后的Bootloader中就不够使用中断了。

二 STM8 IAP 升级流程及实现

前面对升级过程中的一些问题进行了详细分析,其实实现IAP升级功能只需要5个步骤即可:

  1. 修改icf链接文件,并且设置新的.icf链接文件为当前工程的链接文件;
  2. 在Bootloader中重定向中断向量表;
  3. 自己编写或者下载一个bin文件的分包发送工具;
  4. 接收下载的内容写入到 Flash 中 ;
  5. 跳转执行app程序.

1.修改链接文件

由于APP需要设置起始地址为0x9000(假设BootLoader预留的空间为4k),这就需要修改App工程中的链接文件。

note:通常每个芯片开发商都会针对每款芯片来编写一个*.icf链接文件。通常这个*.icf文件足以满足你
的工程需要。但有时也会需要改动,比如重设程序的地址、添加外部RAM、定义变量的绝对地址等。

首先打开官方*.icf文件查看一下:


然后icf文件拷贝到当前工程的目录下,并选择拷贝过来的 icf文件为新的链接文件:

BootLoader需要做下面的修改(BootLoader小于4KB时):
如果BootLoader的程序不超过4KB(0x8000 - 0x8FFF),需更改0x80为0x100,因为重新映射了中断向量的定义,不然编译会报错。

APP需要做以下修改 (STM8L151C8T6是64KB的Flash,最大到0X17FFF) :

更多关于ICF文件的分析请参考文章 《IAR中ICF链接文件详细分析》

2. 重定向中断向量表

IAR中重定向中断只需要在Bootloader程序中定义以下数数组即可 (Bootloader为4k,APP地址为0x009000时):

 __root const long reintvec[]@".intvec"=  {  0x82008080,0x82009004,0x82009008,0x8200900c, 0x82009010,0x82009014,0x82009018,0x8200901c,0x82009020,0x82009024,0x82009028,0x8200902c,0x82009030,0x82009034,0x82009038,0x8200903c,0x82009040,0x82009044,0x82009048,0x8200904c,0x82009050,0x82009054,0x82009058,0x8200905c,0x82009060,0x82009064,0x82009068,0x8200906c,0x82009070,0x82009074,0x82009078,0x8200907c,};

注意:Bootloader的复位中断向量不需要修改。如果这里修改为了App中的复位中断向量地址,那就会直接跳转到App的复位中断函数中,然后再执行App的mian函数,就无法执行Bootloader中的程序了。

3. 编写Bootloader升级程序

Bootloader的实现可以很简单,只需要判断是否需要升级,如果不需要直接跳转到App的地址执行。如果需要升级,则获取App升级文件写入到Flash,最后再跳转到App的地址执行。

1. 升级判断条件
可以通过按键,主动获取版本号比较等方式判断是否需要升级2.下载升级文件传输bin文件可以通过很多方式,这里我自己用QT写了一个串口bin文件的传输工具,将bin文件分包
发送给单片机,单片机接收到数据后直接写入Flash即可。这里需要注意的是,普通的串口调试助手虽然能
够发送bin文件,但是无法分包,对于STM8来说一般一次只能接收2-4k的内容,接收完成后需要写到Flash
中, 然后再去接收下一包,所以最好能自己写一个下载工具,规定自己的传输协议。也考虑使用有传输延时
的串口工具或者超级终端,每发送完一行数据之后延时一定时间再发送下一包的数据,这样才能保证接收到的
数据能够正确写入flash中。另外需要注意,在Bootloader中不能够使用中断,所以串口接收只能通过while循环判断标志位来读
取串口接收的数据。3.写入flash每接收到一包数据之后写入flash,然后再偏移写入地址,接收下一包数据继续写入,直到最后一包数
据写入完成后,再跳转执行。这里需要注意的是,如果需要使用STM8的块擦除FLASH_EraseBlock和块写
入FLASH_ProgramBlock等函数,需要注意库函数中的这段注释的内容:
- For IAR Compiler:
1- Use the __ramfunc keyword in the function declaration to specify that it
can be executed from RAM.
This is done within the stm8l15x_flash.c file, and it's conditioned by
RAM_EXECUTION definition.
2- Uncomment the "#define RAM_EXECUTION  (1)" line in the stm8l15x.h file, or
define it in IAR compiler preprocessor to enable the access for the
__ramfunc functions.这里提示了需要将FLASH_EraseBlock,FLASH_ProgramBlock等函数用 __ramfunc关键字声明,
将这些函数定义到ram中,在ram中执行。这里还说明了要使用__ramfunc关键字需要在stm8l15x.h文件
中取消#define RAM_EXECUTION (1) 这行的注释。4. 跳转到app地址执行
可以直接使用官方例程中提供的汇编跳转代码:
void _ASM_JumpTo_App(void)
{
asm("LDW X,  SP ");
asm("LD  A,  $FF");
asm("LD  XL, A  ");
asm("LDW SP, X  ");
asm("JPF $9000");
}

其他参考:
单片机启动流程分析
单片机内存分配详解

STM8 IAP升级程序设计详解 - IAR环境相关推荐

  1. iar升级芯片库_STM8 IAP升级程序设计详解 - IAR环境

    1.STM8内存空间分配 首先我们在STM8L15x的官方手册中查看一下CPU的内存空间分配: 除了系统预留的部分我们实际用到的内存空间并不多,下面简单说明主要部分: -- RAM 0x00 0000 ...

  2. STM32芯片IAP升级机制详解

    一.先了解ICP和ISP.IAP之间的区别: 1. ISP(In System Programing 在系统编程)的实现相对要简单一些,一般通用做法是内部的存储器可以由上位机的软件通过串口来进行改写. ...

  3. 图文详解Java环境变量配置方法

    今天动力节点java学院小编为大家介绍"图文详解Java环境变量配置方法",希望对各位小伙伴有帮助,下面就和小编一起来看看Java环境变量配置方法吧. 首先是要安装JDK,JDK安 ...

  4. 程序的编译(详解翻译环境)

    程序的编译 1. 程序的翻译环境和执行环境 2. 详解翻译环境 2.1 详解编译过程 2.1.1 预编译(预处理) 2.1.2 编译 ①词法分析 ②语法分析 ③语义分析 2.1.3 汇编 ①将汇编代码 ...

  5. 【嵌入式开发】 Bootloader 详解 ( 代码环境 | ARM 启动流程 | uboot 工作流程 | 架构设计)

    作者 : 韩曙亮 博客地址 : http://blog.csdn.net/shulianghan/article/details/42462795 转载请著名出处 相关资源下载 :  -- u-boo ...

  6. java环境变量设置详解_JAVA环境变量配置详解(Windows)

    JAVA环境变量JAVA_HOME.CLASSPATH.PATH设置详解 Windows下JAVA用到的环境变量主要有3个,JAVA_HOME.CLASSPATH.PATH. JAVA_HOME指向的 ...

  7. 详解 Linux环境中DHCP分配IP地址(实验详解)

    Linux中DHCP小实验详解 一.DHCP中继概述 二.DHCP在linux系统中的相关配置 1.配置DHCP服务器 2.设置全局配置参数 3.subnet网段声明 4.host主机声明 三.实验例 ...

  8. 详解Linux环境软RAID 5建立过程

    1:Raid定义   RAID,全称Redundant Array of Inexpensive Disks,中文名为廉价磁盘冗余阵列.RAID可分为软RAID和硬RAID,软RAID是通过软件实现多 ...

  9. 【转】linux /centos 中OpenSSL升级方法详解

    相关软件下载地址Apache:http://httpd.apache.org/ Nginx:http://nginx.org/en/download.html OpenSSL:http://www.o ...

最新文章

  1. insert into与insert ignore以及replace into的区别
  2. mybatis-嵌套(关联)查询/ N+1 / 延迟加载
  3. 设计模式之Composite模式(笔记)
  4. false shell 判断_六、Shell流程控制-if判断语句
  5. 再议libcurl编程
  6. 从功能、交互、性能全方位解读,BI工具FineBI4.0.2测评报告
  7. 2017.8.14 分手是祝愿 失败总结
  8. 《C++ Primer Plus(第六版)》(30)(第十四章 C++中的代码重用 编程题答案)
  9. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn
  10. MODULE_DEVICE_TABLE【转】
  11. 华为OLT(MA5680T)修改系统时间
  12. 互联网大病公益众筹项目文本分析
  13. ffmpeg将文件转码后推向服务器,FFmpeg转码服务器搭建
  14. adb官方最新下载链接和常用操作
  15. 达芬奇的十大经典名画解读
  16. NEWLAB之光照度传感综合实验(一)——实验介绍
  17. 微机原理与接口 极其基础知识点
  18. IMX6UL GPIO复用
  19. java-php-python-ssm“花花世界”网站计算机毕业设计
  20. ac1900 linksys 恢复_tplink ac1900路由器怎么恢复出厂设置? | 192路由网

热门文章

  1. python调用youdao百度翻译API,翻译文本(tcy)
  2. 剑指offer66之构建乘积数组(java)
  3. IT忍者神龟之javascript规范
  4. 【HTML特效程序】① 给女神表白的程序(让女神看科技烟花),输入名字自动生成表白二维码
  5. 全新证照之星XE版下载及发布新增功能介绍
  6. HTML中DIV常用属性
  7. 问题 AZ: 找朋友
  8. 农村电商是什么,如何做农村电商?
  9. 整理了 10 本前端好书分享给大家~
  10. 微软新一代搜索引擎NEW Bing如何提前注册使用