硬件:stm32f103cbt6

软件:STM32F10x_StdPeriph_Lib_V3.5.0


1 预备知识

基于标准外设库(STM32F10x_StdPeriph_Lib_V3.5.0)的IAP升级相关资料可以参考 IAP ST官方资料汇总。

STM32升级的三种方式:IAP,ICP,ISP;具体有什么区别可以自行Google;

本文需要实现STM32的Bootloader(后面Bootloader/IAP不加以区分),文件传输基于ymodem协议通过串口进行传输,这里参考了ST官方的DEMO —— STM32F10xxx in-application programming using the USART AN2557,在此基础上做了部分修改,增加了延时启动的功能,最终可以实现想要的效果。



整体架构分为两个部分;Bootloader和Application,具体如下图所示;

由上图可知,STM32内置的Flash被分成了两个部分,分别用来保存Bootloader和Application程序,这里有两个有两个FLASH起始地址0x8000000和0x8003000;

为什么是0x8000000这个地址呢?而不是其他地址呢?

这是由M3内核硬件上的设计就已经这么做了,人为设计好了,可以参考M3内核权威指南;

0x8003000这个地址则是由我们自己来规定的,这个地址的范围必须在0x8000000和0x8020000之间,所以一般根据Bootloader程序的最终大小,在这范围之间取一个比较合理的值即可。如下图所示;

注意:本文使用的stm32f103cb,属于中等大小Flash,128K = 0x20000,所以地址范围是0x8000000~0x8020000;

2 Bootloader

2.1 启动流程

这里的Bootloader即为IAP程序,它具备以下几个功能;

  • 支持文件传输;本文基于ymodem协议通过串口通讯接收或发送的bin文件;当然也可以通过I2C,SPI,USB,WiFi,蓝牙等等进行文件传输;
  • 对内置Flash进行读写,擦除和编程;
  • 启动Application程序;

前面分析STM32启动文件的时候,我们可以知道,正常一个系统的启动流程,可以参考《STM32 标准库V3.5启动文件startup_stm32f10xxx.s分析》;

由该图可以知道程序正常启动流程;以下表格一四个向量是必须的,从图中也可以了解到;

地址 异常编号 值
0x0800_0000 - MSP 的初始值
0x0800_0004 1 复位向量(PC 初始值)
0x0800_0008 2 NMI 服务例程的入口地址
0x0800_000C 3 硬 fault 服务例程的入口地址
… … …

2.2 校验跳转地址是否有效

在主函数中可以看到如下程序;甚是不解和迷茫;沉思一会儿才恍然大悟;

    /* Test if user code is programmed starting from address "ApplicationAddress" */
if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
{
/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
}

本文中ApplicationAddress = 0x8000000;

那么*(__IO uint32_t*)ApplicationAddress)则是这个地址中所保存的值,由表格一可以知道,程序起始地址的第一个向量地址保存的栈顶的,因此,地址0x800_0000和0x800_3000中保存的值都是指向栈顶,如下图所示;

栈是在RAM上分配,因此RAM的有效范围要做一个检测,栈顶地址和0x2FFE0000做与运算可以推算出,要校验的RAM范围是0x2000_0000—0x2001_FFFF,所以RAM大小是128K,官方DEMO默认使用HD高密度系列,所以是128K,本文是CBT6,20K的RAM,则需要改成0x2FFFB000:

    /* Test if user code is programmed starting from address "ApplicationAddress" */
if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFFB000 ) == 0x20000000)
{
/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
}

计算方式:

20K = 20*1024= 0x5000,

0x2FFF_FFFF - (0x5000 - 1) = 0x2FFF_B000

2.3 Keil工程IAP的相关设置

2.3.1 修改Flash地址



设置程序起始地址0x800000和大小0x3000;

设置Debug工具烧写时Flash的起始地址0x800000和大小0x3000;

2.3.2 使用自己的链接脚本

该项为选配,与上述配置二选一即可,如果仍然想使用自己的链接脚本,在Option-->Linker下将Use Memort Layout from Target Dialog选项勾选去掉,然后选择自己的链接脚本,如下图进行配置;

参考ARMCC的链接脚本编写方法,可以自己编写的srt文件,参考ARM分散加载技术;

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; ************************************************************* LR_IROM1 0x08000000 0x00003000 { ; load region size_region
ER_IROM1 0x08000000 0x00003000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x00005000 { ; RW data
.ANY (+RW +ZI)
}
}

如果用的gcc工具链,则要编写gcc的链接脚本ld文件;

2.3.3 下载固件

配置完成之后进行Build,然后通过SWD的方式先下载固件,进行实验;

3 Application

3.1 启动流程

用户的Application需要在IAP启动完成后,才能正常执行;具体启动过程,比正常应用的启动多了一个IAP启动的过程,并最终通过IAP引导进入Application;具体如下图所示;

白色部分为IAP;

灰色部分为Application;

图中的0x8000004+N+M 就等于0x8003004,所以Application的启动地址需要进行修改,另外还有其他需要修改的地方,下面会详细指出。

3.2 IAP中的引导部分

参考IAP中的引导程序;

#define ApplicationAddress    0x8003000
      /* Jump to user application */
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();

可以发现的是SP的值为0x8003000,指向栈顶,而0x8003004则为ResetHander的地址,系统会进行复位,然后开始Application正常启动流程;

3.3 关于 VTOR

VTOR是向量表偏移量寄存器,它将用来告诉CPU,从Flash的哪个地方去取向量地址,第一个要取的是MSP的值,然后就是复位向量地址ResetHandler,如果这里设置错误,那么程序是无法正常启动的。下面是标准库中与其相关的代码片段;

__IO uint32_t VTOR;  /*!< Offset: 0x08  Vector Table Offset Register  */

/*!< FLASH base address in the alias region */
#define FLASH_BASE ((uint32_t)0x08000000) /*!< Vector Table base offset field. This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x0 /* Vector Table Relocation in Internal FLASH. */
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;

所以Application中还需要修改VECT_TAB_OFFSET的值为0x3000;

参考M3权威指南:

如果需要动态地更改向量表,则对于任何器件来说,向量表的起始处都必须包含以下向量:

  • 主堆栈指针(MSP)的初始值
  • 复位向量
  • NMI
  • 硬 fault 服务例程

    后两者也是必需的,因为有可能在引导过程中发生这两种异常。可以在 SRAM 中开出一块空间用于存储向量表。在引导期间先填写好各向量,然后在引导完成后,就可以启用内存中的新向量表,从而实现向量可动态调整的能力。

3.4 Keil工程设置

3.4.1 Flash地址设置

与IAP工程设置类似,这里的Application是另一个Keil工程,同样的需要对Flash进行设置,如下图所示;



这里Application工程的Flash地址偏移了0x3000,正是之前Bootloader所占用的Flash空间大小,这里和VTOR的设置也必须保持一致;

3.4.2 hex2bin

配置工程最终生成hex文件,如下图所示;

最终我们需要使用的是bin文件,所以,这里需要使用将hex文件转成bin文件,本文使用hex2bin的工具;配置工程运行之后执行转换文件的脚本;



create_bin.bat

echo %cd%
set ROOT_PATH=.\..\..
set SRC=%ROOT_PATH%\..\Project\STM32F10x_StdPeriph_Template\MDK-ARM\STM3210B-EVAL\*.hex
set TOOL=%ROOT_PATH%\..\Bin\hex2bin.exe if exist %SRC% (%TOOL% %SRC%)
exit

copy_firmware.bat

echo %cd%

set ROOT_PATH=.\..\..
set HEX_FILE=%ROOT_PATH%\..\Project\STM32F10x_StdPeriph_Template\MDK-ARM\STM3210B-EVAL\*.hex
set BIN_FILE=%ROOT_PATH%\..\Project\STM32F10x_StdPeriph_Template\MDK-ARM\STM3210B-EVAL\*.bin
set DST_DIR=%ROOT_PATH%\..\Firmware\
if exist %HEX_FILE% (XCOPY /Y /S /F %HEX_FILE% %DST_DIR%)
if exist %BIN_FILE% (XCOPY /Y /S /F %BIN_FILE% %DST_DIR%)
exit

最终在Build之后,可以在Firmware中找到STM321-APP.bin,这个文件就是要用来IAP程序进行串口下载的程序。

3.4.3 用户程序串口下载测试

SecureCRT软件支持ymodem协议,可以安装该软件,打开串口连接,设置ymodem的协议;

打开菜单选项:Options–Session Options,配置如下;



为了便于测试,在STM32F1-APP进行串口发送以下信息,便于观察APP是否正常启动;

usart_printf(" \r\n STM32F1-APP start running*******************");

打开连接的串口,并根据终端提示进行操作,最终下载固件STM32F1-APP成功,并成功运行;

4 附件

stm32f10x-bootloader

STM32 Bootloader基于ymodem传输协议串口IAP升级详解的更多相关文章

  1. 实时消息传输协议(RTMP)详解

    一.概念与摘要 RTMP协议从属于应用层,被设计用来在适合的传输协议(如TCP)上复用和打包多媒体传输流(如音频.视频和互动内容).RTMP提供了一套全双工的可靠的多路复用消息服务,类似于TCP协议[ ...

  2. 安全超文本传输协议(HTTPS)详解

    一.概念与摘要 HTTPS (Secure Hypertext Transfer Protocol)安全超文本传输协议,是一个安全通信通道,它基于HTTP开发用于在客户计算机和服务器之间交换信息.它使 ...

  3. stm32 Bootloader设计(YModem协议) (转)

    源:stm32 Bootloader设计(YModem协议) 相信很多人都希望,不开盖就可以对固件进行升级吧,就像手机那些.下文中的bootload就来实现这样的功能. 前段时间有项目关于Bootlo ...

  4. FTP协议及工作原理详解

    1. FTP协议 什么是FTP呢?FTP 是 TCP/IP 协议组中的协议之一,是英文File Transfer Protocol的缩写. 该协议是Internet文件传送的基础,它由一系列规格说明文 ...

  5. 第8章 应用协议 图解TCP/IP 详解

    第8章 应用协议 图解TCP/IP 详解 8.1 应用层协议概要 应用层协议的定义 TCP和IP等下层协议是不依赖上层应用类型.实用性非常广的协议.而应用协议则是为了实现某种应用而设计和创造的协议. ...

  6. TCP协议粘包问题详解

    TCP协议粘包问题详解 前言 在本章节中,我们将探讨TCP协议基于流式传输的最大一个问题,即粘包问题.本章主要介绍TCP粘包的原理与其三种解决粘包的方案.并且还会介绍为什么UDP协议不会产生粘包. 基 ...

  7. C#串口通信程序详解

    C#串口通信程序详解 摘要:创建C#串口通信程序需要注意什么呢?创建C#串口通信程序的步骤是什么?那么本文就向你详细介绍创建C#串口通信程序集体的内容. 在.NET平台下创建C#串口通信程序,.NET ...

  8. SSL协议之数据加密过程详解

    前言 总括: 原文博客地址:SSL协议之数据加密过程详解 知乎专栏&&简书专题:前端进击者(知乎)&&前端进击者(简书) 博主博客地址:Damonare的个人博客 生活 ...

  9. Java生鲜电商平台-APP/小程序接口传输常见的加密算法及详解

    Java生鲜电商平台-APP/小程序接口传输常见的加密算法及详解 说明:Java生鲜电商平台-APP/小程序接口传输常见的加密算法及详解,加密算法,是现在每个软件项目里必须用到的内容. 广泛应用在包括 ...

随机推荐

  1. 资料整理:python自动化测试——操作测试对象

    文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:爱吃米饭的猪 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自 ...

  2. L19深度学习中的优化问题和凸性介绍

    优化与深度学习 优化与估计 尽管优化方法可以最小化深度学习中的损失函数值,但本质上优化方法达到的目标与深度学习的目标并不相同. 优化方法目标:训练集损失函数值 深度学习目标:测试集损失函数值(泛化性) ...

  3. 原创Hbase1.2.1集群安装

    [hadoop@Hmaster install]$ tar -zxvf hbase-1.2.1-bin.tar.gz -C ~ [hadoop@Hmaster install]$vi ~/.bash_ ...

  4. Python - 翻译Talk Python To Me (和我聊Python) 播客

    “和我聊Python”是一个美国的聊天播客,英文名Talk Python To Me,类似于喜马拉雅的音频课程节目,只不过这个主题是编程语言Python.该节目从2015年的节目到现在,已经超过256 ...

  5. TortoiseSVN的使用,以及冲突解决办法

    接下来,试试用TortoiseSVN修改文件,添加文件,删除文件,以及如何解决冲突等. 添加文件 在检出的工作副本中添加一个Readme.txt文本文件,这时候这个文本文件会显示为没有版本控制的状态, ...

  6. Upload-Labs 实验操作记录

    0x01 安装 下载:https://github.com/c0ny1/upload-labs 环境:简单搭建phpstudy环境即可,记得在upload-labs根目录下创建该文件夹 0x02 文件 ...

  7. 详解PHP反序列化中的字符逃逸

    首发先知社区,https://xz.aliyun.com/t/6718/ PHP 反序列化字符逃逸 下述所有测试均在 php 7.1.13 nts 下完成 先说几个特性,PHP 在反序列化时,对类中不 ...

  8. Redis 5.0.9 安装

    目录 系统环境 系统版本 内核版本 安装步骤 安装 gcc 依赖 下载 Redis 解压 Redis 切换到 redis 解压目录下,执行编译 指定目录安装 启动 Redis 服务 最后 系统环境 系 ...

  9. python入门学习之Python爬取最新笔趣阁小说

    Python爬取新笔趣阁小说,并保存到TXT文件中      我写的这篇文章,是利用Python爬取小说编写的程序,这是我学习Python爬虫当中自己独立写的第一个程序,中途也遇到了一些困难,但是最后 ...

  10. System.Timers.Timer

    前言 System.Timers.Timer组件是基于服务器的计时器,它能够指定在应用程序中引发Elapsed事件周期性间隔,以处理相应事件. 使用示例: 运行结果展示: System.Timers. ...