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

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

[复制链接]
qq344269956 发布时间:2020-1-19 15:47
这段时间用到STM32F417XXX一芯片做项目需要用到IAP进行串口在线升级,官方例程是利用了一个IO进行控制升级,我的想法是,使用STM32的串口控制升级,大约的流程如下:
  {, i1 w4 o- \1 s3 n上电---->通过串口发送指定字符串------>自延时约200ms------>接收是否有上位机的指定字符串-------->如有进行升级,如无直接进行APP跳转。
- I( f5 G( q3 N6 S
4 g  N. `  V9 |% S1 B, J& T首先我们下载了STM32F4xx_AN3965_V1.0.0作为初始例程,而且这个例程还有说明都一并放置到下载区了。3 z8 L. J, B+ W5 `

3 k" ?; J1 L% j$ g5 U然后,我们首先生成了一个基于HAL的例程文件,只开启了UART1,其它的功能不用动
+ A; a* D; \$ w/ c, h) B2 n& B5 t# R# x( I0 M/ x
% P3 A# [8 J( M5 t* _, ~4 {4 V# K
设置了时间为168MHz,然后生成了一个HAL库的代码。
. G8 b! _: D- g% @9 p& ?" M7 c2 K# Y/ }
将STM32F4xx_AN3965_V1.0.0里面的: z% R' e& o, P* w1 I: H( w
common.c
/ ^" \& W7 m& ?' ^* l: Sflash_if.c
& l1 G4 r  b$ T" }menu.c! p; E; u" B, i
ymodem.c' r4 k) B) _2 @) b
放置到Src文件夹中,头文件放置到inc文件夹中,在工程中将这几个文件添加到工程中(Application/usr文件夹上右键,add  existiong .....)
% v- y0 f& m0 j7 m
: d( N/ g2 \* x5 @2 Q在头文件中添加上头文件
7 c5 n) I' w  J/ p9 v#include "menu.h"+ A* b' L5 B) I/ z) B1 t9 X
#include "common.h"
9 o" F- X; }% q; x# i+ i4 M#include "string.h"
& A! W$ b. S  {9 }#include "stdio.h"; X. P! J  W8 f  O9 ]0 [2 f. S7 ~

2 P2 O4 x/ m7 P& z, ~+ b& s( |  b' N* ?1 B
添加下面的这些外部定义
+ ?( ^  F0 s$ V4 g" |! iextern pFunction Jump_To_Application;( P5 ^0 O/ T' a! W2 L+ U
extern uint32_t JumpAddress;) C9 O% [' Y# c4 s& ~, `
extern uint32_t FlashProtection;
9 E8 C) }- C8 |% o
. I% T& O# n8 J) G) S( x! f7 l, I
7 U% \. S) o- v编译后会出现一些错误,主要有:! Z6 M, Q+ q- A7 P) L$ ]
FLASH_Sector_x的报错,找不到这些,打到这些地方全部改成FLASH_SECTOR_X/ S$ v8 a& T0 h8 U0 p( R3 h

1 ^( r  S9 U; S0 Y$ U9 kFLASH_Erase_SectorXX的报错,HAL中没有返回,相应更改一下:
( I" W2 |) E) o, ^$ f6 K8 K' t0 Q' Euint32_t FLASH_If_Erase(uint32_t StartSector)
# c7 S6 e+ V) ?# e% X  `{
; ^  |1 F7 W& h; [( y- g! a  uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;- O) D4 k$ V' x1 O
' r, v2 x+ M3 S/ z: p6 w- {: s
  /* Get the sector where start the user flash area */7 N) |, \4 ^  n( i5 m. `: r
  UserStartSector = GetSector(APPLICATION_ADDRESS);- _& @2 l' N: e% W# C
, e& A- r- S  A* k
  for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)& C) ?- z, `. p3 t8 k
  {6 T/ S; M, \" d" f; r5 m: n& W
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will$ P8 h( g2 ~4 @1 @
       be done by word */
! B4 @4 q* w, X. N: {! M    FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);
# L3 u: I' O1 I/ p  }
( Y6 _9 l. j# g+ o  t0 ]2 w+ M3 F2 a2 D. D  p: ]- W
  return (0);- q+ F: u) t. F
}
# J8 g% k9 K/ V7 N  U+ G. E
! \* u  I9 D, o# i9 r9 S( {; ?: _: v" `
其它的一些基本类似,解决办法都是是到:% M3 A" D" ~- H. J* V7 z6 I6 R2 n- F+ D
stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c和中找到对应的函数进行替换: _* m; H" \- ]! n
需要注意的是% a. T4 o. g0 k3 T9 |
有些函数:& }( s8 S. `8 n, M
FLASH_Erase_Sector等,会出现一个默认定义的情况,这时只需要将本来声明到在stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c中
$ L4 T* i& v# q& R) K: ]void               FLASH_MassErase(uint8_t VoltageRange, uint32_t Banks);' i0 w1 X1 \2 ^1 h( K, _- ]: H
HAL_StatusTypeDef  FLASH_OB_EnableWRP(uint32_t WRPSector, uint32_t Banks);
9 E, B, ?# }. c, @# PHAL_StatusTypeDef  FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks);. D' d! b/ P, g( d4 V5 q# o( B# n
HAL_StatusTypeDef  FLASH_OB_RDP_LevelConfig(uint8_t Level);3 g6 M) z* f, C' z0 B  m
HAL_StatusTypeDef  FLASH_OB_UserConfig(uint8_t Iwdg, uint8_t Stop, uint8_t Stdby);
" _0 Y( E9 d3 uHAL_StatusTypeDef  FLASH_OB_BOR_LevelConfig(uint8_t Level);
$ o6 w* O3 n9 m: }" Suint8_t            FLASH_OB_GetUser(void);8 ^6 j7 j$ L% w# a9 i
uint16_t           FLASH_OB_GetWRP(void);5 R% h( F# I( S* Z* ~$ {. z# I
uint8_t            FLASH_OB_GetRDP(void);
5 E$ I1 C9 \* {0 r  G: Wuint8_t            FLASH_OB_GetBOR(void);7 |% z- G( a: H+ M5 [7 u
0 [1 H* g8 G, A3 \+ A
将这些声明直接放置到对应的头文件中去,同时将头文件包含到需要用*.c中。
6 @% `& |$ [: g4 S7 ?7 ~还需要修改这个函数
% K$ K7 b3 e5 Y5 tuint32_t FLASH_If_Erase(uint32_t StartSector)  C7 G, G+ U+ b- u: b/ E
{
' a0 h% N3 I; B1 ^  uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;
+ t- u$ G( ]6 W6 ]  X' B. {2 j0 _* q# w8 g% m1 Q0 C" S) N
  /* Get the sector where start the user flash area */# K  u6 @& K" f6 P- d: v1 `
  UserStartSector = GetSector(APPLICATION_ADDRESS);. O  Y8 m* h( R+ g8 h- H
% h; `' K- Y: v) `7 b
  for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)//原来是i+=8,查一下定义这里应该是+1
+ _5 d% v* |" g7 Q  {
1 W, q1 v( z# \, w    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
) m% Z2 I- Y7 Y+ {* A       be done by word */
" y$ y& s' a. X# ~. F    FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);
4 X6 [& ]5 y  ]0 r3 H2 t  }
9 D5 Q' u" i( N9 x% n' n( F0 J! o2 {; n8 i
  return (0);
# o5 t- }! N7 x7 Z}( y# m' c' H* S5 [" j
) l1 V- F% y. ~3 r3 ]* ^1 t) Z

. C2 r. g) @9 f1 C& l+ R) q; P8 T$ O2 ?* @) }8 \8 i8 d
这个函数需要修改一下,标红的两句是新加的:
& l; |% w1 e' Q: }+ X8 |void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange)  S/ M' T  a: r0 b- n& R" i
{, c- T3 B8 G" f+ k2 @
  uint32_t tmp_psize = 0U;
) S0 _7 `* \2 k7 k+ P
2 }8 e1 x9 U# G, D2 P$ w' a  /* Check the parameters */
  k4 O5 a/ O% P9 n  assert_param(IS_FLASH_SECTOR(Sector));- _% j4 z5 X; D& v$ l
  assert_param(IS_VOLTAGERANGE(VoltageRange));
% E' ]8 U2 R5 W- e8 c9 H" v  FLASH_WaitForLastOperation(0xFFF);
. C& T0 u& y! J- R# \. P: y  if(VoltageRange == FLASH_VOLTAGE_RANGE_1)0 V/ g6 \, _0 D5 ^0 f" a$ v- v
  {6 S4 z/ c. E' U
     tmp_psize = FLASH_PSIZE_BYTE;6 ]) n3 P1 t7 E
  }
, N0 l1 v8 A7 J8 }" ?- l8 T: _  Z  else if(VoltageRange == FLASH_VOLTAGE_RANGE_2)
) s: `  q0 y3 I+ \  {
) U+ K; a: l$ V% Q5 U    tmp_psize = FLASH_PSIZE_HALF_WORD;
# m5 \, q" F/ Y4 f  x2 }  }. P$ A) a4 c/ G3 q) N* O- f# H
  else if(VoltageRange == FLASH_VOLTAGE_RANGE_3)% f( _( C4 F/ m* M" q- Z8 ^3 |2 t, T! H
  {( c6 d/ ^4 \9 U3 x9 t4 t
    tmp_psize = FLASH_PSIZE_WORD;
2 E/ K. N2 ?) Z" ~' d* I  }
9 q( x& U+ @4 U6 ~* H" y* k  else
6 X# @! Z: x, x' [; H% c  {5 K% f0 x& T4 T4 h- r% W0 z
    tmp_psize = FLASH_PSIZE_DOUBLE_WORD;# g# q- J6 Q0 j& W
  }: F: }' C- f8 F3 w" k7 c
       
5 i+ N" L# |& _7 q        FLASH_WaitForLastOperation(0xFFF);
5 K& ^: Z' p3 y7 U  /* If the previous operation is completed, proceed to erase the sector */" ]3 m5 a, s, R
  CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);) G- b2 ~+ A. M. r1 l1 Y7 L
  FLASH->CR |= tmp_psize;
5 Y* j& B) B& e  ~6 Y  CLEAR_BIT(FLASH->CR, FLASH_CR_SNB);" s! x& |2 z- _1 |( z
  FLASH->CR |= FLASH_CR_SER | (Sector << FLASH_CR_SNB_Pos);
3 B. P! E* W! H2 I0 x0 p% |- H/ a  FLASH->CR |= FLASH_CR_STRT;( n7 u" @, a+ E. R4 O% ~( _
}
2 Q9 P& k( G. i: R) r& }, o2 M  C# y* a; L6 V' j# N
3 x0 U& m; J, r6 ?0 B

. M1 G4 L- M- C, u& ^, Q其它修改,串口修改:
1 R! z% [; u2 q' r% ]% W' Qvoid SerialPutChar(uint8_t c)
! {8 I1 U/ a% j5 K0 q{# I7 y) N; o+ F( K
  HAL_UART_Transmit_IT(&huart1, &c,1);& z& q; [, l' Q. U5 d' K
        while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET);
' S8 D3 }6 ]5 Y' D  b! u- ~- D}
0 Z. ]- G5 c1 g1 s5 ?* {
) q: G1 Q- s1 ]" l! {4 E7 ^( F( `$ \! J$ f$ N

8 }7 J" ]; d5 r' huint32_t SerialKeyPressed(uint8_t *key): c9 |9 l0 n/ B3 V6 P- F
{
& ?3 u- Z1 E3 ~       
' L# a) U- I- ]. n9 ]0 ?        if(HAL_UART_Receive(&huart1,key,1,0xFF) == HAL_OK)  v5 z# P3 e. C/ U. p! w
        {
* O/ c/ _0 d7 q/ K4 t. \, f                return 1;
/ p+ _! }. ^: l% _/ a0 t' [+ O        }$ t  D1 m) r# ~
        else" P: `- q7 H1 L- N% e0 }
        {
3 |" o. [2 ?( p9 Q: M                return 0;
1 U, D9 l* {( Z' G: S& d        }& X8 N0 w4 k, X! \) l

$ A2 |7 d0 u. h; D! o' C- S6 z}
  Y6 q9 i6 S+ v$ B# Q3 a. b* U2 w5 ]' I
在修改完成确认没有错误了,就需要如下操作:
4 l/ H1 ]  M( G7 f9 Y+ P修改main函数:" n" ]" c8 Z: H. S3 p6 o! i
int CmpStr(const char *data,const char *data1,int index1,int index2,int length);+ z6 }- J, ]& E) H

0 c" j; D" V' E7 F& G#ifdef  __GNUC__; y" e  V# h7 I( U% g3 u. P
/ |' _$ O8 g; y5 L- X$ A2 V1 o6 H
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
$ e. v' S; j) d# x% l$ M" s        5 d4 n+ `/ E" I
#else8 c6 B5 Y* s; h" j% d
' L  a: h* w* W, W) f  }9 J& i
#define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)
. I" ]: k3 J9 }3 n       
: A0 d3 F) Y8 ]8 G6 t- ?8 T#endif0 I0 }5 l. r5 l$ @: Y; h

! @: H8 L- |6 Q& M, Y0 l/ @2 |PUTCHAR_PROTOTYPE
( h' d' P+ _1 m4 b{
5 u: V0 D7 ]0 _2 v. E) Z        HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);* f# x* t4 M8 o
        return ch;% z* r# W8 ?3 j. m( [3 l) b% E9 n
}
; ^% L- J- w; U/* USER CODE END 0 */
" {1 O1 j) D4 h, x+ Y; l7 J8 _* y) o( p2 w6 N* z* K9 g2 S# j+ U* `% j
/**
- e0 ]  @, ^# _1 ^  * @brief  The application entry point.
' b- A0 g" P& U  * @retval int7 ^7 l, A! A3 ^$ W6 ?8 Y
  */0 l. t( ^2 G$ K* t9 w" C, S) I
int main(void)  w6 r% R1 k5 G2 M! P6 N+ D; y
{9 T- D$ [& P% _) B
  /* USER CODE BEGIN 1 */( X! G4 U2 w# b; S" R
        //FLASH_If_Init();, j, k# ^6 s( ^( T; G6 _/ z
  /* USER CODE END 1 */9 Y2 p' a) e) l9 d5 X
7 g9 m7 ?/ X* s, T0 G2 S# h
; F; L; f( P- @. Z, S1 [
  /* MCU Configuration--------------------------------------------------------*/4 M9 t3 I. [5 ?5 F

6 S; @  _! h+ @" p! w  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
3 J7 p9 D7 E* k5 ^, z  HAL_Init();2 X6 T# v  \  K# u

: [$ f4 |( a5 }6 D, S% o. M  /* USER CODE BEGIN Init */
$ b1 {. Z+ v" L1 O  uint8_t mychar[30] = "*****************\n\r";//上下交互的语句,请自定义
; o, [+ \1 A1 ?  /* USER CODE END Init */) o; w& t5 B: G% \2 c  d

( M, O# C( p+ N/ W8 R  /* Configure the system clock */
# A. `2 I* @, H2 t/ f* F) U  SystemClock_Config();  r5 G( u0 q5 O/ m) {0 ]7 y4 T
6 G3 J- g$ u6 K7 }
  /* USER CODE BEGIN SysInit */
% m' R5 F7 m; j2 O& c
# u) Q. Z. M) Z: D$ q  /* USER CODE END SysInit */
% f3 f( @; S* h' [% v. O& Z
0 }& S7 x& s) P& G9 ~8 O  /* Initialize all configured peripherals */9 l5 B7 P; M  u$ o7 V2 D& F9 ]" Y
  MX_GPIO_Init();, a9 Q+ P; V1 N' J+ f
  MX_USART1_UART_Init();
- T  [! Q' y. B& V  /* USER CODE BEGIN 2 */3 F( n5 T: Q/ V
       
* I/ [- e; I( |2 ]' I
# R/ x) b+ v2 E1 y$ Z& T% R0 e0 I  /* USER CODE END 2 */, _% @* K7 G/ ?& @% x+ U

, L; c, V% z+ Q  `, m. D  /* Infinite loop */
6 \; P" D) r) M, Z0 X, }! z  /* USER CODE BEGIN WHILE */5 L5 ~' T: ]. ?  d+ w/ ]
  while (1)7 J& b1 K8 w7 u8 d' n
  {
" K* }  `: u& O# x7 ^& Y' d                & C. S' e) q% z) i3 V
                Serial_PutString(mychar);1 r% X5 n! V/ L

6 x! Y! w) K" j/ K                if(HAL_UART_Receive(&huart1,mychar,16,0xFF) == HAL_OK)
' A1 z/ a* q6 @! Q8 O! ^1 o: O                {
+ h7 s5 [2 K7 L0 {3 |5 d0 _                        if(CmpStr((char *)mychar,"**************",0,0,strlen("***********")) == 0)//标红的需要自已定义
  d$ l1 g$ W2 z3 ?/ j                        {  W8 M' T8 ]0 R) f; A
                                printf("正在等待数据文件下发......\r\n");
) k" [5 K& |; |7 c! V2 p" m
5 _4 K& j0 d& s) v, y- b- X; Z4 ~' v% r/ ?                                # K$ ?- b5 P$ U9 _, t9 C
                                FLASH_If_Init();
$ t6 X9 N* y% J" I# o7 b                                1 i6 Z# C+ i3 v9 ^
                                //Main_Menu();
# U7 \0 W: p' U                                //FlashProtection = !FLASH_If_GetWriteProtectionStatus();
$ C! q; `' O0 S: l) J                                SerialDownload();
) Y; v* l, y. u0 ]; g                        }                       
5 |5 M& ]+ P) Z9 l. h: j                }
* H$ u1 L# @, f, s- r9 n3 ~
6 W% }5 A; _# X' ^1 G' l    /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
8 W+ s6 o$ |/ b3 u    if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
) d, u! ~/ J% W1 y  O+ V    {
1 T& u3 Q6 ~$ r. W* o" N  Z' z* y3 I                        Serial_PutString((uint8_t *)"start user Program!\r\n\n");4 }0 n+ B/ R" t* D1 y2 j
                        //HAL_Delay(100);;6 A( ^& }; k- q8 E7 ^; V1 ^
                        /* Jump to user application */+ Z! l8 f$ w7 g: Z6 L* h% n
      JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);) d: h% C- u8 }, ~3 z  T1 r% e
      Jump_To_Application = (pFunction) JumpAddress;
8 Q, y7 \) s6 j9 e  Y) \5 d* |2 T      /* Initialize user application's Stack Pointer */
6 x6 w7 ~% ?2 s* Q; V; F: j      __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
, x% C; j& ]& m+ z5 Y                        Serial_PutString((uint8_t *)"Start program execution......\r\n\n");% I; k; E# f" S8 w
                        //HAL_Delay(100);
6 r9 F0 i4 Q+ |# ^      Jump_To_Application();
$ c% s5 D" i* a+ B, b    }
0 E/ y3 F' z  C& V" P& _4 `& f                else
2 ]0 D1 w7 P; q" A                {0 _, S: N; p: O8 i6 Y* h
                        Serial_PutString((uint8_t *)"no user Program\r\n\n");! |( t: [& q! r/ Y* a& {
                }
( E; Y9 m, C) W6 a& A6 B               
7 z( L- f% T. c. V" U, c; Z    /* USER CODE END WHILE */& F6 L9 V  ]0 u- g
- ?) r* X. G$ m
    /* USER CODE BEGIN 3 */
+ X, d) k1 l. T2 b. J2 V  }& o* e# B  w# f# b
  /* USER CODE END 3 */  F/ P; K$ a- P+ T5 v
}/ \5 K8 j. o- k

4 n$ X) ?; A: X: D5 w7 ]
$ }; C- p# b. ~5 T6 \( g3 l/ m
int CmpStr(const char *data,const char *data1,int index1,int index2,int length)$ W4 b, q* t+ X. A3 E9 O
{$ N* x. n( M+ T
         //int temp = 0;
7 U6 ]3 f, D- w5 _& s9 t" D         for(int i = 0; i< length;i++)' Y" S# Z7 l2 n* G* n
         {
7 ^1 Z: e. S- u) |& i                 if(*(data+index1+i)- *(data1+index2+i) >0)  M# l8 B  y3 Y& d
                 {
( @1 K3 R9 j  v4 A& j% F, q# v2 y4 ?                         return 1;  ( E+ y: h2 N- n: f
                 }
% M- h! B6 d6 e" ~                 if(*(data+index1+i)- *(data1+index2+i) <0)9 Z/ @" Z# B. {# T6 E
                 {
! P& S; |( q% b; X+ V9 Q0 m$ g                          return -1;
4 ]: X8 n: i- O% \                 }' H- B9 \6 g' m" c
         }
- c  H2 `0 K  y0 l' c# m7 I/ ]         return 0;
. E" m4 O* C7 G' p# W* w4 S }& N+ K$ k6 C1 Y: F6 i+ q
' I2 t, M4 g8 c8 g* k! S. x& }! C

, i9 x% q& H2 i2 w4 p( W$ s好了,基本就这些,有问题留言,我有时间就回复。。。) X4 G$ V. P& }3 s( @+ k
如果有好的提议,可以一起探讨一下!
1 w/ M( k. S1 ^+ @8 I

串口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 手机版