STM32H743集成了高速USB 2.0 OTG(On-The-Go) 外设,支持Host(主机)、Device(设备)、OTG(双模)三种模式,最高传输速率达480Mbps(高速模式),兼容USB 1.1(低速/全速12Mbps)。USB是嵌入式系统中实现与PC/外设数据交互的核心接口,可实现U盘读写、虚拟串口、USB摄像头、自定义HID设备等功能。

一、STM32H743 USB 核心硬件特性

        STM32H743的USB OTG外设分为USB_OTG_FS(全速,12Mbps)USB_OTG_HS(高速,480Mbps),其中HS可兼容FS模式,核心特性如下:

特性

说明

传输速率

低速(1.5Mbps)、全速(12Mbps)、高速(480Mbps)

工作模式

Device(设备):如虚拟串口、U盘、HID键盘;Host(主机):读写U盘、连接USB外设;OTG:双模切换

接口类型

USB_OTG_HS:D+(PA12)、D-(PA11)、VBUS(PA9)、ID(PA10);USB_OTG_FS:同HS(引脚复用)

传输方式

批量传输(Bulk)、中断传输(Interrupt)、同步传输(Isochronous)、控制传输(Control)

硬件加速

内置DMA控制器,支持高速数据传输,降低CPU占用

电源管理

支持VBUS检测(Host模式)、软/硬件电源控制

协议兼容

USB 2.0规范,支持CDC(虚拟串口)、MSC(大容量存储,U盘)、HID(人机交互)、自定义类

典型应用

虚拟串口(CDC)、USB U盘(MSC)、USB转CAN、自定义HID设备、USB数据采集

USB 核心信号

信号名称

功能

典型引脚(STM32H743)

备注

USB_DP

差分数据+线

PA12(OTG_HS/FS)

全速/高速模式必备,低速模式D+接1.5kΩ上拉

USB_DM

差分数据-线

PA11(OTG_HS/FS)

所有模式必备

USB_VBUS

总线电压检测

PA9(OTG_HS)

Host模式下检测外设是否接入,Device模式下检测供电

USB_ID

OTG模式识别

PA10(OTG_HS)

区分Host/Device模式(接地=Host,悬空=Device)

关键:

  1. Device模式:D+需接1.5kΩ上拉电阻(全速/高速),D-接1.5kΩ上拉(低速);
  2. Host模式:需外接5V电源给USB外设供电(如U盘),并检测VBUS电平;
  3. STM32H743的USB_OTG_HS默认使用内部PHY,无需外接USB PHY芯片(简化硬件)。

二、USB 工作原理

USB通信的核心是“主机(Host)发起请求,设备(Device)响应”,STM32可作为Host或Device,核心概念和流程如下:

1. 核心概念

  • 端点(Endpoint):USB设备的通信端口,每个端点对应一种传输类型:
    • 控制端点(Endpoint 0):所有设备必备,用于设备枚举、配置;
    • 批量端点(Bulk):用于大量数据传输(如U盘、虚拟串口),容错重传;
    • 中断端点(Interrupt):用于小数据高频传输(如HID键盘、鼠标);
    • 同步端点(Isochronous):用于实时数据传输(如音频、视频),不重传。
  • 枚举(Enumeration):Device接入Host后,Host通过控制端点获取设备信息(厂商ID、产品ID、设备类),并分配地址的过程。
  • USB类(Class):标准化的设备类型,无需自定义驱动:
    • CDC(通信设备类):虚拟串口,PC端识别为COM口;
    • MSC(大容量存储类):U盘,PC端识别为可移动磁盘;
    • HID(人机交互类):键盘、鼠标,免驱;
    • 自定义类:需编写专用驱动(新手不推荐)。

2. 典型工作流程

(1)Device模式(以CDC虚拟串口为例)
  1. 初始化:配置USB引脚、时钟、端点,注册CDC类回调函数;
  2. 枚举:PC检测到USB设备,通过Endpoint 0获取设备信息,安装驱动;
  3. 数据传输:
    • PC→STM32:Host通过批量IN端点发送数据,STM32中断接收;
    • STM32→PC:STM32通过批量OUT端点发送数据,PC端COM口接收。
(2)Host模式(以读写U盘为例)
  1. 初始化:配置USB Host,启用VBUS检测,初始化USB库(如FatFs);
  2. 设备接入:检测到U盘接入后,枚举U盘,获取设备信息;
  3. 数据传输:通过批量端点读写U盘扇区,结合FatFs实现文件级操作。

三、STM32H743 USB 配置步骤(HAL库+CubeMX)

推荐从Device模式-CDC虚拟串口入手(最简单,免驱),CubeMX配置步骤如下:

步骤1:硬件准备

  • 核心板:STM32H743(引出PA11/PA12/PA9/PA10);
  • USB线:Micro-USB/Type-C线(连接STM32和PC);
  • 硬件接线:
    • PA11(DM)、PA12(DP)接USB座子的DM/DP;
    • PA12接1.5kΩ上拉电阻到3.3V(Device模式必备);
    • VBUS(PA9)可选接分压电阻检测5V供电。

步骤2:CubeMX 配置

  • 配置系统时钟
    • H743主频设为280MHz,USB时钟源设为PLL3Q(480MHz,需精准);
    • 确保USB_OTG_HS时钟=480MHz(高速模式)或48MHz(全速模式);
  • 开启USB_OTG_HS外设
    • 进入“Connectivity → USB_OTG_HS”:
      • Mode:Device Only(仅设备模式,新手推荐);
      • PHY Selection:Internal PHY(内部PHY,无需外接);
      • VBUS Detection:Disabled(新手先禁用,简化配置);
      • Tick the FS Only Mode(可选,仅全速模式,降低复杂度);
  • 配置USB设备类
    • 进入“Middleware → USB_DEVICE”:
      • Class For FS IP:Communication Device Class (CDC)(虚拟串口);
      • 其他默认(无需修改);
  • 配置GPIO
    • PA11/PA12自动配置为USB_OTG_HS_DM/DP(Alternate Function模式);
    • PA5配置为LED(推挽输出,用于指示状态);
  • 生成代码:选择HAL库,生成MDK/STM32CubeIDE工程。

步骤3:HAL库核心API

函数

功能

MX_USB_DEVICE_Init()

初始化USB Device(CubeMX自动生成)

CDC_Transmit_FS()

CDC模式发送数据到PC(核心函数)

CDC_Receive_FS()

CDC模式接收PC发送的数据(需注册回调)

HAL_PCD_IRQHandler()

USB Device中断服务函数

HAL_PCD_DataOutStageCallback()

数据发送完成回调函数

HAL_PCD_DataInStageCallback()

数据接收完成回调函数

CDC模式关键宏定义:

#define CDC_TX_BUF_SIZE 512 // 发送缓冲区大小
#define CDC_RX_BUF_SIZE 512 // 接收缓冲区大小
extern uint8_t UserRxBufferFS[CDC_RX_BUF_SIZE]; // 接收缓冲区

四、实战代码示例

示例1:CDC虚拟串口(Device模式)

实现STM32作为USB虚拟串口,与PC双向通信(PC端识别为COM口):

1. 核心代码(main.c)
#include "stm32h7xx_hal.h"
#include "usbd_cdc.h"
#include "usbd_core.h"
#include <stdio.h>
#include <string.h>

/* USB Device句柄(CubeMX自动生成) */
USBD_HandleTypeDef hUsbDeviceFS;

/* LED引脚定义(PA5) */
#define LED_PIN GPIO_PIN_5
#define LED_PORT GPIOA

/* 接收缓冲区(CubeMX生成在usbd_cdc_if.c中) */
extern uint8_t UserRxBufferFS[CDC_RX_BUF_SIZE];
extern uint32_t UserRxLengthFS;

/* 错误处理函数 */
void Error_Handler(void)
{
  while(1)
  {
    HAL_GPIO_TogglePin(LED_PORT, LED_PIN); // LED快闪表示错误
    HAL_Delay(200);
  }
}

/**
 * @brief  重定向printf到USB虚拟串口
 */
int fputc(int ch, FILE *f)
{
  uint8_t temp[1] = {ch};
  CDC_Transmit_FS(temp, 1);
  return ch;
}

/**
 * @brief  CDC接收回调函数(usbd_cdc_if.c中重定义)
 * 当PC发送数据到虚拟串口时,触发此函数
 */
void CDC_ReceiveCallback(uint8_t *Buf, uint32_t Len)
{
  // 1. 点亮LED表示接收到数据
  HAL_GPIO_SetPin(LED_PORT, LED_PIN);
  
  // 2. 回显接收到的数据到PC
  CDC_Transmit_FS(Buf, Len);
  
  // 3. 打印调试信息(通过虚拟串口输出)
  printf("Received Data: ");
  for(uint32_t i=0; i<Len; i++)
  {
    printf("%02X ", Buf[i]);
  }
  printf("\r\n");
  
  // 4. 延时后熄灭LED
  HAL_Delay(500);
  HAL_GPIO_ResetPin(LED_PORT, LED_PIN);
  
  // 5. 重新启用接收(必须!否则无法接收下一次数据)
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
}

int main(void)
{
  /* 初始化HAL库、系统时钟、GPIO、USB Device */
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();    // 初始化LED引脚
  MX_USB_DEVICE_Init(); // 初始化USB CDC设备
  
  // 初始化LED为熄灭状态
  HAL_GPIO_ResetPin(LED_PORT, LED_PIN);
  
  printf("STM32H743 USB CDC Virtual COM Port Test\r\n");
  printf("Send Data from PC to COM Port to Test...\r\n");
  
  while (1)
  {
    // 每隔1秒发送测试数据到PC
    printf("Hello USB CDC! Time: %lu ms\r\n", HAL_GetTick());
    HAL_Delay(1000);
  }
}
2. 回调函数修改(usbd_cdc_if.c)
// 找到USBD_CDC_Receive_FS函数,修改为:
static int8_t USBD_CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  UserRxLengthFS = *Len;
  memcpy(UserRxBufferFS, Buf, UserRxLengthFS);
  // 调用自定义接收回调
  CDC_ReceiveCallback(UserRxBufferFS, UserRxLengthFS);
  // 重新启用接收
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  return (USBD_OK);
}

// 声明回调函数(头文件中添加)
void CDC_ReceiveCallback(uint8_t *Buf, uint32_t Len);
3. 测试步骤
  1. 编译下载代码到STM32H743;
  2. 用USB线连接STM32和PC,PC自动识别为“USB Serial Device”(COM口);
  3. 打开串口助手(如SecureCRT、串口调试助手),选择对应的COM口,波特率任意(CDC无需波特率匹配);
  4. 发送数据,STM32回显数据并点亮LED,同时STM32每隔1秒发送“Hello USB CDC!”到PC。

示例2:MSC大容量存储(U盘模式)

实现STM32模拟U盘,PC可读写STM32内部Flash/外部SD卡(此处以内部RAM模拟U盘为例):

1. CubeMX配置修改
  • Middleware → USB_DEVICE → Class For FS IP:Mass Storage Class (MSC);
  • 配置MSC参数:Storage Size=1MB(RAM模拟),LUN(逻辑单元)=1;
2. 核心代码(main.c)
#include "stm32h7xx_hal.h"
#include "usbd_msc.h"
#include "usbd_core.h"

USBD_HandleTypeDef hUsbDeviceFS;

// 模拟U盘的RAM缓冲区(1MB)
uint8_t MSC_Buffer[1024*1024] __attribute__((aligned(4)));

// MSC设备描述符(CubeMX自动生成,需修改容量)
extern USBD_StorageTypeDef USBD_MSC_FS_fops;

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USB_DEVICE_Init();
  
  // 初始化模拟U盘缓冲区(填充测试数据)
  memset(MSC_Buffer, 0xAA, sizeof(MSC_Buffer));
  
  printf("STM32H743 USB MSC U Disk Test\r\n");
  printf("Connect to PC, U Disk Size: 1MB\r\n");
  
  while (1)
  {
    // MSC模式无需主循环操作,硬件自动处理读写
    HAL_Delay(1000);
  }
}
3. 测试效果
  • PC识别到“可移动磁盘”(1MB),可新建文件、写入数据;
  • 数据实际存储在STM32的RAM中(掉电丢失),如需持久化可改为外部Flash/SD卡。

示例3:USB Host模式(读写U盘)

实现STM32作为USB主机,读写外接U盘(需结合FatFs文件系统):

1. CubeMX配置
  • USB_OTG_HS Mode:Host Only;
  • Middleware → USB_HOST → Class Support:MSC Class;
  • 启用FatFs文件系统,绑定USB Host;
2. 核心代码(main.c)
#include "stm32h7xx_hal.h"
#include "usb_host.h"
#include "ff.h"
#include "stdio.h"

FATFS fs; // 文件系统对象
FIL file; // 文件对象
char buffer[512]; // 读写缓冲区

/* USB Host状态回调 */
void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id)
{
  switch(id)
  {
    case HOST_USER_SELECT_CONFIGURATION:
      break;
    case HOST_USER_DISCONNECTION:
      f_mount(NULL, "", 0); // 卸载文件系统
      printf("USB Disk Disconnected!\r\n");
      break;
    case HOST_USER_CLASS_ACTIVE:
      // U盘接入,挂载文件系统
      if(f_mount(&fs, "", 0) == FR_OK)
      {
        printf("USB Disk Mounted!\r\n");
        // 新建并写入文件
        if(f_open(&file, "test.txt", FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
        {
          f_write(&file, "Hello USB Host!", 14, NULL);
          f_close(&file);
          printf("Write to test.txt Success!\r\n");
          
          // 读取文件
          if(f_open(&file, "test.txt", FA_READ) == FR_OK)
          {
            f_read(&file, buffer, 512, NULL);
            printf("Read from test.txt: %s\r\n", buffer);
            f_close(&file);
          }
        }
      }
      break;
    default:
      break;
  }
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USB_HOST_Init(); // 初始化USB Host
  
  printf("STM32H743 USB Host Test\r\n");
  printf("Insert USB Disk to Test...\r\n");
  
  while (1)
  {
    // USB Host主循环(必须调用)
    USBH_Process(&hUsbHostHS);
    HAL_Delay(10);
  }
}

五、常见问题与避坑指南

1. USB Device枚举失败(PC识别不到设备)

  • 原因1:时钟配置错误
    USB时钟不是精准的48MHz(全速)/480MHz(高速),H743需配置PLL3Q=480MHz;
    → 解决:CubeMX中“Clock Configuration”确保USB时钟=480MHz(HS)或48MHz(FS);
  • 原因2:上拉电阻缺失
    Device模式下D+未接1.5kΩ上拉电阻,PC无法检测到设备;
    → 解决:PA12接1.5kΩ上拉到3.3V(全速/高速);
  • 原因3:引脚配置错误
    PA11/PA12未设为USB_OTG_HS_DM/DP模式,或被其他外设占用;
    → 解决:核对引脚模式为Alternate Function 10(USB_OTG_HS);
  • 原因4:USB库初始化顺序错误
    先初始化GPIO,再初始化USB Device,否则引脚未配置导致枚举失败;
    → 解决:按“时钟→GPIO→USB”顺序初始化。

2. CDC虚拟串口能发不能收/能收不能发

  • 原因1:未重新启用接收
    接收回调函数中未调用USBD_CDC_ReceivePacket(&hUsbDeviceFS),导致仅能接收一次数据;
    → 解决:每次接收完成后必须重新启用接收;
  • 原因2:缓冲区溢出
    接收缓冲区过小(如64字节),PC发送大数据时溢出;
    → 解决:增大缓冲区(如512/1024字节);
  • 原因3:发送函数阻塞
    CDC_Transmit_FS()返回忙(USBD_BUSY),未等待发送完成就再次发送;
    → 解决:添加发送状态检查:
while(CDC_Transmit_FS(buf, len) == USBD_BUSY);

3. USB Host无法识别U盘

  • 原因1:VBUS供电不足
    Host模式下未给U盘提供5V供电,或供电电流不足(U盘需≥100mA);
    → 解决:外接5V/1A电源给USB接口供电,避免STM32 3.3V引脚直接供电;
  • 原因2:未调用USBH_Process()
    主循环中未执行USBH_Process(&hUsbHostHS),USB Host无法处理枚举流程;
    → 解决:主循环中高频调用此函数(间隔≤10ms);
  • 原因3:U盘格式不支持
    U盘格式为NTFS/exFAT,FatFs默认仅支持FAT32;
    → 解决:将U盘格式化为FAT32,簇大小≤32KB。

4. 高速模式(480Mbps)传输卡顿

  • 原因1:未启用DMA
    USB传输使用CPU轮询,未启用DMA,导致高速传输时CPU占用率100%;
    → 解决:CubeMX中启用USB DMA(默认已启用);
  • 原因2:总线带宽不足
    同时进行多个USB传输(如CDC+MSC),导致带宽耗尽;
    → 解决:单模式测试(仅CDC或仅MSC),降低传输频率;
  • 原因3:缓存未对齐
    传输缓冲区未按32位对齐,DMA传输出错;
    → 解决:用__attribute__((aligned(4)))修饰缓冲区。

5. USB设备频繁断开重连

  • 原因1:电源纹波过大
    USB供电电源纹波>100mV,导致设备复位;
    → 解决:USB接口添加100uF电解电容+0.1uF陶瓷电容滤波;
  • 原因2:数据线过长/屏蔽差
    USB线超过2米,或无屏蔽,信号干扰导致断开;
    → 解决:使用≤1米的屏蔽USB线,靠近接口处接磁环;
  • 原因3:中断优先级冲突
    USB中断优先级低于其他高优先级中断(如SysTick),导致枚举超时;
    → 解决:将USB中断优先级设为最高(NVIC优先级0)。

六、调试顺序

1. 入门步骤

  • 第一步:CDC虚拟串口(Device模式),实现双向通信(最简单,免驱);
  • 第二步:MSC U盘模式(Device),模拟RAM/Flash为U盘;
  • 第三步:USB Host模式,读写外接U盘(结合FatFs);
  • 第四步:OTG双模切换,实现Device/Host动态切换;
  • 第五步:自定义HID设备(如USB按键、USB数据采集器)。

2. 调试技巧

  • USB分析仪调试
    用USB协议分析仪(如Beagle USB)抓取枚举/传输数据包,定位枚举失败原因;
  • 串口日志调试
    在USB初始化、枚举、传输等关键节点打印日志,定位问题环节;
  • 分步测试
  • 先测试全速模式(12Mbps),再切换到高速模式(480Mbps);
  • 先测试小数据传输(1字节),再测试大数据(512字节);
  • 硬件排查
    用万用表测D+/DM电压(Device模式:D+≈3.3V,DM≈0V),VBUS电压(Host模式≈5V)。

3. 重点注意事项

  • 时钟精准性:USB时钟必须是48MHz/480MHz精准值(误差≤0.25%),否则枚举失败;
  • 电源设计:Host模式下USB外设供电必须稳定,避免电流不足导致U盘断开;
  • 回调函数:USB依赖回调函数处理事件,必须正确实现(如CDC接收回调、Host插拔回调);
  • 兼容性:不同U盘/PC的USB兼容性不同,测试时优先用知名品牌U盘(如金士顿)。

4. 实际应用练习

  • 数据采集:通过CDC虚拟串口将传感器数据(温湿度、ADC)实时上传到PC;
  • 固件升级:通过USB MSC模式,将bin文件写入STM32 Flash,实现USB升级;
  • USB转串口:STM32作为USB Host,连接USB转串口模块,实现多串口扩展;
  • 自定义HID设备:实现USB游戏手柄、USB数据记录仪,免驱接入PC。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐