Чтобы подключиться к локальной сети обычно используют интерфейс Ethernet. Но не всегда удобно размещать его на своей плате. Интерфейс USB может дать больше возможностей и обходится гораздо дешевле. Здесь расскажу как к микроконтроллеру с USB подключить недорогой USB-Ethernet адаптер и получить выход в локальную сеть. Для примера использован полифункциональный зарядник.
Надо сказать, что выход в сеть и в интернет через USB для предыдущей версии нашего зарядника уже был продемонстрирован в этой статье. Но там требовался в качестве посредника компьютер, к которому подключался дивайс. В Azure RTOS для этого использовался класс USB device RNDIS.
Но вот хоста RNDIS в Azure RTOS нет, поскольку это проприетарный протокол, и скорее всего не будет. В свою очередь он нужен чтобы подключать мобильные телефоны и мобильные модемы. Отсутствие RNDIS хоста для подключения к мобильным гаджетам печально, но не критично. Мы выбираем host класс CDC-ECM и USB-Ethernet адаптеры.
Адаптеры USB-Ethernet строятся по одно-чиповой схеме. Такими чипами могут быть: ASIX AX88772A , ASIX AX88179, RTL8152, RTL8153, RTL8156... Эти чипсеты поддерживают классы устройств CDC-ECM с теми или иными особенностями. В Azure RTOS есть host классы для работы с CDC-ECM и ASIX.
Как видно по фотографии, дополнительным преимуществом USB-Ethernet адаптеров является некоторая гальвано-изоляция USB и Ethernet интерфейсов друг от друга с помощью трансформатора. Гальвано-изолированные домены соединяет лишь конденсатор ёмкостью 1000 пФ и максимальным напряжением 2 кВ.
Я приобрёл один из недорогих USB-Ethernet адаптеров NIC-mU2-01 на чипсете Realtek RTL8152B.
При подключении к компьютеру выяснилось, что адаптер имеет две конфигурации в дескрипторе USB дивайса. И первая конфигурация оказалась полностью проприетарной. К сожалению её-то и использует драйвер на компьютере под управлением Windows. Из-за наличия под первым номером проприетарной конфигурации Azure RTOS тоже отказалась работать с адаптером.
Проблема обнаружилась в функции _ux_host_stack_class_interface_scan стека USBX. Там обрабатывается только первая конфигурация устройства.
Вот такое простое изменение функции решает проблему:
UINT _ux_host_stack_class_interface_scan(UX_DEVICE *device)
{
UX_CONFIGURATION *configuration;
UINT status;
/* Get the 1st and only configuration. If the device has multiple
configurations, we simply use the first one as default. */
configuration = device -> ux_device_first_configuration;
if (configuration == UX_NULL)
return(UX_ERROR);
/* Scan interfaces for this configuration. */
status = _ux_host_stack_configuration_interface_scan(configuration);
if (status != UX_SUCCESS)
{
configuration = device -> ux_device_first_configuration->ux_configuration_next_configuration;
if (configuration == UX_NULL) return(status);
status = _ux_host_stack_configuration_interface_scan(configuration);
}
/* Return operation result. */
return(status);
}
Кроме того нашлась проблема в HAL поставляемом для STM32H7. В функциях USB_WritePacket и USB_ReadPacket не выровненные запись и чтение слов происходили со сбоями и пришлось переписать их реализацию.
Весь демонстрационный проект находится на Github.
Плата выполняет все те же функции как и в предыдущем демо проекте. Также включается и регулируется напряжение на выходе платы. Но теперь на экран выводится только информация о текущем сетевом подключении и интерфейс USB по умолчанию работает в режиме хоста. Причём хост реагирует только на подключение USB устройств содержащих класс CDC ECM.
Как только микроконтроллер на плате обнаруживает подключение дивайса с CDC ECM он запускает работу DHCP клиента и получает от сервера в локальной сети свой IP адрес.
После этого включается задача сервера Telnet и поверх Telnet начинает работать задача интерактивного управления по протоколу эмулятора терминала VT100.
Достаточно включить на PC какую либо терминальную программу и можно подключиться к плате по IP адресу указанному на её дисплее. Будет доступен просмотр лога платы, установка параметров и прочие команды.
Дополнительно в демо проекте можно выполнить и другие действия. Например отключить DHCP клиента и установить статические адреса. Можно переключить USB интерфейс с режима host в режим device, и снова сделать композитный интерфейс с классами RNDIS и CDC ACM (виртуальный COM порт), как в прошлом проекте.
По прежнему будет работать протокол FreeMaster поверх VCOM.
Некоторые замечания по организации работы со стеками:
Инициализация сетевого стека должна производится до инициализации USB стека. Это видно здесь. Дело в том что класс CDC ECM в Azure RTOS имеет жёсткие связи с сетевым драйвером. И если USB начнёт работать первым и сразу обнаружит Ethernet адаптер, он тут же попытается вызвать сетевой драйвер для передачи пакетов. Но поскольку сетевой стек ещё не инициализирован пакеты пойдут в пустоту и потом сетевой стек уже не подхватит интерфейс через USB.
При инициализации стека USB в режиме хоста нужно выделить как кэшируемую память так и некэшируемую память и достаточного объёма. Не меньше 27 КБайт на каждую.
Вектора прерываний USB находятся во Flash памяти и реализованы в файле App_ISRs.c. По прерыванию вызываются функции HAL. На некоторых отладочных платах от ST можно найти иную реализацию драйверов для хоста USB. Этот вариант не тестировался и там необходимо вызывать другую функцию обработчика прерываний из файла ux_hcd_stm32_interrupt_handler.c.
Работа DHCP клиента не быстрая и может занять до десятка секунд.
Нельзя конфигурировать через MPU регион памяти выделяемой стеку USB, иначе возникнут ошибки записи в память данных типа uint32_t по адресу невыровненному по границе 4 байт. По умолчанию в Cortex-M7 позволяется запись по невыровненному адресу и директива вроде __UNALIGNED_UINT32_WRITE(pDest, USBx_DFIFO(0U)); компилятором будет преобразована к простой записи одного слова в память.
Стек USB во Flash памяти микроконтроллера занял около 42 кбайт. В RAM пришлось отдать на USB около 100 кбайт. Но при этом не выполнялись никакие оптимизации.