
这段时间用到STM32F417XXX一芯片做项目需要用到IAP进行串口在线升级,官方例程是利用了一个IO进行控制升级,我的想法是,使用STM32的串口控制升级,大约的流程如下:% z, x& y8 A$ g7 p 上电---->通过串口发送指定字符串------>自延时约200ms------>接收是否有上位机的指定字符串-------->如有进行升级,如无直接进行APP跳转。 ! d/ q1 v4 s3 J% P1 v3 W, o4 X, J 首先我们下载了STM32F4xx_AN3965_V1.0.0作为初始例程,而且这个例程还有说明都一并放置到下载区了。 然后,我们首先生成了一个基于HAL的例程文件,只开启了UART1,其它的功能不用动, b) U7 J7 |. m0 U% y% p ( Z: E3 m: j- H! l- O; `# K' m! F 设置了时间为168MHz,然后生成了一个HAL库的代码。 将STM32F4xx_AN3965_V1.0.0里面的# R4 D3 F( }& v I. p6 O& q, i common.c flash_if.c; N8 i/ V0 f* e0 N menu.c$ b' W Q$ x) g/ W( k ymodem.c' C# R1 |, G% ]# ], i 放置到Src文件夹中,头文件放置到inc文件夹中,在工程中将这几个文件添加到工程中(Application/usr文件夹上右键,add existiong .....) + I X3 ]5 A$ s* J! B7 h 在头文件中添加上头文件1 M0 _( |2 b5 V' z5 @: r #include "menu.h"8 T2 s/ I2 L5 [ #include "common.h"9 v0 S6 O& h4 I& { #include "string.h"7 p L e+ g7 z8 v+ F8 A- o& x2 u #include "stdio.h"- l9 @2 F& ^" b& }3 T) j; J: G 8 W' f3 e1 H" n+ ]4 _ 添加下面的这些外部定义$ m; Q; Z# j' h extern pFunction Jump_To_Application;5 M' ?- s# z7 t0 l extern uint32_t JumpAddress; extern uint32_t FlashProtection;5 r) ]( P/ _' ^# Q+ i $ r0 _# l4 E$ i% e) k/ q 编译后会出现一些错误,主要有:7 V% h4 Z- C5 }. S. D FLASH_Sector_x的报错,找不到这些,打到这些地方全部改成FLASH_SECTOR_X FLASH_Erase_SectorXX的报错,HAL中没有返回,相应更改一下: uint32_t FLASH_If_Erase(uint32_t StartSector); H( q% I' l# T @ {" e& b1 J& v/ o5 P! h7 [1 Y2 r% [ uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;" |! T+ j; [1 a /* Get the sector where start the user flash area */ UserStartSector = GetSector(APPLICATION_ADDRESS); 1 F2 Y" m( A. w6 U+ Q0 C2 B5 m- O for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1); Y2 g1 u7 C& } Z) Y: p$ i# c { /* Device voltage range supposed to be [2.7V to 3.6V], the operation will8 O |9 t. E$ v" C) G- g& \+ z. l be done by word */ ) w/ [, _- ~) g2 u; j' V FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3); }# M! j2 S$ {1 Y* G; j , r, H: W+ _2 Q( M return (0); }' p$ i F( X& j3 ] z: Q $ n1 Q, W! t9 x9 b 其它的一些基本类似,解决办法都是是到: stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c和中找到对应的函数进行替换0 R" X- }8 N7 ~5 s7 K$ ^, v+ L" r 需要注意的是 有些函数:" q; [- T |: F FLASH_Erase_Sector等,会出现一个默认定义的情况,这时只需要将本来声明到在stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c中$ W5 J* ~& m$ c9 C void FLASH_MassErase(uint8_t VoltageRange, uint32_t Banks); HAL_StatusTypeDef FLASH_OB_EnableWRP(uint32_t WRPSector, uint32_t Banks); HAL_StatusTypeDef FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks);8 F R) |) Y" M# C* T6 e HAL_StatusTypeDef FLASH_OB_RDP_LevelConfig(uint8_t Level);* ~- m% u& S# n$ ]- z HAL_StatusTypeDef FLASH_OB_UserConfig(uint8_t Iwdg, uint8_t Stop, uint8_t Stdby); HAL_StatusTypeDef FLASH_OB_BOR_LevelConfig(uint8_t Level); uint8_t FLASH_OB_GetUser(void);& h- n* z! f9 V; ]0 ]8 r/ y5 Q( X2 y8 i, k uint16_t FLASH_OB_GetWRP(void); uint8_t FLASH_OB_GetRDP(void); uint8_t FLASH_OB_GetBOR(void); ; g2 z1 A! q" u; W 将这些声明直接放置到对应的头文件中去,同时将头文件包含到需要用*.c中。+ k' c+ D' k; L P2 T5 Z: a- C. L8 ]1 P 还需要修改这个函数 uint32_t FLASH_If_Erase(uint32_t StartSector) {) d* b5 s8 E1 m5 q M uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;7 Y7 P) U- @) o. j8 _2 p /* Get the sector where start the user flash area */ UserStartSector = GetSector(APPLICATION_ADDRESS);/ C0 P( s8 N5 C- B7 X ; M/ n9 K0 V0 B) S) h for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)//原来是i+=8,查一下定义这里应该是+1 { /* Device voltage range supposed to be [2.7V to 3.6V], the operation will0 ?6 D4 X1 K1 g* ?# Y4 f; j; }' _ be done by word */ / N# J! X; E9 w, _/ ?% G FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);# `/ o6 O, H- h6 o& o. H; K8 W } R' V+ L+ ]' T2 k$ [3 x return (0); }2 E6 o b! o: D& H+ \$ Q8 j * N; `( u2 Y% X$ Z % Y" ^8 ^* E4 B% t 这个函数需要修改一下,标红的两句是新加的: void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange) { uint32_t tmp_psize = 0U; |' M! s' |. z2 L ) y9 p; O4 g8 l, M+ D6 b- p2 ] /* Check the parameters */+ ]1 m& b8 J3 f7 D assert_param(IS_FLASH_SECTOR(Sector));. [7 M" H* D$ Y, B$ g! ` assert_param(IS_VOLTAGERANGE(VoltageRange));) y! v9 b/ F$ e: c, t FLASH_WaitForLastOperation(0xFFF);( E3 a$ J% r" I2 I+ V; X* E% r% V if(VoltageRange == FLASH_VOLTAGE_RANGE_1) {6 D3 _ L7 E( a& R% M" K& F/ h. @ tmp_psize = FLASH_PSIZE_BYTE; } else if(VoltageRange == FLASH_VOLTAGE_RANGE_2)& r/ { D& q* x8 s8 R {4 ~. y1 c, x$ z/ p) c. v+ h tmp_psize = FLASH_PSIZE_HALF_WORD;/ d% P6 _, q' ^, k3 T9 Q } else if(VoltageRange == FLASH_VOLTAGE_RANGE_3) {5 L3 n- D. c. j8 X/ V tmp_psize = FLASH_PSIZE_WORD;' L! _, Y: a( t: P3 G0 m9 X/ N } else: b6 y# h* v7 K1 b! `5 p% _! a { tmp_psize = FLASH_PSIZE_DOUBLE_WORD; } 4 V3 O9 t% P h9 p }: D5 f" ?1 O FLASH_WaitForLastOperation(0xFFF); /* If the previous operation is completed, proceed to erase the sector */4 S: o {9 I8 g0 x& y6 i. ~ CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE); FLASH->CR |= tmp_psize; CLEAR_BIT(FLASH->CR, FLASH_CR_SNB); FLASH->CR |= FLASH_CR_SER | (Sector << FLASH_CR_SNB_Pos); FLASH->CR |= FLASH_CR_STRT; } ( z/ y" X) i8 i. F. H/ G 其它修改,串口修改: void SerialPutChar(uint8_t c)6 h6 H5 U- ~* W; H% j% d6 \2 t {4 |4 P$ i, H: _ HAL_UART_Transmit_IT(&huart1, &c,1); while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET);! j/ a8 }1 z/ G }2 Q2 q1 r( D, Y$ s- e' j' { , e1 l: J* Z& W+ c* ] 3 n) B1 s8 c3 K6 e. } uint32_t SerialKeyPressed(uint8_t *key)4 z4 S0 n/ c; | {2 V$ V# _7 n" q5 u0 K; G! K+ r/ L 4 L: |: O( a: ]5 p if(HAL_UART_Receive(&huart1,key,1,0xFF) == HAL_OK)3 m, A$ a' Z' `/ ~ { return 1; }5 S8 Z b' X Y8 R else5 Z. g1 \. R/ h, H { return 0;' \# o9 `3 U! u/ j, i% M4 n/ ` } } 在修改完成确认没有错误了,就需要如下操作:' ^7 b% i" n4 Q( g( K( p 修改main函数:( h0 \; f$ ] B int CmpStr(const char *data,const char *data1,int index1,int index2,int length);) m$ E* ^1 V3 a6 y5 Y0 Y0 q* P #ifdef __GNUC__ 1 V. x6 N' M& h t #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) w( t# q/ C; b, l ( j$ p# H& s; l #else2 Y7 A# j0 d6 M4 Q! ] , u/ c6 M. p5 Q+ F9 S #define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f) #endif; Z+ C7 T& A) y3 k f! K PUTCHAR_PROTOTYPE {1 s5 i0 ~! [0 \1 y: l6 g/ m HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF); return ch;! o# t- V7 ^/ W5 M4 o) V }0 W2 D, }9 H% ] o" b+ F /* USER CODE END 0 */ & r G; `% ?3 U4 V: Y% V /**$ A9 g$ z. w2 y9 T * @brief The application entry point.! F) C. l& y$ f! o * @retval int& a* ?, G t0 r" |. K *// V% |! Q9 F" Z int main(void) {, V# L. Q0 v7 R6 h# w+ m4 j; w /* USER CODE BEGIN 1 *// O2 m; M( t1 W //FLASH_If_Init();7 ~5 {; F i6 N9 s. x/ B0 @0 B W( S) G /* USER CODE END 1 */ 3 `: i G- ?' q* N) Q /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */) c! s* A, P) i" F4 @2 O HAL_Init(); ( r4 @; V( L2 a /* USER CODE BEGIN Init */- E+ R/ j8 a: `- H+ @ uint8_t mychar[30] = "*****************\n\r";//上下交互的语句,请自定义 /* USER CODE END Init */4 R: E# X2 [. j. M /* Configure the system clock */0 f5 {1 O- X0 E& T; r SystemClock_Config(); & n! o0 B7 V$ d$ Q /* USER CODE BEGIN SysInit */6 ?: V0 o& q1 o% P5 E /* USER CODE END SysInit */ /* Initialize all configured peripherals */! ]# k1 r/ L: x MX_GPIO_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */. l& S. n+ I+ c( v7 d8 N# N+ z /* USER CODE END 2 */ 4 ?$ a. }) w6 \! s$ N# a, Z) R /* Infinite loop */ /* USER CODE BEGIN WHILE */4 y% E& X. G# S) e. u: b while (1)4 g# Q9 \& i* V( Z/ a1 D' t {$ t& n; ~* C' ~- ?9 V8 l% r6 s Serial_PutString(mychar); if(HAL_UART_Receive(&huart1,mychar,16,0xFF) == HAL_OK) {9 C& b# ^& s+ K3 D5 e7 o4 e if(CmpStr((char *)mychar,"**************",0,0,strlen("***********")) == 0)//标红的需要自已定义5 ]& V4 x2 Y }: E! z: \) {/ }! D {. }) P7 X3 v; y7 I1 k printf("正在等待数据文件下发......\r\n");0 @) \9 ?' U) f, h" l4 v . G9 W( s' m6 B FLASH_If_Init(); //Main_Menu(); //FlashProtection = !FLASH_If_GetWriteProtectionStatus();; O1 A: ~" c q& H2 N4 Y SerialDownload();" q; p5 _# T3 b } % d$ y+ O+ D. ~/ o }6 y1 g8 {0 S$ M+ t- N. ] 4 _' B0 h: W B* n3 L; I8 P: o /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */ if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000). o) A* ~: q6 F) T% t { Serial_PutString((uint8_t *)"start user Program!\r\n\n"); //HAL_Delay(100);;8 @2 m3 ]1 J* G* z+ x# X /* Jump to user application */ JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);& U+ @# r6 h" m) I+ ]. | Jump_To_Application = (pFunction) JumpAddress;8 z: o5 y. d% V1 ` /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);6 a! ~5 Z5 z6 C8 U8 F Serial_PutString((uint8_t *)"Start program execution......\r\n\n"); //HAL_Delay(100);$ U' B7 y% B, ~8 [9 m Jump_To_Application(); }$ [! z% g& j; T- v0 @) P+ E! k else {; e9 ?# B" N* V3 x9 Q: `+ E Serial_PutString((uint8_t *)"no user Program\r\n\n"); } /* USER CODE END WHILE */ % s" }* L$ a7 U' e1 m, Q; L /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } $ H' n ?0 A( q5 T 5 J1 P; A. G, ^. s & a% T) t; Z, @9 A6 \) \) W7 m int CmpStr(const char *data,const char *data1,int index1,int index2,int length)+ n- ]4 z/ O' [2 \5 D& w# U { //int temp = 0; for(int i = 0; i< length;i++) { if(*(data+index1+i)- *(data1+index2+i) >0) {$ J3 y! H! |5 _/ |* W return 1; 1 C3 i6 @. ^' @1 K6 {- S }1 J% b+ V, P- G! z8 a0 x if(*(data+index1+i)- *(data1+index2+i) <0)6 E- T6 D+ a7 V7 d5 {6 z p$ R { return -1; } } return 0;: k- o/ ?' t% | } 好了,基本就这些,有问题留言,我有时间就回复。。。 如果有好的提议,可以一起探讨一下! k$ l; Z' C9 G/ [ |
謝謝分享![]() |
感恩分享 |
谢谢 分享 |
我用的CUBEMX里的例程,自己用CUBEMX建立工程将文件添加进去后,通过Ymodem下载程序,可以正常跑但执行到HAL_Delay()就卡死了,版主有遇到同样的情况吗 |