你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32F103的HAL库实现USB(HID) OTA升级

[复制链接]
和良 提问时间:2025-3-27 16:52 / 未解决

求助,有没有大神使用cubeMX生成初始代码开发实现通过USB(HID)进行OTA升级功能的

1 收藏 评论1 发布时间:2025-3-27 16:52

举报

1个回答
STMCU-管管 回答时间:3 天前

1. 硬件与软件准备

  • 硬件
    • STM32F103C8T6(或其他F103系列,需支持USB)
    • USB接口(PA11/DM, PA12/DP)
    • 串口(可选,用于调试)
  • 软件
    • STM32CubeMX
    • Keil MDK/STM32CubeIDE
    • USB HID协议库(或自定义协议)

2. CubeMX配置

步骤1:创建工程
  1. 打开CubeMX,选择 STM32F103C8T6
  2. 配置时钟:
    • HSE(8MHz外部晶振)→ PLL → SYSCLK 72MHz。
    • USB时钟需48MHz(通过PLL分频实现,72MHz / 1.5 = 48MHz)。
步骤2:启用USB
  1. Connectivity 中启用 USB Device
  2. 选择 Human Interface Device (HID)
    • MiddlewareUSB_DEVICEHID
步骤3:配置GPIO和时钟
  1. 确保PA11(DM)和PA12(DP)已自动配置为USB。
  2. 检查时钟树:
    • PLLCLK = 72MHz(HSE 8MHz × 9)。
    • USBCLK = 48MHz(72MHz / 1.5)。
步骤4:生成代码
  1. 选择IDE(如Keil),生成代码。

3. 代码实现

3.1 修改HID描述符

usbd_hid.c 中修改报告描述符(64字节输入/输出):

c

复制

__ALIGN_BEGIN static uint8_t HID_ReportDesc[] __ALIGN_END = {
  0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined)
  0x09, 0x01,        // Usage (Vendor Usage 1)
  0xA1, 0x01,        // Collection (Application)
  0x15, 0x00,        // Logical Minimum (0)
  0x26, 0xFF, 0x00,  // Logical Maximum (255)
  0x75, 0x08,        // Report Size (8 bits)
  0x95, 0x40,        // Report Count (64 bytes)
  0x09, 0x01,        // Usage (Vendor Usage 1)
  0x81, 0x02,        // Input (Data, Var, Abs)
  0x95, 0x40,        // Report Count (64 bytes)
  0x09, 0x01,        // Usage (Vendor Usage 1)
  0x91, 0x02,        // Output (Data, Var, Abs)
  0xC0               // End Collection
};
3.2 实现OTA协议
  1. 接收固件数据 (在 usbd_hid.c 中):

c

复制

void USBD_HID_SendReport(uint8_t *report, uint16_t len) {
  if (USBD_HID_HandleTypeDef *hid = hUsbDeviceFS.pClassData) {
    USBD_LL_Transmit(&hUsbDeviceFS, HID_EPIN_ADDR, report, len);
  }
}

void USBD_HID_Receive(uint8_t *data, uint32_t length) {
  if (data[0] == OTA_HEADER) {  // 检查固件头
    write_to_flash(APP_ADDRESS, &data[1], length - 1);
  }
}
  1. Flash操作 (添加 stm32f1xx_hal_flash.c):

c

复制

void write_to_flash(uint32_t addr, uint8_t *data, uint32_t len) {
  HAL_FLASH_Unlock();
  FLASH_EraseInitTypeDef erase = {
    .TypeErase = FLASH_TYPEERASE_PAGES,
    .PageAddress = APP_ADDRESS,
    .NbPages = (len + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE
  };
  uint32_t page_error;
  HAL_FLASHEx_Erase(&erase, &page_error);

  for (uint32_t i = 0; i < len; i += 2) {
    uint16_t val = *(uint16_t*)(data + i);
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, addr + i, val);
  }
  HAL_FLASH_Lock();
}
  1. 跳转函数 (在 main.c 中):

c

复制

void jump_to_app(void) {
  void (*app_reset_handler)(void) = (void (*)(void))(*((uint32_t*)(APP_ADDRESS + 4)));
  __disable_irq();
  HAL_RCC_DeInit();
  HAL_DeInit();
  __set_MSP(*(__IO uint32_t*)APP_ADDRESS);
  app_reset_handler();
}
3.3 主循环逻辑

c

复制

while (1) {
  if (ota_complete) {
    jump_to_app();
  }
  HAL_Delay(100);
}

4. 上位机工具(Python示例)

python

复制

import hid
device = hid.device()
device.open(0x0483, 0x5750)  # STM32默认VID/PID

# 发送固件
with open("firmware.bin", "rb") as f:
    data = f.read()
    chunk_size = 64
    for i in range(0, len(data), chunk_size):
        chunk = data[i:i+chunk_size]
        device.write([0x00] + list(chunk))  # HID报告ID为0x00

5. 测试步骤

  1. 编译烧录 :将Bootloader代码烧录到STM32F103。
  2. 发送固件
    • 运行Python脚本发送 .bin 文件。
    • MCU接收后写入Flash(地址 0x08004000,避开Bootloader)。
  3. 跳转验证 :重启后自动运行新固件。

6. 常见问题

  • USB枚举失败
    • 检查PA11/PA12引脚连接。
    • 确认时钟配置(USBCLK=48MHz)。
  • Flash写入错误
    • 确保地址对齐(半字写入,2字节)。
    • 关闭写保护(HAL_FLASH_Unlock())。
  • 兼容性
    • STM32F103的USB仅支持全速模式(12Mbps)。

7. 优化建议

  • 校验机制 :添加CRC校验固件完整性。
  • 双Bank升级 :STM32F103无双Bank,可设计备份分区。
  • 调试输出 :通过串口打印日志(如HAL_UART_Transmit)。

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版