你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

移植官方STM32F4XX IAP程序为HAL库的过程

[复制链接]
qq344269956 发布时间:2020-1-19 15:47
这段时间用到STM32F417XXX一芯片做项目需要用到IAP进行串口在线升级,官方例程是利用了一个IO进行控制升级,我的想法是,使用STM32的串口控制升级,大约的流程如下:4 D; B4 r8 i& j% u& R; ~0 c
上电---->通过串口发送指定字符串------>自延时约200ms------>接收是否有上位机的指定字符串-------->如有进行升级,如无直接进行APP跳转。! J$ y- [- g3 A9 z: E" L0 V/ o0 c

  E/ }+ J( Z$ w% P$ o, b8 \首先我们下载了STM32F4xx_AN3965_V1.0.0作为初始例程,而且这个例程还有说明都一并放置到下载区了。
  a" _! E1 ?. i+ g7 x9 z" Q' \3 j2 g8 o) H: Y: W; \  G
然后,我们首先生成了一个基于HAL的例程文件,只开启了UART1,其它的功能不用动
$ @$ n( a& A- R$ G) t; F
. a6 G8 g& x, c* a+ {
, ~* Y5 f6 a5 t2 d2 J  {! Y- [# G设置了时间为168MHz,然后生成了一个HAL库的代码。
/ X; e( P6 U* l+ `- M+ m  r# t; S  v6 R7 D
将STM32F4xx_AN3965_V1.0.0里面的  v9 R9 y5 _: J. J; c
common.c. t* `+ e* u+ y* X) t' c
flash_if.c
) o- R' M$ p' ?- P, nmenu.c
8 y# m- `2 p# P7 G4 E4 Kymodem.c
; g0 `% z9 H% U放置到Src文件夹中,头文件放置到inc文件夹中,在工程中将这几个文件添加到工程中(Application/usr文件夹上右键,add  existiong .....)
# K' i( B. d9 B6 R
) L1 _6 |0 R' C: s/ |4 _; _在头文件中添加上头文件
5 `# o4 n+ b5 ~3 w8 s* B#include "menu.h"& I9 n5 ?8 m! F& Y1 M5 z8 e4 g2 U
#include "common.h"3 w$ V* [. A3 m& I
#include "string.h"4 J6 D0 ~6 _1 b* Z$ J  h7 W
#include "stdio.h"4 P( P" }9 [4 e% M

1 z7 E$ ]$ U* _9 X: }/ d0 d2 _7 p* c: _5 Z) s4 ?. B, P
添加下面的这些外部定义
. z, J7 \4 @' }$ w1 ^$ P) X# m. Bextern pFunction Jump_To_Application;* K& T3 `$ X( }; t3 ?) f, q6 U
extern uint32_t JumpAddress;: L$ O  `/ Q; f: I' X0 ?
extern uint32_t FlashProtection;
9 }% \' V0 v* @: \
' l# R$ u2 W" A9 Q
% V# a+ K* s: r9 p4 O编译后会出现一些错误,主要有:
3 d- r! Y  y8 X& D9 mFLASH_Sector_x的报错,找不到这些,打到这些地方全部改成FLASH_SECTOR_X- e8 x) z2 F4 c0 G

- G" u% |" _, ~& ?) e: wFLASH_Erase_SectorXX的报错,HAL中没有返回,相应更改一下:- e1 v. J) C+ @1 r: A3 J
uint32_t FLASH_If_Erase(uint32_t StartSector)$ G7 G. N  _* E; q/ R2 l+ x# D
{
, i) g/ W# L* D5 \  uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;3 Y) u( s% y. w+ p, F: i$ x8 s

. K& P" |" o$ |& t; X3 k# m  /* Get the sector where start the user flash area *// V- m" Y& g- u! a, c$ `
  UserStartSector = GetSector(APPLICATION_ADDRESS);  n- A! p* L( J- g& ^
/ ^2 j9 N8 G* Y6 ?3 C
  for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)
2 c4 p0 r' Y: w. ~, h$ m  {* T$ P& u1 @$ s2 V/ q
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
+ f; ?6 A; w# q/ U/ _       be done by word */ 0 v$ B+ f  A6 ?- ^  K9 V
    FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);
+ S: J; I% |0 K) N  }
6 Z" u- R+ T+ b& f- ^6 ?) F9 @1 S1 {: @7 L# ?" k" A8 N! s; n
  return (0);! X3 a" R8 h8 \" [) ~/ \; x
}
6 T4 d+ T3 _; N$ Y9 Z6 X: M+ ~' g, b8 {3 b$ L: B" I
4 l% V9 k% w% C% `3 \5 b
其它的一些基本类似,解决办法都是是到:
: I5 G% p9 u% w$ [: C% Hstm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c和中找到对应的函数进行替换- N2 ]* P- a# C9 T
需要注意的是
4 O' {* J/ ]+ ?有些函数:
5 ~0 v3 l, v( I2 \% d" g* f. vFLASH_Erase_Sector等,会出现一个默认定义的情况,这时只需要将本来声明到在stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c中
" Q! Z; e" _0 I$ x3 l2 K$ Dvoid               FLASH_MassErase(uint8_t VoltageRange, uint32_t Banks);. X  s- O1 }, h& A3 S% Y
HAL_StatusTypeDef  FLASH_OB_EnableWRP(uint32_t WRPSector, uint32_t Banks);* ]; m# _) _# V' P
HAL_StatusTypeDef  FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks);
/ `( V6 ?# m8 S+ e8 H( U2 NHAL_StatusTypeDef  FLASH_OB_RDP_LevelConfig(uint8_t Level);
5 h2 i: m1 p7 i1 C' M8 }) sHAL_StatusTypeDef  FLASH_OB_UserConfig(uint8_t Iwdg, uint8_t Stop, uint8_t Stdby);
7 B# G; N, R# nHAL_StatusTypeDef  FLASH_OB_BOR_LevelConfig(uint8_t Level);1 q# s# }3 j: n/ k: R! ^' O% ]
uint8_t            FLASH_OB_GetUser(void);
+ ~+ Q; d" r& Duint16_t           FLASH_OB_GetWRP(void);2 \* t! H0 J% j$ u5 u" r/ x
uint8_t            FLASH_OB_GetRDP(void);
- H/ J1 }9 {8 d$ p1 nuint8_t            FLASH_OB_GetBOR(void);
: ~! ^. B! L1 T9 A* i9 A# K% o2 f0 @+ R! f0 Y3 i$ |
将这些声明直接放置到对应的头文件中去,同时将头文件包含到需要用*.c中。- m8 U/ r6 W! A$ _& F7 R, G
还需要修改这个函数
* B  j7 c# ?  j" W5 J7 Vuint32_t FLASH_If_Erase(uint32_t StartSector)( U1 f6 Y9 u+ Y# v
{$ t; g" [; A+ x5 p8 n1 d9 x! _
  uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;% I# H- d% f9 @1 `' l; _

. ?) k7 Y. k* e* b! F  /* Get the sector where start the user flash area *// Y, o% U+ r5 A7 M9 ?9 s
  UserStartSector = GetSector(APPLICATION_ADDRESS);2 c( F( R  m6 B$ [; P5 s
8 ?4 g! T' }3 B+ `5 _8 [( S
  for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)//原来是i+=8,查一下定义这里应该是+1$ R" ?5 B$ z$ A% [# Q
  {) P- K4 I+ k, V
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will% P3 |9 e6 t( H) X( n
       be done by word */
; R6 x$ C: k9 e& o" j1 i    FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);9 j5 x: g( d5 I9 i! F$ g+ m. m
  }
3 R3 U% ^2 B! E$ i2 i! g* o# D  V( u( o) u3 l# I0 {
  return (0);
& p  K; F. `, L/ j" i7 h: Y}9 g0 @9 W8 k: o/ [

. t6 S/ |  i6 I5 ?6 ]8 I7 Z7 O2 S8 R
/ E: N& t* V: s/ M. M' Z
这个函数需要修改一下,标红的两句是新加的:+ Q/ p3 g% {3 k( `* O5 g- O+ e
void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange)
* p! s8 j8 T7 J# j{) |2 D" G. x3 D& V
  uint32_t tmp_psize = 0U;, N4 m, K0 C; W* p: ^$ S# i
/ i, W7 c- B/ V
  /* Check the parameters */: }' |3 H9 v! B8 C- g
  assert_param(IS_FLASH_SECTOR(Sector));
6 G! t+ b6 z( L* F; E  assert_param(IS_VOLTAGERANGE(VoltageRange));
4 r4 Q  {; |: k3 H3 t2 P# E  FLASH_WaitForLastOperation(0xFFF);
- ]( P9 X4 K7 x3 f# g  if(VoltageRange == FLASH_VOLTAGE_RANGE_1)
/ W, r) \6 j! e" n; O. ]  {% C, Y! p5 R5 h7 d! p
     tmp_psize = FLASH_PSIZE_BYTE;
$ |2 y8 g0 ?6 c0 e  }
; @9 ^  j  \* z) I3 O/ S* b  else if(VoltageRange == FLASH_VOLTAGE_RANGE_2)- k) G7 E8 P* m% Y; Z
  {
9 y3 P: [5 Z, i4 n) ~/ K; _    tmp_psize = FLASH_PSIZE_HALF_WORD;
1 A  D5 `4 I' S; s* W  }
- |8 ^- d4 X7 E6 p: C( C! B. g. [  else if(VoltageRange == FLASH_VOLTAGE_RANGE_3)! Q5 T& |$ P' x4 A" p
  {  H# c" C7 X2 o% W1 a2 O+ I
    tmp_psize = FLASH_PSIZE_WORD;% a- a$ {5 G# g! C: H8 b& [( ~
  }
' o1 I5 S, T( F" W) g: ~% W1 N  else& N( B2 k2 }8 F' Q$ a2 V
  {
. G: T1 R" ?, b: R6 S    tmp_psize = FLASH_PSIZE_DOUBLE_WORD;
3 ?8 C. H" B% Z. K9 k$ G3 [0 |  }
- X% T6 b: C7 v1 {) q) v8 i3 d3 {       
1 c5 R5 `! E! L. F0 C        FLASH_WaitForLastOperation(0xFFF);
' D$ r/ x1 Y8 i  /* If the previous operation is completed, proceed to erase the sector */; j; b4 d1 a) o! S( u. a* r, \. O
  CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
6 S  s# o$ P. p( @4 A" m  FLASH->CR |= tmp_psize;
2 \$ a3 v; Z. Q  Q" R/ z! I  CLEAR_BIT(FLASH->CR, FLASH_CR_SNB);& f7 N/ n0 v0 o9 X1 D
  FLASH->CR |= FLASH_CR_SER | (Sector << FLASH_CR_SNB_Pos);
! Z% |  s# a1 U- @# o3 d9 A  FLASH->CR |= FLASH_CR_STRT;
/ N# A6 {/ Q* S' s' `2 i}5 f" ]; E- R8 Z" t2 |, }
" T+ m7 @' X" q% e* v! m" K. T

9 ~- B% T3 _) `# ?& f8 B( @4 Z1 {7 y; y) m: R/ m3 ]. O
其它修改,串口修改:
( J$ z& }5 s( E, D) L# Ovoid SerialPutChar(uint8_t c)
$ e% `2 t. v( ]) h8 Q4 d2 _3 c{; B1 d+ g7 I; J- k1 y
  HAL_UART_Transmit_IT(&huart1, &c,1);* m) x8 [/ X) l0 o4 x0 i3 ~
        while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET);4 \, Q! P" ?# R. }, S) ~9 C. e! R
}2 X/ w5 B7 E. ^% \: H, n8 P

$ _4 q  E1 ^2 O% }1 e9 r5 }9 _9 }! \0 m$ r

/ T4 g6 U" f; h# I4 g0 k5 M% vuint32_t SerialKeyPressed(uint8_t *key)
8 P; _6 Q! b7 N) }& n) c, x{0 k  _. q" ~, F& W/ I
        7 s* l9 k8 }6 }3 q
        if(HAL_UART_Receive(&huart1,key,1,0xFF) == HAL_OK)
' }8 P7 K- D# ]/ W1 G) O        {
: R# {' A+ v! }$ n0 E$ E                return 1;6 }9 ?( `6 h  M+ a  g0 M
        }
+ k+ x$ G) J% d$ |        else
7 E3 k7 p5 q8 k3 \  C' m0 b        {
" G  Y) Y! W$ H! O1 _, p1 q" S                return 0;9 y7 u+ z- R: v: T/ \
        }
* J4 m+ J- q- e* w
7 L6 i/ q9 [+ V}
$ W, ^' P/ n5 t
' i3 z6 I  P2 V1 |; p9 ]' W7 Y在修改完成确认没有错误了,就需要如下操作:0 r  f* n" o) t4 ]. b
修改main函数:% i$ |6 b- v2 z6 p
int CmpStr(const char *data,const char *data1,int index1,int index2,int length);
. O- q" b! K+ D/ `! l' T/ @* w  p# o0 I
#ifdef  __GNUC__  W6 C* Z# X# h

6 ~* k, c9 F! D# Y% \#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)+ q, y5 S& X7 Q+ P8 K
       
( d1 I: `. M+ u8 k+ c#else
2 m% ?4 K" i7 [5 ^
- F: y# Y0 s2 y& W, S+ M$ a#define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)& d' k! _9 B/ {8 R; [
        9 E) d& A2 N2 q: D
#endif8 {6 `! _& f) {" }- e0 v4 v) W
: D$ C7 U# L' V4 n& m' k' ~8 x1 C
PUTCHAR_PROTOTYPE
  B6 `+ w/ U2 |5 {3 h; n{
- P+ Z, S. R9 _- \/ q- t4 \  s        HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
! N3 J2 R- N4 F( x! H6 E        return ch;
+ v, b: o5 a6 x1 Q% ?% c}
: f5 p( x$ X' P6 o! S+ e: B/* USER CODE END 0 */
+ W: ^# r& |# \& Q" x' w! I1 A; ]3 |3 d' n: l5 _4 s1 [+ o% [+ U
/**
/ M. f; a! K5 j4 ?- i; ^, s& G  * @brief  The application entry point.
7 b3 j  [" _( d3 j3 s' H  * @retval int
0 i" x( J) x) D; [. U" g  */1 Z- r0 j$ A% o$ I
int main(void)
; c; X/ Q; J8 ^{! u+ L1 E' q+ X$ X
  /* USER CODE BEGIN 1 */; u% r# \0 A) [, |! U! V
        //FLASH_If_Init();  w+ q5 H4 w8 Q
  /* USER CODE END 1 */) K  T4 ?  B: r' @4 `" u
: ?2 j4 D$ }0 t/ p6 A- }( e; e! J
- R. z( {) H& Y0 R9 d
  /* MCU Configuration--------------------------------------------------------*/: f1 H/ o# ^; c' H7 T* t
3 z. b% X+ x# S4 j
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
7 I" M3 v4 h. v( x% X, J! ]9 I  HAL_Init();+ y  m0 Q: G& `

% d! H0 S6 a+ c. k; u6 x$ A+ e  /* USER CODE BEGIN Init */( o5 q0 h& Y4 c- g) i# {( X  I
  uint8_t mychar[30] = "*****************\n\r";//上下交互的语句,请自定义* ]- m, ~' N  h$ u  K5 d$ s" {
  /* USER CODE END Init */; X3 Z2 Q# w' z4 n& l1 c
/ R; i% Y; L3 n( }# |; [
  /* Configure the system clock */
0 Z+ g  b  N4 P- F5 L  o: H  SystemClock_Config();
, f+ R7 X2 v5 T- C5 `
5 ]- r# L) S- C5 |: ~: W  /* USER CODE BEGIN SysInit */
5 u3 l" ^, U2 @# _1 L9 }
7 m; ]. N, R; `  /* USER CODE END SysInit */
8 F: q3 V4 ~1 t; g2 u; r. w; c, B: b% e
  /* Initialize all configured peripherals */
1 B7 G1 g' I; e0 U+ d  MX_GPIO_Init();
7 \/ c1 Z% R4 @4 ~( [' ^- x7 `  MX_USART1_UART_Init();
/ o$ l7 `! {/ Q7 J$ i$ T  /* USER CODE BEGIN 2 */! B# I3 D5 G) U% z$ Y
       
1 B% j; ]# _- H
0 d  [: s4 q, Q5 N4 k  /* USER CODE END 2 */
1 ^: X& M) A* _& p6 @: w. \: m" j$ m$ s2 h6 G: `
  /* Infinite loop */
; n! u1 B6 e) l, ]5 W) m  /* USER CODE BEGIN WHILE */
" v, r+ `" R( u+ T. R4 ]$ L  while (1)
8 M  k& K0 S2 _6 o  {5 k# w% K) m" s1 m% A
               
! [9 A5 b# g& ^                Serial_PutString(mychar);
" W% h, P) P* E; l2 m3 [0 e* |8 W4 g
; a# J8 P6 P, H( Z4 {' n                if(HAL_UART_Receive(&huart1,mychar,16,0xFF) == HAL_OK)/ Q1 H. Z7 |% l5 T( N6 {
                {$ N  N0 _* k7 A! X( N4 C
                        if(CmpStr((char *)mychar,"**************",0,0,strlen("***********")) == 0)//标红的需要自已定义! e4 X6 l9 R6 w
                        {
/ r7 @; V9 M$ w, n% D4 ~                                printf("正在等待数据文件下发......\r\n");: y+ V2 ~. ]" {% P. i$ [
# g* Q+ c3 H1 [6 v; @  q: z$ Q) r1 q
                               
! Y+ e) a; q' r  E/ h                                FLASH_If_Init();
: g7 J  q/ L6 x! {                                " Q  `) [9 G' f8 H. e& D
                                //Main_Menu();
- D2 G1 H( V: {1 b: o                                //FlashProtection = !FLASH_If_GetWriteProtectionStatus();9 j* _/ a! C6 e, l  S" h  l& R) a, t
                                SerialDownload();" B: i# |* n+ C$ J
                        }                        ; a; _6 S3 c. O- S% S6 e" v+ F1 g
                }. X* @4 A1 ]6 h/ i/ W& {

. ?9 G; y9 @* i! r& h    /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
6 j) q  r, h) ~. _3 r    if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)& Y6 Q( S7 B( r' x: w% g
    {
. Z4 R9 p( v% d4 {( R                        Serial_PutString((uint8_t *)"start user Program!\r\n\n");
5 p4 \# p$ O( L* V+ L) y9 Q                        //HAL_Delay(100);;& C8 E* n. [' Q# _" A
                        /* Jump to user application */
" {. |- ~5 a' W6 c      JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
6 v" B' ]3 H0 }& q4 u6 ]4 z      Jump_To_Application = (pFunction) JumpAddress;% ~, J- O. w6 w2 f" c: Z5 ]0 v
      /* Initialize user application's Stack Pointer */" }2 G9 m) k! j
      __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
- I. R9 H% u& ]* P' X* I                        Serial_PutString((uint8_t *)"Start program execution......\r\n\n");  x) S$ R, O3 h5 S
                        //HAL_Delay(100);3 l: a( y9 P/ A: i: G
      Jump_To_Application();2 Q; M0 r$ s" E" ^5 ?" G! Q0 ^
    }+ ?; J+ p, C7 m1 y- |( |  `
                else' Y; t' m$ _. Y8 T
                {; c) t3 l# v6 x3 P: R6 C0 D) _* v
                        Serial_PutString((uint8_t *)"no user Program\r\n\n");
. Z% N1 x8 Y5 P2 W, V4 N; o0 f& B8 y                }) G3 z2 a$ g! ?3 h4 L" X; |$ R
                6 W4 ]9 x" u: Z7 E( n! k  j: ^3 `
    /* USER CODE END WHILE */8 V, g5 n/ J4 e7 f1 E

" M8 `/ J& m/ A) ?) B    /* USER CODE BEGIN 3 */
9 ^9 A% U$ `. N8 w5 o  }
3 O4 u( {" `( f4 A) D7 ]  /* USER CODE END 3 */: X* X' E1 @8 N( R9 X2 k& M
}0 V3 u+ x/ v4 |# o$ c2 w: D
, `  A6 M7 N; }4 q" X* C3 {
# h7 ?( I# S1 \
( h& [$ z; |7 P* _: ?5 v
int CmpStr(const char *data,const char *data1,int index1,int index2,int length)7 \. G' o! [& {( F* ~
{* f4 u' {$ \9 O: I
         //int temp = 0;
  N* ?6 |- _' s  H         for(int i = 0; i< length;i++)! }( U% L' Q! z6 z/ Y; N! F
         {
+ `, [/ w2 h- @& k# @. A# r+ w/ f3 y                 if(*(data+index1+i)- *(data1+index2+i) >0)8 E) Y. m5 ~( B0 ^( V1 Q5 v4 n+ p
                 {6 i, R; G/ Z  D  l% {" Q4 F
                         return 1;  
7 d$ B! A2 u, V, k                 }% a6 E- G$ L, r5 Q- `9 [
                 if(*(data+index1+i)- *(data1+index2+i) <0)
. `: g* Q, o+ u6 ~) L                 {" ?2 o0 K! _# b7 A7 Q' ^& i
                          return -1;, F: U( A, N  h  g: n3 J6 q: f) ]
                 }
( l# ^8 ~% @5 ]0 l3 E) p+ I         }+ L2 J* h- F9 G) m) f
         return 0;
" Q. r4 {& Y. ?! w2 j }
7 J# O2 X/ S+ ?  P  V) D3 M0 F+ {. G( P; E  B

5 H  b1 }6 o, f1 Q2 l8 A) M好了,基本就这些,有问题留言,我有时间就回复。。。$ ^' ~1 p' ~1 s0 I- ]
如果有好的提议,可以一起探讨一下!7 }5 O) J9 O* _' ?, F  E; U. c

串口1设置

串口1设置

stm32f4_iap_using_usart.zip

下载

1.66 MB, 下载次数: 203

STM32 MCU IAP例程跳转到APP代码简要分析.pdf

下载

38.67 KB, 下载次数: 79

赞 收藏 5 评论4 发布时间:2020-1-19 15:47

举报

4个回答
jeffhe1 回答时间:2020-1-20 09:12:11
謝謝分享
慎微 回答时间:2020-1-20 15:20:55
感恩分享
生命在于折腾! 回答时间:2020-1-31 09:56:06
谢谢 分享
LaLaLa321 回答时间:2020-8-27 16:01:51
我用的CUBEMX里的例程,自己用CUBEMX建立工程将文件添加进去后,通过Ymodem下载程序,可以正常跑但执行到HAL_Delay()就卡死了,版主有遇到同样的情况吗

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版