95 lines
8.5 KiB
C
95 lines
8.5 KiB
C
/* STM32G474 USB FS device, dedicated PA11/PA12 pins, single-buffer PMA. */
|
||
#include "usbd_core.h"
|
||
#include "usbd_cdc.h"
|
||
|
||
static PCD_HandleTypeDef pcd;
|
||
/* Единственный статический объект CDC вместо heap. Контракт предполагает один экземпляр класса. */
|
||
static USBD_CDC_HandleTypeDef class_memory;
|
||
/* Проверяет размер запроса и возвращает статический объект либо NULL. Не является универсальным malloc. */
|
||
void *BoardUsb_Alloc(uint32_t size) { return size<=sizeof(class_memory)?&class_memory:NULL; }
|
||
/* Освобождение не требуется: объект существует до перезапуска MCU. */
|
||
void BoardUsb_Free(void *ptr) { (void)ptr; }
|
||
/* Согласует enum HAL и USB: OK -> OK, BUSY -> BUSY, остальные результаты -> FAIL. */
|
||
static USBD_StatusTypeDef status(HAL_StatusTypeDef s) {
|
||
return s==HAL_OK?USBD_OK:s==HAL_BUSY?USBD_BUSY:USBD_FAIL;
|
||
}
|
||
/* Единственная точка входа USB ISR; события декодирует HAL_PCD_IRQHandler. */
|
||
void USB_LP_IRQHandler(void) { HAL_PCD_IRQHandler(&pcd); }
|
||
/* Передаёт 8-байтовый SETUP control-запрос стандартному обработчику USB Device. */
|
||
void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *h) { (void)USBD_LL_SetupStage(h->pData,(uint8_t *)h->Setup); }
|
||
/* OUT: хост отправил данные устройству; передаём номер endpoint и его принятый буфер. */
|
||
void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *h,uint8_t ep) { (void)USBD_LL_DataOutStage(h->pData,ep,h->OUT_ep[ep].xfer_buff); }
|
||
/* IN: завершена передача данных от устройства к хосту; уведомляем USB Device. */
|
||
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *h,uint8_t ep) { (void)USBD_LL_DataInStage(h->pData,ep,h->IN_ep[ep].xfer_buff); }
|
||
/* Передаёт событие начала USB-кадра; в текущей конфигурации SOF-прерывания отключены. */
|
||
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *h) { (void)USBD_LL_SOF(h->pData); }
|
||
/* При reset шины фиксируем Full Speed и сбрасываем состояние USB Device. */
|
||
void HAL_PCD_ResetCallback(PCD_HandleTypeDef *h) {
|
||
(void)USBD_LL_SetSpeed(h->pData,USBD_SPEED_FULL); (void)USBD_LL_Reset(h->pData);
|
||
}
|
||
/* Сообщает middleware о приостановке шины; аппаратный low-power режим здесь не включается. */
|
||
void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *h) { (void)USBD_LL_Suspend(h->pData); }
|
||
/* Сообщает middleware о возобновлении обмена после suspend. */
|
||
void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *h) { (void)USBD_LL_Resume(h->pData); }
|
||
/* Уведомление верхнего уровня о подключении контроллера. */
|
||
void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *h) { (void)USBD_LL_DevConnected(h->pData); }
|
||
/* Уведомление верхнего уровня об отключении контроллера. */
|
||
void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *h) { (void)USBD_LL_DevDisconnected(h->pData); }
|
||
/* Переадресует незавершённую изохронную IN-передачу; обычный CDC использует bulk endpoints. */
|
||
void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *h,uint8_t ep) { (void)USBD_LL_IsoINIncomplete(h->pData,ep); }
|
||
/* Переадресует незавершённую изохронную OUT-передачу для полноты порта PCD. */
|
||
void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *h,uint8_t ep) { (void)USBD_LL_IsoOUTIncomplete(h->pData,ep); }
|
||
|
||
USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *d) {
|
||
/* Dedicated USB pins: no GPIO alternate-function selection on G474. */
|
||
__HAL_RCC_USB_CLK_ENABLE();
|
||
pcd.Instance = USB; pcd.Init.dev_endpoints = 8;
|
||
pcd.Init.speed = PCD_SPEED_FULL; pcd.Init.phy_itface = PCD_PHY_EMBEDDED;
|
||
pcd.Init.Sof_enable = DISABLE; pcd.Init.low_power_enable = DISABLE;
|
||
pcd.Init.lpm_enable = DISABLE; pcd.Init.battery_charging_enable = DISABLE;
|
||
pcd.pData = d; d->pData = &pcd;
|
||
if (HAL_PCD_Init(&pcd) != HAL_OK) return USBD_FAIL;
|
||
/* BTABLE: 0x00..0x3f; EP0 RX/TX 64 bytes each; CDC data RX/TX 64;
|
||
* CDC notification 16. Byte offsets are disjoint within the 1 KB PMA. */
|
||
if (HAL_PCDEx_PMAConfig(&pcd, 0x00, PCD_SNG_BUF, 0x40) != HAL_OK ||
|
||
HAL_PCDEx_PMAConfig(&pcd, 0x80, PCD_SNG_BUF, 0x80) != HAL_OK ||
|
||
HAL_PCDEx_PMAConfig(&pcd, CDC_OUT_EP, PCD_SNG_BUF, 0xc0) != HAL_OK ||
|
||
HAL_PCDEx_PMAConfig(&pcd, CDC_IN_EP, PCD_SNG_BUF, 0x100) != HAL_OK ||
|
||
HAL_PCDEx_PMAConfig(&pcd, CDC_CMD_EP, PCD_SNG_BUF, 0x140) != HAL_OK)
|
||
return USBD_FAIL;
|
||
HAL_NVIC_SetPriority(USB_LP_IRQn, 7, 0); HAL_NVIC_EnableIRQ(USB_LP_IRQn);
|
||
return USBD_OK;
|
||
}
|
||
/* Запрещает USB IRQ до деинициализации контроллера, чтобы callbacks не работали с разобранным состоянием. */
|
||
USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *d) {
|
||
HAL_NVIC_DisableIRQ(USB_LP_IRQn); return status(HAL_PCD_DeInit(d->pData));
|
||
}
|
||
/* Включает USB device через HAL после завершения настройки класса и endpoints. */
|
||
USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *d) { return status(HAL_PCD_Start(d->pData)); }
|
||
/* Останавливает контроллер USB device; память состояния остаётся статической. */
|
||
USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *d) { return status(HAL_PCD_Stop(d->pData)); }
|
||
/* Открывает endpoint: ep содержит номер и направление (бит 7), type — тип, mps — максимальный пакет в байтах. */
|
||
USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *d,uint8_t ep,uint8_t type,uint16_t mps) { return status(HAL_PCD_EP_Open(d->pData,ep,mps,type)); }
|
||
/* Закрывает endpoint по USB-адресу ep, включая бит направления. */
|
||
USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *d,uint8_t ep) { return status(HAL_PCD_EP_Close(d->pData,ep)); }
|
||
/* Очищает FIFO указанного endpoint через HAL. */
|
||
USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *d,uint8_t ep) { return status(HAL_PCD_EP_Flush(d->pData,ep)); }
|
||
/* Устанавливает STALL: endpoint отклоняет неподдерживаемую операцию хоста. */
|
||
USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *d,uint8_t ep) { return status(HAL_PCD_EP_SetStall(d->pData,ep)); }
|
||
/* Снимает STALL по запросу верхнего уровня USB Device. */
|
||
USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *d,uint8_t ep) { return status(HAL_PCD_EP_ClrStall(d->pData,ep)); }
|
||
/* Применяет адрес устройства, назначенный хостом при перечислении USB. */
|
||
USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *d,uint8_t address) { return status(HAL_PCD_SetAddress(d->pData,address)); }
|
||
/* Запускает IN-передачу size байтов из buf. Буфер должен жить до callback завершения; копии здесь нет. */
|
||
USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *d,uint8_t ep,uint8_t *buf,uint32_t size) { return status(HAL_PCD_EP_Transmit(d->pData,ep,buf,size)); }
|
||
/* Взводит OUT endpoint для приёма в buf ёмкостью size байтов; завершение придёт через callback PCD. */
|
||
USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *d,uint8_t ep,uint8_t *buf,uint32_t size) { return status(HAL_PCD_EP_Receive(d->pData,ep,buf,size)); }
|
||
/* Читает состояние endpoint из HAL handle: bit7 выбирает IN, младшие 7 бит — номер. */
|
||
uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *d,uint8_t ep) {
|
||
PCD_HandleTypeDef *h=d->pData; return ep&0x80?h->IN_ep[ep&0x7F].is_stall:h->OUT_ep[ep].is_stall;
|
||
}
|
||
/* Возвращает фактическое число принятых байтов последней OUT-передачи. */
|
||
uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *d,uint8_t ep) { return HAL_PCD_EP_GetRxCount(d->pData,ep); }
|
||
/* Блокирующая задержка ST middleware в миллисекундах HAL; требует работающего SysTick. */
|
||
void USBD_LL_Delay(uint32_t ms) { HAL_Delay(ms); }
|