Программирование ARM: работа с USB STM32Cube: библиотека устройства USB Thu, November 21 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


STM32Cube: библиотека устройства USB Печать
Добавил(а) microsin   

Инициатива STMCube™ была разработана компанией STMicroelectronics (далее просто ST) для упрощения жизни разработчикам в процессе разработки, снижая их усилия, время и цену работ. Библиотека STM32Cube версии 1.x включает:

STM32CubeMX, графическая утилита конфигурирования, которая позволяет генерировать код инициализации на языке C. это делается с помощью графических визардов.

• Продвинутая программная платформа, нацеленная на каждую из серий микроконтроллеров (такую как STM32CubeF4 для серии STM32F4).

   – STM32Cube HAL, слой абстракции встроенного программного обеспечения, гарантирующий максимальное портирование между семействами STM32.
   – Набор промежуточных программных компонентов, таких как RTOS, стеки USB, TCP/IP, графические библиотеки.
   – Все встраиваемое программное обеспечение поставляется с полным набором примеров.

Шина USB - самое полезное в истории персональных компьютеров средство для подключения различных устройств, таких как мышь, геймпады, джойстики, сканеры, принтеры, цифровые камеры и т. д. USB также встраивается в большинство потребительской и мобильной электроники.

Это руководство (перевод UM1734 [1]) описывает библиотеку устройств USB STM32Cube, которая входит как часть в пакет STM32Cube. Этот пакет можно бесплатно загрузить с сайта ST (http://www.st.com/stm32cube). Здесь описывается, как начать разрабатывать и реализовать приложения устройства USB основных классов (HID, MSC, Audio, CDC...) на базе стека устройства USB, поддерживаемого всеми сериями микроконтроллеров STM32.

Примечание: этот документ применим ко всем сериям STM32, которые имеют на борту периферийное устройство USB. Однако для упрощения изложения в качестве образцовой платформы выбрана разновидность микроконтроллеров STM32F4xx и пакет STM32CubeF4. Чтобы получить дополнительную информацию по примерам реализации на Вашем STM32, обратитесь к файлу readme, предоставленному в соответствующем пакете STM32Cube.

API Application Programming Interface (программный интерфейс доступа к функциям библиотеки).

BOT Bulk Only Transfer, передача только блоками.

CBW Command Block Wrapper, блок команды SCSI, который содержит информацию длины команды, направление, логический юнит (LUT), куда отправляется команда, и уникальный идентификатор, который будет возвращен в ответ от устройства, который может использоваться для проверки соответствия ответа запросу хоста. Command Block Wrapper отправляется устройству с использованием первого направления Out конечной точки Block интерфейса перед тем, как любые данные будут отправлены устройству или приняты из него. Затем хосту устройством отправляется финальный CSW, содержащий результаты операции.

CDC Communication Device Class.

CSW Command Status Wrapper, блок протокола SCSI.

DFU Device Firmware Upgrade, класс и протокол для обновления программного обеспечения (firmware) встраиваемого устройства.

firmware встраиваемое программное обеспечение микроконтроллера, так называемая "прошивка".

FS Full Speed, полная скорость (12 мегабит/сек).

HAL Hardware Abstraction Layer, программный уровень библиотек (драйверов) для абстрагирования от версии аппаратуры.

HCD Host Controller Driver.

HID Human Interface Device.

HS High Speed, высокая скорость (480 мегабит/сек).

HSI high-speed internal oscillator, внутренний генератор на 8 МГц.

I2C популярная последовательная шина для обмена данными в электронной аппаратуре.

I2S Inter-IC Sound, последовательный стандартный интерфейс для соединения друг с другом звуковых устройств. Альтернативно вместо I2S используют аббревиатуру IIS.

LBA Logical Block Address.

LUN Logical Unit, термин протокола SCSI.

Mbps Megabit per second, мегабит/сек.

MCU MicroController Unit, микроконтроллер.

MSC Mass Storage Class, класс устройства хранения данных. Иногда этот класс называют аббревиатурой MSD (Mass Storage Device).

MSP MCU Support Package.

MUN Max Unit Number, максимальный номер LUN.

OTG On-The-Go: периферийное устройство, поддерживающее OTG, может на лету переключаться между ролями HOST/DEVICE.

PCD Peripheral Controller Driver, драйвер контроллера периферийного устройства.

PID USB Product Identifier, идентификатор продукта устройства USB.

PSTN Public Switched Telephone Network, телефонная коммутационная сеть общего пользования.

RCC Reset and Clock Control, система управления сбросом и тактированием.

SCSI Small Computer System Interface, популярный стандарт шины и одноименный протокол обмена.

SOF Start Of Frame, сигнал начала фрейма.

VID USB Vendor Identifier, идентификатор производителя устройства USB.

USB Universal Serial Bus.

ZLP Zero Length Packet, пакет нулевой длины.

[Документация от ST]

• USB Host library user manual (UM1720), руководство библиотеки реализации хоста USB.
• Описание драйверов STM32F4xx HAL (UM1725), где можно найти описания двух стандартных драйвера (HCD для хоста и PCD для устройства).

[Внешние ссылки]

• Universal Serial Bus Specification, Revision 2.0, http: //www.usb.org
• USB device class specifications (Audio, HID, MSC, etc.), http://www.usb.org

[Описание библиотеки устройства USB]

ST предоставляет своим клиентам новые стеки USB (стек устройства и стек хоста) которые поддерживают все STM32 MCU, вместе с многими инструментами разработки, такими как Atollic® TrueSTUDIO, IAR Embedded Workbench for ARM® и Keil uVision®.

Этот документ фокусируется на стеке устройства USB. Для стека хоста обратитесь к соответствующему руководству.

Библиотека устройства USB является стандартной для всех микроконтроллеров STM32, и только слой HAL адаптируется для каждого отдельного устройства STM32.

Библиотека устройства USB работает поверх HAL-драйвера STM32Cube для USB устройства, и предоставляет все необходимое API для разработки приложения устройства USB. Представленный документ описывает промежуточный модуль библиотеки STM32Cube устройства USB, и иллюстрирует, как пользователь может с помощью этого модуля просто разработать собственное приложение устройства USB.

Библиотека устройства USB является частью пакета STM32Cube для каждой серии STM32. Она содержит:

• Низкоуровневый драйвер USB.
• Драйверы общеизвестных классов USB.
• Набор приложений для большинства классов устройства USB, поддерживающих типы передач USB Full speed и High speed (control, interrupt, bulk и isochronous).

Библиотека устройства USB предоставляет как минимум по одному демонстрационному примеру firmware для каждого типа передач USB:

• Human Interface Device HID. Демонстрируется HID-джойстик, основанный на оценочных платах (EVAL board), также есть примеры пользовательского устройства (Custom HID example).
• Audio streaming. Звуковое устройство для потоковых аудиоданных.
• Communication Device (CDC), коммуникационное устройство. Мост VCP USB-RS232 для реализации виртуального COM-порта.
• Mass storage. Демонстрируется устройство хранения на основе карты microSD, слот для которой есть на платах EVAL.
• Device Firmware Upgrade, обновление прошивки. Устройство DFU предназначено для загрузки и выгрузки firmware.
• Dual Core devices demonstration. Демонстрационные примеры сдвоенных устройств, основанные на mass storage + HID и mass storage + CDC.

Рассматриваются следующие темы:

• Архитектура библиотеки устройства USB.
• Описание библиотеки устройства USB.
• Обзор машины состояний библиотеки устройства USB.
• Обзор классов устройства USB.

Функции библиотеки. Основные функции библиотеки устройства USB:

• Поддержка функции многопакетной передачи, что позволяет отправлять большое количество данных без разделения из на пакеты максимально допустимого размера.
• Поддерживает до трек back-to-back передач на управляющих контрольных точках, control endpoints (совместимо с контроллерами OHCI).
• Конфигурационные файлы для изменения настроек ядра и библиотек без изменения самого кода библиотеки (Read Only).
• Структуры с выравниванием данных на 32 бита (4 байта), чтобы обрабатывать передачи на основе DMA в режимах High speed.
• Поддерживаются несколько экземпляров ядра USB OTG из уровня пользователя (конфигурационный файл).

Замечание: библиотека устройства USB может использоваться как вместе с RTOS, так и отдельно; используется обертка (CMSIS RTOS wrapper) для реализации абстракции с ядром операционной системы. Примеры устройства USB не отображают сообщения лога.

STM32Cube USB device library fig01

Рис. 1.  STM32Cube USB device library (библиотека устройства USB).

На рисунке выше приложение пользователя показано зеленым цветом, ядро библиотеки USB желтым и драйвер USB Device HAL синим.

[Архитектура библиотеки устройства USB]

Библиотека устройства USB разделена на три основных слоя. Приложение разрабатывается над самым верхним слоем, как показано на рис. 2.

STM32Cube USB device library architecture fig02

Рис. 2. Архитектура USB device library.

На этом рисунке блоки ядра библиотеки USB показаны желтым цветом, конфигурация устройства USB (USB Device Configuration) фиолетовым, и синим показан драйвер USB HAL.

Первый слой состоит из драйверов ядра и драйверов класса USB.

Драйверы ядра (Core drivers). Ядро библиотеки составлено из 4 основных блоков:

– Модуль ядра USB, который предоставляет полный набор API для управления внутренним состоянием библиотеки машины устройства USB и процессами обратных вызовов (callback) из прерываний USB.
– Модуль обработки запросов USB (в соответствии с Главой 9 стандарта USB).
– Модуль обработки низкоуровневых запросов ввода/вывода USB.
– Модуль лога и отладки USB, который настраивается на уровень вывода отладочных сообщений макросом USB_DEBUG_LEVEL. Модуль выводит сообщения пользователя, лога, ошибок и отладки.

Драйверы класса. Классы устройств USB представлены набором драйверов, которые могут быть состыкованы с ядром USB через подпрограмму USBD_RegisterClass().

Библиотека устройства USB это стандартный стек, совместимый с USB 2.0 и со всеми ядрами STM32 USB. Он может быть просто состыкован с любым драйвером USB HAL благодаря конфигурационному файлу обертки, который обходит зависимости между библиотекой USB и драйверами низкого уровня.

[Слой USB OTG HAL]

STM32Cube Driver architecture overview fig03

Рис. 3. Обзор архитектуры драйвера.

Архитектура драйвера:

• Нижний слой (Low Layer USB driver) предоставляет общее API для режимов устройства и OTG. Он выполняет инициализацию ядра в каждом режиме и управляет потоком передач.
• Слой Peripheral Controller Driver (PCD) предоставляет API для доступа в режиме устройства, и главную подпрограмму прерывания для этого режима.
• Слой драйвера контроллера OTG предоставляет API для доступа в режиме OTG главную подпрограмму прерывания для этого режима.

Примечание: для дополнительной информации по использованию драйвера PCD пожалуйста обратитесь к документу UM1725, где описаны все вызовы API драйвера PCD.

[Программирование драйвера USB]

Конфигурирование структуры драйвера, инициализация.

Инициализация устройства. Устройство инициализируется использованием следующей функции, содержащейся в файле stm32fxxx_hal_pcd.c:

HAL_StatusTypeDef HAL_PCD_Init(PCD_HandleTypeDef *hpcd);

Конфигурация конечной точки. Как только ядро USB инициализировано, верхний слой может вызвать драйвер низкого уровня, чтобы открыть или закрыть активную конечную точку с целью перемещения данных. Могут использоваться следующие 2 API-вызова:

HAL_StatusTypeDef HAL_PCD_EP_Open(PCD_HandleTypeDef *hpcd,
                                  uint8_t ep_addr,
                                  uint16_t ep_mps,
                                  uint8_t ep_type);
HAL_StatusTypeDef HAL_PCD_EP_Close(PCD_HandleTypeDef *hpcd,
                                   uint8_t ep_addr);

Здесь ep_addr, ep_mps и ep_type это адрес конечной точки, максимум передачи данных и тип передачи соответственно.

Структура ядра устройства. Основная структура, используемая в библиотеке устройства, это дескриптор устройства (device handle) типа USBD_HandleTypedef:

typedef struct _USBD_HandleTypeDef
{
   uint8_t id;
   uint32_t dev_config;
   uint32_t dev_default_config;
   uint32_t dev_config_status;
   USBD_SpeedTypeDef dev_speed;
   USBD_EndpointTypeDef ep_in[15];
   USBD_EndpointTypeDef ep_out[15];
   uint32_t ep0_state;
   uint32_t ep0_data_len;
   uint8_t dev_state;
   uint8_t dev_old_state;
   uint8_t dev_address;
   uint8_t dev_connection_status;
   uint8_t dev_test_mode;
   uint32_t dev_remote_wakeup;
   USBD_SetupReqTypedef request;
   USBD_DescriptorsTypeDef *pDesc;
   USBD_ClassTypeDef *pClass;
   void *pClassData;
   void *pUserData;
   void *pData;
} USBD_HandleTypeDef;

Глобальная структура устройства USB содержит все переменные и структуры, чтобы хранить информацию реального времени, относящуюся к устройству, а также для хранения состояний машины управления передачами(control transfer state machine), и информации/статуса конечной точки.

В этой структуре dev_config хранит текущую конфигурацию устройства USB, и ep0_state управляет машиной, которая принимает следующие состояния:

/* Состояние управляющей конечной точки (EP0 State) */
#define USBD_EP0_IDLE         0
#define USBD_EP0_SETUP        1
#define USBD_EP0_DATA_IN      2
#define USBD_EP0_DATA_OUT     3
#define USBD_EP0_STATUS_IN    4
#define USBD_EP0_STATUS_OUT   5
#define USBD_EP0_STALL        6

В этой структуре dev_state определяет соединение, конфигурацию и состояние питания:

/* Состояние устройства */
#define USBD_DEFAULT    1
#define USBD_ADDRESSED  2
#define USBD_CONFIGURED 3
#define USBD_SUSPENDED  4

Спецификация USB определяет 6 состояний устройства USB:

Attached: устройство подключено к шине USB, однако не получает питание.
Powered: устройство подключено к шине USB и получает питание, однако пока не получило никакой запрос сброса (reset request).
Default: устройство подключено к USB. Оно запитано и сброшено, однако ему не был назначен уникальный адрес.
Address: устройство подключено к USB, запитано и сброшено, и получило уникальный адрес.
Configured: устройство уже находится в адресованном состоянии и сконфигурировано. Это не состояние приостановки (suspend).
Suspended: устройство подключено и сконфигурировано, но как минимум 3 мс по шине не было обнаружено связанной с ним активности.

Поток перемещения данных USB. Слой PCD предоставляет все API-вызовы, которые требуются для запуска и управления потоком передачи. Это делает следующий набор функций:

HAL_StatusTypeDef HAL_PCD_EP_Transmit(PCD_HandleTypeDef *hpcd,
                                      uint8_t ep_addr,
                                      uint8_t *pBuf,
                                      uint32_t len);
HAL_StatusTypeDef HAL_PCD_EP_Receive(PCD_HandleTypeDef *hpcd,
                                     uint8_t ep_addr,
                                     uint8_t *pBuf,
                                     uint32_t len);
HAL_StatusTypeDef HAL_PCD_EP_SetStall(PCD_HandleTypeDef *hpcd,
                                      uint8_t ep_addr);
HAL_StatusTypeDef HAL_PCD_EP_ClrStall(PCD_HandleTypeDef *hpcd,
                                      uint8_t ep_addr);
HAL_StatusTypeDef HAL_PCD_EP_Flush(PCD_HandleTypeDef *hpcd,
                                   uint8_t ep_addr);

Слой PCD содержит одну функцию, которая должна быть вызвана прерыванием USB:

void HAL_PCD_IRQHandler(PCD_HandleTypeDef *hpcd);

Файл stm32fxxx_hal_pcd.h содержит прототипы функций, вызываемых из слоя ядра библиотеки, чтобы обработать события USB.

Почти все библиотечные функции возвращают состояние типа USBD_StatusTypeDef. Приложение пользователя должно всегда проверять возвращенное состояние. Ниже показано определение этого типа (перечисление значений), и в таблице 3 описаны возможные возвращаемые состояния.

typedef enum
{
   USBH_OK = 0,
   USBH_BUSY,
   USBH_FAIL,
}USBH_StatusTypeDef;

Таблица 3. Состояния устройства USB.

Status Описание
USBH_OK Будет возвращено, когда операция завершилась успешно.
USBH_BUSY Будет возвращено, когда операция еще не завершилась (устройство занято).
USBH_FAIL Будет возвращено, когда операция потерпела неудачу из-за низкоуровневой ошибки или ошибки в обработке протокола.

[Обзор библиотеки устройства USB]

Библиотека устройства USB основана на стандартном драйвере USB низкого уровня. ПО было разработано для поддержки режимов Full speed и High speed.

Реализована машина состояний устройства USB, как это было определено спецификацией USB 2.0. Библиотечные функции находятся в файлах папки Core из пакета USB device library firmware package (см. рис. 5). Модули класса USB (папка Class) разработаны для обеспечения совместимости со спецификацией протокола.

STM32Cube USB device library directory structure fig05

Рис. 5. Структура каталогов библиотеки устройства USB.

Обработка control endpoint. Спецификация USB определяет 4 типа передач: control, interrupt, bulk и isochronous. Хост USB отправляет запросы к устройству через управляющую точку, control endpoint (в этом случае control endpoint является конечной точкой с номером 0). Запросы отправляются в устройство как пакеты SETUP. Эти запросы можно классифицировать на 3 категории: standard, class-specific и vendor-specific. Поскольку стандартные запросы являются общими для всех видов устройств USB, библиотека принимает и обрабатывает все стандартные запросы на control endpoint 0.

Формат и смысл специфичных для класса запросов и специфичных для вендора запросов не совпадают для всех устройств USB.

Все запросы SETUP обрабатываются в машине состояний, реализованной в модели прерывания. Прерывание генерируется по окончании корректной передачи USB. Код библиотеки принимает это прерывание. В подпрограмме обработки прерывания (ISR) идентифицируется триггер конечной точки. Если событие это настройка (setup) на endpoint 0, то полезная нагрузка принятой настройки сохраняется, и запускается машина состояний.

Транзакции на других конечных точках. Ядро, специфическое для класса, использует конечные точки, не относящиеся к конечной точке управления путем вызова набора функций для отправки или приема данных через callback-стадии data IN и data OUT.

Структура данных для пакета SETUP. Когда поступает новый пакет SETUP, все 8 байт пакета SETUP копируются во внутреннюю структуру USB_SETUP_REQ req, чтобы во время обработки следующий пакет SETUP не мог перезаписать предыдущий. Эта внутренняя структура определена следующим образом:

typedef struct usb_setup_req
{
   uint8_t bmRequest;
   uint8_t bRequest;
   uint16_t wValue;
   uint16_t wIndex;
   uint16_t wLength;
}USBD_SetupReqTypedef;

Стандартные запросы. Большинство запросов спецификации USB, показанных в таблице 4, обрабатываются библиотекой как стандартные. Таблица 4 перечисляет все эти стандартные запросы и их допустимые в библиотеке параметры. Запросы, которых нет в таблице 4, считаются нестандартными.

Таблица 4. Стандартные запросы USB.

  STM32Cube table4 col2 State STM32Cube table4 col3 bmRequestType STM32Cube table4 col4 wValue low byte STM32Cube table4 col5 wValue high byte STM32Cube table4 col6 wIndex low byte STM32Cube table4 col7 wIndex high byte STM32Cube table4 col8 wLength Комментарии
CLEAR_FEATURE
A, C 00 01 00 00 00 00 Очищает функцию remote wakeup устройства.
C 02 00 00 EP 00 00 Очищает состояние STALL конечной точки EP. EP не относится к EP0.
SET_FEATURE
A, C 00 01 00 00 00 00 Устанавливает функцию remote wakeup устройства.
C 02 00 00 EP 00 00 Устанавливает состояние STALL конечной точки EP. EP не относится к EP0.
SET_ADDRESS D, A 00 N 00 00 00 00 Устанавливает адрес устройства, N допустимый адрес устройства.
GET_DESCRIPTOR
Все сост. 80 00 01 00 00 не 0 Получает дескриптор устройства.
80 N 02 00 00 не 0 Получает дескриптор конфигурации, где N допустимый индекс конфигурации.
80 N 03 LangID не 0 Получает строковый дескриптор, где N допустимый индекс строки. Этот запрос допустим только когда поддерживается строковый дескриптор.
GET_CONFIGURATION A, C 80 00 00 00 00 1 Получает конфигурацию устройства.
SET_CONFIGURATION A, C 80 N 00 00 00 00 Устанавливает конфигурацию устройства, где N допустимый номер конфигурации устройства.
GET_INTERFACE C 81 00 00 N 00 1 Получает альтернативную настройку интерфейса. Здесь N допустимый номер интерфейса.
SET_INTERFACE C 01 M 00 N 00 00 Устанавливает альтернативную установку N интерфейса M. Здесь N это допустимый номер интерфейса, M это допустимая альтернативная установка интерфейса N.

Примечание: в столбце State применены следующие обозначения состояний. D = Default state (состояние по умолчанию), A = Address state (состояние адресации), C = Configured state (состояние "сконфигурировано"). Значение EP: D0-D3 = адрес конечной точки, D4-D6 = эти биты зарезервированы как нули, D7 = 0: OUT endpoint, 1: IN endpoint.

Нестандартные запросы. Все нестандартные запросы через callback-функции передаются в код, специфичный для класса.

• SETUP stage

Библиотека передает все нестандартные запросы в специфичный для класса код через callback-функцию pdev->pClass->Setup (pdev, req).

Нестандартные запросы включают интерпретируемые пользователем запросы и неправильные запросы (invalid requests). Интерпретируемые пользователем запросы это запросы, специфические для класса, специфические для вендора или запросы, которые библиотека считает недопустимыми (invalid), так что приложение может захотеть обработать их для себя как допустимые.

Invalid-запросы это такие запросы, которые не являются стандартными, и поэтому не могут быть интерпретированы библиотекой. Поскольку pdev->pClass->Setup (pdev, req) вызывается после SETUP stage и перед DATA stage, то код пользователя в pdev->pClass->Setup (pdev, req) отвечает за парсинг содержимого пакета SETUP (req). Если запрос недопустим, то код пользователя должен вызвать USBD_CtlError(pdev, req) и вернуть управление в код, который вызвал pdev->pClass->Setup (pdev, req).

Для запроса, интерпретируемого пользователем, код пользователя подготавливает буфер данных для последующего DATA stage, если в запросе есть стадия данных; иначе пользовательский код выполнит запрос и вернет управление в код, который вызывал pdev->pClass->Setup (pdev, req).

• DATA stage

Слой класса использует стандартные USBD_CtlSendData и USBD_CtlPrepareRx для отправки или приема данных. Поток переноса данных обрабатывается внутренним кодом библиотеки, и пользователю не нужно делить данные в пакеты размера ep_size.

• Status stage

Стадия статуса обрабатывается библиотекой после возврата из callback-функции pdev->pClass->Setup (pdev, req).

STM32Cube USB device library process flowchart fig07

Рис. 7. Обработка в библиотеке устройства USB.

Примечание: красный текст идентифицирует конфигурацию устройства USB.

Как показано на рис. 7, для программирования USB нужны только следующие модули: библиотека USB, класс устройства USB и основное приложение.

Главное приложение выполняет программу пользователя. Модули main.c, stm32fxx_it.c, usbd_conf.c и usbd_desc.c вместе с их заголовочными файлами - все, что пользователю нужно для разработки своего собственного приложения. Пользователь может изменить из в соответствии с требованиями своего приложения (драйвер класса).

Делаются только простые API-вызовы. Они позволяют установить взаимосвязь между слоем приложения и модулем библиотеки USB, который обрабатывает инициализацию USB и получает текущее состояние USB.

Чтобы инициализировать драйвер USB HAL, библиотеку устройства USB и аппаратуру на используемой плате (BSP), и запустить библиотеку, приложение пользователя должно сделать 3 вызова API:

• USBD_Init(): эта функция инициализирует стек устройства и загружает драйвер класса. Дескриптор устройства сохраняется в файлах usbd_desc.c и usbd_desc.h (используется для конфигурации типа дескриптора).
• USBD_RegisterClass(): эта функция привязывает драйвер класса к ядру устройства.
• USBD_Start(): эта функция позволяет запустить ядро устройства USB.

Например, пользователь может добавить дополнительные конечные точки в файле usbd_conf, в зависимости от требований класса. Это делается вызовом функции USBD_LL_Init(). В переменной dev_endpoints должно содержаться количество требуемых конечных точек по спецификации класса USB.

Благодаря файлу usbd_conf.h библиотека устройства USB предоставляет несколько конфигураций (для дополнительной информации см. далее секцию "Конфигурирование firmware библиотеки устройства USB").

Замечание: инициализация библиотеки HAL осуществляется вызовом HAL_Init() API в модуле stm32fxxx_hal.c. Эта функция выполняет следующие операции:

- Сбрасывает все периферийные устройства.
- Конфигурирует выборку инструкций и кэш (Flash prefetch, Instruction cache, Data cache).
- Разрешает SysTick и конфигурирует тик 1 мс (такты по умолчанию после Reset HSI).

Поток данных устройства USB. Библиотека USB (USB core и слой USB class) обрабатывают данные на конечной точке 0 (EP0) через слой запроса I/O, когда необходима обертка для управления функцией multi-packet на control endpoint, или напрямую из слоя stm32fxxx_hal_pcd, когда используются другие конечные точки, поскольку ядро USB OTG поддерживает функцию multi-packet. Рис. 8 показывает эту схему потока данных.

STM32Cube USB device data flow fig08

Рис. 8. Схема потока данных в устройстве (USB device data flow).

Интерфейс ядра с драйвером низкого уровня. Как упоминалось ранее, библиотека устройства USB подключается к низкоуровневому драйверу STM32Cube™ HAL с помощью слоя низкоуровневого интерфейса, который действует как слой соединения (link layer) с STM32Cube™ HAL.

Этот низкоуровневый интерфейс реализует API-функции низкого уровня и вызывает некоторые callback-функции ядра библиотеки при некоторых событиях USB.

В пакете кода STM32Cube™ реализация низкоуровневого интерфейса предоставлена как часть примеров устройства USB, поскольку некоторые части низкоуровневого интерфейса зависят от платы и системы.

Таблица 5 перечисляет низкоуровневые функции API.

Таблица 5. Описание API низкого уровня.

Функция Описание
USBD_LL_Init Инициализация низкого уровня.
USBD_LL_DeInit Отмена инициализации низкого уровня.
USBD_LL_Start Запуск низкого уровня.
USBH_LL_Stop Остановка низкого уровня.
USBD_LL_OpenEP Инициализация конечной точки.
USBD_LL_CloseEP Закрытие конечной точки и отмена инициализации её состояния.
USBD_LL_FlushEP Сбрасывает (flush) данные в конечной точке драйверу низкого уровня.
USBD_LL_StallEP Устанавливает состояние STALL на конечной точке для драйвера низкого уровня.
USBD_LL_ClearStallEP Очищает состояние STALL на конечной точке для драйвера низкого уровня.
USBD_LL_IsStallEP Возвращает информацию, находится ли конечная точка в состоянии STALL.
USBD_LL_SetUSBAddress Назначает адрес устройству USB.
USBD_LL_Transmit Передает данные через конечную точку.
USBD_LL_PrepareReceive Подготавливает конечную точку к приему данных.
USBD_LL_GetRxDataSize Вернет размер данных последнего принятого пакета.

Примечание: это API предоставлено файлов конфигурации устройства USB (usbd_conf.c). Оно должно быть реализована в файлах пользователя и адаптировано для драйвера контроллера устройства USB (USB Device Controller Driver). Пользователь может начать создавать свой файл конфигурации, беря в качестве примера файл usbd_conf.c из пакета STM32Cube™. Этот файл можно также скопировать в папку приложения и изменить в зависимости от требований приложения.

Модель интерфейса библиотеки устройства USB. Библиотека устройства USB построена вокруг стандартных центральных портируемых модулей класса.

STM32Cube USB device library interfacing model fig09

Рис. 9. Модель интерфейса библиотеки устройства USB.

Таблица 6 показывает все callback-функции библиотеки устройства, которые вызываются из низкоуровневого интерфейса в ответ на некоторые события USB.

Таблица 6. Callback-функции событий низкого уровня.

Функция Описание
HAL_PCD_ConnectCallback Событие подключения устройства USB к шине.
HAL_PCD_DataInStageCallback Стадия Data IN.
HAL_PCD_DataOutStageCallback Стадия Data OUT.
HAL_PCD_DisconnectCallback Событие отключения устройства USB.
HAL_PCD_ISOINIncompleteCallback Событие незавершенной изохронной транзакции IN (сокращенно ISO IN).
HAL_PCD_ISOOUTIncompleteCallback Событие незавершенной изохронной транзакции OUT (сокращенно ISO OUT).
HAL_PCD_ResetCallback Событие сброса по шине USB.
HAL_PCD_ResumeCallback Событие возобновления работы.
HAL_PCD_SetupStageCallback Событие стадии настройки.
HAL_PCD_SOFCallback Событие начала фрейма (Start Of Frame, SOF).
HAL_PCD_SuspendCallback Событие приостановки работы.

Конфигурирование firmware библиотеки устройства USB. The USB device library can be configured using the usbd_conf.h file.

Файл usbd_conf.h - специальный конфигурационный файл, используемый для определения некоторых глобальных параметров и специальных конфигураций. Этот файл используется для подключения библиотеке верхнего уровня вместе с драйверами HAL и драйверами BSP.

Таблица 7. Конфигурация библиотеки USB.

Конфигурация Параметр Описание
Общая USBD_MAX_NUM_CONFIGURATION Максимальное количество поддерживаемых конфигураций [1..255].
USBD_MAX_NUM_INTERFACES Максимальное количество поддерживаемых интерфейсов [1..255].
USBD_MAX_STR_DESC_SIZ Максимальный размер строковых дескрипторов [uint16].
USBD_SELF_POWERED Разрешает функцию самостоятельного питания [0/1].
USBD_DEBUG_LEVEL Уровень вывода сообщений отладки и лога.
USBD_SUPPORT_USER_STRING Разрешает поддержку строк пользователя [0/1].
MSC_MEDIA_PACKET Размер буфера ввода/вывода носителя, делящийся нацело на 512 [от 512 байт до 32 килобайт].
HID - Недоступно.
DFU USBD_DFU_MAX_ITF_NUM Максимальный номер интерфейса носителя [1..255].
USBD_DFU_XFER_SIZE Размер буфера ввода/вывода носителя, делящийся нацело на 512 [от 512 байт до 32 килобайт].
USBD_DFU_APP_DEFAULT_ADD Адрес приложения (0x0800C000).
CDC - Недоступно.
Audio USBD_AUDIO_FREQ Частота дискретизации 8..48 кГц.

Примечание: пользователь может начать работу с файла usbd_conf.c, предоставленного в пакете STM32Cube™. Этот файл также может быть скопирован в папку разрабатываемого приложения, и изменен в зависимости от нужд приложения.

По умолчанию для примеров устройств USB библиотечные и пользовательские сообщения не отображаются на LCD. Однако пользователь может реализовать свои собственные сообщения. Для перенаправления библиотечных сообщений на экран LCD к фалам исходного кода приложения должен быть добавлен драйвер lcd_log.c. Он может выбрать, какие сообщения отображать, путем изменения значений #define в конфигурационном файле usbd_conf.h, который должен находиться среди подключаемых файлов проекта. Например:

0: не выводить сообщения лога/отладки.
1: разрешены сообщения лога.
2: разрешены сообщения и лога, и отладки.

Функции управления USB

Device reset. Когда устройство получает сигнал сброса от шины USB, библиотека сбрасывает и инициализирует и программное обеспечение, и аппаратуру приложения. Эта функция - часть подпрограммы обработки прерывания.

Device suspend. Когда устройство определяет состояние (suspend condition) приостановки на шине USB, библиотека останавливает все происходящие операции и переводит систему в состояние приостановки, suspend state (если разрешен режим пониженного энергопотребления в файле usbd_conf.c).

Device resume. Когда устройство определяет сигнал возобновления работы (resume) на шине USB, библиотека восстанавливает тактирование ядра USB и переводит систему в состояние ожидания, idle state (если разрешен режим пониженного энергопотребления в файле usbd_conf.c).

[Функции библиотеки устройства USB]

В папке Core содержатся машины библиотеки устройства USB, как это определено в спецификации USB ревизии 2.0.

Таблица 8. Файлы ядра устройства USB.

Файлы Описание
usbd_core.c, usbd_core.h Функции для обработки всех коммуникаций и машины состояния.
usbd_req.c, usbd_req.h Реализация запросов, перечисленных в Главе 9 спецификации стандарта USB.
usbd_ctlreq.c, usbd_ctlreq.h Обработка результатов транзакций USB.
usbd_conf_template.c, usbd_conf_template.h Шаблон для низкоуровневого интерфейса, должен быть переделан пользователем и подключен к проекту приложения.
usbd_def.c, usbd_def.h Общие определения библиотеки.

Папка Class содержит все файлы, относящиеся к реализации класса, и они соответствуют спецификации протокола этих классов.

Таблица 9. Файлы драйверов классов устройств USB.

Класс USB Файлы Описание
MSC (устройство хранения данных) usbh_msc.c, usbh_msc.h Handler класса MSC.
usbh_msc_bot.c, usbh_msc_bot.h Handler протокола транзакций Bulk-only.
usbh_msc_scsi.c, usbh_msc_scsi.h Команды SCSI.
usbd_msc_data.c, usbd_msc_data.h Важные страницы запроса и чувствительные данные.
HID (Joystick, mouse) usbh_hid.c, usbh_hid.h Handler состояний класса HID.
Custom HID usbd_customhid.c, usbd_customhid.h Handler пользовательского класса HID.
Audio speaker usbh_audio.c, usbh_audio.h Handler класса Audio.
CDC (коммуникационное устройство) usbh_cdc.c, usbh_cdc.h Handler класса CDC (виртуальный последовательный порт).
DFU (устройство обновления firmware) usbd_dfu.c, usbd_dfu.h Handler класса DFU.

Ниже приведено краткое описание назначения функций в различных модулях библиотеки.

Таблица 10. usbd_core.c, usbd_core.h.

Функция Описание
USBD_Init Инициализирует библиотеку устройства, загружает драйвер класса и callback-функции пользователя.
USBD_DeInit Отменяет инициализацию библиотеки устройства.
USBD_RegisterClass Загружает драйвер класса устройства USB.
USBD_Start Запускает обработку библиотеки устройства.
USBD_Stop Останавливает обработку библиотеки устройства.
USBD_LL_SetupStage Обрабатывает стадию настройки в ISR.
USBD_LL_DataOutStage Обрабатывает стадию вывода данных в ISR.
USBD_LL_DataInStage Обрабатывает стадию ввода данных.
USBD_LL_Reset Обрабатывает сброс USB в ISR.
USBD_LL_SetSpeed Устанавливает скорость ядра USB.
USBD_LL_Suspend Обрабатывает событие приостановки (Suspend Event).
USBD_LL_Resume Обрабатывает событие продолжения работы (Resume Event).
USBD_LL_SOF Обрабатывает событие начала фрейма, SOF (Start Of Frame Event).
USBD_LL_IsoINIncomplete Обрабатывает событие неполной изохронной транзакции ввода (ISO IN)
USBD_LL_IsoOUTIncomplete Обрабатывает событие неполной изохронной транзакции вывода (ISO OUT).
USBD_LL_DevConnected Оповещает из ISR о событии подключения устройства.
USBD_LL_DevDisconnected Оповещает из ISR о событии отключения устройства.

Прототипы функций таблицы 10:

USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev,
                             USBD_DescriptorsTypeDef *pdesc,
                             uint8_t id);
USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev,
                                      USBD_ClassTypeDef *pclass);
USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev,
                                      uint8_t *psetup);
USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev,
                                        uint8_t epnum,
                                        uint8_t *pdata);
USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev,
                                       uint8_t epnum,
                                       uint8_t *pdata);
USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev,
                                    USBD_SpeedTypeDef speed);
USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev,
                                           uint8_t epnum);
USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev,
                                            uint8_t epnum);
USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev);

Таблица 11. usbd_ioreq.c, usbd_ioreq.h.

Функция Описание
USBD_CtlSendData Посылает данные через канал управления (control pipe).
USBD_CtlContinueSendData Продолжает отправку данных через канал управления.
USBD_CtlPrepareRx Подготавливает ядро к приему данных через канал управления.
USBD_CtlContinueRx Продолжает прием данных через канал управления.
USBD_CtlSendStatus Отправляет через канал управления пакет нулевой длины (ZLP).
USBD_CtlReceiveStatus Принимает через канал управления пакет ZLP.
USBD_GetRxCount Вернет длину принятых данных.

Прототипы функций таблицы 11:

USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev,
                                     uint8_t *pbuf,
                                     uint16_t len);
USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev,
                                             uint8_t *pbuf,
                                             uint16_t len);
USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev,
                                      uint8_t *pbuf,
                                      uint16_t len);
USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev,
                                       uint8_t *pbuf,
                                       uint16_t len);
USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev);
USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev);
uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev,
                          uint8_t ep_addr);

Таблица 12. usbd_ctrlq.c, usbd_ctrlq.h.

Функция Описание
USBD_StdDevReq Обрабатывает стандартные запросы устройства USB.
USBD_StdItfReq Обрабатывает стандартные запросы интерфейса устройства USB.
USBD_StdEPReq Обрабатывает стандартные запросы конечной точки устройства USB.
USBD_GetDescriptor Обрабатывает запросы получения дескриптора.
USBD_SetAddress Устанавливает новый адрес устройства USB.
USBD_SetConfig Обрабатывает запрос установки конфигурации устройства USB.
USBD_GetConfig Обрабатывает запрос получения конфигурации устройства USB.
USBD_GetStatus Обрабатывает запрос получения состояния устройства USB.
USBD_SetFeature Обрабатывает запрос установки функции устройства USB.
USBD_ClrFeature Обрабатывает запрос очистки функции устройства USB.
USBD_CtlError Обрабатывает ошибки USB на канале управления (control pipe).
USBD_GetString Преобразует строку ASCII в строку Unicode.
USBD_GetLen Возвратит длину строки.
USBD_ParseSetupRequest Копирует буфер запроса в структуру настройки.

Прототипы функций таблицы 12:

USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev,
                                   USBD_SetupReqTypedef *req);
USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev,
                                   USBD_SetupReqTypedef *req);
USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev,
                                  USBD_SetupReqTypedef *req);
static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev,
                               USBD_SetupReqTypedef *req);
static void USBD_SetAddress (USBD_HandleTypeDef *pdev,
                             USBD_SetupReqTypedef *req);
static void USBD_SetConfig (USBD_HandleTypeDef *pdev,
                            USBD_SetupReqTypedef *req);
static void USBD_GetConfig (USBD_HandleTypeDef *pdev,
                            USBD_SetupReqTypedef *req);
static void USBD_GetStatus (USBD_HandleTypeDef *pdev,
                            USBD_SetupReqTypedef *req);
static void USBD_SetFeature (USBD_HandleTypeDef *pdev,
                             USBD_SetupReqTypedef *req);
static void USBD_ClrFeature (USBD_HandleTypeDef *pdev,
                             USBD_SetupReqTypedef *req);
void USBD_CtlError (USBD_HandleTypeDef *pdev,
                    USBD_SetupReqTypedef *req);
void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len);
static uint8_t USBD_GetLen (uint8_t *buf);
void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req,
                             uint8_t *pdata);

[Интерфейс класса устройства USB]

Структура USB Class callback. Класс USB выбирается при инициализации библиотеки устройства USB путем выбора соответствующей callback-структуры класса. Эта структура класса определена следующим образом:

typedef struct _Device_cb
{
   uint8_t (*Init) (struct _USBD_HandleTypeDef *pdev,
                    uint8_t cfgidx);
   uint8_t (*DeInit) (struct _USBD_HandleTypeDef *pdev,
                      uint8_t cfgidx);
   /* Обработка управляющей конечной точки (Control Endpoint, EP0) */
   uint8_t (*Setup) (struct _USBD_HandleTypeDef *pdev,
                     USBD_SetupReqTypedef *req);
   uint8_t (*EP0_TxSent) (struct _USBD_HandleTypeDef *pdev);
   uint8_t (*EP0_RxReady) (struct _USBD_HandleTypeDef *pdev);
   /* Конечные точки, специфичные для класса устройства USB */
   uint8_t (*DataIn) (struct _USBD_HandleTypeDef *pdev,
                      uint8_t epnum);
   uint8_t (*DataOut) (struct _USBD_HandleTypeDef *pdev,
                       uint8_t epnum);
   uint8_t (*SOF) (struct _USBD_HandleTypeDef *pdev);
   uint8_t (*IsoINIncomplete) (struct _USBD_HandleTypeDef *pdev,
                               uint8_t epnum);
   uint8_t (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev,
                                uint8_t epnum);
   uint8_t *(*GetHSConfigDescriptor)(uint16_t *length);
   uint8_t *(*GetFSConfigDescriptor)(uint16_t *length);
   uint8_t *(*GetOtherSpeedConfigDescriptor)(uint16_t *length);
   uint8_t *(*GetDeviceQualifierDescriptor)(uint16_t *length);
} USBD_ClassTypeDef;

В этой структуре определены указатели на следующие callback-функции:

Init: вызывается, когда устройство принимает USB-запрос установки конфигурации; в этой функции открываются конечные точки, используемые в интерфейсе класса.
DeInit: вызывается, когда принят USB-запрос очистки конфигурации; эта функция закрывает конечные точки, используемые в интерфейсе класса.
Setup: вызывается для обработки специфичных для класса запросов настройки (class setup request).
EP0_TxSent: вызывается, когда завершается состояние отправки пакета из управляющей конечной точки.
EP0_RxSent: вызывается, когда завершается состояние приема пакета на управляющей конечной точке.
DataIn: вызывается для выполнения обработки принятых данных, относящихся к не управляющим конечным точкам.
DataOut: вызывается для выполнения обработки передаваемых данных, относящихся к не управляющим конечным точкам.
SOF: вызывается, когда принято прерывание SOF (сигнал начала фрейма); этот callback может использоваться для синхронизации некоторых процессов с сигналом SOF.
IsoINIncomplete: вызывается, когда не завершена последняя изохронная транзакция типа IN (isochronous IN transfer).
IsoOUTIncomplete: вызывается, когда не завершена последняя изохронная транзакция типа OUT (isochronous OUT transfer).
GetHSConfigDescriptor: этот callback вернет дескриптор USB-конфигурации HS.
GetFSConfigDescriptor: этот callback вернет дескриптор USB-конфигурации FS.
GetOtherSpeedConfigDescriptor: этот callback вернет другой дескриптор конфигурации используемого класса в режиме High Speed.
GetDeviceQualifierDescriptor: этот callback вернет дескриптор квалификатора устройства.

Структура дескрипторов устройства USB. Библиотека также предоставляет callback-структуру дескрипторов, что позволяет управлять устройством и строковыми дескрипторами во время работы приложения (run time). Эта структура дескрипторов определена следующим образом:

typedef struct
{
   uint8_t *(*GetDeviceDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
   uint8_t *(*GetLangIDStrDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
   uint8_t *(*GetManufacturerStrDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
   uint8_t *(*GetProductStrDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
   uint8_t *(*GetSerialStrDescriptor)(USBD_SpeedTypeDef speed, uint16_t *length);
   uint8_t *(*GetConfigurationStrDescriptor)( USBD_SpeedTypeDef speed, uint16_t *length);
   uint8_t *(*GetInterfaceStrDescriptor)( USBD_SpeedTypeDef speed, uint16_t *length);
} USBD_DescriptorsTypeDef;

GetDeviceDescriptor: этот callback вернет дескриптор устройства.
GetLangIDStrDescriptor: этот callback вернет строковый дескриптор идентификатора языка (Language ID).
GetManufacturerStrDescriptor: этот callback вернет строковый дескриптор производителя.
GetProductStrDescriptor: этот callback вернет the строковый дескриптор продукта.
GetSerialStrDescriptor: этот callback вернет строковый дескриптор серийного номера.
GetConfigurationStrDescriptor: этот callback вернет строковый дескриптор конфигурации.
GetInterfaceStrDescriptor: этот callback вернет строковый дескриптор интерфейса.

Примечание: в файле usbd_desc.c, предоставляемом с примерами устройства USB, реализованы тела этих callback-функций.

[Модуль класса библиотеки устройства USB]

Модуль класса содержит все файлы, относящиеся к реализации какого-либо класса устройства USB. Они соответствуют спецификации протокола, встроенного в эти классы. Таблица 13 показывает файлы класса устройства USB для классов MSC, HID, DFU, Audio, CDC.

Таблица 13. Файлы классов устройства USB.

Класс USB Файлы Описание
MSC (устройство хранения данных)
usbd_msc.c, usbd_msc.h Здесь содержатся callback-функции класса MSC (драйвер) и дескрипторы конфигурации, относящиеся к этому классу.
usbd_bot.c, usbd_bot.h Обработка протокола транзакций Bulk-only.
usbd_scsi.c, usbd_scsi.h Обработка команд SCSI.
usbd_msc_data.c, usbd_msc_data.h Важные страницы запроса и чувствительные данные устройства хранения.
usbd_msc_storage_template.c, usbd_msc_storage_template.h Шаблон драйвера, который позволит Вам реализовать дополнительные функции класса MSC.
HID (Joystick, mouse) usbd_hid.c, usbd_hid.h Здесь содержатся callback-функции класса HID (драйвер) и дескрипторы конфигурации, относящиеся к этому классу.
Custom HID usbd_customhid.c, usbd_customhid.h Здесь содержатся callback-функции пользовательского класса HID (драйвер) и дескрипторы конфигурации, относящиеся к этому классу.
Audio speaker usbd_audio.c, usbd_audio.h Здесь содержатся callback-функции класса AUDIO (драйвер) и дескрипторы конфигурации, относящиеся к этому классу.
usbd_audio_if_template.c, usbd_audio_if_template.h Шаблон драйвера, который позволит Вам реализовать дополнительные функции класса Audio.
CDC (коммуникационное устройство) usbd_cdc.c, usbd_cdc.h Здесь содержатся callback-функции класса CDC (драйвер) и дескрипторы конфигурации, относящиеся к этому классу.
usbd_cdc_if_template.c, usbd_cdc_if_template.h Шаблон драйвера, который позволит Вам реализовать функции низкого уровня для терминала CDC.
DFU (устройство обновления firmware) usbd_dfu.c, usbd_dfu.h Здесь содержатся callback-функции класса DFU (драйвер) и дескрипторы конфигурации, относящиеся к этому классу.
usbd_dfu_media_template_if.c, usbd_dfu_media_template_if.h Шаблон драйвера, который позволит Вам реализовать дополнительные интерфейсы к памяти класса DFU.

[Класс USB HID]

Реализация класса HID. Этот модуль содержит HID class V1.11, в соответствии со спецификацией "Device Class Definition for Human Interface Devices (HID) Version 1.11 June 27, 2001".

Примечание: спецификацию HID можно найти поиском по ключевому слову hidpage на сайте www.st.com.

Этот драйвер реализует следующие аспекты спецификации:

• Подкласс интерфейса загрузки (boot interface subclass).
• Протокол мыши.
• Usage page: generic desktop (стандартный десктоп).
• Usage: джойстик.
• Collection: приложение.

Пользовательский интерфейс HID. Входные репорты (input reports) отправляются через канал прерывания IN (Interrupt In pipe, см. пример HID mouse).

Репорты Feature и Output должны инициироваться хостом через управляющий канал (Control pipe) или канал прерывания OUT (Interrupt Out pipe, см. пример Custom HID).

Примечание: направления IN и OUT обозначаются по отношению к хосту USB (хост это обычно компьютер или смартфон). Таким образом, канал IN это канал для данных от устройства USB к хосту, а канал OUT это канал для данных от хоста к устройству USB.

Приложением HID mouse для отправки HID-репортов может использоваться функция USBD_HID_SendReport. В этом релизе драйвер HID обрабатывает только трафик IN. Ниже показан пример использования этой функции:

static __IO uint32_t counter=0;
HAL_IncTick();/* Проверка состояния джойстика каждые 10 мс */if (counter++ == 10)
{
   GetPointerData(HID_Buffer);
   /* Отправка данных через конечную точку IN */
   if((HID_Buffer[1] != 0) || (HID_Buffer[2] != 0))
   {
      USBD_HID_SendReport(&USBD_Device, HID_Buffer, 4);
   }
   counter =0;
}
Toggle_Leds();

HID Class Driver API. Ниже в таблице суммарно показаны API-функции драйвера HID-класса, определенные в модуле usbd_hid.c.

Таблица 14. Функции в файлах usbd_hid.c, usbd_hid.h.

Функция Описание
USBD_HID_Init Инициализирует интерфейс HID и откроет используемые конечные точки.
USBD_HID_DeInit Отменяет инициализацию слоя HID и закрывает используемые конечные точки.
USBD_HID_Setup Обрабатывает специфические запросы HID.
USBD_HID_SendReport Отправляет репорты HID.

Прототипы функций таблицы 14:

static uint8_t USBD_HID_Init (USBD_HandleTypeDef *pdev,
                              uint8_t cfgidx);
static uint8_t USBD_HID_DeInit (USBD_HandleTypeDef *pdev,
                                uint8_t cfgidx);
static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
                               USBD_SetupReqTypedef *req);
uint8_t USBD_HID_SendReport (USBD_HandleTypeDef *pdev,
                             uint8_t *report,
                             uint16_t len);

Стек HID инициализируется вызовом USBD_HID_Init(), затем приложение должно вызывать функцию USBD_HID_SendReport() для отправки репортов HID.

Через конечную точку 0 (EP0, Control, конечная точка управления) реализованы следующие запросы, специфичные для HID:

#define HID_REQ_SET_PROTOCOL  0x0B
#define HID_REQ_GET_PROTOCOL  0x03
#define HID_REQ_SET_IDLE      0x0A
#define HID_REQ_GET_IDLE      0x02
#define HID_REQ_SET_REPORT    0x09
#define HID_REQ_GET_REPORT    0x01

Адрес конечной точки IN и максимальное количество байт, которое можно отправить, задаются определениями:

#define HID_EPIN_ADDR         0x81
#define HID_EPIN_SIZE         0x04

[Класс Mass Storage (USB MSC)]

Реализация класса Mass Storage. Этот модуль обслуживает MSC class V1.0 в соответствии со спецификацией "Universal Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0 Sep. 31, 1999".

Драйвер реализует следующие аспекты спецификации:

• Протокол транспорта Bulk-only (только пакетные передачи).
• Подкласс: SCSI transparent command set (прозрачный набор команд SCSI, основной набор команд SCSI Primary Commands - 3).

Класс USB mass storage построен вокруг Bulk Only Transfer (BOT). Он использует прозрачный набор команд SCSI.

Стандартная BOT-транзакция основана на простой машине состояний. Она начинается с ready state (idle state). Если от хоста принят CBW, могут обслуживается 3 случая:

• DATA-OUT-STAGE: когда флаг направления установлен в "0", устройство должно быть подготовлено к приему количества данных, показанного полем cbw.dDataLength блока CBW. По окончанию передачи данных возвращается CSW с оставшейся длиной данных и поле STATUS.
• DATA-IN-STAGE: когда флаг направления установлен в "1", устройство должно быть подготовлено к отправке количества данных, указанного полем cbw.dDataLength в блоке CBW. По окончанию передачи данных возвращается CSW с оставшейся длиной данных и поле STATUS.
• ZERO DATA: в этом случае не требуется стадия данных, и сразу после CBW отправляется блок CSW.

STM32Cube BOT Protocol architecture fig13

Рис. 13. Архитектура протокола BOT.

В следующей таблице показаны поддерживаемые команды SCSI.

Таблица 15. Команды SCSI.

Команда Комментарий
SCSI_PREVENT_REMOVAL  
SCSI_START_STOP_UNIT  
SCSI_TEST_UNIT_READY  
SCSI_INQUIRY  
SCSI_READ_CAPACITY10  
SCSI_READ_FORMAT_CAPACITY READ_FORMAT_CAPACITY (0x23) это команда UFI.
SCSI_MODE_SENSE6  
SCSI_MODE_SENSE10  
SCSI_READ10  
SCSI_WRITE10  
SCSI_VERIFY10  

Реализован запрос сброса устройства хранения (Bulk-only mass storage reset request, это запрос, специфический для класса), как того требует спецификация BOT. Это запрос используется для сброса устройства хранения (mass storage device) и связанного с ним интерфейса. Этот специфический для класса запрос должен подготовить устройство для поступления от хоста следующего CBW.

Чтобы генерировать BOT Mass Storage Reset, хост должен отправить запрос устройству на канале по умолчанию (default pipe):

• bmRequestType: тип запроса Class, interface, от хоста к устройству
• поле bRequest, установленное в 255 (FFh)
• поле wValue, установленное в 0
• поле wIndex, установленное в номер интерфейса
• поле wLength, установленное в 0

Get Max MUN (специфический для класса запрос). Устройство может реализовать несколько логических юнитов (LUN), которые используют общие характеристики устройства. Хост использует bCBWLUN, чтобы показать, какой LUN устройства является пунктом назначения для CBW. Запрос к устройству Get Max LUN используется для того, чтобы определить количество LUN, поддерживаемых устройством.

Для генерации запроса Get Max LUN для устройства, хост отправляет запрос на канале по умолчанию (default pipe):

• bmRequestType: тип запроса Class, Interface, от устройства к хосту
• поле bRequest, установленное в 254 (FEh)
• поле wValue, установленное в 0
• поле wIndex, установленное в номер интерфейса
• поле wLength, установленное в 1

Файлы ядра MSC. Ниже в таблицах показаны модули класса устройства хранения и их функции с кратким описанием.

Таблица 16. Функции в файлах usbd_msc.c, usbd_msc.h.

Функция Описание
USBD_MSC_Init Инициализирует интерфейс MSC и откроет используемые конечные точки.
USBD_MSC_DeInit Отменяет инициализацию слоя MSC и закрывает используемые конечные точки.
USBD_MSC_Setup Обрабатывает специфические запросы MSC.
USBD_MSC_DataIn Обрабатывает стадию получения данных (MSC Data In).
USBD_MSC_DataOut Обрабатывает стадию отправки данных (MSC Data Out).

Прототипы функций таблицы 16:

uint8_t USBD_MSC_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
uint8_t USBD_MSC_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
uint8_t USBD_MSC_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
uint8_t USBD_MSC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
uint8_t USBD_MSC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);

Таблица 17. Функции в файлах usbd_msc_bot.c, usbd_msc_bot.h.

Функция Описание
MSC_BOT_Init Инициализирует обработку BOT и физический носитель данных.
MSC_BOT_Reset Сбрасывает машину состояний BOT.
MSC_BOT_DeInit Отменяет инициализацию обработки BOT.
MSC_BOT_DataIn Обрабатывает стадию получения данных (BOT Data In).
MSC_BOT_DataOut Обрабатывает стадию отправки данных (BOT Data Out).
MSC_BOT_CBW_Decode Декодирует команду CBW и соответственно устанавливает машину состояний BOT.
MSC_BOT_SendData Отправляет запрошенные данные.
MSC_BOT_SendCSW Отправляет Command Status Wrapper (CSW).
MSC_BOT_Abort Обрывает текущую транзакцию.
MSC_BOT_CplClrFeature Завершает запрос очистки функции (Clear Feature).

Прототипы функций таблицы 17:

void MSC_BOT_Init (USBD_HandleTypeDef *pdev);
void MSC_BOT_Reset (USBD_HandleTypeDef *pdev);
void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev);
void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev);
static void MSC_BOT_SendData (USBD_HandleTypeDef *pdev, uint8_t* buf, uint16_t len);
void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev, uint8_t CSW_Status);
static void MSC_BOT_Abort (USBD_HandleTypeDef *pdev);
void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, uint8_t epnum);

Таблица 18. Функции в файлах usbd_msc_scsi.c, usbd_msc_scsi.h.

Функция Описание
SCSI_ProcessCmd Обрабатывает команду SCSI.
SCSI_TestUnitReady Обрабатывает команду проверки готовности SCSI.
SCSI_Inquiry Обрабатывает команду Inquiry (запрос).
SCSI_ReadCapacity10 Обрабатывает команду Read Capacity 10.
SCSI_ReadFormatCapacity Обрабатывает команду Read Format Capacity.
SCSI_ModeSense6 Обрабатывает команду Mode Sense 6.
SCSI_ModeSense10 Обрабатывает команду Mode Sense 10.
SCSI_RequestSense Обрабатывает команду Request Sense.
SCSI_SenseCode Загружает последний код ошибки в список ошибок.
SCSI_StartStopUnit Обрабатывает команду Start Stop Unit.
SCSI_Read10 Обрабатывает команду Read10.
SCSI_Write10 Обрабатывает команду Write10.
SCSI_Verify10 Обрабатывает команду Verify10.
SCSI_CheckAddressRange Проверяет, находится ли LBA в допустимом диапазоне адресов.
SCSI_ProcessRead Обрабатывает процесс Burst Read.
SCSI_ProcessWrite Обрабатывает процесс Burst Write.

Прототипы функций таблицы 18:

int8_t SCSI_ProcessCmd (USBD_HandleTypeDef *pdev,
                        uint8_t lun,
                        uint8_t *params);
static int8_t SCSI_TestUnitReady (USBD_HandleTypeDef *pdev,
                                  uint8_t lun,
                                  uint8_t *params);
static int8_t SCSI_Inquiry (USBD_HandleTypeDef *pdev,
                            uint8_t lun,
                            uint8_t *params);
static int8_t SCSI_ReadCapacity10 (USBD_HandleTypeDef *pdev,
                                   uint8_t lun,
                                   uint8_t *params);
static int8_t SCSI_ReadFormatCapacity (USBD_HandleTypeDef *pdev,
                                       uint8_t lun,
                                       uint8_t *params);
static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev,
                               uint8_t lun,
                               uint8_t *params);
static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev,
                                uint8_t lun,
                                uint8_t *params);
static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev,
                                 uint8_t lun,
                                 uint8_t *params);
void SCSI_SenseCode (USBD_HandleTypeDef *pdev,
                     uint8_t lun,
                     uint8_t sKey,
                     uint8_t ASC);
static int8_t SCSI_StartStopUnit (USBD_HandleTypeDef *pdev,
                                  uint8_t lun,
                                  uint8_t *params);
static int8_t SCSI_Read10 (USBD_HandleTypeDef *pdev,
                           uint8_t lun,
                           uint8_t *params);
static int8_t SCSI_Write10 (USBD_HandleTypeDef *pdev,
                            uint8_t lun,
                            uint8_t *params);
static int8_t SCSI_Verify10 (USBD_HandleTypeDef *pdev,
                             uint8_t lun,
                             uint8_t *params);
static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev,
                                      uint8_t lun,
                                      uint32_t blk_offset,
                                      uint16_t blk_nbr);
static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev,
                                uint8_t lun);
static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev,
                                 uint8_t lun);

Структура для операций диска.

USBD_StorageTypeDef USBD_DISK_fops = {
   STORAGE_Init,
   STORAGE_GetCapacity,
   STORAGE_IsReady,
   STORAGE_IsWriteProtected,
   STORAGE_Read,
   STORAGE_Write,
   STORAGE_GetMaxLun,
   STORAGE_Inquirydata,
};

Примечание: MicroSD - интерфейс носителя памяти по умолчанию (default media interface), предоставленный в библиотеке. Однако Вы можете добавить другие носители данных (память Flash, SDRAM, и т. п.), используя файл шаблона usbd_msc_storage_template.c.

Функция callback хранилища для класса MSC добавляется в приложение пользователя путем вызова USBD_MSC_RegisterStorage(&USBD_Device, &USBD_DISK_fops).

Данные стандартного запроса предоставляются пользователем в массиве STORAGE_Inquiry. Он должен быть определен следующим образом:

int8_t STORAGE_Inquirydata[] = { /* 36 */
   /* LUN 0 */
   0x00,
   0x80,
   0x02,
   0x02,
   (STANDARD_INQUIRY_DATA_LEN - 5),
   0x00,
   0x00,
   0x00,
   'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ',   /* Производитель: 8 байт */
   'P', 'r', 'o', 'd', 'u', 'c', 't', ' ',   /* Продукт: 16 байт */
   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
   '0', '.', '0','1',                        /* Версия: 4 байта */
};

Таблица 19. Функции дисковых операций.

Функция Описание
STORAGE_Init Инициализирует носитель данных (storage medium).
STORAGE_GetCapacity Вернет емкость носителя данных и размер блока.
STORAGE_IsReady Проверяет, готов ли носитель данных.
STORAGE_IsWriteProtected Проверяет, защищен ли от записи носитель данных.
STORAGE_Read Читает данные с носителя. Параметр blk_addr дается в единицах сектора, blk_len количество обрабатываемых секторов.
STORAGE_Write Записывает данные на носитель. Параметр blk_addr дается в единицах сектора, blk_len количество обрабатываемых секторов.
STORAGE_GetMaxLun Возвращает количество поддерживаемых LUN.

Прототипы функций таблицы 19:

int8_t STORAGE_Init (uint8_t lun);
int8_t STORAGE_GetCapacity (uint8_t lun,
                            uint32_t *block_num,
                            uint16_t *block_size);
int8_t STORAGE_IsReady (uint8_t lun);
int8_t STORAGE_IsWriteProtected (uint8_t lun);
int8_t STORAGE_Read (uint8_t lun,
                     uint8_t *buf,
                     uint32_t blk_addr,
                     uint16_t blk_len);
int8_t STORAGE_Write (uint8_t lun,
                      uint8_t *buf,
                      uint32_t blk_addr,
                      uint16_t blk_len);
int8_t STORAGE_GetMaxLun (void);

[Класс обновления прошивки (DFU)]

Ядро класса DFU обслуживает протокол в соответствии со стандартом "Device Class Specification for Device Firmware Upgrade Version 1.1 Aug 5, 2004".

Реализованы следующие аспекты спецификации:

• Обслуживание дескриптора устройства.
• Обслуживание дескриптора конфигурации.
• Энумерация на шине USB как устройства DFU (только в режиме DFU).
• Обслуживание запросов (поддержка разновидности протокола ST DFU).
• Обслуживания запроса к памяти (Download / Upload / Erase / Detach / GetState / GetStatus).
• Машина состояний DFU.

Примечание: разновидность протокола DFU от компании ST (ST DFU sub-protocol) совместима с протоколом DFU. Она использует sub-запросы для обслуживания адресации памяти, обработки команд, специфических операций с памятью (стирание памяти, чтение, запись, и т. д.).

Как требует спецификация DFU, в этом приложении используется только конечная точка 0 (EP0, endpoint 0, или конечная точка управления).

В приложение могут быть добавлены другие конечные точки и функции (HID, и т. п.).

Эти аспекты могут быть расширены или изменены для определенного пользовательского приложения.

Драйвер USB не реализует режим Manifestation Tolerant, определенный в спецификации. Однако есть возможность обслуживать эту функцию путем модификации драйвера.

Реализация класса DFU. Транзакции DFU основаны на endpoint 0 (EP0, управляющая конечная точка). Все запросы и управление состоянием отправляются/принимаются через EP0.

Машина DFU основывается на следующих состояниях:

Таблица 20. Состояния DFU.

Состояние Код состояния
appIDLE 0x00
appDETACH 0x01
dfuIDLE 0x02
dfuDNLOAD-SYNC 0x03
dfuDNBUSY 0x04
dfuDNLOAD-IDLE 0x05
dfuMANIFEST-SYNC 0x06
dfuMANIFEST 0x07
dfuMANIFEST-WAIT-RESET 0x08
dfuUPLOAD-IDLE 0x09
dfuERROR 0x0A

Разрешенные переходы между состояниями описаны в документе спецификации DFU.

STM32Cube DFU Interface state transitions diagram fig16

Рис. 16. Диаграмма перехода состояний интерфейса DFU.

Чтобы защитить приложение от случайных доступов перед инициализацией, начальное состояние ядра DFU (после запуска) будет dfuERROR. Тогда хост должен очистить это состояние путем отправки запроса DFU_CLRSTATE перед генерацией любого другого запроса.

Ядро DFU обслуживает все поддерживаемые запросы (см. таблицу 21).

Таблица 21. Поддерживаемые запросы DFU.

Запрос Код Подробности
DFU_DETACH 0x00 Когда установится бит 3 в поле bmAttributes (бит WillDetach), устройство генерирует последовательность отсоединения-подсоединения (detach-attach sequence) на шине, когда получит этот запрос.
DFU_DNLOAD 0x01 Образ firmware загружается через транзакции управления-записи (control-write transfer), инициированный запросом DFU_DNLOAD, специфичным для класса DFU.
DFU_UPLOAD 0x02 Назначение этого запроса - дать возможности считать прошивку firmware с целью её архивирования.
DFU_GETSTATUS 0x03 Хост применяет запрос DFU_GETSTATUS, чтобы упростить синхронизацию с устройством (оно может быть занято стиранием памяти, записью данных или другими операциями).
DFU_CLRSTATUS 0x04 При получении запроса DFU_CLRSTATUS устройство установит статус OK и перейдет в состояние dfuIDLE.
DFU_GETSTATE 0x05 Этот запрос требует отсчета о состоянии устройства.
DFU_ABORT 0x06 Запрос DFU_ABORT позволяет хосту выйти из определенных состояний и вернуться в состояние DFU_IDLE.

Каждая транзакция к EP0 одной из двух категорий.

• Data transfer: эти транзакции используются для:

   – получения некоторых данных из устройства (DFU_GETSTATUS, DFU_GETSTATE и DFU_UPLOAD).
   – или для отправки данных в устройство (DFU_DNLOAD).

• No-Data transfer: эти транзакции используются для отправки запросов управления от хоста к устройству (DFU_CLRSTATUS, DFU_ABORT и DFU_DETACH).

Файлы ядра класса DFU. Реализация этого драйвера находится в модуле usbd_dfu.c и его заголовочном файле usbd_dfu.h. Здесь обслуживаются все запросы DFU и машина состояний DFU. Модуль не работает напрямую с носителем памяти (это осуществляется драйверами низкого уровня).

Таблица 22. Функции в файлах usbd_dfu.c, usbd_dfu.h.

Функция Описание
USBD_DFU_Init Инициализирует интерфейс DFU.
USBD_DFU_DeInit Отменяет инициализацию слоя DFU.
USBD_DFU_Setup Парсинг запроса DFU.
USBD_DFU_EP0_TxReady Обрабатывает событие Rx Ready конечной точки EP0.
USBD_DFU_EP0_RxReady Обрабатывает событие Tx Ready конечной точки EP0.
USBD_DFU_GetUsrStringDesc Обслуживает строковые дескрипторы интерфейсов памяти.
DFU_Detach Обрабатывает запрос DFU DETACH.
DFU_Download Обрабатывает запрос DFU DNLOAD.
DFU_Upload Обрабатывает запрос DFU UPLOAD.
DFU_GetStatus Обрабатывает запрос DFU GETSTATUS.
DFU_ClearStatus Обрабатывает запрос DFU CLRSTATUS.
DFU_GetState Обрабатывает запрос DFU GETSTATE.
DFU_Abort Обрабатывает запрос DFU ABORT.
DFU_Leave Обрабатывает запрос sub-протокола DFU для выхода из режима DFU (происходит выход из режима DFU и сброс устройства для запуска загруженного пользователем кода firmware).

Примечание: внутренняя память Flash это память по умолчанию, которая обслуживается библиотекой. Однако Вы можете добавить другие носители памяти, используя файл шаблона usbd_dfu_media_template.c.

Прототипы функций таблицы 22:

static uint8_t USBD_DFU_Init (USBD_HandleTypeDef *pdev,
                              uint8_t cfgidx);
static uint8_t USBD_DFU_DeInit (USBD_HandleTypeDef *pdev,
                                uint8_t cfgidx);
static uint8_t USBD_DFU_Setup (USBD_HandleTypeDef *pdev,
                               USBD_SetupReqTypedef *req);
static uint8_t USBD_DFU_EP0_TxReady (USBD_HandleTypeDef *pdev);
static uint8_t USBD_DFU_EP0_RxReady (USBD_HandleTypeDef *pdev);
static uint8_t* USBD_DFU_GetUsrStringDesc (USBD_HandleTypeDef *pdev,
                                           uint8_t index,
                                           uint16_t *length);
static void DFU_Detach (USBD_HandleTypeDef *pdev,
                        USBD_SetupReqTypedef *req);
static void DFU_Download (USBD_HandleTypeDef *pdev,
                          USBD_SetupReqTypedef *req);
static void DFU_Upload (USBD_HandleTypeDef *pdev,
                        USBD_SetupReqTypedef *req);
static void DFU_GetStatus (USBD_HandleTypeDef *pdev);
static void DFU_ClearStatus (USBD_HandleTypeDef *pdev);
static void DFU_GetState (USBD_HandleTypeDef *pdev);
static void DFU_Abort (USBD_HandleTypeDef *pdev);
static void DFU_Leave (USBD_HandleTypeDef *pdev);

Чтобы использовать драйвер DFU:

1. Задайте в файле usbd_conf.h следующие параметры:

   – количество поддерживаемых носителей (видов памяти) в #define USBD_DFU_MAX_ITF_NUM.
   – адрес приложения по умолчанию (куда должен быть загружен образ двоичного кода) в #define USBD_DFU_APP_DEFAULT_ADD.

2. Вызовите функцию USBD_DFU_Init() для инициализации всех интерфейсов памяти и машины состояний DFU.

3. Все операции управления/запроса (control/request) выполняются через EP0 с помощью функций USBD_DFU_Setup() и USBD_DFU_EP0_TxReady(). Эти функции можно использовать для вызова callback каждой памяти (read / write /erase / get state, ...), в зависимости от сгенерированных запросов DFU. Для этих операций от пользователя не требуется никаких действий.

4. Чтобы закрыть коммуникацию, вызовите функцию USBD_DFU_DeInit().

Примечание: когда запускается приложение DFU, то по умолчанию состояние его машины DFU_STATE_ERROR. Это состояние установлено, чтобы защитить приложение от случайных операций перед тем, как будет установлена корректная конфигурация устройства.

[Класс USB Audio]

Драйвер реализует Audio Class 1.0 в соответствии со стандартом "USB Device Class Definition for Audio Devices V1.0 Mar 18, 98". Реализованы следующие аспекты спецификации:

• Обслуживание дескриптора устройства.
• Обслуживание дескриптора конфигурации.
• Обслуживание стандартного дескриптора интерфейса класса аудио (Standard AC Interface Descriptor).
• 1 Audio Streaming Interface (с одним каналом, PCM, режим Stereo).
• 1 Audio Streaming endpoint.
• 1 Audio Terminal Input (1 канал).
• Audio Class-Specific AC Interfaces.
• Audio Class-Specific AS Interfaces.
• Audio Control Requests: поддерживаются только запросы SET_CUR и GET_CUR (для функции Mute).
• Audio Feature Unit (ограниченный управлением Mute).
• Audio Synchronization type: Asynchronous.
• Одна фиксированная скорость следования выборок звука (audio sampling rate, конфигурируется в файлеusbd_conf.h).

Примечание: Audio Class 1.0 основан на USB 1.0, и поэтому поддерживаются только режимы скоростей Low Speed и Full Speed (транзакции High Speed не поддерживаются). За подробностями обращайтесь к стандарту "USB Device Class Definition for Audio Devices V1.0 Mar 18, 98".

Перечисленные аспекты могут быть расширены или модифицированы для специфичного приложения пользователя.

В этом драйвере не реализованы следующие аспекты спецификации (однако их можно обслуживать путем некоторых модификаций драйвера):

• Управление Audio Control endpoint.
• Другие запросы Audio Control, кроме реализованных SET_CUR и GET_CUR.
• Слой абстракции для запросов Audio Control (в настоящий момент обслуживается только функция mute).
• Audio Synchronization type: Adaptive.
• Модули и интерфейсы Audio Compression.
• Интерфейсы и модули MIDI.
• Юниты Mixer / Selector / Processing / Extension (представлен только юнит управления функцией Mute).
• Другие модули, специфичные для приложения.
• Несколько вариантов частоты выборок, переменная частота выборок.
• Audio Out Streaming Endpoint / Interface (микрофон, оцифровка звука).

Реализация класса Audio. Транзакции звука основаны на isochronous endpoint. Запросы управления (Audio control request) также обслуживаются через control endpoint (endpoint 0).

В каждом фрейме передается пакет данных звука, и он должен быть обработан (преобразован в звук) в течение этого фрейма (перед поступления следующего фрейма). Качество звука зависит от синхронизации между транзакциями данных и воспроизведением данных в качестве звука. Этот драйвер реализует простой механизм синхронизации процессов передачи и воспроизведения, полагаясь на точность передаваемой тактовой частоты I2S. В каждом начале фрейма драйвер проверяет, были ли израсходованы данные предыдущего пакета, обрывает запрос передачи, если предыдущие данные все еще воспроизводятся. Для предотвращения перезаписи данных используются 2 основных механизма защиты:

• DMA для перемещения данных между буфером USB и регистрами устройства вывода (I2S).
• Использование нескольких буферов для хранения данных, поступающих от USB.

На основе этого механизма, если точность тактов или частота воспроизведения недостаточно высока, то получится плохое качество звука. Этот механизм может быть улучшен путем реализации более гибкого управления потоком звуковых данных наподобие режима USB feedback, динамической коррекции тактирования звука или генерации/управления тактами звука на основе события начала фрейма (SOF event).

Этот драйвер также поддерживает базовые запросы управления звуком (Audio Control). Чтобы упростить драйвер, реализована обработка только двух запросов. Однако другие запросы могут быть поддержаны путем незначительной модификации драйвера.

Таблица 23. Запросы Audio control.

Запрос Поддерживается Назначение
SET_CUR ДА Устанавливает режим Mute в состояние On или Off (может быть также обновлено для установки уровня громкости).
SET_MIN нет -
SET_MAX нет -
SET_RES нет -
SET_MEM нет -
GET_CUR ДА Получает текущее состояние режима Mute (может быть обновлено до получения текущего уровня громкости).
GET_MIN нет -
GET_MAX нет -
GET_RES нет -
GET_MEM нет -

Файлы класса Audio. Основной код драйвера реализован в модуле usbd_audio_core.c и его заголовочном файле usbd_audio_core.h. Он управляет транзакциями audio-данных и запросами управления (control request). Драйвер не работает напрямую с аппаратурой звука (это обслуживается низкоуровневыми драйверами).

Таблица 24. Функции в файлах usbd_audio_core.c, usbd_audio_core.h.

Функция Описание
USBD_AUDIO_Init Инициализирует интерфейс класса AUDIO.
USBD_AUDIO_DeInit Отменяет инициализацию интерфейса класса AUDIO.
USBD_AUDIO_Setup Обрабатывает запросы, специфические для класса AUDIO.
USBD_AUDIO_EP0_RxReady Обрабатывает событие готовности EP0 Rx (есть звуковые данные).
USBD_AUDIO_DataIn Обрабатывает стадию Data IN.
USBD_AUDIO_DataOut Обрабатывает стадию Data OUT.
USBD_AUDIO_SOF Обрабатывает событие начала фрейма (SOF). Предназначено для синхронизации с обновлением буфера.
AUDIO_REQ_GetCurrent Обрабатывает запрос управления GET_CUR класса AUDIO.
AUDIO_REQ_SetCurrent Обрабатывает запрос управления SET_CUR класса AUDIO.

Прототипы функций таблицы 24:

static uint8_t USBD_AUDIO_EP0_RxReady (USBD_HandleTypeDef *pdev);
static uint8_t USBD_AUDIO_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_AUDIO_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_AUDIO_SOF (USBD_HandleTypeDef *pdev);
static void AUDIO_REQ_GetCurrent(USBD_HandleTypeDef *pdev,
                                 USBD_SetupReqTypedef *req);
static void AUDIO_REQ_SetCurrent(USBD_HandleTypeDef *pdev,
                                 USBD_SetupReqTypedef *req);

Интерфейс низкоуровневого слоя аппаратуры обслуживается через его соответствующую структуру драйвера:

typedef struct
{
   int8_t (*Init) (uint32_t AudioFreq, uint32_t Volume, uint32_t options);
   int8_t (*DeInit) (uint32_t options);
   int8_t (*AudioCmd) (uint8_t* pbuf, uint32_t size, uint8_t cmd);
   int8_t (*VolumeCtl) (uint8_t vol);
   int8_t (*MuteCtl) (uint8_t cmd);
   int8_t (*PeriodicTC) (uint8_t cmd);
   int8_t (*GetState) (void);
}USBD_AUDIO_ItfTypeDef;

Каждый звуковой аппаратный интерфейс драйвер должен предоставить указатель на структуру типа USBD_AUDIO_ItfTypeDef. Функции и константы, на которые указывает эта структура, перечислены в следующих секциях. Если какая-то функциональность не поддерживается в имеющемся интерфейсе памяти, то соответствующее поле устанавливается в значение NULL.

usbd_audio_if.c, usbd_audio_if.h. Этот драйвер на низком уровне управляет аппаратурой звука - интерфейсом Audio Out (обслуживание преобразования данных USB в звук динамика / наушников). Пользователь может вызвать низкоуровневый драйвер кодека (Codec driver, например stm324xg_eval_audio.c, stm324xg_eval_audio.h) для базовых операций со звуком (play / pause / volume control, ...).

Этот драйвер предоставляет указатель на структуру:

extern USBD_AUDIO_ItfTypeDef USBD_AUDIO_fops;

Таблица 25. Функции usbd_audio_if.c, usbd_audio_if.h.

Функция Описание
Audio_Init Инициализирует интерфейс звука.
Audio_DeInit Отменяет инициализацию интерфейса звука и используемых ресурсов.
Audio_PlaybackCmd Обрабатывает команды плеера (play, pause, ...).
Audio_VolumeCtl Обрабатывает громкостью плеера.
Audio_MuteCtl Обрабатывает состояние режима Mute плеера.
Audio_PeriodicTC Обрабатывает окончание текущей передачи пакета (не требуется для текущей версии драйвера).
Audio_GetState Возвращает текущее состояние драйвера аудиоплеера (Playing / Paused / Error / ...).

Примечание: файлы шаблона (usbd_audio_if_template.c, usbd_audio_if_template.h) предоставляют базовый пример драйвера, который позволит Вам реализовать дополнительные функции для своего приложения Audio.

Прототипы функций таблицы 25:

static int8_t Audio_Init (uint32_t AudioFreq, uint32_t Volume, uint32_t options);
static int8_t Audio_DeInit (uint32_t options);
static int8_t Audio_PlaybackCmd (uint8_t* pbuf, uint32_t size, uint8_t cmd);
static int8_t Audio_VolumeCtl (uint8_t vol);
static int8_t Audio_MuteCtl (uint8_t cmd);
static int8_t Audio_PeriodicTC (uint8_t cmd);
static int8_t Audio_GetState (void);

Обслуживаются состояния приложения Audio player, показанные в таблице ниже.

Таблица 26. Состояния Audio player.

Состояние Код Описание
AUDIO_CMD_START 0x00 Аудиоплеер инициализирован и готов к работе.
AUDIO_CMD_PLAY 0x01 Аудиоплеер воспроизводит звук.
AUDIO_CMD_STOP 0x02 Аудиоплеер остановил воспроизведение звука.

Как использовать драйвер USB Audio. Этот драйвер использует слой абстракции от драйвера аппаратуры (например аппаратный кодек, интерфейс I2S, интерфейс управления через I2C, и т. п.). Эта абстракция выполняется через модуль нижнего слоя (например usbd_audio_if.c), который Вы можете модифицировать в зависимости от аппаратуры, доступной для приложения.

Для использования драйвера выполните следующие действия:

1. Сконфигурируйте в файле usbd_conf.h необходимую частоту выборок звука, audio sampling rate (#define USBD_AUDIO_FREQ).

2. При запуске приложения вызовите функцию USBD_AUDIO_Init() для конфигурирования всех необходимых программных и аппаратных компонентов (функции конфигурирования аппаратуры, специфичные для приложения, также вызываются из этой функции). Аппаратные компоненты управляются через низкоуровневый интерфейс (например usbd_audio_if.c), и это может быть изменено пользователем в зависимости от требований приложения.

3. Транзакция полностью обслуживается функциями (пользователю не нужно вызывать никакую функцию для out-транзакций) usbd_audio_DataIn() и usbd_audio_DataOut(), которые обновляют буферы звука принятыми или переданными данными. Для Out-транзакций, когда принимаются данные, они напрямую копируются в звуковой буфер, и инкрементируется указатель буфера записи (wr_ptr).

4. Запросы управления Audio Control обслуживаются функциями USBD_AUDIO_Setup() и USBD_AUDIO_EP0_RxReady(). Эти функции перенаправляют запросы Audio Control на нижний уровень (например, usbd_audio_if.c). В текущей версии драйвера поддерживаются только запросы SET_CUR и GET_CUR для управления функцией выключения звука (mute control).

Известные ограничения:

• Если сконфигурирована низкая частота выборок (#define USBD_AUDIO_FREQ ниже 24 кГц), то могут быть помехи в звуке при операциях pause / resume / stop. Причина в интервале времени между остановкой тактов I2S и отправкой команды mute внешнему кодеку (external Codec).
• Этим драйвером поддерживаются скорости выборок от 96 кГц до 24 кГц (не поддерживаются частоты, которые не делятся нацело на 1 кГц, наподобие 11.025 кГц, 22.05 кГц или 44.1 кГц). Для частот, делящихся на 1000 Гц, хост будет отправлять целое количество байт в каждом фрейме (с частотой 1 мс). Когда частота выборок звука не делится нацело на 1000 Гц, хост должен отправлять не целое количество байт во фрейме. Фактически это приведет к отправке фреймов с разными размерами (например, для частоты выборок 22.05 кГц хост будет отправлять 19 фреймов по 22 байта и один фрейм с 23 байтами). Это различие в размерах не поддерживается ядром драйвера Audio, и дополнительный байт будет игнорироваться. Рекомендуется установить высокую и стандартную частоту выборок, чтобы получить самое лучшее качество звука (например 96 кГц или 48 кГц). Обратите внимание, что максимально допустимая частота звука 96 кГц, это ограничение происходит из-за используемого кодека (Codec) на оценочной плате (Evaluation board). Блок STM32 I2S позволяет достичь частоты выборок 192 кГц.

[Класс USB CDC]

Драйвер класса коммуникационного устройства USB (Communication device class, CDC) работает в соответствии со стандартом "Universal Serial Bus Class Definitions for Communications Devices Revision 1.2 November 16, 2007" и sub-протоколом "Universal Serial Bus Communications Class Subclass Specification for PSTN Devices Revision 1.2 February 9, 2007".

Этот драйвер реализует следующие аспекты спецификации:

• Обслуживание дескриптора устройства.
• Обслуживание дескриптора конфигурации.
• Энумерация как устройства CDC с двумя конечными точками данных (IN и OUT), и одной конечной точкой команд (IN).
• Обслуживание запроса (как это описано в секции 6.2 спецификации).
• Совместимость с Abstract Control Model.
• Коллекция Union Functional (для управления используется одна конечная точка IN).
• Класс интерфейса данных.

Эти аспекты могут быть расширены и улучшены для специфического приложения пользователя.

Примечание: для поддержки Abstract Control Model эта реализация только передает запросы на диспетчер нижнего уровня (например usbd_cdc_vcp.c/usbd_cdc_vcp.h), которые должен обслуживать каждый запрос и выполняет соответствующие действия.

Этот драйвер не реализует следующие аспекты спецификации (однако можно обслужить эти функции путем некоторых модификаций кода драйвера):

• Любой специфический для класса аспект, относящийся к коммуникационному классу, должен обрабатываться приложением пользователя.
• Не обслуживаются все коммуникационные классы, кроме PSTN.

Ядро CDC использует два типа конечных точек/транзакций:

• Конечные точки Bulk endpoint для передач данных (1 OUT endpoint и 1 IN endpoint).
• Конечные точки Interrupt endpoint для управления коммуникацией (запросы CDC; 1 IN endpoint).

Передачи данных для транзакций IN и OUT обслуживаются по-разному.

Обслуживание Data IN transfer (от устройства к хосту). Транзакция данных обслуживается периодически, в зависимости от запроса хоста (устройство задает интервал между пакетами запроса). По этой причине для сохранения отправляемых в терминал данных используется статический буфер (например USART в случае терминала Virtual COM Port).

Обслуживание Data OUT transfer (от хоста к устройству). Обычно канал передачи данных USB намного быстрее, чем вывод терминала (например, максимальная скорость бит для USART составляет 115.2 Kbps, в то время как скорость USB составляет 12 Mbps для режима Full Speed и 480 Mbps в режиме High Speed). Соответственно перед отправкой новых пакетов хост ждет, пока устройство не завершит обработку данных, которые ранее передал хост. Таким образом, не требуется кольцевой буфер, когда данные принимаются от хоста: драйвер вызывает функцию низкого уровня для OUT транзакции и ждет, пока эта функция не завершится, перед тем, как будут разрешены новые транзакции на OUT endpoint (при этом пакеты OUT будут отклоняться, NACK).

Обслуживание Command request. В этом драйвере управляющая конечная точка (control endpoint, endpoint 0, EP0) используется для обслуживания запросов управления. Однако для обслуживания команд также может использоваться data interrupt endpoint. Если размер данных запроса не превышает 64 байт, то размер endpoint 0 достаточен для обслуживания этих запросов.

Драйвер CDC не делает парсинг командных запросов. Вместо этого он вызывает функцию низкоуровневого драйвера управления с кодом запроса, длиной и буфером данных. Тогда эта функция должна обработать запрос, и выполнить соответствующие требуемые действия.

Файлы драйвера USB CDC. Ядро драйвера находится в файлах usbd_cdc.c, usbd_cdc.h. Этот код обслуживает транзакции данных и запросы управления. Он не работает напрямую с аппаратурой CDC (это обслуживается драйверами низкого уровня).

Таблица 27. Функции в файлах usbd_cdc.c, usbd_cdc.h.

Функция Описание
USBD_CDC_Init Инициализирует интерфейс CDC.
USBD_CDC_DeInit Отменяет инициализацию интерфейса CDC.
USBD_CDC_Setup Обрабатывает запросы управления CDC.
USBD_CDC_EP0_RxReady Обрабатывает данные запроса управления CDC.
USBD_CDC_DataIn Обрабатывает стадию данных CDC IN.
USBD_CDC_DataOut Обрабатывает стадию данных CDC OUT.
USBD_CDC_RegisterInterface Добавляет интерфейс класса CDC.
USBD_CDC_SetTxBuffer Устанавливает буфер передачи приложения.
USBD_CDC_SetRxBuffer Устанавливает буфер приема приложения.
USBD_CDC_TransmitPacket Callback-функция завершения транзакции передачи.
USBD_CDC_ReceivePacket Callback-функция завершения транзакции приема.

Прототипы функций таблицы 27:

static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
                               USBD_SetupReqTypedef *req);
static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev);
static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
uint8_t USBD_CDC_RegisterInterface (USBD_HandleTypeDef *pdev,
                                    USBD_CDC_ItfTypeDef *fops);
uint8_t USBD_CDC_SetTxBuffer (USBD_HandleTypeDef *pdev,
                              uint8_t *pbuff,
                              uint16_t length);
uint8_t USBD_CDC_SetRxBuffer (USBD_HandleTypeDef *pdev, uint8_t *pbuff);
uint8_t USBD_CDC_TransmitPacket (USBD_HandleTypeDef *pdev);
uint8_t USBD_CDC_ReceivePacket (USBD_HandleTypeDef *pdev);

Низкоуровневые аппаратные интерфейсы обслуживаются через соответствующую структуру драйвера, где поля представляют указатели на callback-функции:

typedef struct _USBD_CDC_Itf
{
   int8_t (* Init) (void);
   int8_t (* DeInit) (void);
   int8_t (* Control) (uint8_t, uint8_t *, uint16_t);
   int8_t (* Receive) (uint8_t *, uint32_t *);
}USBD_CDC_ItfTypeDef;

Каждый драйвер аппаратного интерфейса должен предоставить указатель на структуру типа USBD_CDC_ItfTypeDef. Функции, на которые указывают поля в этой структуры, перечислены в последующих секциях. Если какая-то функция не поддерживается, то соответствующее поле должно быть установлено в значение NULL.

Замечание: чтобы достичь самой высокой производительности, рекомендуется вычислить значения, необходимые для следующих параметров (все они конфигурируются в файлах usbd_cdc.h и usbd_cdc_interface.h), см. таблицу 28.

Таблица 28. Конфигурируемые параметры CDC.

Определение #define
Параметр
Типовое значение
Full Speed High Speed
CDC_DATA_HS_IN_PACKET_SIZE Размер каждого пакета данных IN. 64 512
CDC_DATA_FS_IN_PACKET_SIZE
CDC_DATA_HS_OUT_PACKET_SIZE Размер каждого пакета данных OUT. 64 512
CDC_DATA_FS_OUT_PACKET_SIZE
APP_TX_DATA_SIZE Общий размер кольцевого временного буфера для OUT-транзакций данных. 2048 2048
APP_RX_DATA_SIZE Общий размер кольцевого временного буфера для IN-транзакций данных. 2048 2048

usbd_cdc_interface.c, usbd_cdc_interface.h. Этот драйвер может быть частью приложения пользователя. Он не предоставлен в библиотеке, однако можно использовать шаблон (usbd_cdc_if_template.c, usbd_cdc_if_template.h), чтобы создать собственный драйвер, и предоставлен пример для интерфейса USART. Он обслуживает нижний слой аппаратуры CDC. Драйвер usbd_cdc_interface.c / usbd_cdc_interface.c.h управляет интерфейсом терминала и обменом данными (например конфигурацией интерфейса USART и передачей / приемом данных).

Этот драйвер предоставляет указатель на структуру:

USBD_CDC_ItfTypeDef USBD_CDC_fops =
{
   CDC_Itf_Init,
   CDC_Itf_DeInit,
   CDC_Itf_Control,
   CDC_Itf_Receive
};

Таблица 29. Функции usbd_cdc_interface.c, usbd_cdc_interface.h.

Функция Описание
CDC_Itf_Init Инициализирует интерфейс CDC низкого уровня.
CDC_Itf_DeInit Отменяет инициализацию интерфейса CDC низкого уровня.
CDC_Itf_Control Обрабатывает парсинг и выполнение запросов управления CDC.
CDC_Itf_Receive Обрабатывает прием данных от хоста USB, предназначенные для слоя нижнего уровня терминала CDC (OUT-транзакции).

Прототипы функций таблицы 29:

static int8_t CDC_Itf_Init (void);
static int8_t CDC_Itf_DeInit (void);
static int8_t CDC_Itf_Control (uint8_t cmd, uint8_t* pbuf, uint16_t length);
static int8_t CDC_Itf_Receive (uint8_t* pbuf, uint32_t *Len);

Чтобы ускорить обслуживание данных для транзакций IN/OUT, низкоуровневый драйвер использует следующие глобальные переменные (находятся в usbd_cdc_interface.c / usbd_cdc_interface.h):

Таблица 30. Переменные, используемые в usbd_cdc_xxx_if.c, / usbd_cdc_xxx_if.h.

Переменная Использование
uint8_t UserRxBuffer[APP_RX_DATA_SIZE]; Записывает принятые из USART данные в этот буфер. Эти данные отправляются через конечную точку USB IN в функциях ядра CDC.
uint32_t UserTxBufPtrOut; Это указатель инкрементируется или возвращается в начало, когда принятые данные записываются в буфер UserRxBuffer.
uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; В этот буфер записываются принятые CDC данные. Эти данные принимаются из конечной точки USB OUT в функциях ядра CDC.
uint32_t UserTxBufPtrIn; Этот указатель инкрементируется или возвращается в начало, когда данные принимаются через USART.

Как использовать драйвер USB CDC. В драйвере применен уровень абстракции для низкоуровневого драйвера аппаратуры CDC (например, интерфейс управления USART). Эта абстракция низкого уровня (например stm32fxxx_hal_msp.c) позволяет Вам модифицировать адаптировать приложение к имеющейся аппаратуре.

Чтобы использовать драйвер, выполните следующее.

1. В файлах usbd_cdc.h и usbd_cdc_interface.h сконфигурируйте параметры:

   – размеры пакетов Data IN, OUT и команд (определения #define CDC_DATA_XX_IN_PACKET_SIZE, CDC_DATA_XX_OUT_PACKET_SIZE). Здесь вместо "XX" надо подставить FS или HS, в зависимости от режима скорости Fast Speed или High Speed.
   – размер временного кольцевого буфера для транзакций данных IN/OUT (#define APP_RX_DATA_SIZE и APP_TX_DATA_SIZE).
   – строковые дескрипторы устройства.

2. Вызовите функцию USBD_CDC_Init() при запуске приложения, чтобы сконфигурировать все необходимые программные и аппаратные компоненты (эта функция также вызовет зависящие от приложения функции конфигурации оборудования). Компоненты аппаратуры управляются низкоуровневым интерфейсом (например usbd_cdc_interface.c) и это может быть изменено пользователем в зависимости от требований приложения.

3. CDC-транзакции данных IN и OUT управляются двумя функциями:

   – USBD_CDC_SetTxBuffer должна быть вызвана из приложения пользователя каждый раз, когда имеются данные для отправки хосту USB.
   – USBD_CDC_SetRxBuffer вызывается ядром CDC всякий раз, когда приняты данные от хоста, и они должны быть переданы через аппаратуру терминала. Из этой функции должен произойти выход только когда все данные в буфере были отправлены (ядро CDC на это время блокирует все поступающие пакеты OUT, пока эта функция не завершит обработку данных предыдущего пакета).

4. Запросы управления (CDC control requests) должны быть обработаны функцией Controllability(). Эта функция вызывается каждый раз, когда принят запрос от хоста, и доступны все соответствующие данные, если таковые имеются. Эта функция должна парсить запрос, и выполнять требуемые запросом действия.

5. Чтобы закрыть обмен, вызовите функцию USBD_CDC_DeInit(). Она закрывает используемые конечные точки, и вызывает низкоуровневые функции, отменяющие сделанные ранее инициализации.

Известные ограничения CDC. Когда этот драйвер используется с ядром OTG HS, разрешение режима DMA (#define USB_OTG_HS_INTERNAL_DMA_ENABLED в файле usb_conf.h) приведет к тому, что количество отправляемых данных всегда будет нацело делиться на 4. Причина в том, что фактически USB DMA не позволяет передавать данные, не выровненные по адресу на границу слова. Для этого специфичного приложения не рекомендуется разрешать эту опцию без специальной необходимости.

[Добавление пользовательского класса USB]

В этой секции описывается, как создать новый пользовательский класс USB (custom class), основанный на существующем классе USB.

Чтобы создать новый custom Class, выполните следующие шаги:

1. Добавьте USBD_CustomClass_cb (чтобы принимать различные события шины USB) как это описано выше в разделе "Интерфейс класса устройства USB", в usbd_template.c / usbd_template.h, находящемся в каталоге Class/Template. Этот шаблон содержит все функции, которые должны быть адаптированы к потребностям приложения, и он может использоваться для реализации любого типа класса устройства USB.

2. Настройте дескрипторы. Эти дескрипторы запрашивает хост, и они должны быть сконфигурированы, чтобы описать устройство, в зависимости от спецификации класса устройства приложения. Следующий список не полный, однако дает обзор различных дескрипторов, которые могут потребоваться:

   – стандартный дескриптор устройства
   – стандартный дескриптор интерфейса
   – стандартный дескриптор интерфейса для реализуемого класса устройства USB
   – стандартные дескрипторы конечных точек для IN endpoint и OUT endpoint.

3. Программа должна сконфигурировать STM32, чтобы разрешить транзакции USB (isochronous, Bulk, Interrupt или Control), в зависимости от приложения пользователя:

   – В функциях DataIn и DataOut пользователь может реализовать внутренний протокол или машину состояний.
   – В функции Setup реализуется обработка запросов, специфичных для класса. Добавляется дескриптор как массив,  и передается библиотеке устройства USB.
   – Функция GetConfigDescriptor должна вернуть указатель на дескриптор конфигурации USB и его длину.
   – Могут быть добавлены дополнительные функции, как IsoINIncomplete и IsoOUTIncomplete, которые используются при необходимости для обработки неполных изохронных транзакций (для дополнительной информации см. пример USB audio device).
   – По мере необходимости должны использоваться EP0_TxSent и EP0_RxReady, когда приложению нужно обработать события, происходящие перед пакетами нулевой длины (Zero Length Packets, см. пример устройства DFU).

4. Процесс выделения памяти: память выделяется приложением с использованием malloc (USBD_malloc):

   – USBD_malloc(sizeof (USBD_CUSTOM_CLASS_HandleTypeDef)): это динамически выделяемая память для структуры класса.

[Оптимизация кода библиотеки USB]

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

Уменьшение размера используемой памяти в примерах USB всегда является важным вопросом для микроконтроллеров STM32, особенно для тех, у которых маленькие объемы памяти Flash/RAM, таких как серии STM32L0 и F0.

Уменьшение размера кучи и стека (настройка в файле линкера). Стек это область оперативной памяти, где программа сохраняет:

• Локальные переменные, аргументы функции
• Адреса возврата
• Временные переменные, которое использует компилятор
• Контексты прерывания

Куча это специальная область памяти, из которой можно динамически (во время выполнения программы, run time) выделять блоки памяти нужного размера. Во многих встраиваемых приложениях куча вообще не используется.

Если Ваша конфигурация линкера резервирует слишком много памяти для кучи и стека, то Вы можете уточнить количество памяти, которое на самом деле требуется программе.

Старайтесь всегда, если это возможно, использовать локальные переменные вместо глобальных. Если переменная используется только в одной функции, и её значение не нужно сохранять между отдельными вызовами этой функции, то такая переменная должна быть определена как локальная переменная.

Константы должны выделяться из памяти flash. Рекомендуется все глобальные переменные, которые не изменяются, определить как константы в секции памяти, предназначенной только для чтения. Например, дескрипторы USB это хорошие кандидаты для декларации в виде констант, используя ключевое слово const языка C.

Пример декларации дескрипторов USB как const:

/* Стандартный дескриптор устройства USB */
const uint8_t USBD_DeviceDesc[USB_LEN_DEV_DESC]= {
  0x12,                       /* bLength */
  USB_DESC_TYPE_DEVICE,       /* bDescriptorType */
  0x00,                       /* bcdUSB */
  0x02,
  0x00,                       /* bDeviceClass */
  0x00,                       /* bDeviceSubClass */
  0x00,                       /* bDeviceProtocol */
  USB_MAX_EP0_SIZE,           /* bMaxPacketSize */
  LOBYTE(USBD_VID),           /* idVendor */
  HIBYTE(USBD_VID),           /* idVendor */
  LOBYTE(USBD_PID),           /* idVendor */
  HIBYTE(USBD_PID),           /* idVendor */
  0x00,                       /* bcdDevice rel. 2.00 */
  0x02,
  USBD_IDX_MFC_STR,           /* Индекс строки описания производителя */
  USBD_IDX_PRODUCT_STR,       /* Индекс строки описания продукта */
  USBD_IDX_SERIAL_STR,        /* Индекс строки серийного номера */
  USBD_MAX_NUM_CONFIGURATION  /* bNumConfigurations */
}; /* USB_DeviceDescriptor */

Используйте статическую память вместо malloc. Библиотека устройства USB использует динамическую память для выделения памяти под структуру класса (class handle structure), чтобы можно было поддерживать несколько экземпляров объектов (в случае работы в двухядерной среде). Это означает, к примеру, что мы можем иметь иметь два экземпляра одного и того же класса USB (HS и FS).

Вторая причина использования динамического выделения памяти - возможность её освобождения, когда USB больше не используется.

Однако динамическое выделение вносит некоторые дополнительные затраты как памяти кода, так и памяти данных, особенно в памяти кода. По этой причине рекомендуется использовать статическое выделение памяти вместо динамического для устройств STM32 с малым объемом памяти, или когда не требуется поддержка несколько экземпляров (вариантов) стека USB. Для этого необходимо декларировать статический буфер достаточного размера, чтобы в нем разместилась структура класса USB (class handle structure).

Ниже показан пример реализации:

1. В файле usbd_conf.h определите статическое выделение памяти и подпрограммы для этого:

USBD_static_malloc()and USBD_static_free()
#define MAX_STATIC_ALLOC_SIZE 4 /* HID Class structure size */
#define USBD_malloc (uint32_t *)USBD_static_malloc
#define USBD_free USBD_static_free

2. Ниже показана готовая реализация в файле usbd_conf.c:

/**  * @brief  Одиночное статическое выделение памяти.
 * @param  size: размер выделяемой памяти
 * @retval вернет указатель на выделенную память
 */
void *USBD_static_malloc(uint32_t size)
{
  static uint32_t mem[MAX_STATIC_ALLOC_SIZE];
  return mem;
}
 
/** 
 * @brief  Заглушка для "освобождения" памяти
 * @param  *p указатель на выделенную память
 * @retval нет возвращаемого значения
 */
void USBD_static_free(void *p)
{
}

[FAQ]

1. Как можно на лету модифицировать дескриптор устройства и строковые дескрипторы?

В файле usbd_desc.c дескриптор, относящийся к устройству и строки могут быть изменены в помощью callback-вызовов Get Descriptor. Приложение может вернуть корректный буфер дескриптора относительно индекса приложения, используя оператор switch/case.

2. Как драйверу класса устройства хранения (mass storage class, MSC) поддержать больше одного логического юнита (LUN)?

В файле usbd_msc_storage_template.c определено все API, необходимое для использования физического носителя данных (physical media). Каждая функция поставляется с параметром LUN для выбора адресованного носителя.

Количество поддерживаемых The LUN можно поменять с помощью изменения #define STORAGE_LUN_NBR в файле usbd_msc_storage_xxx.c (здесь xxx обозначает используемый носитель).

Для запроса данных буфер STORAGE_Inquirydata содержит стандартные данные запроса для каждого LUN. Ниже показан пример использования двух LUN.

const int8_t STORAGE_Inquirydata[] = {
   /* LUN 0 */
   0x00,
   0x80,
   0x02,
   0x02,
   (USBD_STD_INQUIRY_LENGTH - 5),
   0x00,
   0x00,
   0x00,
   'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Производитель: 8 байт */
   'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', /* Продукт: 16 байт */
   'F', 'l', 'a', 's', 'h', ' ', ' ', ' ',
   '1', '.', '0' ,'0',                     /* Версия: 4 байт */
   /* LUN 0 */
   0x00,
   0x80,
   0x02,
   0x02,
   (USBD_STD_INQUIRY_LENGTH - 5),
   0x00,
   0x00,
   0x00,
   'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Производитель: 8 bytes */
   'N', 'a', 'n', 'd', ' ', ' ', ' ', ' ', /* Продукт: 16 Bytes */
   'F', 'l', 'a', 's', 'h', ' ', ' ', ' ',
   '1', '.', '0' ,'0',                     /* Версия: 4 Bytes */
};

3. Где определены адреса конечных точек?

Адреса конечных точек определены в файле заголовка драйвера класса. В случае MSC demo, например, адреса конечных точке IN/OUT определены в файле usbd_msc.h следующим образом:

#define MSC_EPIN_ADDR   0x81  // для Endpoint 1 IN
#define MSC_EPOUT_ADDR  0x01  // для Endpoint 1 OUT

4. Может ли библиотека устройства USB быть сконфигурированной для работы либо в режиме High Speed, либо в режиме Full Speed?

Да, библиотека может обработать USB OTG HS и USB OTG FS, и если ядро USB OTG FS может работать только в Full Speed mode, то USB OTG HS может работать и режимах High Speed и Full Speed.

Для выбора подходящего ядра To USB, с которым нужно работать, пользователь должен добавить следующие макроопределения для препроцессора компилятора (это уже сделано в заранее сконфигурированных проектах примеров):

- "USE_USB_HS" когда используется ядро USB High Speed (HS)
- "USE_USB_FS" когда используется ядро USB Full Speed (FS)
- "USE_USB_HS" и "USE_USB_HS_IN_FS" когда ядро USB High Speed (HS) может использоваться и в режиме в FS.

5. Как можно использовать измененные конечные точки в драйвере класса устройства USB?

Для изменения конечных точке или добавления новой конечной точки:

a) Выполните инициализацию конечной точки с помощью USBD_LL_OpenEP().
b) Сконфигурируйте размер Tx FIFO или Rx FIFO Новых определяемых конечных точек в файле usb_conf.c с помощью следующих вызовов APIs в файле USBD_LL_Init().

Для серий STM32F2 и STM32F4 (ядра FS и HS):

HAL_PCD_SetRxFiFo()
HAL_PCD_SetTxFiFo()

Общий размер Rx FIFO и Tx FIFO должен быть меньше, чем общий размер FIFO, используемого ядром, 320 x 32 бит (1.25 килобайт) для ядра USB OTG FS и 1024 x 32 бит (4 килобайта) для ядра USB OTG HS.

Для серий STM32F0, STM32L0, STM32F1 и STM32F3 (только ядро FS):

HAL_PCD_PMA_Config()

6. Совместима ли библиотека устройства USB с операционной системой реального времени (RTOS)?

Да, библиотека устройства USB может использоваться вместе с RTOS, обертка CMSIS RTOS wrapper используется при создании абстракции для ядра операционной системы (OS kernel).

[Ссылки]

1. UM1734 STM32Cube USB device library site:st.com.
2. USB Mass Storage Class Devices site:wiki.osdev.org.
3Контроллер USB STM32 серий STM32F103xx и STM32F102xx.

 

Комментарии  

 
0 #1 Сергей 22.03.2024 10:02
Подскажите, а в структуре _USBD_HandleTyp eDef есть поле, по которому можно определить, со стороны хоста "подключена" какая-нибудь программа? Например, чтобы при открытии Терминала СОМ-порта вывести "приветственное меню"?

microsin: чтобы определить подключение клиента к хосту CDC, обрабатывайте событие HOST_USER_CONNE CTION в функции USBH_UserProces s (см. модуль usb_host.c).
Цитировать
 

Добавить комментарий


Защитный код
Обновить

Top of Page