STM32 USB VCP 错误

电器工程 USB stm32
2022-01-09 05:37:04

过去两周我一直在做一个项目,调试这个问题已经占用了整整一周。想知道是否有人可以提供帮助,我将尝试尽可能明确和清晰。

我正在尝试在基于 STM32F302K8 (Cortex M4) 的微控制器上实现 USB 虚拟通信端口。我使用 STM32CubMX 生成了设置实现 CDC 类的 USB 全速设备所需的代码。我的设备同时显示在 Windows(设备管理器)和 Linux 中。我可以根据示例代码实现一个简单的回显函数,但是当我现在尝试使用函数USBD_CDC_SetTxBuffer向 PC 发送数据时,这会触发硬故障处理程序。我已将范围缩小到 UsbDeviceFS.pClass(USBD_CDC_SetTxBuffer 需要)字段从未初始化的事实,因为USBD_CDC_Init () 在 USB 设备的初始化中从未被调用。

我已经在 ST 论坛上记录的示例代码中修复了几个错误(包括更改堆大小、修复USBD_CDC_TransmitPacket中的传输标志以及将 CDC_DATA_HS_MAX_PACKET_SIZE 的大小从 512 更改为 256),但仍然出现相同的错误。

我的设备设置代码是

* USB Device Core handle declaration */
USBD_HandleTypeDef hUsbDeviceFS;

/* init function */                    
void MX_USB_DEVICE_Init(void)
{
  /* Init Device Library,Add Supported Class and Start the library*/
  USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);

  USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC);

  USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS);

  USBD_Start(&hUsbDeviceFS);

}
4个回答

要回答我自己的问题,问题是我的代码没有等待 USB 完成初始化并立即开始发送数据。在布尔值上插入活动等待或添加延迟(如@ramez 指出的那样)可以解决问题。

更新此错误已在 ST 的后续 USB CDC 驱动程序版本中得到修复。设置中现在有一个 HAL_Delay。需要注意的是,如果由于任何原因 Sys_Tick 不起作用/被停用/尚未初始化,您的代码将挂起。

我使用 CubeMX 为 STM32F4 发现生成代码。我和你一样把它用作虚拟 COM 端口。我没有直接使用USBD_CDC_SetTxBuffer()函数。usbd_cdc_if.c文件中有一个名为CDC_Transmit_FS()的函数。生成的代码中有一个错误,该函数将缓冲区作为参数,但它什么也没做。修正后的功能代码如下:

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  memcpy(UserTxBufferFS, Buf, sizeof(char) * Len);
  USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, Len);   
  result = USBD_CDC_TransmitPacket(hUsbDevice_0);
  return result;
}

实际上我不得不将 memcpy 添加到代码中。校正后,我可以使用此传输功能将数据从微控制器发送到 PC。例如:

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_USB_DEVICE_Init();
  configureGPIOs();

  uint8_t Buf[] = "Test";

  HAL_Delay(1000);

  while (1)
  {
      CDC_Transmit_FS(Buf, 4);
      HAL_Delay(1000);
  }
}

MX_USB_DEVICE_Init()中的初始化对我来说和你的一样。

所以我最近与这个问题斗争了很长时间。

如果您的 STM32CubeIDE 生成的代码从一开始就无法正常工作,那么您真的需要考虑确保您的时钟设置正确。

请记住,USB FS 需要 48 MHz 时钟,对我来说它只在 PLL1 中工作。我用的是STM32H7。

首先,检查 hUsbDevice_0 是否为空(解决方案中缺少元素):

    if (hUsbDevice_0 == NULL)
            return USBD_FAIL;

这将防止挂起您的 uC,并且不需要忙于延迟等待。

您可以将其放置在 CDC_Transmit_FS 中的某个位置:

USBD_StatusTypeDef CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) {

    if (hUsbDevice_0 == NULL)
        return USBD_FAIL;

    USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) hUsbDevice_0->pClassData;

    if (hcdc->TxState != 0)
        return USBD_BUSY;

    uint8_t result = USBD_OK;

    USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len);
    result = USBD_CDC_TransmitPacket(hUsbDevice_0);

    return result;
}