
这段时间用到STM32F417XXX一芯片做项目需要用到IAP进行串口在线升级,官方例程是利用了一个IO进行控制升级,我的想法是,使用STM32的串口控制升级,大约的流程如下: 上电---->通过串口发送指定字符串------>自延时约200ms------>接收是否有上位机的指定字符串-------->如有进行升级,如无直接进行APP跳转。 首先我们下载了STM32F4xx_AN3965_V1.0.0作为初始例程,而且这个例程还有说明都一并放置到下载区了。 然后,我们首先生成了一个基于HAL的例程文件,只开启了UART1,其它的功能不用动 设置了时间为168MHz,然后生成了一个HAL库的代码。 将STM32F4xx_AN3965_V1.0.0里面的 common.c flash_if.c menu.c ymodem.c 放置到Src文件夹中,头文件放置到inc文件夹中,在工程中将这几个文件添加到工程中(Application/usr文件夹上右键,add existiong .....) 在头文件中添加上头文件 #include "menu.h" #include "common.h" #include "string.h" #include "stdio.h" 添加下面的这些外部定义 extern pFunction Jump_To_Application; extern uint32_t JumpAddress; extern uint32_t FlashProtection; 编译后会出现一些错误,主要有: FLASH_Sector_x的报错,找不到这些,打到这些地方全部改成FLASH_SECTOR_X FLASH_Erase_SectorXX的报错,HAL中没有返回,相应更改一下: uint32_t FLASH_If_Erase(uint32_t StartSector) { uint32_t UserStartSector = FLASH_SECTOR_1, i = 0; /* Get the sector where start the user flash area */ UserStartSector = GetSector(APPLICATION_ADDRESS); for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1) { /* Device voltage range supposed to be [2.7V to 3.6V], the operation will be done by word */ FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3); } return (0); } 其它的一些基本类似,解决办法都是是到: 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); 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); HAL_StatusTypeDef FLASH_OB_BOR_LevelConfig(uint8_t Level); uint8_t FLASH_OB_GetUser(void); uint16_t FLASH_OB_GetWRP(void); uint8_t FLASH_OB_GetRDP(void); uint8_t FLASH_OB_GetBOR(void); 将这些声明直接放置到对应的头文件中去,同时将头文件包含到需要用*.c中。 还需要修改这个函数 uint32_t FLASH_If_Erase(uint32_t StartSector) { uint32_t UserStartSector = FLASH_SECTOR_1, i = 0; /* Get the sector where start the user flash area */ UserStartSector = GetSector(APPLICATION_ADDRESS); 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 will be done by word */ FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3); } return (0); } 这个函数需要修改一下,标红的两句是新加的: void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange) { uint32_t tmp_psize = 0U; /* Check the parameters */ assert_param(IS_FLASH_SECTOR(Sector)); assert_param(IS_VOLTAGERANGE(VoltageRange)); FLASH_WaitForLastOperation(0xFFF); if(VoltageRange == FLASH_VOLTAGE_RANGE_1) { tmp_psize = FLASH_PSIZE_BYTE; } else if(VoltageRange == FLASH_VOLTAGE_RANGE_2) { tmp_psize = FLASH_PSIZE_HALF_WORD; } else if(VoltageRange == FLASH_VOLTAGE_RANGE_3) { tmp_psize = FLASH_PSIZE_WORD; } else { 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); 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; } 其它修改,串口修改: void SerialPutChar(uint8_t c) { HAL_UART_Transmit_IT(&huart1, &c,1); while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET); } uint32_t SerialKeyPressed(uint8_t *key) { if(HAL_UART_Receive(&huart1,key,1,0xFF) == HAL_OK) { return 1; } else { return 0; } } 在修改完成确认没有错误了,就需要如下操作: 修改main函数: int CmpStr(const char *data,const char *data1,int index1,int index2,int length); #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f) #endif PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF); return ch; } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ //FLASH_If_Init(); /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ uint8_t mychar[30] = "*****************\n\r";//上下交互的语句,请自定义 /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* 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 */ while (1) { Serial_PutString(mychar); if(HAL_UART_Receive(&huart1,mychar,16,0xFF) == HAL_OK) { if(CmpStr((char *)mychar,"**************",0,0,strlen("***********")) == 0)//标红的需要自已定义 { printf("正在等待数据文件下发......\r\n"); FLASH_If_Init(); //Main_Menu(); //FlashProtection = !FLASH_If_GetWriteProtectionStatus(); SerialDownload(); } } /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */ 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 */ 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(); } else { Serial_PutString((uint8_t *)"no user Program\r\n\n"); } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } int CmpStr(const char *data,const char *data1,int index1,int index2,int length) { //int temp = 0; for(int i = 0; i< length;i++) { if(*(data+index1+i)- *(data1+index2+i) >0) { return 1; } if(*(data+index1+i)- *(data1+index2+i) <0) { return -1; } } return 0; } 好了,基本就这些,有问题留言,我有时间就回复。。。 如果有好的提议,可以一起探讨一下! |
謝謝分享![]() |
感恩分享 |
谢谢 分享 |
我用的CUBEMX里的例程,自己用CUBEMX建立工程将文件添加进去后,通过Ymodem下载程序,可以正常跑但执行到HAL_Delay()就卡死了,版主有遇到同样的情况吗 |