这段时间用到STM32F417XXX一芯片做项目需要用到IAP进行串口在线升级,官方例程是利用了一个IO进行控制升级,我的想法是,使用STM32的串口控制升级,大约的流程如下: 上电---->通过串口发送指定字符串------>自延时约200ms------>接收是否有上位机的指定字符串-------->如有进行升级,如无直接进行APP跳转。 首先我们下载了STM32F4xx_AN3965_V1.0.0作为初始例程,而且这个例程还有说明都一并放置到下载区了。 然后,我们首先生成了一个基于HAL的例程文件,只开启了UART1,其它的功能不用动 * v i7 Z) }0 i/ r1 e* } % f* E ?* M0 P$ \; u% q 设置了时间为168MHz,然后生成了一个HAL库的代码。 . d6 R* B; {$ q6 @ 将STM32F4xx_AN3965_V1.0.0里面的 common.c flash_if.c) @: d8 x1 v/ S: _( |. Y, d menu.c ymodem.c i3 f6 D, M; B& g! O. Y( J 放置到Src文件夹中,头文件放置到inc文件夹中,在工程中将这几个文件添加到工程中(Application/usr文件夹上右键,add existiong .....) # A' W- G4 G7 S0 B# b 在头文件中添加上头文件 #include "menu.h" #include "common.h" #include "string.h" #include "stdio.h" & r+ U+ u9 C0 A$ m- k4 E 添加下面的这些外部定义3 P* `4 `: A, b$ K$ b7 ], Z" T extern pFunction Jump_To_Application; extern uint32_t JumpAddress;1 A4 W8 K k2 _& o extern uint32_t FlashProtection; ]! m; F8 m& b% \ 编译后会出现一些错误,主要有:* [6 v3 G7 x+ \2 R FLASH_Sector_x的报错,找不到这些,打到这些地方全部改成FLASH_SECTOR_X' ]) ]8 u, l: w# s, G" B9 D8 W- k FLASH_Erase_SectorXX的报错,HAL中没有返回,相应更改一下: uint32_t FLASH_If_Erase(uint32_t StartSector)+ q+ q4 o/ J9 }. Y; Z3 P {4 `' r* v$ _2 T2 w/ |* Q; k uint32_t UserStartSector = FLASH_SECTOR_1, i = 0; /* Get the sector where start the user flash area */ UserStartSector = GetSector(APPLICATION_ADDRESS);. c* t* M& E* }! }7 S3 D for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1) { /* Device voltage range supposed to be [2.7V to 3.6V], the operation will7 u7 M" ]7 ^* g: o/ m2 Z be done by word */ ) |2 o9 s4 A* A% ^* {) ^! s FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);4 w7 i! H# c( a2 l }9 H/ ]" _+ h L$ u3 m) j o- } 0 L2 S) A0 q7 p/ E2 x' m- z return (0);: G: d9 F% B6 o& b5 l. |2 [7 R } M2 _- ^6 a! F p 其它的一些基本类似,解决办法都是是到:' B# c8 s6 o0 O$ Y4 J stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c和中找到对应的函数进行替换# U& C9 @1 u6 M) f 需要注意的是 有些函数: 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); HAL_StatusTypeDef FLASH_OB_RDP_LevelConfig(uint8_t Level); HAL_StatusTypeDef FLASH_OB_UserConfig(uint8_t Iwdg, uint8_t Stop, uint8_t Stdby);8 p( y+ B# {7 \ HAL_StatusTypeDef FLASH_OB_BOR_LevelConfig(uint8_t Level);0 d! N% }- i0 u0 l0 `, D( ^ uint8_t FLASH_OB_GetUser(void);- o( N, |# w% o7 v" B$ ^ uint16_t FLASH_OB_GetWRP(void);0 C4 q& I2 m4 c) r4 H0 q0 O Z ? uint8_t FLASH_OB_GetRDP(void);. z1 N$ D( t0 E% o uint8_t FLASH_OB_GetBOR(void); 3 b: x" [/ A" r1 V( _- z! a6 |) Z1 L 将这些声明直接放置到对应的头文件中去,同时将头文件包含到需要用*.c中。 还需要修改这个函数 uint32_t FLASH_If_Erase(uint32_t StartSector)! x0 _( h3 k8 F( V* s. x { uint32_t UserStartSector = FLASH_SECTOR_1, i = 0; /* Get the sector where start the user flash area */ UserStartSector = GetSector(APPLICATION_ADDRESS);6 b9 v. l+ K# w- S3 g for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)//原来是i+=8,查一下定义这里应该是+18 A- X0 m' z/ J2 v/ V$ l/ V5 T: z { /* Device voltage range supposed to be [2.7V to 3.6V], the operation will* N+ d( K1 p$ L be done by word */ FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);8 \4 ]4 c2 B# z" b } return (0); } ' [7 }% U1 `: v. A5 U5 W 9 N. G& l9 ^1 o8 f6 t % t0 A v' J1 I" T8 e) ^ 这个函数需要修改一下,标红的两句是新加的: void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange)8 k8 X1 X& x; P) z- A {) v3 w* F: ]7 B. A5 I% r1 I uint32_t tmp_psize = 0U;% Q9 r+ z2 O* M" _: w 7 k# K" k( v: D- N /* Check the parameters */ assert_param(IS_FLASH_SECTOR(Sector));6 Z0 r" g+ p& ]# ^: U3 n assert_param(IS_VOLTAGERANGE(VoltageRange)); FLASH_WaitForLastOperation(0xFFF); if(VoltageRange == FLASH_VOLTAGE_RANGE_1)* Y- O( |+ p! z0 m4 ] t; v( y) \9 `" d( _0 n { tmp_psize = FLASH_PSIZE_BYTE; } else if(VoltageRange == FLASH_VOLTAGE_RANGE_2)2 C3 Z) L% N# b: z+ E# M& W) ] { tmp_psize = FLASH_PSIZE_HALF_WORD; }2 S# U3 d/ _( y$ V) T' @ else if(VoltageRange == FLASH_VOLTAGE_RANGE_3)9 b- `1 v% \2 F, g0 } { tmp_psize = FLASH_PSIZE_WORD;& {# ?7 s0 q, K2 L) m. K! u }4 O2 f1 p$ J( M, z' i else! f5 x! s$ j9 I6 r6 r' E {0 W4 f# W' _) s- T/ w9 c( S tmp_psize = FLASH_PSIZE_DOUBLE_WORD; } FLASH_WaitForLastOperation(0xFFF); /* If the previous operation is completed, proceed to erase the sector */ CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);% {7 d, b7 r5 Z4 { FLASH->CR |= tmp_psize; CLEAR_BIT(FLASH->CR, FLASH_CR_SNB); FLASH->CR |= FLASH_CR_SER | (Sector << FLASH_CR_SNB_Pos);. X5 c2 d8 V7 S FLASH->CR |= FLASH_CR_STRT;- j8 J$ O2 S+ E. I0 m } ! [, o# m- ]3 Y% G/ B 其它修改,串口修改: void SerialPutChar(uint8_t c)6 b4 u6 s: G9 H { HAL_UART_Transmit_IT(&huart1, &c,1); while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET);; A" _8 ~! m, ]2 b } 8 ]- x+ q5 r* b$ s ) i0 j; q& X; P' H& u uint32_t SerialKeyPressed(uint8_t *key)& W) G3 p8 m7 K# h! ` {" D" _1 J6 o( O 2 i! ~/ X" \. h) ^ if(HAL_UART_Receive(&huart1,key,1,0xFF) == HAL_OK) { return 1; }: {: ^# i. m7 `8 G! o" ?( J else3 U( m- e9 N: S$ k0 J4 v1 F {( J4 C5 R; T* m. T1 h' c5 H; k0 X return 0; } } 在修改完成确认没有错误了,就需要如下操作:: m, Y6 E# S( ?) _: i 修改main函数:4 P4 s }. a( z" o, o int CmpStr(const char *data,const char *data1,int index1,int index2,int length);! Z* h; R0 [ { C' a6 `5 } + F2 o, m) V2 ^5 K6 T, W #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)% P3 ]9 ~2 Z! S' W ; I4 { o' ^- G3 Q( X' S #else4 h, p) N0 f. \; f* J % ?. C$ _2 @2 U; w. `5 B- Y #define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f) #endif; L) G, z! n* ] PUTCHAR_PROTOTYPE) [8 I. T) g, o3 r0 v. K) U6 B {& U$ D6 e6 I0 ]: B2 g HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);3 V6 l* }, O* ]2 C9 T. _8 {! p; a return ch; }( Z- n, M7 v- Z7 G /* USER CODE END 0 */% e4 W& ~) N' p* {$ E; n6 a /**! W* F/ [+ T9 v8 A3 G2 b * @brief The application entry point. * @retval int* `0 L7 U- a; X" o* U */$ i' f. }! K) U0 t int main(void) { /* USER CODE BEGIN 1 */8 d. d8 ?% S! v //FLASH_If_Init(); /* USER CODE END 1 */ ]6 h& j8 T$ o- ]- L V" }# D$ | * B. }) a0 \, ~- N1 i /* MCU Configuration--------------------------------------------------------*/9 N) h3 Y7 Z+ k /* Reset of all peripherals, Initializes the Flash interface and the Systick. */" T8 {6 W7 _0 w: x HAL_Init();& i/ I& l0 p6 ` w 1 o( C( B; R+ X. O( ]' O; w /* USER CODE BEGIN Init */" t% D' y' S# C! ~3 h3 `/ ?6 E uint8_t mychar[30] = "*****************\n\r";//上下交互的语句,请自定义$ _: ?0 [& Y# U /* USER CODE END Init */, A1 o' D/ {( K. C" t3 k " f5 \9 v- ?% l/ e: x /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */; m" D: M2 u/ Z8 k% v6 i 9 A2 l1 k; L" N8 t& e /* USER CODE END SysInit */ ; _3 }. y2 R3 K /* Initialize all configured peripherals */1 O0 X7 N- [' k+ k' u) A MX_GPIO_Init(); MX_USART1_UART_Init();) C8 t* }% p- h8 b p$ l% z /* USER CODE BEGIN 2 */ 4 D3 p' ]+ q& n5 L/ x /* USER CODE END 2 */ ; n- [7 {9 x; ^! Q /* Infinite loop */ /* USER CODE BEGIN WHILE */* I0 q$ N: J0 m" X$ U# \ while (1) { $ U- A- l L/ Z; c$ ^. ? Serial_PutString(mychar); a: @9 l* j& g! I" M if(HAL_UART_Receive(&huart1,mychar,16,0xFF) == HAL_OK) { if(CmpStr((char *)mychar,"**************",0,0,strlen("***********")) == 0)//标红的需要自已定义 { printf("正在等待数据文件下发......\r\n"); - P; G2 m# M- i5 ]$ ?* q( } FLASH_If_Init(); //Main_Menu();4 T9 H6 F2 q' a+ v/ o //FlashProtection = !FLASH_If_GetWriteProtectionStatus(); SerialDownload();6 n$ _. V, \! x. p+ k1 d } 3 M( ?# R1 X1 h4 |! `7 k } ) m! n* z; r8 F0 a /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */1 Q- y, `0 ?! v% b8 \- L if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { Serial_PutString((uint8_t *)"start user Program!\r\n\n"); //HAL_Delay(100);; /* Jump to user application */+ P" z3 u6 Y, q0 c( ~9 Y J+ ` JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */7 O( q N' Q& |. P* u# y" n( R: ?' L% j) |" _ __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); Serial_PutString((uint8_t *)"Start program execution......\r\n\n");6 A8 m; l3 o n6 w; M- ^6 } //HAL_Delay(100);, A' w7 b+ x% S/ _, ?0 t$ V Jump_To_Application(); }) i- V/ r! m4 n% x/ U else {$ ]$ _$ M0 m4 ? n* J9 | Serial_PutString((uint8_t *)"no user Program\r\n\n");7 F; e Z( t. j } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ }0 x9 v2 o/ y7 t; H& R /* USER CODE END 3 */ } 0 Y7 c# T* k6 k/ W" y0 P/ b int CmpStr(const char *data,const char *data1,int index1,int index2,int length)! \2 S) H: _8 { { //int temp = 0;3 y* L+ F2 J6 U. A) U for(int i = 0; i< length;i++) {' ]# G$ b: q7 l7 G" W0 h if(*(data+index1+i)- *(data1+index2+i) >0) {, z+ _; j2 A7 P. K1 w return 1; - t5 F/ K, a9 ~& H4 z }# X9 M4 u) N9 V$ v3 A# ~ if(*(data+index1+i)- *(data1+index2+i) <0)6 |+ o0 q# l* R' ` { return -1; } }9 {' d: n, x W, f- z# b return 0; } & H1 |* y$ X% `' H 好了,基本就这些,有问题留言,我有时间就回复。。。2 {5 Z0 U, b, {4 ? N 如果有好的提议,可以一起探讨一下! |
謝謝分享 |
感恩分享 |
谢谢 分享 |
我用的CUBEMX里的例程,自己用CUBEMX建立工程将文件添加进去后,通过Ymodem下载程序,可以正常跑但执行到HAL_Delay()就卡死了,版主有遇到同样的情况吗 |
STM32固件库分享,超全系列整理
【中文文档】AN3965_STM32F40x和STM32F41x基于串口的IAP
STM32F4-DISC 实现USB主机(U盘)和USB设备(虚拟串口)自动切换
STM32F4中文用户手册
基于STM32F407的FreeRTOS阶段性的总结(13)
STM32F400、STM32F402 Cortex-M4超值单片机
基于STM32F407的FreeRTOS获取各任务运行时间及占用情况(4)
基于STM32F407的FreeRTOS任务的挂起与恢复(3)
基于STM32F407的FreeRTOS任务的创建与删除经验分享(2)
基于STM32F407的FreeRTOS环境搭建经验分享(1)