当前位置:   article > 正文

STM32HAL库 基于Flash+FatFs模拟U盘形式进行固件拷贝升级(详解)

STM32HAL库 基于Flash+FatFs模拟U盘形式进行固件拷贝升级(详解)

目录

概述

一、开发环境

二、STM32CubeMx配置

三、编码

   3.1、Bootloader

   3.2、Application

四、运行结果

五、总结


概述

      编写本篇文章​原因,​​​​​​前段时间也写了一篇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点看实际使用情况而定。
 

  1. 初步内存分配情况:
  2. FLASH_START_ADDR     : 0x8000000 
  3. FLASH_MAX_SIZE       : 512KByte 
  4. BOOT_START_ADDR      : 0x8000000 
  5. BOOT_MEM_SIZE        : 64KByte 
  6. USER_START_ADDR      : 0x8010000 
  7. USER_MEM_SIZE        : 200KByte 
  8. FLASH_MSD_START_ADDR : 0x8042000 
  9. MSD_MEM_SIZE         : 200KByte 
  10. OTHER_START_ADDR     : 0x8074000 
  11. OTHER_MEM_SIZE       : 48KByte 

二、STM32CubeMx配置

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


三、编码

   3.1、Bootloader

       首先分别创建flash_if.h、flash_if.c、w25qxx.h、w25qxx.c文件

       3.1.1、mian.c文件   
  

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by ST under Ultimate Liberty license
  13. * SLA0044, the "License"; You may not use this file except in compliance with
  14. * the License. You may obtain a copy of the License at:
  15. * www.st.com/SLA0044
  16. *
  17. ******************************************************************************
  18. */
  19. /* USER CODE END Header */
  20. /* Includes ------------------------------------------------------------------*/
  21. #include "main.h"
  22. #include "fatfs.h"
  23. #include "rtc.h"
  24. #include "spi.h"
  25. #include "usart.h"
  26. #include "usb_device.h"
  27. #include "gpio.h"
  28. /* Private includes ----------------------------------------------------------*/
  29. /* USER CODE BEGIN Includes */
  30. #include "stdio.h"
  31. #include "flash_if.h"
  32. /* USER CODE END Includes */
  33. /* Private typedef -----------------------------------------------------------*/
  34. /* USER CODE BEGIN PTD */
  35. extern USBD_HandleTypeDef hUsbDeviceFS;
  36. /* USER CODE END PTD */
  37. /* Private define ------------------------------------------------------------*/
  38. /* USER CODE BEGIN PD */
  39. /* USER CODE END PD */
  40. /* Private macro -------------------------------------------------------------*/
  41. /* USER CODE BEGIN PM */
  42. /* USER CODE END PM */
  43. /* Private variables ---------------------------------------------------------*/
  44. /* USER CODE BEGIN PV */
  45. /* USER CODE END PV */
  46. /* Private function prototypes -----------------------------------------------*/
  47. void SystemClock_Config(void);
  48. /* USER CODE BEGIN PFP */
  49. void Read_MSD_FATFS(void);
  50. void CopyAppToUserMemory(void);
  51. void JumpToApp(void);
  52. void PeriphDeinit(void);
  53. /* USER CODE END PFP */
  54. /* Private user code ---------------------------------------------------------*/
  55. /* USER CODE BEGIN 0 */
  56. char str[80] = {0};
  57. FRESULT FatFs_Status = FR_OK;
  58. DWORD appSize = 0; //DWORD: 32bit
  59. #define APPDATABYTESIZE 1024 //每读取一次文件大小
  60. uint8_t AppDataByte[APPDATABYTESIZE] = {0};
  61. UINT readBytes = 0;
  62. /* USER CODE END 0 */
  63. /**
  64. * @brief The application entry point.
  65. * @retval int
  66. */
  67. int main(void)
  68. {
  69. /* USER CODE BEGIN 1 */
  70. uint8_t usb_current_state = 0;
  71. uint8_t usb_input_state = 0;
  72. uint32_t overTime = 0;
  73. /* USER CODE END 1 */
  74. /* MCU Configuration--------------------------------------------------------*/
  75. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  76. HAL_Init();
  77. /* USER CODE BEGIN Init */
  78. /* USER CODE END Init */
  79. /* Configure the system clock */
  80. SystemClock_Config();
  81. /* USER CODE BEGIN SysInit */
  82. FLASH_If_Init();
  83. /* USER CODE END SysInit */
  84. /* Initialize all configured peripherals */
  85. MX_GPIO_Init();
  86. MX_USART1_UART_Init();
  87. MX_RTC_Init();
  88. MX_SPI1_Init();
  89. MX_FATFS_Init();
  90. MX_USB_DEVICE_Init();
  91. /* USER CODE BEGIN 2 */
  92. // HAL_Delay(1000);
  93. printf ("-----START LOG----- \n\r\n\r");
  94. printf ("FLASH_START_ADDR : %#x \n\r", FLASH_START_ADDR);
  95. printf ("FLASH_MAX_SIZE : %dKByte \n\r", FLASH_MAX_SIZE/1024);
  96. printf ("BOOT_START_ADDR : %#x \n\r", FLASH_BOOT_START_ADDR);
  97. printf ("BOOT_MEM_SIZE : %dKByte \n\r", FLASH_BOOT_SIZE/1024);
  98. printf ("USER_START_ADDR : %#x \n\r", FLASH_USER_START_ADDR);
  99. printf ("USER_MEM_SIZE : %dKByte \n\r", FLASH_USER_SIZE/1024);
  100. printf ("FLASH_MSD_START_ADDR : %#x \n\r", FLASH_MSD_START_ADDR);
  101. printf ("MSD_MEM_SIZE : %dKByte \n\r", FLASH_MSD_SIZE/1024);
  102. printf ("OTHER_START_ADDR : %#x \n\r", FLASH_OTHER_START_ADDR);
  103. printf ("OTHER_MEM_SIZE : %dKByte \n\r\n\r", FLASH_OTHER_SIZE/1024);
  104. //Flash_Test();
  105. /* USER CODE END 2 */
  106. /* Infinite loop */
  107. /* USER CODE BEGIN WHILE */
  108. while (1)
  109. {
  110. if(hUsbDeviceFS.dev_state != usb_current_state){
  111. if(hUsbDeviceFS.dev_state== USBD_STATE_CONFIGURED){
  112. usb_input_state = 1;
  113. printf("usb is connect \r\n");
  114. }else if(hUsbDeviceFS.dev_state== USBD_STATE_SUSPENDED){
  115. printf("usb disconnect \r\n");
  116. //开始读取大容量存储器文件 (mass storage class)
  117. Read_MSD_FATFS();
  118. }else{
  119. //
  120. }
  121. usb_current_state = hUsbDeviceFS.dev_state;
  122. }
  123. if(overTime++ > 3)
  124. {
  125. //大于3s后,还没检查到USB 直接运行APP
  126. if(usb_input_state == 0){
  127. printf("---system run -app\r\n");
  128. //禁止所使用的外设
  129. printf ("Peripheral deinit and go to main programm \n\r");
  130. printf ("JumpToApp is addr : %x \n\r", FLASH_USER_START_ADDR);
  131. PeriphDeinit(); //Periphery deinit
  132. JumpToApp();
  133. printf("---system run -app error!!!!\r\n");
  134. }
  135. }
  136. HAL_Delay(1000);
  137. HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
  138. printf("heihei, I'm an bootloader\r\n");
  139. /* USER CODE END WHILE */
  140. /* USER CODE BEGIN 3 */
  141. }
  142. /* USER CODE END 3 */
  143. }
  144. /**
  145. * @brief System Clock Configuration
  146. * @retval None
  147. */
  148. void SystemClock_Config(void)
  149. {
  150. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  151. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  152. RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  153. /** Configure the main internal regulator output voltage
  154. */
  155. __HAL_RCC_PWR_CLK_ENABLE();
  156. __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
  157. /** Initializes the RCC Oscillators according to the specified parameters
  158. * in the RCC_OscInitTypeDef structure.
  159. */
  160. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
  161. RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  162. RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  163. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  164. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  165. RCC_OscInitStruct.PLL.PLLM = 25;
  166. RCC_OscInitStruct.PLL.PLLN = 336;
  167. RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  168. RCC_OscInitStruct.PLL.PLLQ = 7;
  169. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  170. {
  171. Error_Handler();
  172. }
  173. /** Initializes the CPU, AHB and APB buses clocks
  174. */
  175. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  176. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  177. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  178. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  179. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  180. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  181. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  182. {
  183. Error_Handler();
  184. }
  185. PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  186. PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  187. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  188. {
  189. Error_Handler();
  190. }
  191. }
  192. /* USER CODE BEGIN 4 */
  193. void Read_MSD_FATFS(void)
  194. {
  195. int i = 0;
  196. printf ("BOOTLOADER Update... \n\r");
  197. MX_FATFS_Init(); // Init FatFs
  198. FatFs_Status = f_mount(&USERFatFS, (TCHAR const*)USERPath, 0);
  199. if(FatFs_Status == FR_OK)
  200. {
  201. printf ("FatFs mount status = %s \n\r", "FR_OK");
  202. // if ((strcmp(USERPath, ".bin") == 0) || (strcmp(USERPath, ".BIN") == 0)
  203. // || (strcmp(USERPath, ".hex") == 0) || (strcmp(USERPath, ".HEX") == 0))
  204. // {
  205. // }
  206. FatFs_Status = f_open(&USERFile, "APP.bin", FA_OPEN_EXISTING | FA_READ);
  207. if(FatFs_Status == FR_OK)
  208. {
  209. printf ("Application file open status = %s \n\r", "FR_OK");
  210. appSize = f_size(&USERFile);
  211. printf ("Application file size = %lu \n\r", appSize);
  212. for(i = 0; i < appSize; i++) //Byte-to-byte compare files in MSD_MEM and USER_MEM
  213. {
  214. f_read(&USERFile, AppDataByte, 1, &readBytes);
  215. if(*((volatile uint8_t*)(FLASH_USER_START_ADDR + i)) != AppDataByte[0]) break;
  216. }
  217. if (i != appSize) //=> was done "break" instruction in for(;;) cycle => new firmware in MSD_FLASH
  218. {
  219. i=0;
  220. printf ("Find difference in %d byte \n\r\n\r", i);
  221. CopyAppToUserMemory();
  222. }
  223. else
  224. {
  225. printf ("Versions of firmwares are the same. No update required.\n\r");
  226. }
  227. FatFs_Status = f_close(&USERFile);
  228. if (FatFs_Status == FR_OK)
  229. {
  230. printf ("Application file close status = %s \n\r", "FR_OK");
  231. }
  232. else
  233. {
  234. printf ("Application file close status = %s \n\r", "ERROR");
  235. }
  236. FatFs_Status = f_mount(0, (TCHAR const*)USERPath, 0);
  237. if (FatFs_Status == FR_OK)
  238. {
  239. printf ("FatFs unmount status = %s \n\r\n\r", "FR_OK");
  240. }
  241. else
  242. {
  243. printf ("FatFs unmount status = %s \n\r\n\r", "ERROR");
  244. }
  245. }
  246. else
  247. {
  248. printf ("Application file open status = %s \n\r", "ERROR");
  249. FatFs_Status = f_mount(0, (TCHAR const*)USERPath, 0);
  250. }
  251. }
  252. else
  253. {
  254. printf ("FatFs mount status = %s \n\r", "ERROR");
  255. }
  256. }
  257. void JumpToApp(void)
  258. {
  259. typedef void (*pFunction)(void);
  260. static pFunction JumpToApplication;
  261. static uint32_t JumpAddress;
  262. /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
  263. if (((*(__IO uint32_t*)FLASH_USER_START_ADDR) & 0x2FFE0000 ) == 0x20000000)
  264. {
  265. /* Jump to user application */
  266. JumpAddress = *(__IO uint32_t*) (FLASH_USER_START_ADDR + 4u);
  267. JumpToApplication = (pFunction) JumpAddress;
  268. SCB->VTOR = FLASH_USER_START_ADDR; //注:这里添加上地址设置偏移量,此时在app程序无需添加,否则无效。
  269. /* Initialize user application's Stack Pointer */
  270. __set_MSP(*(__IO uint32_t*) FLASH_USER_START_ADDR);
  271. JumpToApplication();
  272. }
  273. }
  274. //---------------------------------------------------------------------
  275. void PeriphDeinit(void)
  276. {
  277. __disable_irq();//注意,这里关闭所有中断,在对应的app程序需要在main函数里最前面添加上 __enable_irq();即可,则跳转过去,程序无法运行
  278. FATFS_UnLinkDriver(USERPath);
  279. __HAL_RCC_GPIOC_CLK_DISABLE();
  280. __HAL_RCC_GPIOA_CLK_DISABLE();
  281. __HAL_RCC_GPIOB_CLK_DISABLE();
  282. HAL_GPIO_DeInit(LED_GPIO_Port,LED_Pin);
  283. //HAL_UART_MspDeInit(&huart1);
  284. }
  285. void CopyAppToUserMemory(void)
  286. {
  287. uint32_t remain_bytes = 0;
  288. uint32_t number_of_blok = 0;
  289. float write_percents = 0;
  290. printf ("Start to copy new firmware \n\r");
  291. f_lseek(&USERFile, 0); // Go to the fist position of file
  292. appSize = f_size(&USERFile); // Bytes in file
  293. number_of_blok = appSize / APPDATABYTESIZE;
  294. remain_bytes = appSize % APPDATABYTESIZE; // APPDATABYTESIZE = 1024byte
  295. if (remain_bytes != 0) number_of_blok++;
  296. printf ("Total cycles number = %d. Remain bytes = %d \n\r", number_of_blok, remain_bytes);
  297. for (int j=0; j<number_of_blok; j++)
  298. {
  299. f_read(&USERFile, AppDataByte, APPDATABYTESIZE, &readBytes); // Read 1024 byte from file
  300. printf ("%d Cycle. Read %u bytes \n\r",j ,readBytes);
  301. if (readBytes != APPDATABYTESIZE) //APPDATABYTESIZE = 1024
  302. {
  303. for (int k=0; k<(APPDATABYTESIZE-readBytes); k++)
  304. {
  305. AppDataByte[readBytes+k] = 0xFF;
  306. }
  307. }
  308. Flas
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/464036
推荐阅读
相关标签
  

闽ICP备14008679号