STM32 USB VCP ошибка

8

Последние две недели я работаю над проектом, и отладка этого вопроса заняла всю эту неделю. Хотите знать, если кто-нибудь может помочь, я постараюсь быть максимально четким и ясным.

Я пытаюсь реализовать виртуальный порт USB на микроконтроллере на базе STM32F302K8 (Cortex M4). Я использовал STM32CubMX для генерации кода, необходимого для настройки устройства USB Full Speed, реализующего класс CDC. Мое устройство отображается как в Windows (диспетчер устройств), так и в Linux. Я могу реализовать простую функцию эха на основе примера кода, но когда я сейчас пытаюсь использовать функцию USBD_CDC_SetTxBuffer для отправки данных на ПК, это отключает Hard Fault Handler. Я сузил это до того факта, что поле UsbDeviceFS.pClass (которое требуется USBD_CDC_SetTxBuffer) никогда не инициализируется, потому что USBD_CDC_Init () никогда не вызывается при инициализации USB-устройства.

Я внес исправления в несколько ошибок (включая изменение размера кучи, исправление флага передачи в USBD_CDC_TransmitPacket и изменение размера CDC_DATA_HS_MAX_PACKET_SIZE на 256 из 512) в примере кода, как описано на форуме ST, но все еще получаю ту же ошибку.

Код настройки моего устройства

* 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);

}
галактика
источник
Прошло много времени с тех пор, как я последний раз работал с USB на STM, но я думаю, что USBD_CDC_Init () пытается выполнить malloc. Проблема заключалась в том, что в настройках по умолчанию недостаточно места в куче, и вам нужно его увеличить.
brhans
Привет! Я увеличил размер кучи до 0x600 и ничего не происходит. Какая функция вызывает malloc, потому что когда я ставлю на нее точку останова, оказывается, она никогда не вызывается.
Galaxy

Ответы:

6

Чтобы ответить на мой собственный вопрос, проблема в том, что мой код не дождался завершения инициализации USB и сразу начал отправлять данные. Вставка активного ожидания в логическое значение или добавление задержки (как указано @ramez) решает проблему.

ОБНОВЛЕНИЕ Эта ошибка была исправлена ​​в последующих версиях драйвера USB CDC от ST. Теперь в настройках есть HAL_Delay. Предостережение заключается в том, что если по какой-либо причине Sys_Tick не работает / деактивирован / еще не инициализирован, ваш код зависнет.

галактика
источник
1
Да, вы должны опубликовать это как отдельный вопрос. Оставьте в этом ответе только информацию, относящуюся к исходному вопросу.
м.Алин
2

Я использовал 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 в код. После этой коррекции я мог отправить данные с микроконтроллера на ПК с этой функцией передачи. Например:

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 () у меня такая же, как и у вас.

tenkmilan
источник
1
Спасибо, Рамез. Я обнаружил проблему, я должен был проверить, завершил ли инициализацию виртуальный коммуникационный порт, я использовал логическое значение в CDC_Init_FS, которое основной цикл ожидал, чтобы быть истинным, прежде чем вызывать CDC_Transmit_FS. Я думаю, что HAL_DELAY в вашем коде достигает того же эффекта. Спасибо вам за помощь.
Galaxy
1

Во-первых, проверьте, является ли hUsbDevice_0 нулевым (отсутствует элемент в вашем решении):

    if (hUsbDevice_0 == NULL)
            return USBD_FAIL;

Это предотвратит зависание вашего ОК и не потребует много времени на ожидание.

Вы можете разместить его где-нибудь в 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;
}
jemdream
источник
0

У меня была та же проблема, но оказалось, что единственное, что мне нужно сделать, это снова подключить USB-соединение к компьютеру. В большинстве случаев вы прошиваете код и перезагружаете микроконтроллер, но на стороне ПК перечисление не обновляется. USBD_CDC_Init вызывается, когда хост начинает проверять ваше устройство, и поэтому pClassData имеет значение NULL.

Юаньи Ву
источник
1
Вы также можете принудительно выполнить повторное перечисление в программном обеспечении. Второй самый глупый способ после повторного подключения - отключить / включить ваш порт в диспетчере устройств, если у вас нет собственного драйвера, который обрабатывает это более
изящным