
这段时间用到STM32F417XXX一芯片做项目需要用到IAP进行串口在线升级,官方例程是利用了一个IO进行控制升级,我的想法是,使用STM32的串口控制升级,大约的流程如下: 上电---->通过串口发送指定字符串------>自延时约200ms------>接收是否有上位机的指定字符串-------->如有进行升级,如无直接进行APP跳转。' R) M7 q& z4 m, u7 b3 b4 I 7 k. ^% q- J1 x( _" L. u 首先我们下载了STM32F4xx_AN3965_V1.0.0作为初始例程,而且这个例程还有说明都一并放置到下载区了。 然后,我们首先生成了一个基于HAL的例程文件,只开启了UART1,其它的功能不用动 7 t" z* P8 z! z 设置了时间为168MHz,然后生成了一个HAL库的代码。 & {% ]2 T/ A! K 将STM32F4xx_AN3965_V1.0.0里面的4 w1 y/ w1 l7 a; Q3 H4 }0 B common.c- ]5 R1 Z2 E1 G+ [. R flash_if.c ^/ v5 L% F; X/ E w8 V menu.c- l q% Y5 A8 r5 m/ t ymodem.c6 q* D- x. D- K. q 放置到Src文件夹中,头文件放置到inc文件夹中,在工程中将这几个文件添加到工程中(Application/usr文件夹上右键,add existiong .....) 7 ~6 M: ?* e" n- O5 W) v 在头文件中添加上头文件 #include "menu.h" #include "common.h" #include "string.h" #include "stdio.h" 3 A+ r+ ?; }; X8 [/ `0 [ / n, X: G, ?- [ 添加下面的这些外部定义 extern pFunction Jump_To_Application; extern uint32_t JumpAddress;0 A9 T, B/ T T: B* U7 z( ]7 [5 O extern uint32_t FlashProtection;( H# Q `/ |/ o5 h1 }) T , \( E8 u* a. d3 }, m/ K* F" u2 `) Z $ O! p- I1 k8 f: o 编译后会出现一些错误,主要有:; y/ e8 S- y, ~ W1 I* v @* o FLASH_Sector_x的报错,找不到这些,打到这些地方全部改成FLASH_SECTOR_X 8 t: J- D. M3 c1 O4 I FLASH_Erase_SectorXX的报错,HAL中没有返回,相应更改一下: uint32_t FLASH_If_Erase(uint32_t StartSector)) \+ }- \' V$ h7 ]2 y; m { uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;/ F6 V) j0 Z9 H6 R7 T 2 f8 h& C9 n& ^1 ~! o% h% o /* Get the sector where start the user flash area */ UserStartSector = GetSector(APPLICATION_ADDRESS);1 U9 x" f8 p# Y for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)) u0 S) X! y# z, k6 G {+ R( v8 m8 e8 a; s% b" K# M /* Device voltage range supposed to be [2.7V to 3.6V], the operation will+ P$ G- q/ P8 W4 ~ be done by word */ , l% E% W0 B) c: E FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);7 v# @$ T! L* _0 ], E. E } $ [1 U/ J$ u5 X% _1 ?9 G2 G* D return (0);0 A8 x2 K' x3 ~, |+ { Y } 9 Y. p8 {1 E2 K( ~4 @6 t 其它的一些基本类似,解决办法都是是到: stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c和中找到对应的函数进行替换 需要注意的是 有些函数: FLASH_Erase_Sector等,会出现一个默认定义的情况,这时只需要将本来声明到在stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c中 void FLASH_MassErase(uint8_t VoltageRange, uint32_t Banks);% k7 n: G I& Z9 K5 Q y HAL_StatusTypeDef FLASH_OB_EnableWRP(uint32_t WRPSector, uint32_t Banks);! S- o2 R/ h% i HAL_StatusTypeDef FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks);. C. ^+ t/ f d: ^ HAL_StatusTypeDef FLASH_OB_RDP_LevelConfig(uint8_t Level);( t X+ `+ t* l0 ^: e7 n3 M' r5 X/ a HAL_StatusTypeDef FLASH_OB_UserConfig(uint8_t Iwdg, uint8_t Stop, uint8_t Stdby);. V+ d: R# `4 K1 t0 o3 T8 S HAL_StatusTypeDef FLASH_OB_BOR_LevelConfig(uint8_t Level);: N. |1 M& j$ P' n7 X uint8_t FLASH_OB_GetUser(void);" B( K$ `$ |$ _4 C8 s& c. q uint16_t FLASH_OB_GetWRP(void);8 Q6 r* V+ j6 z2 Q. @( s7 B uint8_t FLASH_OB_GetRDP(void);) ^0 J# w3 D0 x. }3 I uint8_t FLASH_OB_GetBOR(void); ' p4 i8 {& e6 x% s y) k 将这些声明直接放置到对应的头文件中去,同时将头文件包含到需要用*.c中。. {! D& j* ]2 w7 O- h: {# L 还需要修改这个函数* n( w- o. Q+ o0 o e X# b( ?# l uint32_t FLASH_If_Erase(uint32_t StartSector) {) K% X9 J# U0 A uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;5 Z J# j3 x0 C9 h2 O8 ` $ P' f+ Z6 c O" V& }1 z /* Get the sector where start the user flash area */ UserStartSector = GetSector(APPLICATION_ADDRESS); * i/ L! t# ~& ^6 s. p for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)//原来是i+=8,查一下定义这里应该是+10 Q, ]! v/ q' G {9 `3 `1 D- @$ R! I /* Device voltage range supposed to be [2.7V to 3.6V], the operation will( U# S9 J6 T G6 N; |3 R be done by word */ FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3); }5 N; f. W# R# L. ? ! j8 s& _0 S+ j* h return (0);! [6 Y4 p" X. p1 y6 r; h } : n( K9 s2 \9 Y! t/ b) q. Z. x $ x0 r. E4 D& O# u) u, { 这个函数需要修改一下,标红的两句是新加的:2 w3 d4 |$ F @3 O* ~. f void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange) { uint32_t tmp_psize = 0U;9 q! ]& r! v* ]5 N /* Check the parameters */ assert_param(IS_FLASH_SECTOR(Sector));( }8 a/ B- q# V$ ^( J# V$ U- s @ assert_param(IS_VOLTAGERANGE(VoltageRange));% ~0 l x# U3 V% W! M' q7 x FLASH_WaitForLastOperation(0xFFF); if(VoltageRange == FLASH_VOLTAGE_RANGE_1) { tmp_psize = FLASH_PSIZE_BYTE; M* O7 P8 M6 n5 J7 U }1 Y8 N: |# b0 \5 c% J" m r else if(VoltageRange == FLASH_VOLTAGE_RANGE_2) { tmp_psize = FLASH_PSIZE_HALF_WORD;" |, A! X ~2 R* b' ~+ ]# p* H } else if(VoltageRange == FLASH_VOLTAGE_RANGE_3) { tmp_psize = FLASH_PSIZE_WORD; }! g) v. y- R7 t8 ~) Y else { tmp_psize = FLASH_PSIZE_DOUBLE_WORD; }# a( v+ F' Q. T . M- W! G( M ^; o+ q9 j FLASH_WaitForLastOperation(0xFFF);: P+ R' H" Z: Q, y3 ] /* If the previous operation is completed, proceed to erase the sector */1 b1 }5 s3 i; f; O CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);% n* M& e4 m! w; i" U: ^; \ FLASH->CR |= tmp_psize;- b# _- L+ t5 j* Z X CLEAR_BIT(FLASH->CR, FLASH_CR_SNB);; O4 q- h) |4 ~0 F; I FLASH->CR |= FLASH_CR_SER | (Sector << FLASH_CR_SNB_Pos);, S# f6 G A9 a& C FLASH->CR |= FLASH_CR_STRT; }6 v4 ~+ f5 c0 a4 Y2 _! d " M& @2 A* h0 v1 b9 d& L 其它修改,串口修改: void SerialPutChar(uint8_t c) {: ]8 w w- {9 l: j, k HAL_UART_Transmit_IT(&huart1, &c,1); while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET);1 R/ P, Y& s& m8 W( T j7 U+ J/ c } 5 a8 ~$ p$ {& t k2 v: Z 4 y1 k& A3 D m9 g: x q5 A uint32_t SerialKeyPressed(uint8_t *key)3 y! W) z% x( \6 W: [; C { ' g& u; e$ q# n if(HAL_UART_Receive(&huart1,key,1,0xFF) == HAL_OK) { return 1; }, q# c' `+ S l5 _ else! C7 b+ ~/ f" u! ? { return 0;8 A( h; U( |! L/ U! l0 ] } : T3 H% n! h, \& L; U6 Q }$ j! [* ?$ X7 r. b( Z, Y3 J 0 A+ h1 r) t5 z% q 在修改完成确认没有错误了,就需要如下操作: 修改main函数: int CmpStr(const char *data,const char *data1,int index1,int index2,int length);* O( h! `* D8 d ) ~# P+ V# ]' `) J #ifdef __GNUC__ q6 C8 t0 J8 X* e2 u B: g- ^ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)3 b& f4 i- R. K5 d$ Z$ K #else5 q' D9 Y2 v1 X# l9 o, X7 S$ d ( |* Q7 X) k* g% H0 T# P/ v4 C #define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)( ~3 \" Y' {" ` #endif 5 q' b3 g$ f+ h PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);6 I7 H, b* p& Q# g return ch; } /* USER CODE END 0 */ /**) G/ Y- p v$ k * @brief The application entry point.7 S/ \& e2 Y1 R8 z- p/ ^ * @retval int */) a$ {0 I _ o1 n6 }; d int main(void)+ k2 e! J1 `7 N* {9 K# Z { /* USER CODE BEGIN 1 */4 y G4 ^6 \& |" X+ g; Y% o& ` //FLASH_If_Init();% J4 u5 v- o- ~$ C8 p /* USER CODE END 1 */" z% {/ i: O6 M6 Q /* MCU Configuration--------------------------------------------------------*/$ V0 S% ]: V' K 7 X& N3 T7 C6 A" d( b /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init();+ Y b! D u! H : I& K6 }& m k9 X; x9 i /* USER CODE BEGIN Init */ uint8_t mychar[30] = "*****************\n\r";//上下交互的语句,请自定义 /* USER CODE END Init */# J( d- A/ Y5 U' G8 U / }9 S. P0 k* ]6 ^3 R5 [' Z1 K' K /* Configure the system clock */ SystemClock_Config();3 n9 k$ x2 \; `/ n# p* X$ w1 x" s /* USER CODE BEGIN SysInit */: h+ ]( t2 O# P 3 Y2 m2 R9 K/ _( x5 |8 \2 R6 N /* USER CODE END SysInit */ /* Initialize all configured peripherals *// [& u' N; p! I- o MX_GPIO_Init();0 c$ b8 l8 W8 ?* K MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */3 X" D8 R: |, `/ b" z& o+ |" s. a 9 t, z4 w$ |* H3 l /* USER CODE END 2 */ / ?: y& s( {9 H5 b: M0 ` /* Infinite loop */1 w# g8 y' C; [3 U' j /* USER CODE BEGIN WHILE */ while (1) {8 K# s$ A$ `) G: H6 t. k Serial_PutString(mychar);5 ~/ L6 B& I( N8 r) i $ X# f/ x1 q2 W! A. A' e* j2 P0 ]3 t! ^ if(HAL_UART_Receive(&huart1,mychar,16,0xFF) == HAL_OK) {6 m4 h+ l. ]$ D+ a if(CmpStr((char *)mychar,"**************",0,0,strlen("***********")) == 0)//标红的需要自已定义 {( ?! r+ y% k8 t4 H printf("正在等待数据文件下发......\r\n"); n0 C) Q- H% w+ r FLASH_If_Init();7 \+ N4 w/ M1 g8 [ 1 K% V" [) `( u" w" r //Main_Menu(); //FlashProtection = !FLASH_If_GetWriteProtectionStatus(); SerialDownload();5 Z' s; E; n! E% l0 Q* Q; b* f0 [ } }8 b. E+ b! ^$ X9 y/ D+ M6 } 4 D8 ^8 Y) \6 Q* [) ^ /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */4 v% C' ^, R: V) i' L$ ]3 [ if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { 6 U4 Q2 R( ]9 P' t) k0 L Serial_PutString((uint8_t *)"start user Program!\r\n\n"); //HAL_Delay(100);; /* Jump to user application */ `$ y' X0 F) r/ q1 X6 g0 s, k8 _ JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);6 l% D- l0 Z0 Z" e Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */, J0 A( k' p8 u$ f. j* _ __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); Serial_PutString((uint8_t *)"Start program execution......\r\n\n"); //HAL_Delay(100); Jump_To_Application(); }* t- G. z& I- r5 y( H else5 T* |2 w. o! j/ R- T# |: ` { Serial_PutString((uint8_t *)"no user Program\r\n\n");* e- o2 Y0 y: M3 P6 _$ j } /* USER CODE END WHILE */ - V4 o1 `9 P% q1 Q I /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } 1 L$ ]: B( c3 @) C; ~4 X int CmpStr(const char *data,const char *data1,int index1,int index2,int length) {& ^: W! @- B" u; U1 B9 { //int temp = 0;) r" r1 b9 e: w for(int i = 0; i< length;i++)1 k5 Q1 T! d; `. @ { if(*(data+index1+i)- *(data1+index2+i) >0)* I- W" T5 W6 N; N { return 1; - f6 r4 S% S/ J6 h& z$ ? } if(*(data+index1+i)- *(data1+index2+i) <0). E( ^& N0 K5 B: K8 I { return -1;4 Y, I$ q$ n. f, R2 X/ M( W5 _ }" c; O8 \9 F% D8 ]+ o. u } return 0;, ]1 m8 _4 r: a+ d( E9 ~; x( ~9 d } " ]6 E# ?: o0 X8 t' Y0 ?. Q " x8 c. z0 B5 U+ `$ U( q 好了,基本就这些,有问题留言,我有时间就回复。。。1 u7 z& O% r6 _; k) o 如果有好的提议,可以一起探讨一下! |
謝謝分享![]() |
感恩分享 |
谢谢 分享 |
我用的CUBEMX里的例程,自己用CUBEMX建立工程将文件添加进去后,通过Ymodem下载程序,可以正常跑但执行到HAL_Delay()就卡死了,版主有遇到同样的情况吗 |