这段时间用到STM32F417XXX一芯片做项目需要用到IAP进行串口在线升级,官方例程是利用了一个IO进行控制升级,我的想法是,使用STM32的串口控制升级,大约的流程如下:8 }2 Y+ m B8 y$ v9 M& X. r/ ]0 I 上电---->通过串口发送指定字符串------>自延时约200ms------>接收是否有上位机的指定字符串-------->如有进行升级,如无直接进行APP跳转。0 [' J9 w: m' ?# a + Y5 Q, Z, g; H" ]' q* h 首先我们下载了STM32F4xx_AN3965_V1.0.0作为初始例程,而且这个例程还有说明都一并放置到下载区了。 然后,我们首先生成了一个基于HAL的例程文件,只开启了UART1,其它的功能不用动 : u9 I, r; ^6 Y 设置了时间为168MHz,然后生成了一个HAL库的代码。9 }& a# L G8 Y( M6 P. k) F- | [ 将STM32F4xx_AN3965_V1.0.0里面的 common.c8 M. p" @1 ~1 E/ u4 H flash_if.c$ M/ q+ S7 s9 j W' n* ~, p! g3 n) R menu.c ymodem.c2 G# e$ {( `- r: ^% } 放置到Src文件夹中,头文件放置到inc文件夹中,在工程中将这几个文件添加到工程中(Application/usr文件夹上右键,add existiong .....) 5 W2 {7 R! w4 r! X 在头文件中添加上头文件 #include "menu.h". o! m: W( D; Z2 V Q #include "common.h"$ B# u, B1 L) r5 c; D #include "string.h": u5 R- c7 H, R$ Z- O& N# r8 k #include "stdio.h" & W# _0 P* X6 n" F$ X& t9 e 8 r% b& c: C% A 添加下面的这些外部定义 h2 x7 h1 D; D% p& g extern pFunction Jump_To_Application; extern uint32_t JumpAddress;% t" Y2 \4 ^3 y$ C extern uint32_t FlashProtection; 8 ^% Y( d' d% d, N 编译后会出现一些错误,主要有: FLASH_Sector_x的报错,找不到这些,打到这些地方全部改成FLASH_SECTOR_X9 |4 T" C: A" ~( E1 t4 m . e8 Q; d: t0 Y% m# k FLASH_Erase_SectorXX的报错,HAL中没有返回,相应更改一下: uint32_t FLASH_If_Erase(uint32_t StartSector) {( |1 L: X5 y6 b& b! s9 b: C* m- \ uint32_t UserStartSector = FLASH_SECTOR_1, i = 0; /* Get the sector where start the user flash area */ UserStartSector = GetSector(APPLICATION_ADDRESS);( [" u; z+ {: O1 [1 |; M4 L 8 p `, U2 y+ e# M* o for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1) {9 N0 g+ ]9 a: H% y% V" d4 j8 @8 ] /* Device voltage range supposed to be [2.7V to 3.6V], the operation will$ H# q2 o% G, V1 O8 L( J8 ~9 G; w1 c be done by word */ FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);+ `- k* @$ [. g' O# H: f( g4 @ }$ }- ^6 _0 \" M$ H : h3 A7 w6 B& z- v8 _4 j7 V4 D return (0);! N- |$ k+ V5 @" b1 V* L4 ^3 R9 Q }6 U" v7 m* Q7 d7 f* S# N6 u* \ 9 q* P( A# ]: q4 ~ 其它的一些基本类似,解决办法都是是到:" V6 l' G) S/ u" t- a7 z/ W9 k- u. t stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c和中找到对应的函数进行替换 需要注意的是 有些函数:5 M$ y: \1 {+ ~ FLASH_Erase_Sector等,会出现一个默认定义的情况,这时只需要将本来声明到在stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.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);7 s6 ^" L2 k( m$ w$ o6 e HAL_StatusTypeDef FLASH_OB_RDP_LevelConfig(uint8_t Level); HAL_StatusTypeDef FLASH_OB_UserConfig(uint8_t Iwdg, uint8_t Stop, uint8_t Stdby); HAL_StatusTypeDef FLASH_OB_BOR_LevelConfig(uint8_t Level);4 |/ n2 W3 A5 l7 p& S0 c uint8_t FLASH_OB_GetUser(void); uint16_t FLASH_OB_GetWRP(void); uint8_t FLASH_OB_GetRDP(void); uint8_t FLASH_OB_GetBOR(void);* {9 K% U U' H3 ^ 将这些声明直接放置到对应的头文件中去,同时将头文件包含到需要用*.c中。 还需要修改这个函数+ ]/ M1 v& d" u5 f2 a% P8 _ uint32_t FLASH_If_Erase(uint32_t StartSector)3 r. z! t; h. d- H1 Y {6 C2 M' N# w6 D9 l3 j* K9 _ uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;+ P0 h, e$ `% ^, o* E8 U /* Get the sector where start the user flash area */6 T2 R- ]4 a" r) }1 \ UserStartSector = GetSector(APPLICATION_ADDRESS); ' e: f/ N3 C* X# U/ O for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)//原来是i+=8,查一下定义这里应该是+1' i2 B: E/ E& G9 d { /* Device voltage range supposed to be [2.7V to 3.6V], the operation will# x, \2 E/ j3 y be done by word */ ( p. o; |* x& }8 i) W& i' b# ~ FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3); }! N- O( o0 v. B: B, }0 {1 x + w/ s2 S: |0 [6 `, E5 Q return (0); }. t( S2 ^( \0 Z$ _ s. ?( I) R" Z# ?1 A+ D5 `1 d . _! D) r* N. z* h4 b2 G0 u# y1 P 这个函数需要修改一下,标红的两句是新加的: void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange)) U( p3 H E; p6 j, b3 T) p3 [" \ {* C# K: f. N, t$ C; s% a uint32_t tmp_psize = 0U; /* Check the parameters */ assert_param(IS_FLASH_SECTOR(Sector)); assert_param(IS_VOLTAGERANGE(VoltageRange));: k; K+ @! }% j! X8 M FLASH_WaitForLastOperation(0xFFF); B# ]% I; M$ g" V. o, { if(VoltageRange == FLASH_VOLTAGE_RANGE_1)2 }* J( z3 h) v( O: {( E% t' U { tmp_psize = FLASH_PSIZE_BYTE;" c7 ]: U- M. j1 v- @ }- Y$ r! N( U' _! U; n. `5 d+ f, J else if(VoltageRange == FLASH_VOLTAGE_RANGE_2) { tmp_psize = FLASH_PSIZE_HALF_WORD; } else if(VoltageRange == FLASH_VOLTAGE_RANGE_3)* ~) L9 a1 U1 \* L/ z { tmp_psize = FLASH_PSIZE_WORD; } else9 A2 i* K# x5 ^7 }" y5 s { tmp_psize = FLASH_PSIZE_DOUBLE_WORD; }: N1 X9 B3 `) O6 @7 K$ q N+ B4 R . B. {8 W, k4 Q& Y- R q; P/ _ FLASH_WaitForLastOperation(0xFFF);- q! n8 Z2 P m2 C /* If the previous operation is completed, proceed to erase the sector */. p8 Y; ]) I7 W D CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE); FLASH->CR |= tmp_psize;5 g+ G3 z3 O8 x( A, p+ { CLEAR_BIT(FLASH->CR, FLASH_CR_SNB); FLASH->CR |= FLASH_CR_SER | (Sector << FLASH_CR_SNB_Pos); FLASH->CR |= FLASH_CR_STRT;+ D5 _$ L$ p# p; }$ Z4 _ }2 P! c' O* ^- m+ s$ s1 n; w, J # a- [0 o# Z( x* _* ` e " F5 o* L/ f9 @- N& ] 其它修改,串口修改:4 w- o: |7 k0 C1 d- g void SerialPutChar(uint8_t c)! u J' i: N0 c/ ^: D5 p$ Q {) f+ | A7 z; x; r7 e( o- T# ~2 h HAL_UART_Transmit_IT(&huart1, &c,1); while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET);, u& s' p& R" W5 | }- d4 F$ B- b0 o uint32_t SerialKeyPressed(uint8_t *key)5 l3 @- V0 F- e. F: `) p9 c/ ~9 M0 {* G {1 J' y+ A: r: `3 p 3 U$ q2 a5 N1 s! A. H2 |$ K3 r if(HAL_UART_Receive(&huart1,key,1,0xFF) == HAL_OK) { return 1; }" M9 S; s7 s! n" n8 M! M) M/ J else { return 0; } 4 M0 V' u8 b9 X" Y4 k5 X5 X }4 Y2 L# M9 g- W 在修改完成确认没有错误了,就需要如下操作:5 L- d; \! C0 W+ i) X 修改main函数:& c" N% q+ H: C2 f int CmpStr(const char *data,const char *data1,int index1,int index2,int length);3 @* k1 N4 M5 M" J $ E8 A2 n# ~& x+ u/ c #ifdef __GNUC__ 1 t9 W. w/ L6 D& } F4 ] #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else0 z+ D x, b; R- S+ k. c * n* n' t0 D3 S5 {5 f #define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f) 5 \0 V1 P9 g" i* P9 z #endif PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);( R! v B9 @( c+ ^! _ return ch; }( @ q9 N7 z# Z } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int6 N/ s* V9 M5 V4 z3 Z. e6 X */ int main(void) { /* USER CODE BEGIN 1 */ //FLASH_If_Init();! @7 K+ l* P; f1 e7 z /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/6 [# n/ O8 `. _2 g- c/ F. P /* Reset of all peripherals, Initializes the Flash interface and the Systick. */* k" \) V( I2 I: t# U1 y HAL_Init(); % B M# E: ^5 k; g' B; i0 y /* USER CODE BEGIN Init */ ~* r3 j* E- q0 r+ [4 `' |* A n uint8_t mychar[30] = "*****************\n\r";//上下交互的语句,请自定义5 ]3 x* P5 M7 W6 e! ^ /* USER CODE END Init */" H* K2 U! l% V# |9 t ; [6 U! s+ ?0 Y k( b" Z- Z! t /* Configure the system clock */ SystemClock_Config(); ( o6 c! V) y" C9 Y1 n9 u) s/ y' q" V7 h /* USER CODE BEGIN SysInit */ + t; T+ Z$ T1 H0 f+ u3 W /* USER CODE END SysInit */9 R" D4 I- m# o2 U' k5 ]0 f8 _ 4 N# B5 M1 a! v) g- ^! O /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */( V) g1 R' m$ ?; x while (1)$ \" G$ s- `1 f" z8 v9 M { * y2 L1 f4 L' Y0 Q: t) s Serial_PutString(mychar);; V& M7 w: q9 W if(HAL_UART_Receive(&huart1,mychar,16,0xFF) == HAL_OK)9 O9 u& F. z" [( g/ d. ~" c { if(CmpStr((char *)mychar,"**************",0,0,strlen("***********")) == 0)//标红的需要自已定义 {* C) y8 r' _, L- ^ printf("正在等待数据文件下发......\r\n");4 I1 Z# \7 }) C) s" m8 p7 F/ o * @( K7 s6 n8 U1 i& q; B5 o# s8 z ) C2 P; [3 ]$ C FLASH_If_Init();* ?+ k) R# j3 Z* c4 {+ C) m* P . s. }* p* V7 |+ a* W; _9 i //Main_Menu(); //FlashProtection = !FLASH_If_GetWriteProtectionStatus(); SerialDownload(); } }) y7 e$ w" b: \' q6 ^! y /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */) n- M9 M- M" ]5 e; X if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { % X4 |. r& Q/ \ Serial_PutString((uint8_t *)"start user Program!\r\n\n");' Q! [9 S. @1 h0 w2 `7 F$ T //HAL_Delay(100);;( U# c) \5 ~6 [ /* Jump to user application */ JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); Serial_PutString((uint8_t *)"Start program execution......\r\n\n"); //HAL_Delay(100); Jump_To_Application();+ V* N3 b' {9 k! N% Q' S } else { Serial_PutString((uint8_t *)"no user Program\r\n\n"); }8 e1 E9 e1 ~9 X3 N 9 J/ ^& G0 \5 f9 k" @; q1 n /* USER CODE END WHILE */$ \7 x6 ^% T$ i1 g 6 f& V6 { D+ j" j6 V' S /* USER CODE BEGIN 3 */1 W) l P* t- f% z) N } /* USER CODE END 3 */ } : e1 Z! p3 W& B 7 J: k! q7 j' z+ N! { ; \1 p7 g3 @8 Q0 W int CmpStr(const char *data,const char *data1,int index1,int index2,int length) {$ Q' f+ M! I8 ~& w //int temp = 0;! M0 H y2 X. Z5 _3 q$ G for(int i = 0; i< length;i++) { if(*(data+index1+i)- *(data1+index2+i) >0)1 H8 N+ T4 Y: v( w& f X6 r {, q* g% f5 M0 [5 N4 b return 1; }3 s8 `$ @4 q) R if(*(data+index1+i)- *(data1+index2+i) <0)# ^- l0 A0 z- K; K, e4 W { return -1; }( s6 ?; e- Y9 i) R }& u* W: l% r5 D$ w9 {0 J return 0;6 h4 ] Y2 [3 _- ~. [* d } 8 ^( w+ O- }6 A# _: M7 y " n* l: p( P4 H! }# w6 L( Q 好了,基本就这些,有问题留言,我有时间就回复。。。) Q8 S' h2 e4 O# `, [ 如果有好的提议,可以一起探讨一下! |
謝謝分享 |
感恩分享 |
谢谢 分享 |
我用的CUBEMX里的例程,自己用CUBEMX建立工程将文件添加进去后,通过Ymodem下载程序,可以正常跑但执行到HAL_Delay()就卡死了,版主有遇到同样的情况吗 |
【中文文档】AN3965_STM32F40x和STM32F41x基于串口的IAP
STM32F4-DISC 实现USB主机(U盘)和USB设备(虚拟串口)自动切换
STM32固件库分享,超全系列整理
STM32F4中文用户手册
基于STM32F407的FreeRTOS阶段性的总结(13)
STM32F400、STM32F402 Cortex-M4超值单片机
基于STM32F407的FreeRTOS获取各任务运行时间及占用情况(4)
基于STM32F407的FreeRTOS任务的挂起与恢复(3)
基于STM32F407的FreeRTOS任务的创建与删除经验分享(2)
基于STM32F407的FreeRTOS环境搭建经验分享(1)