STM32F103 U盘升级方案设计与实现

STM32F103 U盘升级方案设计与实现

一、系统概述

U盘升级是通过USB接口将U盘中的固件文件(.bin)读取到STM32F103内部Flash,实现程序更新的技术。本方案基于STM32F103C8T6(64KB Flash,20KB RAM),通过CH375 USB Host控制器连接U盘,结合FATFS文件系统读取升级文件,最终将文件写入应用程序区Flash,实现无缝升级。核心功能包括:U盘识别、FAT32文件解析、固件校验、Flash擦写、 bootloader跳转。

二、硬件设计

2.1 核心组件

模块 型号/参数 功能说明
主控 STM32F103C8T6(Cortex-M3,72MHz) Bootloader程序、USB Host控制、Flash擦写
USB Host CH375(USB Host控制器,SPI接口) 转换USB Host信号为SPI,连接U盘
存储介质 MicroSD卡/U盘(FAT32格式,≤32GB) 存储升级文件(如UPDATE.bin)
电源 5V USB供电(或3.3V LDO) 为STM32、CH375、U盘供电

2.2 硬件连接

模块 引脚(STM32F103C8T6) CH375引脚 说明
SPI1 PA5(SCK) SCK SPI时钟
  PA6(MISO) MISO SPI数据输入(CH375→STM32)
  PA7(MOSI) MOSI SPI数据输出(STM32→CH375)
  PA4(NSS) CS SPI片选(低电平有效)
CH375 INT(中断输出) PB0(EXTI0) U盘插入/数据就绪中断
U盘 USB_DP/USB_DM CH375 USB接口 连接U盘

三、软件设计

3.1 系统架构

graph TD
    A[Bootloader启动] --> B{检测升级请求?}
    B -->|U盘插入+按键按下| C[初始化CH375+SPI]
    C --> D[枚举U盘+FATFS挂载]
    D --> E[读取UPDATE.bin文件]
    E --> F[校验文件(CRC32)]
    F --> G[擦除应用程序区Flash]
    G --> H[写入新固件]
    H --> I[校验Flash数据]
    I --> J[跳转到应用程序]
    B -->|无升级请求| J

3.2 核心模块实现

3.2.1 Bootloader分区设计

STM32F103C8T6 Flash共64KB,划分为:

3.2.2 CH375 USB Host驱动(SPI接口)

CH375通过SPI与STM32通信,核心函数包括初始化、读写寄存器、枚举U盘:

#include "ch375spi.h"
#include "spi.h"

// SPI读写CH375寄存器
uint8_t CH375_ReadReg(uint8_t reg) {
  uint8_t data;
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);  // CS=0
  HAL_SPI_Transmit(&hspi1, &reg, 1, 100);               // 发送寄存器地址
  HAL_SPI_Receive(&hspi1, &data, 1, 100);                // 读取数据
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);    // CS=1
  return data;
}

void CH375_WriteReg(uint8_t reg, uint8_t data) {
  uint8_t buf[2] = {reg, data};
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&hspi1, buf, 2, 100);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
}

// 初始化CH375(USB Host模式)
void CH375_Init(void) {
  CH375_WriteReg(CH375_MODE, 0x06);  // 模式寄存器:USB Host,SPI接口
  HAL_Delay(100);
  uint8_t status = CH375_ReadReg(CH375_STATUS);
  if (status == 0x15) printf("CH375初始化成功\r\n");
}

3.2.3 FATFS文件系统挂载(读取U盘文件)

使用FATFS R0.14b读取U盘中的UPDATE.bin:

#include "ff.h"
#include "diskio.h"

FATFS fs;
FIL file;
UINT br;

// 挂载U盘
FRESULT Mount_USB(void) {
  FRESULT res = f_mount(&fs, "0:", 1);  // "0:"为U盘盘符
  if (res != FR_OK) printf("挂载失败: %d\r\n", res);
  return res;
}

// 读取UPDATE.bin文件
uint8_t Read_UpdateFile(uint8_t *buf, uint32_t len) {
  FRESULT res = f_open(&file, "0:/UPDATE.bin", FA_READ);
  if (res != FR_OK) return 1;
  
  res = f_read(&file, buf, len, &br);  // 读取len字节
  f_close(&file);
  return (res == FR_OK && br == len) ? 0 : 1;
}

3.2.4 Flash擦写驱动(STM32内部Flash)

STM32F103 Flash擦除按页(1KB),写入按字(32位):

#include "stm32f10x_flash.h"

// 擦除应用程序区(0x08004000~0x0801FFFF)
void Flash_EraseApp(void) {
  FLASH_Unlock();
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
  
  uint32_t addr = 0x08004000;
  while (addr < 0x08020000) {  // 应用程序区结束地址
    FLASH_ErasePage(addr);
    addr += 1024;  // 1KB页
  }
  
  FLASH_Lock();
}

// 写入固件数据(addr:Flash地址,buf:数据,len:字节数)
void Flash_Write(uint32_t addr, uint8_t *buf, uint32_t len) {
  FLASH_Unlock();
  uint32_t *src = (uint32_t*)buf;
  uint32_t words = len / 4;
  
  for (uint32_t i=0; i<words; i++) {
    FLASH_ProgramWord(addr, src[i]);  // 按字写入
    addr += 4;
  }
  
  FLASH_Lock();
}

3.2.5 Bootloader主流程

int main(void) {
  HAL_Init();
  SystemClock_Config();
  SPI1_Init();       // SPI1初始化(CH375通信)
  CH375_Init();      // CH375初始化
  Button_Init();     // 按键初始化(触发升级)
  
  // 检测升级标志(标志区0x0801FFFC)
  uint32_t flag = *(uint32_t*)0x0801FFFC;
  if (flag == 0xAA55 || (Button_IsPressed() && CH375_UDiskInserted())) {
    // 执行升级流程
    if (Mount_USB() == FR_OK) {
      uint8_t firmware[48 * 1024];  // 应用程序区大小(48KB)
      if (Read_UpdateFile(firmware, sizeof(firmware)) == 0) {
        Flash_EraseApp();
        Flash_Write(0x08004000, firmware, sizeof(firmware));
        *(uint32_t*)0x0801FFFC = 0x55AA;  // 清除升级标志
        NVIC_SystemReset();  // 重启
      }
    }
  }
  
  // 跳转到应用程序(0x08004000)
  JumpToApp(0x08004000);
}

// 跳转到应用程序
void JumpToApp(uint32_t addr) {
  typedef void (*AppFunc)(void);
  AppFunc app = (AppFunc)*(uint32_t*)(addr + 4);  // 应用程序入口地址
  __set_MSP(*(uint32_t*)addr);  // 设置堆栈指针
  app();  // 跳转
}

参考代码 STM32F103实现U盘升级 www.youwenfan.com/contentcss/56419.html

四、关键问题与解决方案

4.1 U盘枚举失败

4.2 Flash写入错误

4.3 升级文件校验失败

五、测试步骤

  1. 硬件连接:按2.2节连接STM32、CH375、U盘;
  2. 编译Bootloader:生成.bin文件,通过ST-Link烧录至0x08000000;
  3. 准备升级文件:将用户程序编译为.bin,重命名为UPDATE.bin放入U盘根目录;
  4. 触发升级:插入U盘,按下升级按键,观察串口输出(如“升级成功”);
  5. 验证:重启后运行新程序,确认功能正常。

六、总结

本方案基于STM32F103和CH375实现了U盘升级,核心是Bootloader分区、USB Host控制、FATFS文件读取、Flash擦写。通过模块化设计,可扩展支持加密升级(如AES解密)、断点续传等功能。

专注于matlab/simulink,电子电路,编程