RT-Thread论坛
直播中

王桂英

8年用户 1410经验值
私信 关注
[问答]

STM32F7使用USB获取设备描述符失败怎么解决?


  • 本帖最后由 hxcnz 于 2019-12-17 15:14 编辑 *
正点原子阿波罗STM32F767开发板,用正点原子官方例程测试过USB Device,读卡器和虚拟串口都没问题。想在RTT上使用USB,于是参考这篇文档(https://blog.csdn.net/newbie_Blogger/article/details/92617242)进行了移植,但尝试很多遍永远是“未知USB设备(设备描述符请求失败)”:
配置界面:

用的是2019.12.17克隆下来的RTT源码。程序能正常执行,LED在闪,就是USB无法识别
如果主函数中执行了“MX_USB_OTG_FS_PCD_Init()”函数的话,插USB就没反应了,大神们教下这个USB该怎么移植?


回帖(1)

张虎豹

2025-10-11 16:15:09

我们正在解决STM32F7在RTT(RT-Thread)上使用USB时出现的设备描述符请求失败问题。根据描述,开发板是正点原子阿波罗STM32F767,使用官方例程(读卡器和虚拟串口)正常,但在RTT上移植后出现“未知USB设备(设备描述符请求失败)”。

问题分析:
1. 当主函数执行`MX_USB_OTG_FS_PCD_Init()`时,插入USB没有反应。这可能是USB初始化不正确,或者USB时钟配置有问题。
2. 参考的移植文档可能遗漏了某些关键点。

解决步骤:
1. 确认USB的时钟配置:STM32F7的USB OTG FS需要48MHz时钟。通常,时钟源可以来自HSE通过PLL分频得到。需要检查时钟树配置,确保USB时钟正确。
2. 检查USB端口配置:确认DP(PA12)和DM(PA11)的引脚配置正确,包括复用功能和速度。
3. 检查中断配置:USB OTG FS需要中断服务函数,并且中断优先级配置合理,确保中断能够被触发。
4. 在RTT中,需要正确实现USB设备框架,并注册设备驱动。

根据提供的参考文档(CSDN博客),我们可能需要做以下工作:

- 在CubeMX中配置USB_OTG_FS为设备模式(Device Only),并生成初始化代码(包括时钟、引脚、中断等)。
- 将生成的USB相关代码(如`usb_otg.c`,`usbd_conf.c`等)整合到RTT工程中。
- 在RTT中实现USB设备类(如CDC、MSC等)的驱动,并注册。

但是,根据问题描述,执行`MX_USB_OTG_FS_PCD_Init()`后插入USB无反应,说明硬件初始化可能有问题,或者USB中断没有正确处理。

建议的解决方案:

步骤1:检查时钟配置
确保系统时钟配置正确,并且USB时钟为48MHz。可以通过以下方式检查:
   - 在`SystemClock_Config()`函数中,确认PLL配置。例如,HSE为25MHz,PLL配置为:
        PLL.PLLState = RCC_PLL_ON;
        PLL.PLLSource = RCC_PLLSOURCE_HSE;
        PLL.PLLM = 25;          // 分频后为1MHz(如果HSE是25MHz,则25/25=1)
        PLL.PLLN = 432;         // 1*432=432MHz
        PLL.PLLP = RCC_PLLP_DIV2; // 432/2=216MHz (系统时钟)
        PLL.PLLQ = 9;            // 432/9=48MHz (USB时钟)
   - 注意:不同开发板外部晶振可能不同,请根据实际情况调整。

步骤2:检查引脚配置
确保PA11和PA12被正确配置为USB_OTG_FS的DM和DP,并且没有其他功能冲突。

步骤3:检查中断
   - 确保USB OTG FS的中断使能,并且中断服务函数被正确实现和注册。在RTT中,通常使用`rt_hw_interrupt_install()`来注册中断。
   - 中断服务函数名称需要与启动文件中的向量表一致。对于STM32F7,USB OTG FS的中断服务函数名为`OTG_FS_IRQHandler`。

步骤4:在RTT中正确初始化和注册USB设备
   - 参考RTT的USB设备框架,需要实现一个USB设备驱动,并调用`rt_usb_device_init()`来初始化。
   - 对于CDC设备,还需要实现CDC类相关的操作,并注册为CDC设备。

步骤5:调试技巧
   - 使用逻辑分析仪或示波器检查USB数据线(DP/DM)是否有信号。如果插入USB时没有看到任何信号,可能是硬件初始化问题。
   - 在USB初始化函数中检查返回值,确保每一步都成功。
   - 在中断服务函数中添加调试信息,看是否进入中断。

由于问题中提到了执行`MX_USB_OTG_FS_PCD_Init()`后插入USB无反应,我们可以先集中检查硬件初始化部分。

这里提供一个可能的初始化代码框架(基于HAL库和RTT):

1. 在`drv_usb.c`中实现USB驱动,包括初始化和中断处理。
2. 在`board.h`中定义USB相关的时钟和引脚。

由于代码较长,我们只给出关键部分:

关键初始化代码(在board.c中的`SystemClock_Config`):
```c
void SystemClock_Config(void)
{
    // ... 其他时钟配置

    // 配置PLL,确保USB时钟为48MHz
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    // 根据实际外部晶振调整
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 25;
    RCC_OscInitStruct.PLL.PLLN = 432;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 9;

    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    // 时钟配置
    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_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
    {
        Error_Handler();
    }

    // 使能USB时钟
    __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
}
```

引脚配置(在board.c的`rt_hw_board_init`中调用):
```c
static void MX_GPIO_Init(void)
{
    __HAL_RCC_GPIOA_CLK_ENABLE();

    // 配置PA11和PA12为USB
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
```

USB初始化和中断配置:
```c
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_cdc.h"
#include "usbd_cdc_if.h"

// 外部变量
extern USBD_HandleTypeDef hUsbDeviceFS;

int usb_device_init(void)
{
    // 初始化GPIO和时钟(如果还没有初始化)
    MX_GPIO_Init();
    // 注意:时钟已经在SystemClock_Config中配置

    // 初始化USB设备库
    if (MX_USB_DEVICE_Init() != HAL_OK) // 这个函数由CubeMX生成,在usbd_conf.c中
    {
        return -1;
    }

    // 注册中断
    rt_hw_interrupt_install(OTG_FS_IRQn, (rt_isr_handler_t)OTG_FS_IRQHandler, RT_NULL, "usbfs");
    rt_hw_interrupt_umask(OTG_FS_IRQn);

    return 0;
}
INIT_APP_EXPORT(usb_device_init); // 自动初始化
```

注意:`MX_USB_DEVICE_Init`是CubeMX生成的函数,它调用了`HAL_PCD_Init`等函数进行初始化。

如果上述步骤都正确,但问题仍然存在,请检查:
   - 在`MX_USB_DEVICE_Init`中,是否正确地设置了USB设备描述符、配置描述符等。
   - 在中断服务函数中,是否调用了`HAL_PCD_IRQHandler`。

中断服务函数示例:
```c
void OTG_FS_IRQHandler(void)
{
    rt_interrupt_enter();
    HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); // hpcd_USB_OTG_FS是PCD句柄
    rt_interrupt_leave();
}
```

如果还是不行,建议在RTT论坛或社区寻求帮助,或者检查RTT的USB设备栈是否有针对STM32F7的更新。

最后,请确保在工程中正确包含了HAL库的USB驱动,并且没有编译错误。

由于问题描述有限,以上解决步骤可能需要根据实际工程进行调整。希望这些指导能帮助你解决问题。

针对STM32F7在RT-Thread中USB设备描述符请求失败的问题,以下是系统化的解决方案:


1. 检查时钟配置(关键步骤)



  • USB需要精确的48MHz时钟(由PLLQ提供)。在board.c中确认时钟配置:
    void SystemClock_Config(void) {
    // 确保PLL配置正确(以HSE=25MHz为例):
    RCC_OscInitStruct.PLL.PLLM = 25;     // HSE分频至1MHz
    RCC_OscInitStruct.PLL.PLLN = 432;    // 主PLL倍频至432MHz
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // 系统时钟216MHz
    RCC_OscInitStruct.PLL.PLLQ = 9;      // USB时钟=432/9=48MHz
    // 启用USB时钟
    __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
    }

  • 使用逻辑分析仪或printf输出时钟寄存器值(RCC->DCKCFGR2OTGFSSELOTGFSPS位)。


2. 引脚与GPIO配置


   static void MX_GPIO_Init(void) {
     // 配置USB FS的DM(PA11)/DP(PA12)
     GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
   }

3. 中断配置



  • stm32f7xx_hal_conf.h中启用USB全局中断:
     #define HAL_PCD_MODULE_ENABLED

  • 注册中断服务函数:
     rt_hw_interrupt_install(OTG_FS_IRQn, (rt_isr_handler_t)OTG_FS_IRQHandler, RT_NULL);
    rt_hw_interrupt_umask(OTG_FS_IRQn);


4. USB协议栈集成



  • 避免直接调用MX_USB_OTG_FS_PCD_Init(),改用RT-Thread的USB框架:
     #include 
    int usbd_init(void) {
         rt_usb_device_init(); // 核心初始化
         // 注册设备类(如CDC)
         rt_usb_cdc_init();
         return 0;
    }
    INIT_APP_EXPORT(usbd_init); // 自动初始化


5. 描述符配置



  • usbd_descriptor.c中检查设备描述符:
     const uint8_t DeviceDescriptor[18] = {
       0x12, 0x01, 0x00, 0x02, 0xEF, 0x02, 0x01, 0x40,
       0x48, 0x12, 0x34, 0x56, 0x78, 0x01, 0x01, 0x02,
       0x03, 0x01 // 确保bcdUSB=0x0200, bDeviceClass=0xEF
    };


6. 调试技巧



  • 信号检测:用示波器检查PA11(DM)/PA12(DP)在插入USB时是否有1.5KΩ上拉电压(DP线约3.3V)。

  • 软件追踪

    • 在USB中断中添加日志:rt_kprintf("USB IRQ: %dn", state);

    • 检查hpcd.Init结构体参数(速度模式、端点大小等)。


  • 最小化测试:仅保留USB初始化代码,屏蔽其他外设。


7. 参考已验证方案



  • 对比RT-Thread官方STM32F7 USB驱动的实现。

  • 使用USB协议分析仪捕获设备枚举过程的通信数据。



关键点总结:问题多由时钟配置错误或框架集成不当导致。优先确保48MHz时钟精确,并通过RT-Thread USB框架替代裸机初始化。若仍失败,请提供以下信息进一步分析:



  1. 完整的时钟树配置(SystemClock_Config()

  2. USB初始化代码片段(drv_usb.c

  3. 硬件连接图(重点检查USB-DP的上拉电阻)


举报

更多回帖

发帖
×
20
完善资料,
赚取积分