赞
踩
目录
编写本篇文章原因,前段时间也写了一篇U盘升级方式:链接,感觉不是很好,这次全部基于STM32CubeMx图形生成代码工具来完成,中途断断续续搞了很长时间,不过结果还是很不错,终于成功。网上很多资料都是讲解接入外部(U盘/SD卡)方式进行固件升级,其实原理都差不多。(注该项目,只要是讲线下升级,不是讲远程升级,可以移植到其它型号芯片上使用),后期有时间写一篇基于串口远程升级文章,这估计要有时间再去写了,写这篇文章只要是给一些攻城狮们借鉴,同时也给自己做个笔录,方便后期参阅,加油 ^_^ 。文章篇幅有点长,需要耐心看完。
采用分包形式,来进行固件升级。
ST官网例程(AN4657-STM32Cube_IAP_using_UART)链接
1、硬件平台
STM32F401CEU6
内部Flash : 512Kbytes,SARM : 96 Kbytes
Flash地址映射表:
2、软件平台
IDE: STM32CubeMx6.2.1 + Keil 2.9
技术栈:W25Q32(Flash) + FatFs(文件系统) + USART(Debug)
实现:Flash模拟U盘功能,需要分别关注这三个文件:
1)user_diskio.c (跟fatfs关联,U盘分配空间等逻辑)
2)fatfs.c(文件系统相关逻辑处理)
3)usbd_storage_if.c(U盘分配空间等逻辑)
最主要的还是关注:1、3,第2点看实际使用情况而定。
- 初步内存分配情况:
-
- FLASH_START_ADDR : 0x8000000
- FLASH_MAX_SIZE : 512KByte
- BOOT_START_ADDR : 0x8000000
- BOOT_MEM_SIZE : 64KByte
- USER_START_ADDR : 0x8010000
- USER_MEM_SIZE : 200KByte
- FLASH_MSD_START_ADDR : 0x8042000
- MSD_MEM_SIZE : 200KByte
- OTHER_START_ADDR : 0x8074000
- OTHER_MEM_SIZE : 48KByte
bootloader
2.1、系统时钟配置
2.2、下载调试配置
2.3、RTC配置
2.4、SPI配置
2.5、串口调试配置
2.6、USB配置
2.7、FATFS配置
2.8、SUB_DEVICE配置
2.9生成keil工程代码配置
application
首先分别创建flash_if.h、flash_if.c、w25qxx.h、w25qxx.c文件
3.1.1、mian.c文件
- /* USER CODE BEGIN Header */
- /**
- ******************************************************************************
- * @file : main.c
- * @brief : Main program body
- ******************************************************************************
- * @attention
- *
- * <h2><center>© Copyright (c) 2021 STMicroelectronics.
- * All rights reserved.</center></h2>
- *
- * This software component is licensed by ST under Ultimate Liberty license
- * SLA0044, the "License"; You may not use this file except in compliance with
- * the License. You may obtain a copy of the License at:
- * www.st.com/SLA0044
- *
- ******************************************************************************
- */
- /* USER CODE END Header */
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
- #include "fatfs.h"
- #include "rtc.h"
- #include "spi.h"
- #include "usart.h"
- #include "usb_device.h"
- #include "gpio.h"
-
- /* Private includes ----------------------------------------------------------*/
- /* USER CODE BEGIN Includes */
- #include "stdio.h"
- #include "flash_if.h"
- /* USER CODE END Includes */
-
- /* Private typedef -----------------------------------------------------------*/
- /* USER CODE BEGIN PTD */
- extern USBD_HandleTypeDef hUsbDeviceFS;
- /* USER CODE END PTD */
-
- /* Private define ------------------------------------------------------------*/
- /* USER CODE BEGIN PD */
- /* USER CODE END PD */
-
- /* Private macro -------------------------------------------------------------*/
- /* USER CODE BEGIN PM */
-
- /* USER CODE END PM */
-
- /* Private variables ---------------------------------------------------------*/
-
- /* USER CODE BEGIN PV */
-
- /* USER CODE END PV */
-
- /* Private function prototypes -----------------------------------------------*/
- void SystemClock_Config(void);
- /* USER CODE BEGIN PFP */
- void Read_MSD_FATFS(void);
- void CopyAppToUserMemory(void);
- void JumpToApp(void);
- void PeriphDeinit(void);
- /* USER CODE END PFP */
-
- /* Private user code ---------------------------------------------------------*/
- /* USER CODE BEGIN 0 */
- char str[80] = {0};
- FRESULT FatFs_Status = FR_OK;
- DWORD appSize = 0; //DWORD: 32bit
- #define APPDATABYTESIZE 1024 //每读取一次文件大小
- uint8_t AppDataByte[APPDATABYTESIZE] = {0};
- UINT readBytes = 0;
-
- /* USER CODE END 0 */
-
- /**
- * @brief The application entry point.
- * @retval int
- */
- int main(void)
- {
- /* USER CODE BEGIN 1 */
- uint8_t usb_current_state = 0;
- uint8_t usb_input_state = 0;
-
- uint32_t overTime = 0;
- /* USER CODE END 1 */
-
- /* MCU Configuration--------------------------------------------------------*/
-
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
-
- /* USER CODE BEGIN Init */
-
- /* USER CODE END Init */
-
- /* Configure the system clock */
- SystemClock_Config();
-
- /* USER CODE BEGIN SysInit */
- FLASH_If_Init();
- /* USER CODE END SysInit */
-
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USART1_UART_Init();
- MX_RTC_Init();
- MX_SPI1_Init();
- MX_FATFS_Init();
- MX_USB_DEVICE_Init();
- /* USER CODE BEGIN 2 */
- // HAL_Delay(1000);
-
- printf ("-----START LOG----- \n\r\n\r");
- printf ("FLASH_START_ADDR : %#x \n\r", FLASH_START_ADDR);
- printf ("FLASH_MAX_SIZE : %dKByte \n\r", FLASH_MAX_SIZE/1024);
- printf ("BOOT_START_ADDR : %#x \n\r", FLASH_BOOT_START_ADDR);
- printf ("BOOT_MEM_SIZE : %dKByte \n\r", FLASH_BOOT_SIZE/1024);
- printf ("USER_START_ADDR : %#x \n\r", FLASH_USER_START_ADDR);
- printf ("USER_MEM_SIZE : %dKByte \n\r", FLASH_USER_SIZE/1024);
- printf ("FLASH_MSD_START_ADDR : %#x \n\r", FLASH_MSD_START_ADDR);
- printf ("MSD_MEM_SIZE : %dKByte \n\r", FLASH_MSD_SIZE/1024);
- printf ("OTHER_START_ADDR : %#x \n\r", FLASH_OTHER_START_ADDR);
- printf ("OTHER_MEM_SIZE : %dKByte \n\r\n\r", FLASH_OTHER_SIZE/1024);
-
- //Flash_Test();
-
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- if(hUsbDeviceFS.dev_state != usb_current_state){
- if(hUsbDeviceFS.dev_state== USBD_STATE_CONFIGURED){
- usb_input_state = 1;
- printf("usb is connect \r\n");
- }else if(hUsbDeviceFS.dev_state== USBD_STATE_SUSPENDED){
- printf("usb disconnect \r\n");
- //开始读取大容量存储器文件 (mass storage class)
- Read_MSD_FATFS();
- }else{
- //
- }
- usb_current_state = hUsbDeviceFS.dev_state;
- }
-
- if(overTime++ > 3)
- {
- //大于3s后,还没检查到USB 直接运行APP
- if(usb_input_state == 0){
- printf("---system run -app\r\n");
- //禁止所使用的外设
- printf ("Peripheral deinit and go to main programm \n\r");
-
- printf ("JumpToApp is addr : %x \n\r", FLASH_USER_START_ADDR);
- PeriphDeinit(); //Periphery deinit
- JumpToApp();
- printf("---system run -app error!!!!\r\n");
- }
- }
- HAL_Delay(1000);
- HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
- printf("heihei, I'm an bootloader\r\n");
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
-
- /**
- * @brief System Clock Configuration
- * @retval None
- */
- void SystemClock_Config(void)
- {
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
-
- /** Configure the main internal regulator output voltage
- */
- __HAL_RCC_PWR_CLK_ENABLE();
- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
- /** Initializes the RCC Oscillators according to the specified parameters
- * in the RCC_OscInitTypeDef structure.
- */
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
- RCC_OscInitStruct.LSEState = RCC_LSE_ON;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
- RCC_OscInitStruct.PLL.PLLM = 25;
- RCC_OscInitStruct.PLL.PLLN = 336;
- RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
- RCC_OscInitStruct.PLL.PLLQ = 7;
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
- /** Initializes the CPU, AHB and APB buses clocks
- */
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
- RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
-
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
- {
- Error_Handler();
- }
- PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
- PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
- }
-
- /* USER CODE BEGIN 4 */
- void Read_MSD_FATFS(void)
- {
- int i = 0;
- printf ("BOOTLOADER Update... \n\r");
-
- MX_FATFS_Init(); // Init FatFs
-
- FatFs_Status = f_mount(&USERFatFS, (TCHAR const*)USERPath, 0);
- if(FatFs_Status == FR_OK)
- {
- printf ("FatFs mount status = %s \n\r", "FR_OK");
-
- // if ((strcmp(USERPath, ".bin") == 0) || (strcmp(USERPath, ".BIN") == 0)
- // || (strcmp(USERPath, ".hex") == 0) || (strcmp(USERPath, ".HEX") == 0))
- // {
-
- // }
-
- FatFs_Status = f_open(&USERFile, "APP.bin", FA_OPEN_EXISTING | FA_READ);
- if(FatFs_Status == FR_OK)
- {
- printf ("Application file open status = %s \n\r", "FR_OK");
-
- appSize = f_size(&USERFile);
-
- printf ("Application file size = %lu \n\r", appSize);
-
- for(i = 0; i < appSize; i++) //Byte-to-byte compare files in MSD_MEM and USER_MEM
- {
- f_read(&USERFile, AppDataByte, 1, &readBytes);
- if(*((volatile uint8_t*)(FLASH_USER_START_ADDR + i)) != AppDataByte[0]) break;
- }
- if (i != appSize) //=> was done "break" instruction in for(;;) cycle => new firmware in MSD_FLASH
- {
- i=0;
- printf ("Find difference in %d byte \n\r\n\r", i);
-
- CopyAppToUserMemory();
- }
- else
- {
- printf ("Versions of firmwares are the same. No update required.\n\r");
- }
-
- FatFs_Status = f_close(&USERFile);
- if (FatFs_Status == FR_OK)
- {
- printf ("Application file close status = %s \n\r", "FR_OK");
- }
- else
- {
- printf ("Application file close status = %s \n\r", "ERROR");
- }
-
- FatFs_Status = f_mount(0, (TCHAR const*)USERPath, 0);
- if (FatFs_Status == FR_OK)
- {
- printf ("FatFs unmount status = %s \n\r\n\r", "FR_OK");
- }
- else
- {
- printf ("FatFs unmount status = %s \n\r\n\r", "ERROR");
- }
- }
- else
- {
- printf ("Application file open status = %s \n\r", "ERROR");
- FatFs_Status = f_mount(0, (TCHAR const*)USERPath, 0);
- }
- }
- else
- {
- printf ("FatFs mount status = %s \n\r", "ERROR");
- }
-
- }
-
- void JumpToApp(void)
- {
- typedef void (*pFunction)(void);
- static pFunction JumpToApplication;
- static uint32_t JumpAddress;
-
- /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
- if (((*(__IO uint32_t*)FLASH_USER_START_ADDR) & 0x2FFE0000 ) == 0x20000000)
- {
- /* Jump to user application */
- JumpAddress = *(__IO uint32_t*) (FLASH_USER_START_ADDR + 4u);
- JumpToApplication = (pFunction) JumpAddress;
- SCB->VTOR = FLASH_USER_START_ADDR; //注:这里添加上地址设置偏移量,此时在app程序无需添加,否则无效。
- /* Initialize user application's Stack Pointer */
- __set_MSP(*(__IO uint32_t*) FLASH_USER_START_ADDR);
- JumpToApplication();
- }
-
- }
- //---------------------------------------------------------------------
- void PeriphDeinit(void)
- {
- __disable_irq();//注意,这里关闭所有中断,在对应的app程序需要在main函数里最前面添加上 __enable_irq();即可,则跳转过去,程序无法运行
- FATFS_UnLinkDriver(USERPath);
-
- __HAL_RCC_GPIOC_CLK_DISABLE();
- __HAL_RCC_GPIOA_CLK_DISABLE();
- __HAL_RCC_GPIOB_CLK_DISABLE();
- HAL_GPIO_DeInit(LED_GPIO_Port,LED_Pin);
-
- //HAL_UART_MspDeInit(&huart1);
- }
-
- void CopyAppToUserMemory(void)
- {
- uint32_t remain_bytes = 0;
- uint32_t number_of_blok = 0;
- float write_percents = 0;
-
- printf ("Start to copy new firmware \n\r");
-
- f_lseek(&USERFile, 0); // Go to the fist position of file
- appSize = f_size(&USERFile); // Bytes in file
-
- number_of_blok = appSize / APPDATABYTESIZE;
- remain_bytes = appSize % APPDATABYTESIZE; // APPDATABYTESIZE = 1024byte
- if (remain_bytes != 0) number_of_blok++;
- printf ("Total cycles number = %d. Remain bytes = %d \n\r", number_of_blok, remain_bytes);
-
-
- for (int j=0; j<number_of_blok; j++)
- {
- f_read(&USERFile, AppDataByte, APPDATABYTESIZE, &readBytes); // Read 1024 byte from file
- printf ("%d Cycle. Read %u bytes \n\r",j ,readBytes);
-
- if (readBytes != APPDATABYTESIZE) //APPDATABYTESIZE = 1024
- {
- for (int k=0; k<(APPDATABYTESIZE-readBytes); k++)
- {
- AppDataByte[readBytes+k] = 0xFF;
- }
- }
- Flas
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。