STM32 хост USB CDC и чипы FTDI |
Добавил(а) microsin |
Недавно понадобилось запустить хост USB для виртуального последовательного порта (класс USB CDC) на плате STM32F429I-DISC1 (процессор STM32F429ZITx). И неожиданно столкнулся с проблемой взаимодействия с чипами FTDI. Начал, как обычно, с создания шаблона проекта с помощью STM32CubeMX (STM32F429-USB-CDC-host.ioc [8]). После традиционных правок и исправления ошибок хост USB CDC наконец заработал, но категорически отказывался опознавать чипы FTDI. С другими чипами USB CDC, которые создавали стандартный класс, проблем не было. Оказалось, что чипы FTDI работают с хостом через свой драйвер, исходный код для которого компания FTDI не предоставляет, и его протокол официально не опубликован. Есть только двоичные библиотеки и описание API, которое позволяет работать с устройствами CDC FTDI на хосте PC (Windows, Linux или других платформ). Преобразователь USB-CAN CANable AZSMZ-USB2CAN [3]: UP: HOST_USER_CONNECTION USB Device Attached PID: 60c4h VID: ad50h Address (#1) assigned. Manufacturer : Protofusion Labs Product : CANable 1205aa6 https://github.com/normaldotcom/cantact-fw Serial Number : 0029001F4E4E430820353036 Enumeration done. This device has only 1 configuration. Default configuration set. Switching to Interface (#0) Class : 2h SubClass : 2h Protocol : 1h CDC class started. UP: HOST_USER_CLASS_SELECTED UP: HOST_USER_CLASS_ACTIVE Адаптер USB - TTL UART на FT232RL (CN480661), купленный на AliExpress: UP: HOST_USER_CONNECTION USB Device Attached PID: 7523h VID: 1a86h Address (#1) assigned. Manufacturer : N/A Product : USB2.0-Ser! Serial Number : N/A Enumeration done. This device has only 1 configuration. Default configuration set. No registered class for this device. UP: HOST_USER_DISCONNECTION USB Device disconnected UP: HOST_USER_CONNECTION USB Device Attached PID: 6001h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : FT232R USB UART Serial Number : A50285BI Enumeration done. This device has only 1 configuration. Default configuration set. Device remote wakeup enabled No registered class for this device. Адаптер USB - TTL UART на фирменном чипе FT232RL [4]: UP: HOST_USER_CONNECTION USB Device Attached PID: 6001h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : FT232R USB UART Serial Number : A50285BI Enumeration done. This device has only 1 configuration. Default configuration set. Device remote wakeup enabled No registered class for this device. UP: HOST_USER_DISCONNECTION USB Device disconnected UP: HOST_USER_CONNECTION USB Device Attached PID: 6001h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : FT232R USB UART Serial Number : A7006Wml Enumeration done. This device has only 1 configuration. Default configuration set. Device remote wakeup enabled No registered class for this device. Плата на чипе FT2232D [5]: UP: HOST_USER_CONNECTION USB Device Attached PID: 6010h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : Dual RS232 Serial Number : N/A Enumeration done. This device has only 1 configuration. Default configuration set. No registered class for this device. Плата на основе чипа FT2232H [6]: HOST_USER_CONNECTION USB Device Attached PID: 6010h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : Dual RS232-HS Serial Number : N/A Enumeration done. This device has only 1 configuration. Default configuration set. No registered class for this device. Плата на основе чипа FT4232H [6]: UP: HOST_USER_CONNECTION USB Device Attached PID: 6011h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : Quad RS232-HS Serial Number : N/A Enumeration done. This device has only 1 configuration. Default configuration set. No registered class for this device. Решить проблему помог проект HOST_CP_FTDI, который нашел на форуме [1]. Усиленное гугление в поиске других источников позволило найти исходный код драйвера FTDI для Linux ftdi_sio.c [2]. Автор проекта HOST_CP_FTDI [1] брал куски кода из этого драйвера. На основе источников [1, 2] создал рабочий проект на FreeRTOS, который нормально может работать с чипами FTDI. Хост обрабатывает события подключения и отключения устройств, и осуществляет обмен с ними через последовательную консоль на USART1. Все, что передается из устройства к хосту, выводится в эту консоль. Обратно данные можно передавать командой консоли tx. Исходный код проекта для IAR 8.30 можно скачать по ссылке [8]. Адаптер USB - TTL UART на фирменном чипе FT232RL [4]: UP: HOST_USER_CONNECTION USB Device Attached PID: 6001h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : FT232R USB UART Serial Number : A7006V62 Enumeration done. This device has only 1 configuration. Default configuration set. Device remote wakeup enabled Switching to Interface (#0) Class : ffh SubClass : ffh Protocol : ffh CDC class started. UP: HOST_USER_CLASS_SELECTED UP: HOST_USER_CLASS_ACTIVE Плата на чипе FT2232D [5]: UP: HOST_USER_CONNECTION USB Device Attached PID: 6010h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : Dual RS232 Serial Number : N/A Enumeration done. This device has only 1 configuration. Default configuration set. Switching to Interface (#0) Class : ffh SubClass : ffh Protocol : ffh CDC class started. UP: HOST_USER_CLASS_SELECTED UP: HOST_USER_CLASS_ACTIVE Плата на основе чипа FT2232H [6]: UP: HOST_USER_CONNECTION USB Device Attached PID: 6010h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : Dual RS232-HS Serial Number : N/A Enumeration done. This device has only 1 configuration. Default configuration set. Switching to Interface (#0) Class : ffh SubClass : ffh Protocol : ffh CDC class started. UP: HOST_USER_CLASS_SELECTED UP: HOST_USER_CLASS_ACTIVE Плата на основе чипа FT4232H [6]: UP: HOST_USER_CONNECTION USB Device Attached PID: 6011h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : Quad RS232-HS Serial Number : N/A Enumeration done. This device has only 1 configuration. Default configuration set. Switching to Interface (#0) Class : ffh SubClass : ffh Protocol : ffh CDC class started. UP: HOST_USER_CLASS_SELECTED UP: HOST_USER_CLASS_ACTIVE Чип FT231X: UP: HOST_USER_CONNECTION USB Device Attached PID: 6015h VID: 403h Address (#1) assigned. Manufacturer : FTDI Product : FT231X USB UART Serial Number : N/A Enumeration done. This device has only 1 configuration. Default configuration set. Device remote wakeup enabled Switching to Interface (#0) Class : ffh SubClass : ffh Protocol : ffh CDC class started. UP: HOST_USER_CLASS_SELECTED UP: HOST_USER_CLASS_ACTIVE Добавление поддержки хоста CDC под управлением FreeRTOS на примере платы STM32F407G-DISC1, процесс по шагам: 1. Добавьте в один из потоков, перед входом в его бесконечный цикл, вызов MX_USB_HOST_Init(). Для этого добавьте в проект файлы: usb_host.c Также добавьте в пути поиска папки: $PROJ_DIR$/../Middlewares/ST/STM32_USB_Host_Library/Core/Inc 2. Создайте в проекте новую группу (папку) USB_Host_Library, и добавьте в неё следующие файлы. Находится в каталоге Middlewares\ST\STM32_USB_Host_Library\Class\CDC\Src\: usbh_cdc.c Эти файлы находятся в каталоге Middlewares\ST\STM32_USB_Host_Library\Core\Src\: usbh_core.c 3. Добавьте в папку Drivers\STM32F4xx_HAL_Driver проекта модули: stm32f4xx_hal_hcd.c В файле конфигурации HAL (stm32f4xx_hal_conf.h) раскомментируйте определение: #define HAL_HCD_MODULE_ENABLED
4. Проверьте конфигурацию ножек USB в файле usbh_conf.c, они должны соответствовать портам микроконтроллера, подключенным к коннектору microUSB CN5 платы STM32F4DISCOVERY: // USB_OTG_FS_VBUS, ножка входа GPIO, определяющая наличие
// напряжения +5V VBUS на коннекторе CN5 microUSB:
#define VBUS_FS_Pin GPIO_PIN_9
#define VBUS_FS_GPIO_Port GPIOA
// USB_OTG_FS_ID, аппаратный вход идентификации USB OTG.
// Роль хоста определяется по лог. 0 на этом входе:
#define OTG_FS_ID_Pin GPIO_PIN_10
#define OTG_FS_ID_Port GPIOA
// Ножки сигналов D- и D+ USB:
#define OTG_FS_DM_Pin GPIO_PIN_11 // USB_OTG_FS_DM #define OTG_FS_DM_Port GPIOA
#define OTG_FS_DP_Pin GPIO_PIN_12 // USB_OTG_FS_DP #define OTG_FS_DP_Port GPIOA
// Ножка активации ключа U6 STMPS2141STR (активный уровень 0),
// который подает на VBUS напряжение питания +5V:
#define OTG_FS_PowerSwitchOn_Pin GPIO_PIN_0
#define OTG_FS_PowerSwitchOn_GPIO_Port GPIOC
5. Добавьте в MX_GPIO_Init настройку ножки порта OTG_FS_PowerSwitchOn_Pin в режиме выхода, с лог. 1 на выходе по умолчанию: HAL_GPIO_WritePin(OTG_FS_PowerSwitchOn_GPIO_Port, OTG_FS_PowerSwitchOn_Pin, GPIO_PIN_SET); GPIO_InitStruct.Pin = OTG_FS_PowerSwitchOn_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(OTG_FS_PowerSwitchOn_GPIO_Port, &GPIO_InitStruct); 6. В файл stm32f4xx_it.c добавьте обработчики прерывания OTG_FS_IRQHandler: extern HCD_HandleTypeDef hhcd_USB_OTG_FS;
void OTG_FS_IRQHandler(void) { HAL_HCD_IRQHandler(&hhcd_USB_OTG_FS); } При необходимости настройте приоритет прерывания для OTG_FS_IRQn. Это может быть важным, когда у Вас в системе используются другие прерывания, и необходимо соблюсти нужные приоритеты. В частности, такую настройку необходимо обязательно выполнить для FreeRTOS, потому что иначе будет срабатывать configASSERT в функции проверки правильности установки приоритетов vPortValidateInterruptPriority. Приоритет прерывания OTG_FS_IRQn настраивается в функции HAL_HCD_MspInit, по умолчанию настраивается уровень приоритета 0, т. е. самый высокий приоритет для STM32: HAL_NVIC_SetPriority(OTG_FS_IRQn, 0, 0); HAL_NVIC_EnableIRQ(OTG_FS_IRQn); Для FreeRTOS это работать не будет. Поменяйте уровень приоритета в вызове HAL_NVIC_SetPriority на более низкий: HAL_NVIC_SetPriority(OTG_FS_IRQn, 9, 0); 7. Отредактируйте опции в файле usbh_conf.h. Разрешить вывод отладочных сообщений можно редактированием макроса USBH_DEBUG_LEVEL. По умолчанию он определен как 0, что означает отсутствие отладочного вывода хоста USB. Если определить USBH_DEBUG_LEVEL как 3, то будет вывод в консоль терминала IAR (для этого необходимо скомпилировать проект с поддержкой семихостинга, см. [7]): //#define USBH_DEBUG_LEVEL 0U
#define USBH_DEBUG_LEVEL 3U
Если у Вас используется FreeRTOS, то поменяйте макрос USBH_USE_OS на 1: //#define USBH_USE_OS 0U
#define USBH_USE_OS 1U
8. Определитесь с классами устройств USB CDC (Virtual COM Port, VCP), с которыми будет работать Ваш хост. К примеру, стандартное устройство VCP использует код класса 0x02, а устройство VCP компании FTDI использует код класса, определяемого вендором 0xFF. При подключении устройства USB CDC на финальной стадии (usbh_core.c -> USBH_Process -> метка HOST_CHECK_CLASS) проверяется соответствие кода зарегистрированного класса коду класса интерфейса. Если эти коды совпадают, то хост активируется и готов работать с устройством USB CDC. Код зарегистрированного класса USB CDC определяется в момент вызова MX_USB_HOST_Init -> USBH_RegisterClass. В функцию USBH_RegisterClass вторым параметром передается код класса через структуру USBH_ClassTypeDef (код регистрируемого класса находится в поле ClassCode). Если необходимо работать только с устройствами FTDI, то в ClassCode должно находиться значение 0xFF, если со стандартными устройствами USB CDC, то в ClassCode должно находиться 0x02. Таким образом, нужно определить структуру USBH_ClassTypeDef для регистрируемого класса USB CDC/VCP. В ней нужно заполнить поле ClassCode, и поле указателя на функцию инициализации класса Init, остальные поля могут быть заполнены одинаково. Указатель на экземпляр этой структуры нужно будет передать в функцию USBH_RegisterClass. Примеры определения структуры показаны ниже: // Структура для стандартного класса устройств USB CDC: USBH_ClassTypeDef CDC_Class_Standard = { "CDC Standard", USB_CDC_CLASS, // ClassCode = 0x02 USBH_CDC_InterfaceInit, // (*Init)(struct _USBH_HandleTypeDef *phost); USBH_CDC_InterfaceDeInit, USBH_CDC_ClassRequest, USBH_CDC_Process, USBH_CDC_SOFProcess, NULL, }; // Структура для класса устройств USB CDC компании FTDI: USBH_ClassTypeDef CDC_Class_Ftdi = { "CDC FTDI", VENDOR_SPECIFIC, // ClassCode = 0xFF USBH_CDC_FTDI_InterfaceInit, // (*Init)(struct _USBH_HandleTypeDef *phost); USBH_CDC_InterfaceDeInit, USBH_CDC_ClassRequest, USBH_CDC_Process, USBH_CDC_SOFProcess, NULL, }; 9. В файле usbh_conf.h измените настройки, соответствующие FreeRTOS: //#define USBH_USE_OS 0U
#define USBH_USE_OS 1U
//#define USBH_PROCESS_STACK_SIZE ((uint16_t)0)
#define USBH_PROCESS_STACK_SIZE ((uint16_t)512)
10. Передача. Чтобы передать данные от хоста в инициализированное устройство USB CDC, необходимо вызвать функцию USBH_CDC_Transmit, например: USBH_CDC_Transmit(&hUsbHostHS, (uint8_t*)txbuffer, strlen(txbuffer)); В качестве параметров в эту функцию передается указатель на дескриптор хоста, указатель на буфер передачи и количество передаваемых данных. Буфер с данными должен быть статическим. По завершению передачи будет вызвана функция USBH_CDC_TransmitCallback, где можно выполнить необходимые действия для подготовки будущей передачи. 11. Прием. Чтобы хосту принять данные от инициализированного устройства USB CDC, необходимо вызвать функцию USBH_CDC_Receive, например: USBH_CDC_Receive(phost, CDC_RX_Buffer, sizeof(CDC_RX_Buffer));
В качестве параметров в эту функцию передается указатель на дескриптор хоста, указатель на буфер приема и количество принимаемых данных. По завершению передачи будет вызвана функция USBH_CDC_ReceiveCallback, где можно обработать принятые данные, и для продолжения приема нужно снова вызвать USBH_CDC_Receive. Примеры хоста для процессоров STM32F407 и STM32F429 можно скачать по ссылке [8]. [Ссылки] 1. STM32F4 usb cdc host + cp210x site:forum.easyelectronics.ru. |