|
学习了一下使用Ymodem协议串口IAP程序升级的功能,移植的是ST的工程文件。附上下载链接http://www.st.com/content/st_com/en/search.html#q=IAP-t=tools-page=1;ST官网提供的各种IAP,其方法和原理其实都类似:就是将程序文件(二进制文件)写入FLASH。 9 u, y# y O. ~ E& J
% e3 `0 @) r& x& F9 h4 p! }3 j7 d* G# Q' B) p7 |0 q) d/ W
7 K4 A, Q" b: B- b 1、Ymodem协议简介8 w8 r8 v- A8 N
Xmodem、Ymodem和Zmodem协议是最常用的三种通信协议。Xmodem协议是最早的,传输128字节信息块。Ymodem是Xmodem的改进版协议,具有传输快速稳定的优点。它可以一次传输1024字节的信息块,同时还支持传输多个文件。以下协议内容的简介,顺便添加了一点自己的见解。 ( H4 l6 J$ G' p3 N, g4 z& n0 d3 }
; }; q* |( I9 o8 I. h' A, N8 J( w6 x" ~) o/ t' l# r
YModem,数据的发送回使用CRC校验,保证数据传输的正确性。它每传输一个信息块数据时,就会等待接收端回应ACK信号,接收到回应后,才会继续传输下一个信息块,保证数据已经全部接收。
, g$ D, @3 r+ i4 J( Q" g* e- A
- SENDER:发送方。3 r/ g( P" K0 Y* T
- RECEIVER:接收方。
9 G7 Q+ d( l7 K& y2 T5 [ - 第一步先由接收方,发送一个字符'C'; q8 b( g) G& z; {3 a& |7 N6 u0 `
- 发送方收到'C'后,发送第一帧数据包,内容如下:8 g: d. f- _: k4 p( n" x- U1 `
- **SOH 00 FF filename filezise NUL CRCH CRCL**/ S! O3 R" ?2 ^' o4 ^* X3 o
- 帧长=3字节数据首部+128字节数据+2字节CRC16校验码=133字节
S& w7 i p. _8 ]8 } - 如下所示:
, A: u P* {6 q - SOH 00 FF Foo.c NUL[123] CRCH CRCL
4 I' m) K8 r4 F" v; H' O& P9 ^ - 第1字节SOH:表示本包数据区大小有128字节。如果头为STX表示本包数据区大小为1024字节。
! u' I/ g' `( n3 z$ ~ l -
+ L! W; H; s- W4 K T - 第2字节00: 编号,第一包为00,第二包为01,第三包为02依次累加。到FF后继续**从0循环递增**。这样就会出现一个BUG,那就是文件在传输大小上有限制,256x128 = 32768 字节 **32K的限制**。
; @) r. v( H2 R8 C -
& s- O+ H9 ^7 q! I1 K9 Z - 第3字节FF: 编号的反码。 编号为00 对应FF,为01对应FE,以此类推。
9 K2 d$ n* w6 z -
G& ] S4 S1 D7 g- t/ [9 d9 y5 S$ k/ l - 第4字节到最后两字节:若第1字节为SOH时有128字节,为STX时有1024字节,这部分为数据区。“Foo.c” 文件名, 超级终端下,在文件名后还有文件大小。官方dome也是因为使用了这个文件大小进行比对。这就是为什么用SecureCRT中的YMODEM协议而无法正确传输的原因。在文件名和文件大小之后,如果不满128字节,以0补满。最后两字节:这里需要注意,只有数据部分参与了效CRC验,不包括头和编码部分。
) r+ h4 M" I8 j p - 9 m+ B. X0 z0 w1 Z, M$ b
- CRCH和CRCL分别表示16位CRC校验码的高8位与低8位,高字节在前,低字节在后。
$ V# X: S6 O; R - 7 C$ o; V- F$ c! @
- 接收方收到第一帧数据包后,发送ACK正确应答。/ H2 v) k0 a# a: ?8 @# b
-
# n9 g. [( \6 a$ Y: Y! d' {, H - 然后再发送一个字符'C'。
( t7 q4 ?6 }0 m9 G+ w" f - 8 [+ R3 ~$ ?9 {; W% o/ u: _" Z) m- p
- 发送方收到'C'后,开始发送第二帧,第二帧中的数据存放的是第一包数据。
) Z/ \* [( c; V) t0 q; ] C -
: L8 x4 R# X8 A# c0 r+ I$ b) P+ C - 接收方收到数据后,发送一个ACK然后等待下一包数据传送完毕,继续ACK应答。直到所有数据传输完毕。# u7 S" D- ?9 h
-
: l+ A# w7 {# V9 ~, ^% e - 数据传输完毕后,发送方发EOT,第一次接收方以NAK应答,进行二次确认。
5 e. u o; h' u& ]! D4 {9 w) N- r - + d7 J0 k/ H' {7 g/ I! j
- 发送方收到NAK后,重发EOT,接收方第二次收到结束符,就以ACK应答。
: q0 H, l. X* K, v3 V - 5 ]0 Z }# R9 c/ H! q1 `0 ~6 d
- 最后接收方再发送一个'C',发送方在没有第二个文件要传输的情况下,. i2 R' M8 D3 X' r }# z
- 发送如下数据:2 _8 C/ e/ G; b. v. X$ u% ?% z
- SOH 00 FF 00~00(共128个) CRCH CRCL
0 ^- x3 j k& t1 {; z+ G6 ? h - 接收方应答ACK后,正式结束数据传输。
复制代码 ' F" u3 i2 U9 h& M9 P' l% }+ G! r
2、Boodload程序
! E5 b* J5 M' S" k下面所示的部分是移植的文件,移植完成后的工程文件截图: 5 v* T$ X! C( N: H
5 l; q% q! w- K! X; Y! l8 y" Q
( P- V7 ~, n3 }4 B- Zmain.c 文件修改添加:
: a' K/ A3 N4 D$ P
& b# T( D- @7 x: d* g
( N/ S# x6 g+ h- K# P( i- r, {
# X# z( T! K# Q* w: j/ @: @6 A8 P- /* USER CODE BEGIN Includes */
, u3 B9 s4 \ P: p - #include "menu.h"4 F, B0 Y6 b4 E, s
- #include "flash_if.h" Y" z* _+ k: `. D1 `2 s6 I
- /* USER CODE END Includes */
复制代码
5 p$ B! {1 H% c& C
. \+ f x0 C+ S
, r/ @% N3 n' _- /* USER CODE BEGIN 0 */
- j" r) A7 b: y- `' j) U - extern pFunction JumpToApplication;
9 D9 R3 Y' n: j$ j' i' L% a - extern uint32_t JumpAddress;
, J1 Q5 m) A6 |% p8 ]2 H - /* USER CODE END 0 */
复制代码
6 O* V3 p8 u0 X% _. t4 W" E! |9 z* J
) c6 a% K/ G( j, R6 B0 f! w& f' T( |/ K8 Q# y/ s: U- I2 N
2 B6 f$ w1 O1 D' d/ C- /* USER CODE BEGIN 2 */
4 o/ E( l, {. q8 S) o - HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);" w# S# R$ G. {" V
- if (1)
% b5 L5 S3 L' O$ l2 v - {/ v$ x2 s( r) g1 K7 u1 i
- /* Execute the IAP driver in order to reprogram the Flash */! W9 v5 ]* S9 N ]
- FLASH_If_Init();
, U& Y/ @7 l1 Q+ v& z7 S5 m# e" P* U - /* Display main menu */* j- ^" M* }/ ~
- Main_Menu();" T" V9 F5 v0 P
- }
9 E. {( q; M$ u/ S2 I- f - /* Keep the user application running */
( y! M8 D( i1 E8 Y2 @5 O/ m - else0 i& @3 J D1 G+ n
- {
% }; g- R; E" L; u3 G* b+ V - /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */: [2 S3 S( L) K) v6 P4 u4 l" m s
- if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) 检查栈顶地址是否合法.
& d4 M4 ?: x% R - {
- T4 B7 x! Q% N# x: p - /* Jump to user application */
- W! N. G; F( c* f8 |! r* j- o - JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4); //用户代码区第二个字为程序开始地址(复位地址)
- u8 z! h* |+ l" D! B# i - JumpToApplication = (pFunction) JumpAddress;1 q: n& T2 S% {9 A# b. {
- /* Initialize user application's Stack Pointer */% f+ M3 N7 a0 P. y3 u
- __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
$ P! k2 O6 e7 V! {; G - JumpToApplication(); //跳转到APP. L! Q, b$ Z& r
- }/ B" ?' Z# ~' X
- }
复制代码 + m5 j+ Z4 Q: N% i& `. D& z" \! q6 O3 R
还要修改flash_if.h 头文件里面的地址。
9 W5 F3 t9 i4 k; J3 B, K5 B; e a" k1 r* u3 @* f: n
+ I! L1 H$ ?3 r
APPLICATION_ADDRESS 是偏移的地址,可以根据自己程序Boodload文件大小自己设置,USER_FLASH_SIZE 是 APP文件的大小。
4 V) w8 T Z2 B# ~. v% [
- A- T1 |$ C- |; M
2.1 传输32K限制解决( V- {1 B( U; r/ Y8 J5 r8 [! w
secureCRT每包只传输128个字节的有效数据,而每个帧的标号由一个字节表示,所以等到标号到达0xFF之后,下一个帧的标号又变为0,而官方Ymodem程序是判断帧标号为0则认为是传输文件的第一个帧,即文件名和文件大小。所以等到标号由0x00-0xff再到0x00的时候,它认为是一个新的文件,所以出错。只要加一个标志标明第一次出现的帧标号为0的帧为第一帧就OK了。
( U+ X4 z: G) @0 spackets_received 声明为U32类型的数据,判断的时候修改如下
; v5 Y+ [' p0 E: y0 Oif (aPacketData[PACKET_NUMBER_INDEX] != (packets_received & 0xff)) 0 J; k- |4 l% s! Y9 R
! k! b8 q2 N( v/ Y5 k2 a( T# A$ g
7 H" r/ X |" C; U. \. F8 J v) {3 Y+ I5 r- j+ j! R5 y7 [
& ~& u: x+ N$ @) W. Z3、APP程序) i! W3 L$ Q5 n/ H
App需要修改内容: , m! B7 S( E& a' W2 S
编译链接其实地址 8 n$ p4 H) d7 l
4 m/ d# w5 y, T7 u9 Z
中断向量修改。
2 |; ?- I$ ]: e) V- s, `: ~
9 I) r& {. z2 d6 A3 `5 P
( e4 t: K E {; K6 | 4、升级测试
! r7 n; n% |/ z& F* I软件使用secureCRT发送文件。9 n. Y8 Z" l! c$ b. J* X9 B
8 Y- v8 ?1 E1 i/ K9 p; F/ I7 U7 e: C z
/ `( O, U+ p; I+ ]* L
/ l: a( Y& w% g# \* M; `# l# h' E4 `
5 n3 N+ A0 G) s
8 ^ b8 ?' C: a5 `: |
% L8 t" n4 N0 W* q( A
" I2 F3 y l/ }' g1 J% e6 j( I/ O9 U; O9 w# S
; _) u9 f3 H" u5 _! w+ P& I* |) e3 @
|
官方版本库太旧,移植时候出现大量写保护的相关的寄存器找不到定义
这教程对F0系列App部分有点不适用
我调通了
稍后发个教程
不考虑接收方接收异常的情况么