__initial_sp是堆栈指针,它就是FLASH的0x8000000地址前面4个字节(它根据堆栈大小,由编译器自动生成)0x8000004才是复位向量,所以需要在add+4 这两天再看IAP实验,觉得很实用,最近在做一个小项目,日后也肯定需要升级的。原子的程序是写在STM32的内部Flash,内部SRAM。还可以把程序写到外部Flash或者SD卡来更新。 目前做了第一步:从串口更新,移植的正点的代码。先将IAP bootload写入ROM起始地址,这里我的ROM总共256k,我分了一半给bootload,一半给app。注意设置地址问题。 只更新了Flash app。用的流水灯实验。SD卡FAT目前先没用,空间节省不少啊,这个RAM,ROM占用很厉害啊。这个问题还需要去解决。 串口接收APP设置了10k容量。 流程:1,Jlink写bootload到ROM起始,与平时一样 2,串口发送app.bin,串口接收 3,将接收的app.bin写入flash的指定app位置 4,使用bootload中的函数跳转到flash的指定app位置,执行app。 ; A& z, S% \( h1 Z" H* y3 c
- 1 #ifndef __IAP_H__. `; E' ?# U i" ~8 u, L- k h5 G& u
- 2 #define __IAP_H__4 n8 X- D$ W* Y, G1 ~7 @
- 3 #include "sys.h" " \8 c8 m( u$ p8 t; m5 b, Z
- 4 //////////////////////////////////////////////////////////////////////////////////
" d u8 Z, h) i% Y" k( B - 5 //本程序只供学习使用,未经作者许可,不得用于其它任何用途
) X t( E" S* P9 Q8 o - 6 //ALIENTEK战舰STM32开发板
) y) O# |1 b# X8 k) k c - 7 //IAP 代码
( N; `+ a' t, J/ g1 M - 8 //正点原子@ALIENTEK/ E8 h# b. J: l/ F7 }
- 9 //技术论坛:www.openedv.com# j; W2 E* p# R
- 10 //修改日期:2012/9/24
# R( o, @) d$ c8 w - 11 //版本:V1.0/ Y7 Y8 ?: ~1 M; r" V
- 12 //版权所有,盗版必究。
- [2 A! S3 H) _ - 13 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019
# W4 d% p; ?; a' p) K; z. b - 14 //All rights reserved 6 U1 R" W# @7 |
- 15 ////////////////////////////////////////////////////////////////////////////////// # N+ P5 |) y: D/ a# V
- 16 typedef void (*iapfun)(void); //定义一个函数类型的参数.- c4 j5 f: U& G, q& I4 I
- 17 9 x: b8 O5 O& b. A
- 18 #define FLASH_APP1_ADDR 0x08020000 //第一个应用程序起始地址(存放在FLASH)
% C: s: b! G; x, e% m6 g - 19 //保留0X08000000~0X0800FFFF的空间为IAP使用
: ^2 J2 O. ?4 n+ p2 s6 |. _ - 20 . B+ \/ N$ _& O
- 21 void iap_load_app(u32 appxaddr); //执行flash里面的app程序
( r$ v, h. }5 \8 k- i# ~ - 22 void iap_load_appsram(u32 appxaddr); //执行sram里面的app程序1 j8 f q9 R% W! B, G8 B
- 23 void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 applen); //在指定地址开始,写入bin
% r( C1 H/ _# G1 h: w$ F - 24 #endif
/ q( R, @ N/ ~6 v; _# W6 I, {
复制代码- 1 #include "sys.h"
/ X; F" A* T: `% M( M/ z3 W D - 2 #include "systick_config.h"
Z, o5 _) x% y* U - 3 //#include "stmflash.h"
6 J6 Q2 [2 N( Z& I - 4 #include "iap.h"; r: H: C, G; i0 |
- 5 //////////////////////////////////////////////////////////////////////////////////
$ {. o) a# O% m0 a; B - 6 //本程序只供学习使用,未经作者许可,不得用于其它任何用途
1 Q% o1 \8 k0 A1 |* | - 7 //ALIENTEK战舰STM32开发板
8 u5 Y3 G G. X6 n% S - 8 //IAP 代码
; o8 b" A# e+ A2 w" x - 9 //正点原子@ALIENTEK
8 v0 G! d. p4 x7 x - 10 //技术论坛:www.openedv.com. i2 ~: q0 X6 a) x$ e. U
- 11 //修改日期:2012/9/24
( `1 x: {0 ^, M4 v - 12 //版本:V1.08 [7 u; q* H: N& Z/ y* p; W+ C
- 13 //版权所有,盗版必究。9 \: W$ K: k* a& G# h
- 14 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019
- I6 _- y" b2 s4 b% B - 15 //All rights reserved
P0 B0 q$ X( A# w2 Z8 [ - 16 ////////////////////////////////////////////////////////////////////////////////// 7 h1 `9 u. V4 C. t7 k
- 17
( n/ h' K8 a1 q - 18 iapfun jump2app; 4 q/ g/ [: A y% `1 \
- 19 u16 iapbuf[1024];
( k7 X- h' o) g, ^0 j! K7 N - 20 //appxaddr:应用程序的起始地址
' u: E' M7 C$ X6 f% N - 21 //appbuf:应用程序CODE.
( F5 d! H2 |6 S; z - 22 //appsize:应用程序大小(字节).
6 [9 @4 v% B/ z& I, y' g( j - 23 void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
2 }7 P2 f4 G; s/ r8 B9 k* v3 S - 24 {
) y; r/ V; A% p0 E) ^: V; C: f+ R0 A - 25 u16 t;
; z4 e# \7 L9 h - 26 u16 i=0;
1 \; ^5 w. k" {/ @$ h3 c - 27 u16 temp;
& b$ T! H6 u ] - 28 u32 fwaddr=appxaddr;//当前写入的地址) I% Y1 R& l) P
- 29 u8 *dfu=appbuf;9 ]) u! I$ j% q5 r }# i
- 30 for(t=0;t<appsize;t+=2)$ S. }2 z+ T: M, L/ `6 t3 m
- 31 { ; Q0 r5 y/ i4 ~5 h0 \# T
- 32 temp=(u16)dfu[1]<<8;, g, E4 y% P( C9 L, R
- 33 temp+=(u16)dfu[0];
$ m; s0 Z6 N6 E0 G, l, s- a2 Z. M9 [ - 34 dfu+=2;//偏移2个字节1 k) J5 F- y) y9 v2 `2 G
- 35 iapbuf[i++]=temp; ' q: @1 m) v, M" n3 c
- 36 if(i==1024)1 _" s. Y, w. A, r ?4 a) ^
- 37 {$ ]; e0 C4 i! O" w3 k" B) H
- 38 i=0;: E9 G X/ I' d1 U
- 39 STMFLASH_Write(fwaddr,iapbuf,1024);
6 F4 D/ I. {+ L* X' {/ m5 I - 40 fwaddr+=2048;//偏移2048 16=2*8.所以要乘以2.$ e, v! A, P( H. F E" j
- 41 }
% h& Q+ E1 B) ]4 ?+ x - 42 }
7 X$ k J4 [' r3 N+ ~+ f" B/ x* S - 43 if(i)STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去. + Q( F) S0 G1 p; e' B' x
- 44 }
" k) Z2 w! Z) H {" @1 P - 45
* R$ M3 |/ k7 r7 x - 46 //跳转到应用程序段: W' P5 V6 ?& C$ O/ K
- 47 //appxaddr:用户代码起始地址.( E/ a' X5 B6 z1 j$ r
- 48 void iap_load_app(u32 appxaddr)
+ c" {( b8 a f- G4 X* {$ g+ o; Q - 49 {
I6 P' C0 W) z8 A' A, g% x - 50 if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法.
& B- r3 \8 r! W( C. X$ x: C - 51 {
/ A- u( c& b. F$ K" o - 52 jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址)
7 r2 A6 R$ x( E {6 b' e/ b- ^ u - 53 MSR_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址): y- A: Y! e$ } R) g% k% R
- 54 jump2app(); //跳转到APP.
) X# W) x G g- z - 55 }4 ?* k6 c9 w+ L0 C4 _/ G
- 56 } : P0 H' S9 i/ M+ ^, E: z" y/ X o
复制代码- 1 #include "stm32f10x.h"
& h9 U& U4 ]: S4 ~6 |/ `3 \ - 2 #include "stm32f10x_conf.h"
1 k! w; ] N$ u1 N! S4 G - 3 #include "exti_interrupt.h"
8 R8 {; [' {, z5 N - 4 #include "usart_config.h" & D! u; A6 R2 Q B6 [
- 5 #include "timer_config.h"
* e+ ~% R4 K: \ - 6 #include "key_config.h"
3 f4 r6 K) I6 {5 C1 ] - 7 #include "sdspi_config.h"
9 I4 `; {' J* N2 \ - 8 #include "Fatfs_config.h"' j9 R) W2 n! N- G# F
- 9 #include "flashspi_config.h"& M* Y: U- D& w" w5 K
- 10 #include "ff.h"
1 [0 c7 E( x' } - 11 #include "diskio.h"& X5 z: {/ b) _$ f J' o8 N6 W7 x
- 12 #include "iap.h", ~ [1 L1 d% ]3 b! Q7 ?" i
- 13 #include <stdio.h>9 b G( \- l$ E: o
- 14 #include <string.h>/ \; U) u: E) h" q6 e( Y
- 15 //#include "picture.h"
; `1 T* |! Z# j/ ?9 p - 16 5 ]) K5 w' ~: Q% |8 z
- 17 //#define BmpHeadSize (54)' _: m: |& T; G$ r5 }% P, q @* n
- 18 FATFS fs;! W0 u' X }7 R% _/ p- L
- 19 3 {" ?6 \1 i6 T
- 20 #ifdef __GNUC__
9 o% z, n+ t+ k) [5 @" A4 i# j - 21 /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf M3 D+ {1 k7 U0 g1 v
- 22 set to 'Yes') calls __io_putchar() */& O9 }, C+ J" ?+ z2 l3 ^! Z
- 23 #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
" d! |1 R1 m6 P - 24 #else2 Q6 T0 T5 r1 l9 t; P) Y7 X
- 25 #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)$ l- l9 h" }$ n( L, ]! T
- 26 #endif /* __GNUC__ */
: c6 L* V3 O( x5 D% D - 27 , c) A- Q A( c& g3 Z3 i
- 28 static void Delay_ARMJISHU(__IO uint32_t nCount) u& _$ p* e: F+ c8 j3 I
- 29 {
4 m0 c5 I5 B" c: y" N8 h/ Z - 30 for (; nCount != 0; nCount--);
$ }& e4 [ x5 I+ i( w7 f7 N! d - 31 }
S2 L# G" n8 i$ o - 32
0 ?% U# V2 g8 R - 33 extern u8 USART_RX_BUF[]; //接收缓冲,最大USART_REC_LEN个字节.2 J8 l; D' S6 E! v, ^/ u1 J
- 34 extern u16 USART_RX_CNT;: Z* v9 i7 ~5 C0 m" q
- 35 //接收状态
% Y8 W0 w" w; m, i' {) Z8 i" x( ^4 X - 36 //bit15, 接收完成标志0 ]0 t- F2 `6 m& h
- 37 //bit14, 接收到0x0d5 b5 e5 ]) c) R* C6 A* }
- 38 //bit13~0, 接收到的有效字节数目) |0 m6 Y6 W; n
- 39 extern u16 USART_RX_STA;
/ @) q1 H1 \- [ - 40 /**
. R. _% i8 E/ X5 t - 41 * @brief Main program.0 B' E6 U6 x) a5 g6 X
- 42 * @param None
2 ^9 [; Q# ]- [. |% n" r! U3 u - 43 * @retval None
\- H/ z' a: _+ E - 44 */
! r4 O1 S5 L7 k! `# _ - 45 : u9 F% H2 k, [
- 46 int main(void)- {6 q; d- Q# t5 s$ t
- 47 {
& M- U: U- E# z1 s - 48 u8 len,t;
2 \3 V0 \: C3 C - 49 u8 key;
1 O1 l9 Q# M1 I - 50 u16 oldcount=0; //老的串口接收数据值- u1 R' k8 d& S# t
- 51 u16 applenth=0; //接收到的app代码长度
K1 V- k m6 D1 s' } - 52 u8 clearflag=0;
2 J( A6 y: y3 U1 ~2 T - 53
' o2 ~: u8 V# i/ \; l - 54 /* 延时初始化 */
/ ]! m# p( I# ]9 V - 55 delay_init();7 C; k: X# Z8 T" E. p6 N
- 56
" i6 f) q7 `5 [) i2 y( _ - 57 /* 串口设置 */
$ O) j j$ f$ A( t - 58 // Usart1_Config();2 d# A* x! I3 U+ i* l
- 59 Usart2_Config();) u+ R. j( I/ F7 U' d4 h
- 60 USART_SendData(USART2,0x55);( c2 S3 f0 C5 Q; A9 R2 m
- 61 while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
# ?, ]) w6 x' H# f - 62 printf("english\r\n");' B4 ?# R% J) A& ]8 @
- 63 printf("中文测试\r\n");( k& q! E" y; \2 Y! y
- 64
0 l" B* m0 x( O/ O - 65 /* 按键中断设置设置 */
" Y4 C9 l2 N7 U& N8 j" D+ ? - 66 Key_Config();) ^! h: k* n8 G$ S x
- 67 // KEY_EXIT_Init();& t0 W3 G; D# I5 K/ p, n
- 68 // Key_NVIC_Config();
- I1 f/ e$ z' @* ]8 D - 69
4 K7 ]/ Z8 f5 P - 70
( B. Z& ?1 V' ]7 ?7 T" b - 71 // disk_initialize(0);3 P0 M2 ]9 b8 X T$ g! {/ f
- 72 // printf("\n\r f_mount %d\r\n", f_mount(0, &fs));
0 Y6 [9 Y+ C8 s- e! X - 73 // mf_scan_files("0:");5 V* V& ~" b7 ^4 ?
- 74
; g7 T( k1 D# L9 L5 q/ K5 e& }/ D' J5 _ - 75 // printf("\r\n将要进入主程序while:\r\n\r\n");+ J8 A% E; X! g, L5 c
- 76 while(1)
, |- i. F! v8 _, k# Y6 G - 77 { 7 W" \3 X8 n9 {! g# U6 _
- 78 & n, |4 l h7 D9 ?" w8 z% W
- 79 if(USART_RX_CNT)% N% J- l! B- p, \' T
- 80 {
7 W( f0 i3 w9 w - 81 if(oldcount==USART_RX_CNT)//新周期内,没有收到任何数据,认为本次数据接收完成.
5 U# K8 H" q6 E9 W5 z2 y( w4 L% n3 A - 82 {
4 o" [) i' @0 Y' G0 x - 83 applenth=USART_RX_CNT;8 m6 s; B k6 S0 ]; A& n3 f/ ?- i
- 84 oldcount=0;
( v' g ~1 P3 g" Q$ o" Z% M" M - 85 USART_RX_CNT=0;+ g# n+ Y* i5 ^/ |; X: n# u' \9 {
- 86 printf("用户程序接收完成!\r\n");
6 Y7 A+ @7 Y; |5 i, [0 C - 87 printf("代码长度:%dBytes\r\n",applenth);
2 B. u6 e; B/ Q. b1 g - 88 }else oldcount=USART_RX_CNT;
$ A( r1 w! `- L - 89 }
$ t# v3 F+ b. h4 l) U' z } - 90 $ O' Z, @0 p' a6 a$ _ m1 g T
- 91 delay_ms(10);% B- x# _1 x1 w+ `" J* p! h
- 92
: x3 S& D+ G! X3 j4 E - 93 key=KEY_Scan();
b k L# Z* n% M4 }$ t - 94 if(key==KEY1)
! I" c+ a9 G6 F" {7 [3 A - 95 {: u+ G8 F- S: o& I2 b+ g: c k' Q4 z
- 96 printf("KEY1!!\r\n");: s6 k9 Q* e8 X4 s# g" D
- 97 if(applenth)
( ], ]! J T3 _& d( J - 98 {
# g' H' q7 v l - 99 printf("开始更新固件...\r\n"); 4 ~7 |! f3 M# \, f0 ?4 A) _
- 100 // LCD_ShowString(60,210,200,16,16,"Copying APP2FLASH...");
2 U! F1 n. q- m6 W% D - 101 if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
. ?8 F; X* u. _9 m& m# U0 Z - 102 { ( v' b; n8 ~& }9 i( J* g
- 103 iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASH代码
* I% q3 |' ?) b1 j" D6 | - 104 delay_ms(100);
2 B& A0 h0 d7 f% i - 105 // LCD_ShowString(60,210,200,16,16,"Copy APP Successed!!");
- s' M& b9 E/ A2 P0 C) d - 106 printf("固件更新完成!\r\n");
' y6 D; z$ E: S - 107 }else . H7 P: d# W$ ], b" B1 @
- 108 {# H2 r& ?& H/ X$ F/ Z6 e- h& j/ r. o
- 109 // LCD_ShowString(60,210,200,16,16,"Illegal FLASH APP! ");
+ {5 F7 H2 a7 f, |) X* \ - 110 printf("非FLASH应用程序!\r\n");
% b+ e: h. b( e; n, W - 111 }
6 ~/ F7 [+ O4 D) y* o8 X* c @9 H% Y - 112 }
& |0 ^" C$ E& ~* {% | - 113 else 3 g0 k k1 j9 c4 m. V7 d1 p4 z: H7 E
- 114 {
/ ]% Q; l& i4 P0 g& N - 115 printf("没有可以更新的固件!\r\n");. [3 j3 i, F# k9 F7 C9 X
- 116 // LCD_ShowString(60,210,200,16,16,"No APP!");
9 X% y# X6 f$ G! D X - 117 }
2 E6 X. Z* o( c. S D; { - 118 clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示
; y5 c5 A7 v& C5 _; L, A - 119 }& Z% i3 M$ P( Y1 [. b
- 120 + u5 V9 M$ |% U& y( Y% L$ ?: n
- 121 if(key==KEY2)' f- b: V% o- b; I3 Y- G
- 122 {. l/ J3 w0 M+ b: T+ y- U
- 123 printf("KEY2!!\r\n");
) O: Y( A. o! y' P# G) S9 O - 124 if(applenth)
$ a! o# A8 [2 L# d# H; E( k5 e - 125 {
0 [9 H0 s1 K# I# _' G - 126 printf("固件清除完成!\r\n"); : ?( N8 |6 ^" s! ~; `* y5 S
- 127 // LCD_ShowString(60,210,200,16,16,"APP Erase Successed!");- A3 t+ |2 ]4 i1 ^) [) r9 z
- 128 applenth=0;
( c5 c' m G. e& ^5 g/ }5 V/ z, y - 129 }else 4 D% M! g6 W" j l9 j5 J
- 130 {! T# r5 A; O$ n0 z& q4 s& h; l- p
- 131 printf("没有可以清除的固件!\r\n");
" S* r' V6 m1 }8 r8 h3 T9 _" ^ - 132 // LCD_ShowString(60,210,200,16,16,"No APP!");, Y3 f8 } k; p6 g" ?
- 133 }
5 L" f5 ^3 \* O% C - 134 clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示
/ A2 k# }7 n, Q" ?6 B - 135 }
% t5 o+ h# Y! i9 c, p - 136 if(key==KEY3): M9 F _( d& i) d% Y
- 137 {4 i4 ~, g/ Q# H A& p7 e
- 138 printf("开始执行FLASH用户代码!!\r\n");- @5 p8 I& U2 I, J9 B5 {
- 139 if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX./ E I6 t% @' P9 V- ^
- 140 {
' z4 r; f) g5 e( D6 a - 141 iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码6 w; l' U0 X/ T, D7 w" o
- 142 }else
* |& ^9 ~% t/ ^5 s1 s+ V - 143 {
" |/ x" Q0 j8 z5 ` - 144 printf("非FLASH应用程序,无法执行!\r\n");% R1 g. L9 N4 I5 E$ v# i, `' e( H
- 145 // LCD_ShowString(60,210,200,16,16,"Illegal FLASH APP!");
+ C7 [( o B$ W- i$ G I7 N - 146 }
$ h9 \3 _2 h" S5 f8 e$ P; Q - 147 clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示
, G& l1 o. u1 s7 l+ s' b' X6 L - 148 }
) K# Q! L6 `* E+ H0 P - 149 if(key==KEY4)' N' d- i! |3 { ^6 ^& S
- 150 {; ]8 ? o$ y. t, Y
- 151 printf("开始执行SRAM用户代码!!\r\n");
5 u" X6 X+ Z; t( N9 A - 152 if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x20000000)//判断是否为0X20XXXXXX.7 N5 y% {3 J$ X$ B
- 153 { 6 J: P- h8 ]# ^. |8 u
- 154 iap_load_app(0X20001000);//SRAM地址
1 u5 Q, t/ k# o& V, Q$ _ - 155 }else ( r5 ?, m) L8 @; H' J, @
- 156 {
z( w2 h; M/ C- z$ i9 R - 157 printf("非SRAM应用程序,无法执行!\r\n");4 t* ~' r' W' N4 i/ l
- 158 // LCD_ShowString(60,210,200,16,16,"Illegal SRAM APP!");
: h+ u5 f9 i0 U3 p4 D* M - 159 } ' ^; L) B c6 E4 B6 o$ Z* d
- 160 clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示 0 b9 I5 F0 B' w. Q% V2 v2 T1 D: S
- 161 } " d1 v+ n) u$ `! d, M3 ^
- 162
) s7 F: {# v) p/ ^8 g1 e - 163 }
) n d* n9 L& V# g9 }- T - 164
2 Q2 B' ?" f: N/ |* q# T' G - 165 % g/ V. f; w* C9 P+ e- B! a
- 166
: ]) O) D) [5 ?! E" s - 167 }. e) [* q$ X, }4 l6 X( J; v
- 168
: W7 f: Z# m4 F+ f - 169 /**$ M) n( P w5 D( C
- 170 * @brief Retargets the C library printf function to the USART.
6 D, K1 G9 `9 ?& x/ M3 w - 171 * @param None$ \9 ?+ g+ ~, D# J; R6 P, P# S: \
- 172 * @retval None
+ K* D' }9 ?) M8 _* ~2 o; V' F - 173 *// Z2 P; ]' l: Z
- 174 PUTCHAR_PROTOTYPE( A) P* p5 T2 v# q; S# E& ~/ \) q; Y
- 175 {
1 M+ |* U& V( U3 \1 h! L& Z! ? - 176 /* Place your implementation of fputc here */0 I. @! J( v% M2 m
- 177 /* e.g. write a character to the USART */
! N8 v# |' a/ t6 ~$ d1 g6 D - 178 // while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)7 P- e. D9 C$ u- i& V* p
- 179 // {}
3 ~1 z0 G b* s4 d0 K8 `+ l5 C - 180 //
: y- h* N* V& I1 { - 181 // USART_SendData(USART1, (uint8_t) ch);0 M0 x/ \7 Y, l2 U
- 182 ) H! w7 n# H# R( ^. ^1 ]
- 183 while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)9 T& P H5 y" e- h0 ], `9 ]
- 184 {}/ x# ~, S9 }! Z, r6 k* b
- 185 ( O5 j/ ?3 D5 O3 K+ S( z" r
- 186 USART_SendData(USART2, (uint8_t) ch);
3 I$ X7 V, R8 h6 B1 E' R - 187 ) _* }; j7 I% G
- 188 /* Loop until the end of transmission */
* [+ F$ c- W' O/ f - 189 // while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
9 M# D5 N w' _4 \& i- f - 190 // {}
$ O8 L3 e0 l! m; ^ - 191 / ~5 F! l( W6 t. I. O3 R7 f% l
- 192 return ch;
- Y; N4 j+ f) Z- @# R8 [# Y8 @3 x - 193 }1 u' Q3 E0 @# T
- 194
1 d2 s7 g* P. }4 X" B- _ I0 O6 m& ?7 ] U - 195 0 P! m3 K! [8 e
- 196 #ifdef USE_FULL_ASSERT- G/ y9 x' ^& L' Z" j7 }
- 197 % p* T. I2 [& U
- 198 /**
- O2 u3 B5 L& e+ U z& { Y5 N - 199 * @brief Reports the name of the source file and the source line number
5 s. s, A) Q# I( U - 200 * where the assert_param error has occurred.) `: r& T/ E. E, \
- 201 * @param file: pointer to the source file name# Y) Z9 u' ^ o. Q* o) c: }! J
- 202 * @param line: assert_param error line source number
. h# E9 L9 l% F1 m2 I8 M* {( @/ m - 203 * @retval None( \3 [5 N7 H1 f3 r
- 204 */- F7 J j# N% O, \" u% Q0 i j
- 205 void assert_failed(uint8_t* file, uint32_t line)
6 B- V6 v) c H - 206 { k' j$ m m: M7 X* n
- 207 /* User can add his own implementation to report the file name and line number,
( {1 O1 w+ K& A# b7 g- o1 S* \ - 208 ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
4 ]- k$ O! `* ~8 D) b _ - 209 7 K3 y: q6 A7 q/ h2 ^: ^
- 210 /* Infinite loop */
8 l. r# b$ ^3 G# \, E5 U - 211 while (1)
. _) N6 W6 n7 c5 |1 s7 ~ - 212 {
" Y' P2 N4 u: L' Z& ^7 ^ - 213 }
3 A2 A8 {% U: ]# x# D5 ? - 214 }
0 J, D1 O% s, D; `8 j. x- v - 215 #endif$ `9 Y# L- P5 P
- 216
! \2 Z* t) _9 H; n - 217 /**. h( x% G* S7 [7 O( F
- 218 * @}% e: y( H4 k; Q2 m+ x
- 219 */- J0 @* [: n( I4 H6 @
- 220 9 U; L$ x7 w, g6 o6 G% L e" ?
- 221
3 ?% N0 z1 }7 H - 222 /******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/8 f2 }! R4 b+ _8 e- A" Q$ R6 c( X
复制代码 T! z9 G0 M5 w- m7 V- V9 @5 U
我们把程序自己写入片上flash,还需要一些函数 - 1 #include "stm32f10x.h"
' T: f- i6 x& W0 b - 2 #include "stm32f10x_gpio.h"
. A- ]! d8 {0 C; L% j" g - 3 #include "stm32f10x_rcc.h"
3 Z, \( w; j* z( p" L8 p - 4 #include "stm32f10x_rtc.h"; C2 z; T4 }4 F- H* O$ M
- 5 #include "stmflash_config.h"
, I% }7 ~& m$ H, p5 U: X( m- d: d - 6 #include "systick_config.h"( ]1 K: d. h( r7 ^, @' Y* l* I! _4 V& @
- 7
5 t3 w. I: r* {# S; m- z - 8 //读取指定地址的半字(16位数据)9 o) e- J! Z0 d; {" }+ s- F
- 9 //faddr:读地址(此地址必须为2的倍数!!)
+ z, x% r/ s, U4 z: z2 T3 o - 10 //返回值:对应数据." E7 u# M5 B. Y3 {. t# ^) C D1 H* w
- 11 u16 STMFLASH_ReadHalfWord(u32 faddr)3 H. {. P+ u( [. Q9 t0 t1 D
- 12 {7 L' ` c0 P6 e
- 13 return *(vu16*)faddr; n% I% }! N4 k" y) y% ?
- 14 }
# M$ A+ K" M$ S( @) ]8 X0 a - 15 5 ^, c9 b* ?5 R9 @. r
- 16 #if STM32_FLASH_WREN //如果使能了写 ; h# X! c/ N' D+ T& N6 Y2 Z/ [" ^
- 17 //不检查的写入
8 D- |7 x. S) j - 18 //WriteAddr:起始地址
. s1 A5 A: m$ | - 19 //pBuffer:数据指针
3 H( ^. k6 }5 w5 V4 Y - 20 //NumToWrite:半字(16位)数 , j! F, Z, A, [3 S3 X! I- K
- 21 void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
0 O* C! c, N/ N9 C, Q/ s - 22 {
- N$ ~; u7 W% N( {8 \& N - 23 u16 i;; w) [ d+ O6 {
- 24 for(i=0;i<NumToWrite;i++)4 x* j. A' f/ h/ G, }# H
- 25 {1 K* Q, |7 v0 `% s
- 26 FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);1 ]2 L4 c) h- P K. D
- 27 WriteAddr+=2;//地址增加2.
; ~8 f1 Z/ u- M% u - 28 }
! @" x& j# `; Y3 n! Q3 ` - 29 }/ Q' @7 o- e' B v( {) J( l
- 30
( V6 W P; ?3 b - 31 //从指定地址开始写入指定长度的数据$ R$ z$ w; S' i/ |3 g+ M1 V
- 32 //WriteAddr:起始地址(此地址必须为2的倍数!!)
: i$ p3 G. z: q" q, ]* z0 | - 33 //pBuffer:数据指针5 Z, D2 E; U* e, |
- 34 //NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
& K7 s. ]; i4 J# O* _ - 35 #if STM32_FLASH_SIZE<256
% O- o Q) z# m; B2 b5 e+ u - 36 #define STM_SECTOR_SIZE 1024 //字节# d$ b4 y! [& ]$ d( h! S2 \* K
- 37 #else
1 r/ x9 Y, E% k: b3 h - 38 #define STM_SECTOR_SIZE 2048$ o/ }7 \9 w; E& B. B3 F# w
- 39 #endif
! r7 t$ H" b4 P! }; T, r - 40 u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节
6 p/ E- [; b' h9 Z4 a$ `6 H8 Z - 41 void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) * t6 R0 e: y, {/ h
- 42 {# }/ @+ I, i7 J$ T, ]$ F
- 43 u32 secpos; //扇区地址
' k5 M d0 C( `9 G1 W' j - 44 u16 secoff; //扇区内偏移地址(16位字计算)/ v" |% i; Z5 H; l, {* J
- 45 u16 secremain; //扇区内剩余地址(16位字计算)
6 \! L! M1 {0 e4 y3 t- Q. o$ j - 46 u16 i; # X' J9 \& O' V! C5 m. K
- 47 u32 offaddr; //去掉0X08000000后的地址
' u2 ?3 | o+ j5 C - 48 if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址) i' @4 K2 p @2 h; k
- 49 FLASH_Unlock(); //解锁2 u5 L+ x" v3 _& c$ w- ~
- 50 offaddr=WriteAddr-STM32_FLASH_BASE; //实际偏移地址.
7 g& D, ^, P7 o: f. q - 51 secpos=offaddr/STM_SECTOR_SIZE; //扇区地址 0~127 for STM32F103RBT6
2 ?4 y6 t( X2 c, B - 52 secoff=(offaddr%STM_SECTOR_SIZE)/2; //在扇区内的偏移(2个字节为基本单位.)
$ M( f& v9 g. M4 ?9 X8 X - 53 secremain=STM_SECTOR_SIZE/2-secoff; //扇区剩余空间大小
( ^' }6 @/ P5 X H8 ^5 k. ] - 54 if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围- I, l* y/ T/ J7 q9 @, H
- 55 while(1)
* R/ u# c0 G: m G# E( L - 56 {
! o( Q+ Z( ~ K( L, n - 57 STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容# ^$ n0 k, D5 ?5 u- m6 I/ a
- 58 for(i=0;i<secremain;i++)//校验数据6 A$ N7 [/ J; c! m2 q' m
- 59 {& r- [+ Q6 } a9 Q+ u8 {
- 60 if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除 * u7 f/ [+ k7 D
- 61 }: W' i6 y# Z5 P- u ?8 w- Z* w
- 62 if(i<secremain)//需要擦除4 }3 a( m# X2 j8 v
- 63 {# R* q1 d1 M: ~! q3 j
- 64 FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区; `% w0 A) X/ z- O& G6 H7 I! N
- 65 for(i=0;i<secremain;i++)//复制* I, A* o0 x7 h
- 66 {
5 ?6 G) C# ~( S2 q" D, ?0 C - 67 STMFLASH_BUF[i+secoff]=pBuffer[i]; $ x N0 O0 v: V( v; \1 Q/ Y7 C
- 68 }
% J" k* N% m' k2 s+ N! c6 d - 69 STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区 ' C5 V8 U* n6 V3 T
- 70 }else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.
9 N) R) L3 p7 {- d; h+ q& P$ S" h - 71 if(NumToWrite==secremain)break;//写入结束了* s; q0 g$ H4 l( k; {* O. S
- 72 else//写入未结束
6 S- J+ V, C) X1 D- |! {! A - 73 {
4 V9 N9 K- O* W1 p; C8 \ - 74 secpos++; //扇区地址增13 G9 V7 ]9 w& s7 m" W9 u; q# ?, h
- 75 secoff=0; //偏移位置为0
! D: h$ S; J: ^/ { - 76 pBuffer+=secremain; //指针偏移/ H$ c6 n# M* N2 W% Z
- 77 WriteAddr+=secremain; //写地址偏移
5 a$ q5 Z+ c! n5 a) u4 J0 \6 Q - 78 NumToWrite-=secremain; //字节(16位)数递减& R1 o8 k5 ]* K f1 d6 \- r
- 79 if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
6 Y: q& A. T& ?2 U( M' [ - 80 else secremain=NumToWrite;//下一个扇区可以写完了( g- w6 s0 F3 O: t4 a' P$ Y
- 81 } / l# N" N) d7 a# s
- 82 };
8 @0 ~6 A! `: M( Y4 Z+ w$ H5 T - 83 FLASH_Lock();//上锁
0 y+ e$ [2 e' {! y - 84 }$ t7 t/ h- _$ z$ l2 M
- 85 #endif
* l; ]1 }. E! @/ X$ l- ~- o- X4 n - 86
) k0 w2 _2 h+ i# U4 w: J - 87 3 `- l. t+ j* N
- 88 //从指定地址开始读出指定长度的数据) [7 n% J( B) C+ [8 ^- s6 N0 V M
- 89 //ReadAddr:起始地址* q9 A$ I' | T+ z0 ?
- 90 //pBuffer:数据指针
' X1 j- e" V) L - 91 //NumToWrite:半字(16位)数
8 c/ J; G2 x9 \: |% B - 92 void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)
6 W2 b6 R) b* ^; n: S" S+ E: X& e - 93 {) I: i g+ q: E- P& R
- 94 u16 i;
! L2 L1 L2 |' s7 U - 95 for(i=0;i<NumToRead;i++)0 G4 j. p. m# @- X. \8 Y
- 96 {
% W2 U! z8 p( f7 e - 97 pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
; ]: p/ |$ d- S" o9 {) A# F - 98 ReadAddr+=2;//偏移2个字节.
1 a- m# F) }% b4 n$ r - 99 }
# o$ _7 n+ ?& ?7 w - 100 }
, g+ y- A2 U( Y {
复制代码 , |9 O* g- Z' q+ S. p* z
主要就是在iap里面用了void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) - N* N7 X' e* ^; k: [) N) V3 n
|