# USB CDC - 1st stage

This commit is contained in:
Dmitry Akimov 2026-04-03 15:22:41 +03:00
parent 832a542db4
commit 0d062a6c21
17 changed files with 2742 additions and 382 deletions

View file

@ -15,6 +15,7 @@ add_subdirectory(uart_host)
add_subdirectory(opto)
add_subdirectory(can)
add_subdirectory(button)
add_subdirectory(usb_cdc)
# Подавляем предупреждения при компиляции собственных .c файлов библиотеки
target_compile_options(bsp_board PRIVATE -w)

View file

@ -39,6 +39,9 @@ typedef enum bsp_status_e
BSP_ERR_PARAM = 4, /**< Невалидный аргумент */
BSP_ERR_OVERFLOW = 5, /**< Переполнение буфера, данные потеряны. */
BSP_ERR_NOT_SUPPORTED = 6, /**< Функция не поддерживается */
BSP_ERR_INVALID = 7, /**< Невалидная операция. */
BSP_ERR_HW = 8, /**< Ошибки аппаратного стека. */
BSP_ERR_NOT_READY = 9, /**< Модуль не готов. */
} bsp_status_t;
#endif /* BSP_STATUS_H */

View file

@ -0,0 +1,18 @@
if(BUILD_TESTS_HOST)
return()
endif()
add_library(bsp_usb_cdc STATIC src/usb_cdc.c src/usb_cdc_descriptors.c
src/usb_cdc_hw.c src/usb_device_ch9.c)
target_include_directories(
bsp_usb_cdc
PUBLIC include/
PRIVATE src/)
target_link_libraries(
bsp_usb_cdc
PUBLIC bsp_status
PRIVATE bsp_board bsp_tick sdk_usb_device_ehci sdk_usb_phy sdk_osa_bm)
target_compile_options(bsp_usb_cdc PRIVATE -w)

View file

@ -0,0 +1,100 @@
/*
* Copyright 2025 MU LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file usb_cdc.h
* @brief BSP: USB CDC ACM (Virtual COM Port) на USB1 / EHCI0.
*
* Публичный API без зависимостей от NXP SDK.
* Все USB-специфичные типы и хедеры скрыты в реализации.
*/
#ifndef BSP_USB_CDC_H_
#define BSP_USB_CDC_H_
#include "bsp/status.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
/** Максимальный размер одной передачи (HS bulk packet). */
#define BSP_USB_CDC_MAX_PACKET_SIZE (512U)
/**
* @brief Инициализация USB CDC ACM (USB1 / EHCI0).
*
* Включает тактирование USB PHY 480 MHz, инициализирует EHCI контроллер,
* регистрирует CDC ACM дескрипторы и запускает USB device stack.
*
* @pre board_hw_init() вызван (MPU настроен, NonCacheable регион активен).
*
* @return BSP_OK при успехе, BSP_ERR_HW при ошибке инициализациистека.
*/
bsp_status_t bsp_usb_cdc_init(void);
/**
* @brief Проверить готовность канала (хост открыл COM-порт).
*
* Возвращает true когда USB enumeration завершён и хост установил
* DTR (Data Terminal Ready) через SET_CONTROL_LINE_STATE.
*
* @return true можно передавать данные, false хост не подключён.
*/
bool bsp_usb_cdc_is_ready(void);
/**
* @brief Отправить данные хосту (неблокирующая).
*
* Копирует данные во внутренний TX буфер (NonCacheable OCRAM)
* и ставит в очередь USB IN transfer.
*
* @param data Указатель на данные.
* @param len Количество байт, 0 < len <= BSP_USB_CDC_MAX_PACKET_SIZE.
*
* @return BSP_OK transfer поставлен в очередь.
* @return BSP_ERR_BUSY предыдущий transfer не завершён.
* @return BSP_ERR_NOT_READY хост не подключён или USB не инициализирован.
* @return BSP_ERR_INVALID data == NULL или len == 0 или len слишком велик.
*/
bsp_status_t bsp_usb_cdc_write(const uint8_t *p_data, size_t len);
/**
* @brief Готов ли TX канал к следующей отправке.
*
* @return true можно вызывать bsp_usb_cdc_write().
*/
bool bsp_usb_cdc_write_ready(void);
/**
* @brief Прочитать данные от хоста (неблокирующая).
*
* Забирает данные из внутреннего RX буфера, заполненного USB OUT
* callback. Автоматически перепланирует следующий OUT transfer.
*
* @param buf Буфер для приёма.
* @param max_len Размер буфера.
*
* @return Количество прочитанных байт (0 если данных нет).
*/
size_t bsp_usb_cdc_read(uint8_t *p_buf, size_t max_len);
/**
* @brief Поллинг USB стека вызывать из main loop (bare-metal).
*
* Для FreeRTOS не нужен если USB_DEVICE_CONFIG_USE_TASK = 1.
*/
void bsp_usb_cdc_poll(void);
#ifdef __cplusplus
}
#endif
#endif /* BSP_USB_CDC_H_ */

View file

@ -0,0 +1,21 @@
/*
* Copyright 2025 TFT Project
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file fsl_os_abstraction_config.h
* @brief Конфигурация OSA bare-metal для bsp_usb_cdc.
*
* NXP OSA подключает этот файл через include path.
* Настройки под bare-metal (без FreeRTOS).
*/
#ifndef FSL_OS_ABSTRACTION_CONFIG_H_
#define FSL_OS_ABSTRACTION_CONFIG_H_
#define gMainThreadStackSize_c (1024U)
#define gMainThreadPriority_c (7U)
#define gTaskMultipleInstancesManagement_c (0U)
#define FSL_OSA_ALLOCATED_HEAP (1U)
#endif /* FSL_OS_ABSTRACTION_CONFIG_H_ */

664
bsp/usb_cdc/src/usb_cdc.c Normal file
View file

@ -0,0 +1,664 @@
/*
* Copyright 2025 MU LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file usb_cdc.c
* @brief BSP USB CDC ACM реализация публичного API и NXP callbacks.
*
* Архитектура:
* - Публичные функции bsp_usb_cdc_*() вызываются приложением.
* - USB_Device*() callbacks вызываются NXP USB стеком из ISR контекста.
* - Данные между ISR и main loop синхронизируются через volatile флаги
* и DisableGlobalIRQ/EnableGlobalIRQ (bare-metal critical section).
*
* Все DMA-буферы размещены в NonCacheable OCRAM через USB_DMA_*_ALIGN макросы.
*/
#include "bsp/usb_cdc.h"
#include "bsp/tick.h"
#include "fsl_common.h"
#include "usb.h"
#include "usb_device.h"
#include "usb_device_cdc_acm.h"
#include "usb_device_ch9.h"
#include "usb_device_config.h"
#include "usb_device_descriptor.h"
#include <string.h>
/* ========================================================================
* Внутренние определения
* ======================================================================== */
#define CONTROLLER_ID kUSB_ControllerEhci0
/** Размер bulk-буферов. При HS = 512, при FS = 64. Аллоцируем под HS. */
#define DATA_BUFF_SIZE HS_CDC_VCOM_BULK_OUT_PACKET_SIZE
/** Line coding defaults (115200 8N1). */
#define LINE_CODING_DTERATE (115200U)
#define LINE_CODING_CHARFORMAT (0x00U)
#define LINE_CODING_PARITYTYPE (0x00U)
#define LINE_CODING_DATABITS (0x08U)
#define LINE_CODING_SIZE (7U)
#define COMM_FEATURE_DATA_SIZE (2U)
#define STATUS_ABSTRACT_STATE (0x0000U)
#define COUNTRY_SETTING (0x0000U)
#define NOTIF_PACKET_SIZE (8U)
#define UART_BITMAP_SIZE (2U)
#define NOTIF_REQUEST_TYPE (0xA1U)
/** Задержка после USB_DeviceRun для стабилизации DP pull-down (мкс). */
#define USB_ATTACH_DELAY_US (5000U)
#define USB_DEVICE_CDC_REQUEST_SERIAL_STATE_NOTIF (0x20U)
/* ========================================================================
* Состояние устройства
* ======================================================================== */
/** Глобальный handle — используется IRQ handler в usb_cdc_hw.c. */
usb_device_handle g_usbDeviceHandle = NULL;
/** Информация о состоянии ACM (serial state notification). */
typedef struct
{
uint8_t serialStateBuf[NOTIF_PACKET_SIZE + UART_BITMAP_SIZE];
bool dtePresent;
uint16_t breakDuration;
uint8_t dteStatus;
uint8_t currentInterface;
uint16_t uartState;
} usb_cdc_acm_info_t;
/** Внутреннее состояние CDC. */
static struct
{
volatile uint8_t attach; /**< 1 = USB enumeration done. */
volatile uint8_t startTransactions; /**< 1 = DTE present, can TX/RX. */
uint8_t speed; /**< USB_SPEED_HIGH / _FULL. */
uint8_t currentConfiguration;
uint8_t currentInterfaceAlt[USB_CDC_VCOM_INTERFACE_COUNT];
uint8_t hasSentState; /**< Serial state notification sent. */
} s_cdcState;
/* ========================================================================
* DMA-aligned буферы (NonCacheable OCRAM)
* ======================================================================== */
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static uint8_t s_lineCoding[LINE_CODING_SIZE] = {
(LINE_CODING_DTERATE >> 0U) & 0xFFU,
(LINE_CODING_DTERATE >> 8U) & 0xFFU,
(LINE_CODING_DTERATE >> 16U) & 0xFFU,
(LINE_CODING_DTERATE >> 24U) & 0xFFU,
LINE_CODING_CHARFORMAT,
LINE_CODING_PARITYTYPE,
LINE_CODING_DATABITS,
};
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static uint8_t s_abstractState[COMM_FEATURE_DATA_SIZE] = {
(STATUS_ABSTRACT_STATE >> 0U) & 0xFFU,
(STATUS_ABSTRACT_STATE >> 8U) & 0xFFU,
};
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static uint8_t s_countryCode[COMM_FEATURE_DATA_SIZE] = {
(COUNTRY_SETTING >> 0U) & 0xFFU,
(COUNTRY_SETTING >> 8U) & 0xFFU,
};
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static usb_cdc_acm_info_t s_usbCdcAcmInfo;
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static uint8_t s_recvBuf[DATA_BUFF_SIZE];
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static uint8_t s_sendBuf[DATA_BUFF_SIZE];
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static uint8_t s_setupOutBuffer[8];
/** Количество полученных байт (0 = нет данных, заполняется в ISR). */
static volatile uint32_t s_recvSize = 0U;
/** Количество байт для отправки (0 = idle). */
static volatile uint32_t s_sendSize = 0U;
/** Текущий max packet size (обновляется при смене скорости). */
static uint32_t s_bulkMaxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE;
/** TX transfer завершён (1 = можно отправлять следующий). */
static volatile uint8_t s_txIdle = 1U;
/* ========================================================================
* Прототипы внешних функций (usb_cdc_hw.c)
* ======================================================================== */
extern void USB_DeviceClockInit(void);
extern void USB_DeviceIsrEnable(void);
/* ========================================================================
* USB Endpoint Callbacks (вызываются из ISR контекста)
* ======================================================================== */
static usb_status_t
USB_DeviceCdcAcmInterruptIn(usb_device_handle handle,
usb_device_endpoint_callback_message_struct_t *message,
void *callbackParam)
{
(void) handle;
(void) message;
(void) callbackParam;
s_cdcState.hasSentState = 0U;
return kStatus_USB_Error;
}
static usb_status_t USB_DeviceCdcAcmBulkIn(usb_device_handle handle,
usb_device_endpoint_callback_message_struct_t *message,
void *callbackParam)
{
(void) callbackParam;
usb_status_t error = kStatus_USB_Error;
if ((message->length != 0U) && (0U == (message->length % s_bulkMaxPacketSize)))
{
/* Отправить ZLP чтобы хост понял что передача завершена. */
error = USB_DeviceSendRequest(handle, USB_CDC_VCOM_BULK_IN_ENDPOINT, NULL, 0U);
}
else if ((1U == s_cdcState.attach) && (1U == s_cdcState.startTransactions))
{
if ((message->buffer != NULL) || ((message->buffer == NULL) && (message->length == 0U)))
{
s_txIdle = 1U;
/* TX завершён — готовы к следующей отправке. */
error = kStatus_USB_Success;
}
}
else
{
/* no action */
}
return error;
}
static usb_status_t USB_DeviceCdcAcmBulkOut(usb_device_handle handle,
usb_device_endpoint_callback_message_struct_t *message,
void *callbackParam)
{
(void) handle;
(void) callbackParam;
if ((1U == s_cdcState.attach) && (1U == s_cdcState.startTransactions))
{
s_recvSize = message->length;
if (0U == s_recvSize)
{
/* Хост послал ZLP — сразу планируем следующий приём. */
USB_DeviceRecvRequest(handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_recvBuf,
s_bulkMaxPacketSize);
}
return kStatus_USB_Success;
}
return kStatus_USB_Error;
}
/* ========================================================================
* USB Device Callbacks (вызываются стеком)
* ======================================================================== */
usb_status_t USB_DeviceGetSetupBuffer(usb_device_handle handle, usb_setup_struct_t **setupBuffer)
{
(void) handle;
static uint32_t s_setupBuf[2];
if (setupBuffer == NULL)
{
return kStatus_USB_InvalidParameter;
}
*setupBuffer = (usb_setup_struct_t *) &s_setupBuf;
return kStatus_USB_Success;
}
usb_status_t USB_DeviceGetClassReceiveBuffer(usb_device_handle handle, usb_setup_struct_t *setup,
uint32_t *length, uint8_t **buffer)
{
(void) handle;
(void) setup;
if ((buffer == NULL) || ((*length) > sizeof(s_setupOutBuffer)))
{
return kStatus_USB_InvalidRequest;
}
*buffer = s_setupOutBuffer;
return kStatus_USB_Success;
}
usb_status_t USB_DeviceConfigureRemoteWakeup(usb_device_handle handle, uint8_t enable)
{
(void) handle;
(void) enable;
return kStatus_USB_InvalidRequest;
}
usb_status_t USB_DeviceConfigureEndpointStatus(usb_device_handle handle, uint8_t ep, uint8_t status)
{
if (status != 0U)
{
return USB_DeviceStallEndpoint(handle, ep);
}
return USB_DeviceUnstallEndpoint(handle, ep);
}
/* ---- CDC Class-Specific Request Handler ---- */
usb_status_t USB_DeviceProcessClassRequest(usb_device_handle handle, usb_setup_struct_t *setup,
uint32_t *length, uint8_t **buffer)
{
usb_status_t error = kStatus_USB_InvalidRequest;
usb_cdc_acm_info_t *acmInfo = &s_usbCdcAcmInfo;
uint32_t len;
uint8_t *uartBitmap;
if (setup->wIndex != USB_CDC_VCOM_COMM_INTERFACE_INDEX)
{
return error;
}
switch (setup->bRequest)
{
case USB_DEVICE_CDC_REQUEST_SEND_ENCAPSULATED_COMMAND:
case USB_DEVICE_CDC_REQUEST_GET_ENCAPSULATED_RESPONSE:
case USB_DEVICE_CDC_REQUEST_CLEAR_COMM_FEATURE:
case USB_DEVICE_CDC_REQUEST_SEND_BREAK:
break;
case USB_DEVICE_CDC_REQUEST_SET_COMM_FEATURE:
if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT) &&
(setup->wLength != 0U))
{
if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == setup->wValue)
{
(void) memcpy(s_abstractState, *buffer, COMM_FEATURE_DATA_SIZE);
error = kStatus_USB_Success;
}
else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == setup->wValue)
{
(void) memcpy(s_countryCode, *buffer, COMM_FEATURE_DATA_SIZE);
error = kStatus_USB_Success;
}
else
{
/* no action */
}
}
break;
case USB_DEVICE_CDC_REQUEST_GET_COMM_FEATURE:
if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_IN) &&
(setup->wLength != 0U))
{
if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == setup->wValue)
{
*buffer = s_abstractState;
*length = COMM_FEATURE_DATA_SIZE;
error = kStatus_USB_Success;
}
else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == setup->wValue)
{
*buffer = s_countryCode;
*length = COMM_FEATURE_DATA_SIZE;
error = kStatus_USB_Success;
}
else
{
/* no action */
}
}
break;
case USB_DEVICE_CDC_REQUEST_GET_LINE_CODING:
if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_IN) &&
(setup->wLength != 0U))
{
*buffer = s_lineCoding;
*length = LINE_CODING_SIZE;
error = kStatus_USB_Success;
}
break;
case USB_DEVICE_CDC_REQUEST_SET_LINE_CODING:
if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT) &&
(setup->wLength != 0U))
{
(void) memcpy(s_lineCoding, *buffer, LINE_CODING_SIZE);
error = kStatus_USB_Success;
}
break;
case USB_DEVICE_CDC_REQUEST_SET_CONTROL_LINE_STATE:
{
if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT) &&
(setup->wLength == 0U))
{
error = kStatus_USB_Success;
acmInfo->dteStatus = setup->wValue;
/* TX carrier */
if ((acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION) != 0U)
{
acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_TX_CARRIER;
}
else
{
acmInfo->uartState &= (uint16_t) ~USB_DEVICE_CDC_UART_STATE_TX_CARRIER;
}
/* RX carrier (DTE presence) */
if ((acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) != 0U)
{
acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_RX_CARRIER;
}
else
{
acmInfo->uartState &= (uint16_t) ~USB_DEVICE_CDC_UART_STATE_RX_CARRIER;
}
acmInfo->dtePresent =
((acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) != 0U);
/* Формируем serial state notification */
acmInfo->serialStateBuf[0] = NOTIF_REQUEST_TYPE;
acmInfo->serialStateBuf[1] = USB_DEVICE_CDC_REQUEST_SERIAL_STATE_NOTIF;
acmInfo->serialStateBuf[2] = 0x00U;
acmInfo->serialStateBuf[3] = 0x00U;
acmInfo->serialStateBuf[4] = (uint8_t) setup->wIndex;
acmInfo->serialStateBuf[5] = 0x00U;
acmInfo->serialStateBuf[6] = UART_BITMAP_SIZE;
acmInfo->serialStateBuf[7] = 0x00U;
uartBitmap = &acmInfo->serialStateBuf[NOTIF_PACKET_SIZE];
uartBitmap[0] = (uint8_t) (acmInfo->uartState & 0xFFU);
uartBitmap[1] = (uint8_t) ((acmInfo->uartState >> 8U) & 0xFFU);
len = (uint32_t) (NOTIF_PACKET_SIZE + UART_BITMAP_SIZE);
if (0U == s_cdcState.hasSentState)
{
error = USB_DeviceSendRequest(handle, USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT,
acmInfo->serialStateBuf, len);
if (kStatus_USB_Success == error)
{
s_cdcState.hasSentState = 1U;
}
}
if (1U == s_cdcState.attach)
{
s_cdcState.startTransactions = 1U;
}
}
break;
}
default:
break;
}
return error;
}
/* ---- USB_DeviceCallback (bus reset, set configuration) ---- */
usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param)
{
usb_status_t error = kStatus_USB_InvalidRequest;
uint8_t *temp8 = (uint8_t *) param;
switch (event)
{
case kUSB_DeviceEventBusReset:
{
USB_DeviceControlPipeInit(handle);
s_cdcState.attach = 0U;
s_cdcState.currentConfiguration = 0U;
s_txIdle = 1U;
s_recvSize = 0U;
s_sendSize = 0U;
error = kStatus_USB_Success;
if (kStatus_USB_Success ==
USB_DeviceGetStatus(handle, kUSB_DeviceStatusSpeed, &s_cdcState.speed))
{
USB_DeviceSetSpeed(handle, s_cdcState.speed);
}
break;
}
case kUSB_DeviceEventSetConfiguration:
{
if (0U == (*temp8))
{
s_cdcState.attach = 0U;
s_cdcState.currentConfiguration = 0U;
s_cdcState.startTransactions = 0U;
error = kStatus_USB_Success;
}
else if (USB_CDC_VCOM_CONFIGURE_INDEX == (*temp8))
{
usb_device_endpoint_init_struct_t epInit;
usb_device_endpoint_callback_struct_t epCb;
s_cdcState.attach = 1U;
s_cdcState.currentConfiguration = *temp8;
/* Interrupt IN endpoint */
epCb.callbackFn = USB_DeviceCdcAcmInterruptIn;
epCb.callbackParam = handle;
epInit.zlt = 0U;
epInit.transferType = USB_ENDPOINT_INTERRUPT;
epInit.endpointAddress = USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT |
(USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT);
if (USB_SPEED_HIGH == s_cdcState.speed)
{
epInit.maxPacketSize = HS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE;
epInit.interval = HS_CDC_VCOM_INTERRUPT_IN_INTERVAL;
}
else
{
epInit.maxPacketSize = FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE;
epInit.interval = FS_CDC_VCOM_INTERRUPT_IN_INTERVAL;
}
USB_DeviceInitEndpoint(handle, &epInit, &epCb);
/* Bulk IN endpoint */
epCb.callbackFn = USB_DeviceCdcAcmBulkIn;
epCb.callbackParam = handle;
epInit.zlt = 0U;
epInit.interval = 0U;
epInit.transferType = USB_ENDPOINT_BULK;
epInit.endpointAddress = USB_CDC_VCOM_BULK_IN_ENDPOINT |
(USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT);
if (USB_SPEED_HIGH == s_cdcState.speed)
{
epInit.maxPacketSize = HS_CDC_VCOM_BULK_IN_PACKET_SIZE;
}
else
{
epInit.maxPacketSize = FS_CDC_VCOM_BULK_IN_PACKET_SIZE;
}
USB_DeviceInitEndpoint(handle, &epInit, &epCb);
/* Bulk OUT endpoint */
epCb.callbackFn = USB_DeviceCdcAcmBulkOut;
epCb.callbackParam = handle;
epInit.zlt = 0U;
epInit.interval = 0U;
epInit.transferType = USB_ENDPOINT_BULK;
epInit.endpointAddress = USB_CDC_VCOM_BULK_OUT_ENDPOINT |
(USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT);
if (USB_SPEED_HIGH == s_cdcState.speed)
{
epInit.maxPacketSize = HS_CDC_VCOM_BULK_OUT_PACKET_SIZE;
s_bulkMaxPacketSize = HS_CDC_VCOM_BULK_OUT_PACKET_SIZE;
}
else
{
epInit.maxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE;
s_bulkMaxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE;
}
USB_DeviceInitEndpoint(handle, &epInit, &epCb);
/* Планируем первый OUT transfer */
error = USB_DeviceRecvRequest(handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_recvBuf,
s_bulkMaxPacketSize);
}
else
{
/* unknown configuration */
}
break;
}
case kUSB_DeviceEventSetInterface:
error = kStatus_USB_Success;
break;
default:
break;
}
return error;
}
/* ========================================================================
* Публичный API (BSP)
* ======================================================================== */
bsp_status_t bsp_usb_cdc_init(void)
{
s_cdcState.speed = USB_SPEED_FULL;
s_cdcState.attach = 0U;
s_cdcState.startTransactions = 0U;
s_cdcState.hasSentState = 0U;
s_cdcState.currentConfiguration = 0U;
s_txIdle = 1U;
g_usbDeviceHandle = NULL;
USB_DeviceClockInit();
if (kStatus_USB_Success !=
USB_DeviceInit(CONTROLLER_ID, USB_DeviceCallback, &g_usbDeviceHandle))
{
return BSP_ERR_HW;
}
USB_DeviceIsrEnable();
/* FIXME:Задержка для стабилизации DP pull-down. */
//SDK_DelayAtLeastUs(USB_ATTACH_DELAY_US, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
bsp_delay(USB_ATTACH_DELAY_US / 1000);
USB_DeviceRun(g_usbDeviceHandle);
return BSP_OK;
}
bool bsp_usb_cdc_is_ready(void)
{
return (1U == s_cdcState.attach) && (1U == s_cdcState.startTransactions);
}
bool bsp_usb_cdc_write_ready(void)
{
return bsp_usb_cdc_is_ready() && (1U == s_txIdle);
}
bsp_status_t bsp_usb_cdc_write(const uint8_t *data, size_t len)
{
if ((data == NULL) || (len == 0U) || (len > DATA_BUFF_SIZE))
{
return BSP_ERR_INVALID;
}
if (!bsp_usb_cdc_is_ready())
{
return BSP_ERR_NOT_READY;
}
if (0U == s_txIdle)
{
return BSP_ERR_BUSY;
}
/* Копируем в NonCacheable TX буфер и запускаем transfer. */
(void) memcpy(s_sendBuf, data, len);
s_txIdle = 0U;
usb_status_t status = USB_DeviceSendRequest(g_usbDeviceHandle, USB_CDC_VCOM_BULK_IN_ENDPOINT,
s_sendBuf, (uint32_t) len);
if (kStatus_USB_Success != status)
{
s_txIdle = 1U;
return BSP_ERR_HW;
}
return BSP_OK;
}
size_t bsp_usb_cdc_read(uint8_t *buf, size_t max_len)
{
if ((buf == NULL) || (max_len == 0U))
{
return 0U;
}
if (!bsp_usb_cdc_is_ready())
{
return 0U;
}
uint32_t sr;
uint32_t available = 0U;
sr = DisableGlobalIRQ();
if ((s_recvSize != 0U) && (s_recvSize != USB_CANCELLED_TRANSFER_LENGTH))
{
available = s_recvSize;
s_recvSize = 0U;
}
EnableGlobalIRQ(sr);
if (available == 0U)
{
return 0U;
}
size_t to_copy = (available > (uint32_t) max_len) ? max_len : (size_t) available;
(void) memcpy(buf, s_recvBuf, to_copy);
/* Перепланируем приём следующего пакета. */
USB_DeviceRecvRequest(g_usbDeviceHandle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_recvBuf,
s_bulkMaxPacketSize);
return to_copy;
}
void bsp_usb_cdc_poll(void)
{
/* Bare-metal: NXP USB стек на EHCI обрабатывает всё в ISR.
* Эта функция зарезервирована для будущего использования
* (USB_DEVICE_CONFIG_USE_TASK или software event processing). */
}

View file

@ -0,0 +1,428 @@
/*
* Copyright 2025 MU LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file usb_cdc_descriptors.c
* @brief USB CDC ACM дескрипторы и descriptor callbacks.
*
* Содержит device/configuration/string дескрипторы и функции
* которые NXP USB стек вызывает для получения дескрипторов при
* enumeration. Также USB_DeviceSetSpeed() для обновления
* дескрипторов при переключении HS/FS.
*/
#include "usb.h"
#include "usb_device.h"
#include "usb_device_config.h"
#include "usb_device_descriptor.h"
#include <string.h>
/* ========================================================================
* Глобальное состояние (используется ch9 callbacks)
* ======================================================================== */
uint8_t g_currentConfigure = 0U;
uint8_t g_interface[USB_CDC_VCOM_INTERFACE_COUNT];
/* ========================================================================
* Device Descriptor
* ======================================================================== */
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
uint8_t g_UsbDeviceDescriptor[] = {
USB_DESCRIPTOR_LENGTH_DEVICE,
USB_DESCRIPTOR_TYPE_DEVICE,
USB_SHORT_GET_LOW(USB_DEVICE_SPECIFIC_BCD_VERSION),
USB_SHORT_GET_HIGH(USB_DEVICE_SPECIFIC_BCD_VERSION),
USB_DEVICE_CLASS,
USB_DEVICE_SUBCLASS,
USB_DEVICE_PROTOCOL,
USB_CONTROL_MAX_PACKET_SIZE,
USB_SHORT_GET_LOW(USB_DEVICE_VID),
USB_SHORT_GET_HIGH(USB_DEVICE_VID),
USB_SHORT_GET_LOW(USB_DEVICE_PID),
USB_SHORT_GET_HIGH(USB_DEVICE_PID),
USB_SHORT_GET_LOW(USB_DEVICE_DEMO_BCD_VERSION),
USB_SHORT_GET_HIGH(USB_DEVICE_DEMO_BCD_VERSION),
0x01U, /* iManufacturer */
0x02U, /* iProduct */
0x00U, /* iSerialNumber */
USB_DEVICE_CONFIGURATION_COUNT,
};
/* ========================================================================
* Configuration Descriptor (CIC + DIC)
* ======================================================================== */
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
uint8_t g_UsbDeviceConfigurationDescriptor[] = {
/* --- Configuration --- */
USB_DESCRIPTOR_LENGTH_CONFIGURE,
USB_DESCRIPTOR_TYPE_CONFIGURE,
USB_SHORT_GET_LOW(USB_DESCRIPTOR_LENGTH_CONFIGURE + USB_DESCRIPTOR_LENGTH_INTERFACE +
USB_DESCRIPTOR_LENGTH_CDC_HEADER_FUNC + USB_DESCRIPTOR_LENGTH_CDC_CALL_MANAG +
USB_DESCRIPTOR_LENGTH_CDC_ABSTRACT + USB_DESCRIPTOR_LENGTH_CDC_UNION_FUNC +
USB_DESCRIPTOR_LENGTH_ENDPOINT + USB_DESCRIPTOR_LENGTH_INTERFACE +
USB_DESCRIPTOR_LENGTH_ENDPOINT + USB_DESCRIPTOR_LENGTH_ENDPOINT),
USB_SHORT_GET_HIGH(USB_DESCRIPTOR_LENGTH_CONFIGURE + USB_DESCRIPTOR_LENGTH_INTERFACE +
USB_DESCRIPTOR_LENGTH_CDC_HEADER_FUNC +
USB_DESCRIPTOR_LENGTH_CDC_CALL_MANAG + USB_DESCRIPTOR_LENGTH_CDC_ABSTRACT +
USB_DESCRIPTOR_LENGTH_CDC_UNION_FUNC + USB_DESCRIPTOR_LENGTH_ENDPOINT +
USB_DESCRIPTOR_LENGTH_INTERFACE + USB_DESCRIPTOR_LENGTH_ENDPOINT +
USB_DESCRIPTOR_LENGTH_ENDPOINT),
USB_CDC_VCOM_INTERFACE_COUNT,
USB_CDC_VCOM_CONFIGURE_INDEX,
0x00U, /* iConfiguration */
(USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_D7_MASK) |
(1U << USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_SHIFT),
USB_DEVICE_MAX_POWER,
/* --- CIC: Communication Interface --- */
USB_DESCRIPTOR_LENGTH_INTERFACE,
USB_DESCRIPTOR_TYPE_INTERFACE,
USB_CDC_VCOM_COMM_INTERFACE_INDEX,
USB_CDC_VCOM_COMM_INTERFACE_ALTERNATE_0,
USB_CDC_VCOM_ENDPOINT_CIC_COUNT,
USB_CDC_VCOM_CIC_CLASS,
USB_CDC_VCOM_CIC_SUBCLASS,
USB_CDC_VCOM_CIC_PROTOCOL,
0x00U,
/* --- CDC Header Functional Descriptor --- */
USB_DESCRIPTOR_LENGTH_CDC_HEADER_FUNC,
USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE,
USB_CDC_HEADER_FUNC_DESC,
0x10U,
0x01U,
/* --- CDC Call Management Functional Descriptor --- */
USB_DESCRIPTOR_LENGTH_CDC_CALL_MANAG,
USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE,
USB_CDC_CALL_MANAGEMENT_FUNC_DESC,
0x01U,
0x01U,
/* --- CDC ACM Functional Descriptor --- */
USB_DESCRIPTOR_LENGTH_CDC_ABSTRACT,
USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE,
USB_CDC_ABSTRACT_CONTROL_FUNC_DESC,
0x06U,
/* --- CDC Union Functional Descriptor --- */
USB_DESCRIPTOR_LENGTH_CDC_UNION_FUNC,
USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE,
USB_CDC_UNION_FUNC_DESC,
USB_CDC_VCOM_COMM_INTERFACE_INDEX,
USB_CDC_VCOM_DATA_INTERFACE_INDEX,
/* --- Notification Endpoint (Interrupt IN) --- */
USB_DESCRIPTOR_LENGTH_ENDPOINT,
USB_DESCRIPTOR_TYPE_ENDPOINT,
USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT | (USB_IN << 7U),
USB_ENDPOINT_INTERRUPT,
USB_SHORT_GET_LOW(FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE),
USB_SHORT_GET_HIGH(FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE),
FS_CDC_VCOM_INTERRUPT_IN_INTERVAL,
/* --- DIC: Data Interface --- */
USB_DESCRIPTOR_LENGTH_INTERFACE,
USB_DESCRIPTOR_TYPE_INTERFACE,
USB_CDC_VCOM_DATA_INTERFACE_INDEX,
USB_CDC_VCOM_DATA_INTERFACE_ALTERNATE_0,
USB_CDC_VCOM_ENDPOINT_DIC_COUNT,
USB_CDC_VCOM_DIC_CLASS,
USB_CDC_VCOM_DIC_SUBCLASS,
USB_CDC_VCOM_DIC_PROTOCOL,
0x00U,
/* --- Bulk IN Endpoint --- */
USB_DESCRIPTOR_LENGTH_ENDPOINT,
USB_DESCRIPTOR_TYPE_ENDPOINT,
USB_CDC_VCOM_BULK_IN_ENDPOINT | (USB_IN << 7U),
USB_ENDPOINT_BULK,
USB_SHORT_GET_LOW(FS_CDC_VCOM_BULK_IN_PACKET_SIZE),
USB_SHORT_GET_HIGH(FS_CDC_VCOM_BULK_IN_PACKET_SIZE),
0x00U,
/* --- Bulk OUT Endpoint --- */
USB_DESCRIPTOR_LENGTH_ENDPOINT,
USB_DESCRIPTOR_TYPE_ENDPOINT,
USB_CDC_VCOM_BULK_OUT_ENDPOINT | (USB_OUT << 7U),
USB_ENDPOINT_BULK,
USB_SHORT_GET_LOW(FS_CDC_VCOM_BULK_OUT_PACKET_SIZE),
USB_SHORT_GET_HIGH(FS_CDC_VCOM_BULK_OUT_PACKET_SIZE),
0x00U,
};
/* ========================================================================
* String Descriptors
* ======================================================================== */
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
uint8_t g_UsbDeviceString0[] = {
2U + 2U, USB_DESCRIPTOR_TYPE_STRING, 0x09U, 0x04U, /* English (US) */
};
/* Manufacturer: "MU LLC" */
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
uint8_t g_UsbDeviceString1[] = {
2U + 2U * 6U, USB_DESCRIPTOR_TYPE_STRING,
'M', 0x00U,
'U', 0x00U,
' ', 0x00U,
'L', 0x00U,
'L', 0x00U,
'C', 0x00U,
};
/* Product: "TFT Indicator Board" */
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
uint8_t g_UsbDeviceString2[] = {
2U + 2U * 19U, USB_DESCRIPTOR_TYPE_STRING,
'T', 0x00U,
'F', 0x00U,
'T', 0x00U,
' ', 0x00U,
'I', 0x00U,
'n', 0x00U,
'd', 0x00U,
'i', 0x00U,
'c', 0x00U,
'a', 0x00U,
't', 0x00U,
'o', 0x00U,
'r', 0x00U,
' ', 0x00U,
'B', 0x00U,
'o', 0x00U,
'a', 0x00U,
'r', 0x00U,
'd', 0x00U,
};
/* ========================================================================
* Language / String List (используется USB_DeviceGetDescriptor)
* ======================================================================== */
/* Массивы строк и длин — индексируются по (stringIndex - 1) */
static uint8_t *g_UsbDeviceStringDescriptorArray[USB_DEVICE_STRING_COUNT] = {
g_UsbDeviceString0,
g_UsbDeviceString1,
g_UsbDeviceString2,
};
static uint32_t g_UsbDeviceStringDescriptorLength[USB_DEVICE_STRING_COUNT] = {
sizeof(g_UsbDeviceString0),
sizeof(g_UsbDeviceString1),
sizeof(g_UsbDeviceString2),
};
usb_language_t g_UsbDeviceLanguage[USB_DEVICE_LANGUAGE_COUNT] = { {
g_UsbDeviceStringDescriptorArray,
g_UsbDeviceStringDescriptorLength,
(uint16_t) 0x0409U,
} };
usb_language_list_t g_UsbDeviceLanguageList = {
g_UsbDeviceString0,
sizeof(g_UsbDeviceString0),
g_UsbDeviceLanguage,
USB_DEVICE_LANGUAGE_COUNT,
};
/* ========================================================================
* Descriptor Callbacks вызываются NXP USB стеком
* ======================================================================== */
usb_status_t USB_DeviceGetDescriptor(usb_device_handle handle, usb_setup_struct_t *setup,
uint32_t *length, uint8_t **buffer)
{
uint8_t descriptorType = (uint8_t) ((setup->wValue & 0xFF00U) >> 8U);
uint8_t descriptorIndex = (uint8_t) ((setup->wValue & 0x00FFU));
usb_status_t ret = kStatus_USB_Success;
if (USB_REQUEST_STANDARD_GET_DESCRIPTOR != setup->bRequest)
{
return kStatus_USB_InvalidRequest;
}
switch (descriptorType)
{
case USB_DESCRIPTOR_TYPE_STRING:
{
if (descriptorIndex == 0U)
{
*buffer = (uint8_t *) g_UsbDeviceLanguageList.languageString;
*length = g_UsbDeviceLanguageList.stringLength;
}
else
{
uint8_t langId = USB_DEVICE_LANGUAGE_COUNT;
for (uint8_t i = 0U; i < USB_DEVICE_LANGUAGE_COUNT; i++)
{
if (setup->wIndex == g_UsbDeviceLanguageList.languageList[i].languageId)
{
langId = i;
break;
}
}
if (USB_DEVICE_LANGUAGE_COUNT == langId)
{
ret = kStatus_USB_InvalidRequest;
break;
}
uint8_t strIdx = descriptorIndex - 1U;
if (strIdx < USB_DEVICE_STRING_COUNT)
{
*buffer = (uint8_t *) g_UsbDeviceLanguageList.languageList[langId].string[strIdx];
*length = g_UsbDeviceLanguageList.languageList[langId].length[strIdx];
}
else
{
ret = kStatus_USB_InvalidRequest;
}
}
break;
}
case USB_DESCRIPTOR_TYPE_DEVICE:
{
*buffer = g_UsbDeviceDescriptor;
*length = USB_DESCRIPTOR_LENGTH_DEVICE;
break;
}
case USB_DESCRIPTOR_TYPE_CONFIGURE:
{
*buffer = g_UsbDeviceConfigurationDescriptor;
*length = USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL;
break;
}
default:
ret = kStatus_USB_InvalidRequest;
break;
}
return ret;
}
/* ---- Chapter 9: Set/Get Configure/Interface ---- */
usb_status_t USB_DeviceSetConfigure(usb_device_handle handle, uint8_t cfg)
{
if (cfg == 0U)
{
return kStatus_USB_Error;
}
g_currentConfigure = cfg;
return USB_DeviceCallback(handle, kUSB_DeviceEventSetConfiguration, &cfg);
}
usb_status_t USB_DeviceGetConfigure(usb_device_handle handle, uint8_t *cfg)
{
*cfg = g_currentConfigure;
return kStatus_USB_Success;
}
usb_status_t USB_DeviceSetInterface(usb_device_handle handle, uint8_t iface, uint8_t alt)
{
if (iface < USB_CDC_VCOM_INTERFACE_COUNT)
{
g_interface[iface] = alt;
return USB_DeviceCallback(handle, kUSB_DeviceEventSetInterface, &iface);
}
return kStatus_USB_InvalidRequest;
}
usb_status_t USB_DeviceGetInterface(usb_device_handle handle, uint8_t iface, uint8_t *alt)
{
if (iface < USB_CDC_VCOM_INTERFACE_COUNT)
{
*alt = g_interface[iface];
return kStatus_USB_Success;
}
return kStatus_USB_InvalidRequest;
}
/* ---- USB_DeviceSetSpeed ---- */
usb_status_t USB_DeviceSetSpeed(usb_device_handle handle, uint8_t speed)
{
usb_descriptor_union_t *ptr1;
usb_descriptor_union_t *ptr2;
ptr1 = (usb_descriptor_union_t *) (&g_UsbDeviceConfigurationDescriptor[0]);
ptr2 =
(usb_descriptor_union_t
*) (&g_UsbDeviceConfigurationDescriptor[USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL - 1U]);
while (ptr1 < ptr2)
{
if (ptr1->common.bDescriptorType == USB_DESCRIPTOR_TYPE_ENDPOINT)
{
/* Interrupt IN */
if (((ptr1->endpoint.bEndpointAddress &
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) &&
((ptr1->endpoint.bEndpointAddress & 0x0FU) == USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT))
{
if (USB_SPEED_HIGH == speed)
{
ptr1->endpoint.bInterval = HS_CDC_VCOM_INTERRUPT_IN_INTERVAL;
USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(HS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE,
ptr1->endpoint.wMaxPacketSize);
}
else
{
ptr1->endpoint.bInterval = FS_CDC_VCOM_INTERRUPT_IN_INTERVAL;
USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE,
ptr1->endpoint.wMaxPacketSize);
}
}
/* Bulk IN */
else if (((ptr1->endpoint.bEndpointAddress &
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) &&
((ptr1->endpoint.bEndpointAddress & 0x0FU) == USB_CDC_VCOM_BULK_IN_ENDPOINT))
{
if (USB_SPEED_HIGH == speed)
{
USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(HS_CDC_VCOM_BULK_IN_PACKET_SIZE,
ptr1->endpoint.wMaxPacketSize);
}
else
{
USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(FS_CDC_VCOM_BULK_IN_PACKET_SIZE,
ptr1->endpoint.wMaxPacketSize);
}
}
/* Bulk OUT */
else if (((ptr1->endpoint.bEndpointAddress &
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) &&
((ptr1->endpoint.bEndpointAddress & 0x0FU) == USB_CDC_VCOM_BULK_OUT_ENDPOINT))
{
if (USB_SPEED_HIGH == speed)
{
USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(HS_CDC_VCOM_BULK_OUT_PACKET_SIZE,
ptr1->endpoint.wMaxPacketSize);
}
else
{
USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(FS_CDC_VCOM_BULK_OUT_PACKET_SIZE,
ptr1->endpoint.wMaxPacketSize);
}
}
else
{
/* other endpoints — no action */
}
}
ptr1 = (usb_descriptor_union_t *) ((uint8_t *) ptr1 + ptr1->common.bLength);
}
return kStatus_USB_Success;
}

View file

@ -0,0 +1,97 @@
/*
* Copyright 2025 MU LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file usb_cdc_hw.c
* @brief Аппаратная инициализация USB1 (EHCI0): clock, PHY, IRQ.
*
* Функции вызываются из usb_cdc.c при инициализации.
* IRQ handler делегирует обработку в NXP USB device stack.
*/
#include "board.h"
#include "clock_config.h"
#include "usb.h"
#include "usb_device.h"
#include "usb_device_config.h"
#include "usb_phy.h"
/* --------------------------------------------------------------------------
* Определения платы (из board.h / schematic)
* -------------------------------------------------------------------------- */
/** D_CAL, TXCAL45DP, TXCAL45DM — калибровка USB PHY. */
#define BOARD_USB_PHY_D_CAL (0x0CU)
#define BOARD_USB_PHY_TXCAL45DP (0x06U)
#define BOARD_USB_PHY_TXCAL45DM (0x06U)
/** Приоритет USB прерывания (ниже числовое значение = выше приоритет). */
#define USB_DEVICE_INTERRUPT_PRIORITY (3U)
/** Контроллер: USB1 = kUSB_ControllerEhci0. */
#define CONTROLLER_ID kUSB_ControllerEhci0
/* --------------------------------------------------------------------------
* Внешний символ handle USB device, определён в usb_cdc.c
* -------------------------------------------------------------------------- */
extern usb_device_handle g_usbDeviceHandle;
/* --------------------------------------------------------------------------
* IRQ Handler
* -------------------------------------------------------------------------- */
/**
* @brief USB OTG1 IRQ делегирует в NXP EHCI ISR.
*
* Имя совпадает с вектором прерывания в startup_MIMXRT1052.S.
* Внутри только вызов SDK функции, без блокировки и аллокаций.
*/
void USB_OTG1_IRQHandler(void)
{
USB_DeviceEhciIsrFunction(g_usbDeviceHandle);
}
/* --------------------------------------------------------------------------
* Clock + PHY
* -------------------------------------------------------------------------- */
/**
* @brief Включить тактирование USB1 PHY 480 MHz и инициализировать PHY.
*
* Вызывается один раз из bsp_usb_cdc_init() до USB_DeviceInit().
*/
void USB_DeviceClockInit(void)
{
usb_phy_config_struct_t phyConfig = {
BOARD_USB_PHY_D_CAL,
BOARD_USB_PHY_TXCAL45DP,
BOARD_USB_PHY_TXCAL45DM,
};
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
USB_EhciPhyInit(CONTROLLER_ID, BOARD_XTAL0_CLK_HZ, &phyConfig);
}
/* --------------------------------------------------------------------------
* NVIC
* -------------------------------------------------------------------------- */
/**
* @brief Разрешить USB1 прерывание в NVIC.
*
* Вызывается один раз из bsp_usb_cdc_init() после USB_DeviceInit().
*/
void USB_DeviceIsrEnable(void)
{
uint8_t irqNumber;
uint8_t usbDeviceEhciIrq[] = USBHS_IRQS;
irqNumber = usbDeviceEhciIrq[CONTROLLER_ID - kUSB_ControllerEhci0];
NVIC_SetPriority((IRQn_Type) irqNumber, USB_DEVICE_INTERRUPT_PRIORITY);
EnableIRQ((IRQn_Type) irqNumber);
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _USB_DEVICE_CDC_ACM_H_
#define _USB_DEVICE_CDC_ACM_H_ 1
/*******************************************************************************
* Definitions
******************************************************************************/
#define USB_DEVICE_CONFIG_CDC_ACM_MAX_INSTANCE (1)
#define USB_DEVICE_CONFIG_CDC_COMM_CLASS_CODE (0x02)
#define USB_DEVICE_CONFIG_CDC_DATA_CLASS_CODE (0x0A)
/* Class specific request Codes */
#define USB_DEVICE_CDC_REQUEST_SEND_ENCAPSULATED_COMMAND (0x00)
#define USB_DEVICE_CDC_REQUEST_GET_ENCAPSULATED_RESPONSE (0x01)
#define USB_DEVICE_CDC_REQUEST_SET_COMM_FEATURE (0x02)
#define USB_DEVICE_CDC_REQUEST_GET_COMM_FEATURE (0x03)
#define USB_DEVICE_CDC_REQUEST_CLEAR_COMM_FEATURE (0x04)
#define USB_DEVICE_CDC_REQUEST_SET_AUX_LINE_STATE (0x10)
#define USB_DEVICE_CDC_REQUEST_SET_HOOK_STATE (0x11)
#define USB_DEVICE_CDC_REQUEST_PULSE_SETUP (0x12)
#define USB_DEVICE_CDC_REQUEST_SEND_PULSE (0x13)
#define USB_DEVICE_CDC_REQUEST_SET_PULSE_TIME (0x14)
#define USB_DEVICE_CDC_REQUEST_RING_AUX_JACK (0x15)
#define USB_DEVICE_CDC_REQUEST_SET_LINE_CODING (0x20)
#define USB_DEVICE_CDC_REQUEST_GET_LINE_CODING (0x21)
#define USB_DEVICE_CDC_REQUEST_SET_CONTROL_LINE_STATE (0x22)
#define USB_DEVICE_CDC_REQUEST_SEND_BREAK (0x23)
#define USB_DEVICE_CDC_REQUEST_SET_RINGER_PARAMS (0x30)
#define USB_DEVICE_CDC_REQUEST_GET_RINGER_PARAMS (0x31)
#define USB_DEVICE_CDC_REQUEST_SET_OPERATION_PARAM (0x32)
#define USB_DEVICE_CDC_REQUEST_GET_OPERATION_PARAM (0x33)
#define USB_DEVICE_CDC_REQUEST_SET_LINE_PARAMS (0x34)
#define USB_DEVICE_CDC_REQUEST_GET_LINE_PARAMS (0x35)
#define USB_DEVICE_CDC_REQUEST_DIAL_DIGITS (0x36)
#define USB_DEVICE_CDC_REQUEST_SET_UNIT_PARAMETER (0x37)
#define USB_DEVICE_CDC_REQUEST_GET_UNIT_PARAMETER (0x38)
#define USB_DEVICE_CDC_REQUEST_CLEAR_UNIT_PARAMETER (0x39)
#define USB_DEVICE_CDC_REQUEST_GET_PROFILE (0x3A)
#define USB_DEVICE_CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS (0x40)
#define USB_DEVICE_CDC_REQUEST_SET_ETHERNET_POW_PATTER_FILTER (0x41)
#define USB_DEVICE_CDC_REQUEST_GET_ETHERNET_POW_PATTER_FILTER (0x42)
#define USB_DEVICE_CDC_REQUEST_SET_ETHERNET_PACKET_FILTER (0x43)
#define USB_DEVICE_CDC_REQUEST_GET_ETHERNET_STATISTIC (0x44)
#define USB_DEVICE_CDC_REQUEST_SET_ATM_DATA_FORMAT (0x50)
#define USB_DEVICE_CDC_REQUEST_GET_ATM_DEVICE_STATISTICS (0x51)
#define USB_DEVICE_CDC_REQUEST_SET_ATM_DEFAULT_VC (0x52)
#define USB_DEVICE_CDC_REQUEST_GET_ATM_VC_STATISTICS (0x53)
#define USB_DEVICE_CDC_REQUEST_MDLM_SPECIFIC_REQUESTS_MASK (0x7F)
#define USB_DEVICE_CDC_REQUEST_GET_ABSTRACT_STATE (0x23)
#define USB_DEVICE_CDC_REQUEST_GET_COUNTRY_SETTING (0x24)
#define USB_DEVICE_CDC_REQUEST_SET_ABSTRACT_STATE (0x25)
#define USB_DEVICE_CDC_REQUEST_SET_COUNTRY_SETTING (0x26)
/* Class Specific Notification Codes */
#define USB_DEVICE_CDC_REQUEST_NETWORK_CONNECTION_NOTIF (0x00)
#define USB_DEVICE_CDC_REQUEST_RESPONSE_AVAIL_NOTIF (0x01)
#define USB_DEVICE_CDC_REQUEST_AUX_JACK_HOOK_STATE_NOTIF (0x08)
#define USB_DEVICE_CDC_REQUEST_RING_DETECT_NOTIF (0x09)
#define USB_DEVICE_CDC_REQUEST_SERIAL_STATE_NOTIF (0x20)
#define USB_DEVICE_CDC_REQUEST_CALL_STATE_CHANGE_NOTIF (0x28)
#define USB_DEVICE_CDC_REQUEST_LINE_STATE_CHANGE_NOTIF (0x29)
#define USB_DEVICE_CDC_REQUEST_CONNECTION_SPEED_CHANGE_NOTIF (0x2A)
/* Communications Feature Selector Codes */
#define USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE (0x01)
#define USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING (0x02)
/* Control Signal Bitmap Values */
#define USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION (0x02)
#define USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE (0x01)
/* UART State Bitmap Values */
#define USB_DEVICE_CDC_UART_STATE_RX_CARRIER (0x01)
#define USB_DEVICE_CDC_UART_STATE_TX_CARRIER (0x02)
#define USB_DEVICE_CDC_UART_STATE_BREAK (0x04)
#define USB_DEVICE_CDC_UART_STATE_RING_SIGNAL (0x08)
#define USB_DEVICE_CDC_UART_STATE_FRAMING (0x10)
#define USB_DEVICE_CDC_UART_STATE_PARITY (0x20)
#define USB_DEVICE_CDC_UART_STATE_OVERRUN (0x40)
#endif /* _USB_DEVICE_CDC_ACM_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __USB_DEVICE_CH9_H__
#define __USB_DEVICE_CH9_H__
/*******************************************************************************
* Definitions
******************************************************************************/
/*!
* @addtogroup usb_device_ch9
* @{
*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @brief Defines USB device status size when the host request to get device status */
#define USB_DEVICE_STATUS_SIZE (0x02U)
/*! @brief Defines USB device interface status size when the host request to get interface status */
#define USB_INTERFACE_STATUS_SIZE (0x02U)
/*! @brief Defines USB device endpoint status size when the host request to get endpoint status */
#define USB_ENDPOINT_STATUS_SIZE (0x02U)
/*! @brief Defines USB device configuration size when the host request to get current configuration */
#define USB_CONFIGURE_SIZE (0X01U)
/*! @brief Defines USB device interface alternate setting size when the host request to get interface alternate setting
*/
#define USB_INTERFACE_SIZE (0X01U)
/*! @brief Defines USB device status mask */
#define USB_GET_STATUS_DEVICE_MASK (0x03U)
/*! @brief Defines USB device interface status mask */
#define USB_GET_STATUS_INTERFACE_MASK (0x03U)
/*! @brief Defines USB device endpoint status mask */
#define USB_GET_STATUS_ENDPOINT_MASK (0x03U)
/*! @brief Control read and write sequence */
typedef enum _usb_device_control_read_write_sequence
{
kUSB_DeviceControlPipeSetupStage = 0U, /*!< Setup stage */
kUSB_DeviceControlPipeDataStage, /*!< Data stage */
kUSB_DeviceControlPipeStatusStage, /*!< status stage */
} usb_device_control_read_write_sequence_t;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*******************************************************************************
* API
******************************************************************************/
/*!
* @brief Initialize the control pipes.
*
* The function is used to initialize the control pipes. This function should be called when event
* kUSB_DeviceEventBusReset is received.
*
* @param handle The device handle.
*
* @return A USB error code or kStatus_USB_Success.
*/
extern usb_status_t USB_DeviceControlPipeInit(usb_device_handle handle);
#if defined(__cplusplus)
}
#endif
/*! @}*/
#endif /* __USB_DEVICE_CH9_H__ */

View file

@ -0,0 +1,52 @@
/*
* Copyright 2025 TFT Project
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file usb_device_config.h
* @brief Конфигурация NXP USB Device Stack для bsp_usb_cdc.
*
* Этот файл application-specific конфиг, который NXP USB middleware
* подключает через include path. Не является частью SDK.
*
* Настройки под bare-metal CDC ACM на USB1 (EHCI0).
*/
#ifndef USB_DEVICE_CONFIG_H_
#define USB_DEVICE_CONFIG_H_
/* ---- Контроллер -------------------------------------------------------- */
#define USB_DEVICE_CONFIG_EHCI (1U)
#define USB_DEVICE_CONFIG_KHCI (0U)
#define USB_DEVICE_CONFIG_LPCIP3511FS (0U)
#define USB_DEVICE_CONFIG_LPCIP3511HS (0U)
/** Суммарное количество активных контроллеров. */
#define USB_DEVICE_CONFIG_NUM \
(USB_DEVICE_CONFIG_EHCI + USB_DEVICE_CONFIG_KHCI + USB_DEVICE_CONFIG_LPCIP3511FS + \
USB_DEVICE_CONFIG_LPCIP3511HS)
/* ---- EHCI-специфичные -------------------------------------------------- */
#define USB_DEVICE_CONFIG_EHCI_MAX_DTD (16U)
/* ---- Классы устройства ------------------------------------------------- */
#define USB_DEVICE_CONFIG_CDC_ACM (1U)
#define USB_DEVICE_CONFIG_HID (0U)
#define USB_DEVICE_CONFIG_MSC (0U)
#define USB_DEVICE_CONFIG_AUDIO (0U)
#define USB_DEVICE_CONFIG_VIDEO (0U)
#define USB_DEVICE_CONFIG_PHDC (0U)
#define USB_DEVICE_CONFIG_DFU (0U)
#define USB_DEVICE_CONFIG_PRINTER (0U)
#define USB_DEVICE_CONFIG_CCID (0U)
#define USB_DEVICE_CONFIG_MTP (0U)
#define USB_DEVICE_CONFIG_CDC_ECM (0U)
#define USB_DEVICE_CONFIG_CDC_RNDIS (0U)
/* ---- Общие настройки --------------------------------------------------- */
#define USB_DEVICE_CONFIG_ENDPOINTS (4U)
#define USB_DEVICE_CONFIG_SELF_POWER (1U)
#define USB_DEVICE_CONFIG_MAX_MESSAGES (8U)
#define USB_DEVICE_CONFIG_ROOT2_TEST (0U)
#endif /* USB_DEVICE_CONFIG_H_ */

View file

@ -0,0 +1,116 @@
/*
* Copyright 2025 TFT Project
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file usb_device_descriptor.h
* @brief USB CDC ACM дескрипторы константы и прототипы.
*
* Определяет VID/PID, номера эндпоинтов, размеры пакетов.
* Используется только внутри bsp_usb_cdc.
*/
#ifndef USB_DEVICE_DESCRIPTOR_H_
#define USB_DEVICE_DESCRIPTOR_H_
/* ---- Версии USB -------------------------------------------------------- */
#define USB_DEVICE_SPECIFIC_BCD_VERSION (0x0200U)
#define USB_DEVICE_DEMO_BCD_VERSION (0x0101U)
/* ---- VID / PID --------------------------------------------------------- */
#define USB_DEVICE_VID (0x1996U) /* TODO: заменить на свой */
#define USB_DEVICE_PID (0x00ADU) /* TODO: заменить на свой */
/* ---- CDC коды классов -------------------------------------------------- */
#define CDC_COMM_CLASS (0x02U)
#define CDC_DATA_CLASS (0x0AU)
/* ---- CDC SubClass / Protocol ------------------------------------------- */
#define USB_CDC_ABSTRACT_CONTROL_MODEL (0x02U)
#define USB_CDC_NO_CLASS_SPECIFIC_PROTOCOL (0x00U)
/* ---- Functional Descriptor SubTypes ------------------------------------ */
#define USB_CDC_HEADER_FUNC_DESC (0x00U)
#define USB_CDC_CALL_MANAGEMENT_FUNC_DESC (0x01U)
#define USB_CDC_ABSTRACT_CONTROL_FUNC_DESC (0x02U)
#define USB_CDC_UNION_FUNC_DESC (0x06U)
/* ---- Длины функциональных дескрипторов --------------------------------- */
#define USB_DESCRIPTOR_LENGTH_CDC_HEADER_FUNC (5U)
#define USB_DESCRIPTOR_LENGTH_CDC_CALL_MANAG (5U)
#define USB_DESCRIPTOR_LENGTH_CDC_ABSTRACT (4U)
#define USB_DESCRIPTOR_LENGTH_CDC_UNION_FUNC (5U)
/* ---- CS Descriptor Types ----------------------------------------------- */
#define USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE (0x24U)
#define USB_DESCRIPTOR_TYPE_CDC_CS_ENDPOINT (0x25U)
/* ---- Конфигурация, интерфейсы, эндпоинты ------------------------------- */
#define USB_DEVICE_CONFIGURATION_COUNT (1U)
#define USB_DEVICE_STRING_COUNT (3U)
#define USB_DEVICE_LANGUAGE_COUNT (1U)
#define USB_CDC_VCOM_CONFIGURE_INDEX (1U)
#define USB_CDC_VCOM_ENDPOINT_CIC_COUNT (1U)
#define USB_CDC_VCOM_ENDPOINT_DIC_COUNT (2U)
#define USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT (1U)
#define USB_CDC_VCOM_BULK_IN_ENDPOINT (2U)
#define USB_CDC_VCOM_BULK_OUT_ENDPOINT (3U)
#define USB_CDC_VCOM_INTERFACE_COUNT (2U)
#define USB_CDC_VCOM_COMM_INTERFACE_INDEX (0U)
#define USB_CDC_VCOM_DATA_INTERFACE_INDEX (1U)
/* ---- Размеры пакетов --------------------------------------------------- */
#define HS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE (16U)
#define FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE (16U)
#define HS_CDC_VCOM_INTERRUPT_IN_INTERVAL (0x07U)
#define FS_CDC_VCOM_INTERRUPT_IN_INTERVAL (0x08U)
#define HS_CDC_VCOM_BULK_IN_PACKET_SIZE (512U)
#define FS_CDC_VCOM_BULK_IN_PACKET_SIZE (64U)
#define HS_CDC_VCOM_BULK_OUT_PACKET_SIZE (512U)
#define FS_CDC_VCOM_BULK_OUT_PACKET_SIZE (64U)
/* ---- Device class codes ------------------------------------------------ */
#define USB_DEVICE_CLASS (0x02U)
#define USB_DEVICE_SUBCLASS (0x00U)
#define USB_DEVICE_PROTOCOL (0x00U)
#define USB_DEVICE_MAX_POWER (0x32U)
/* ---- CIC / DIC class codes -------------------------------------------- */
#define USB_CDC_VCOM_CIC_CLASS (CDC_COMM_CLASS)
#define USB_CDC_VCOM_CIC_SUBCLASS (USB_CDC_ABSTRACT_CONTROL_MODEL)
#define USB_CDC_VCOM_CIC_PROTOCOL (USB_CDC_NO_CLASS_SPECIFIC_PROTOCOL)
#define USB_CDC_VCOM_DIC_CLASS (CDC_DATA_CLASS)
#define USB_CDC_VCOM_DIC_SUBCLASS (0x00U)
#define USB_CDC_VCOM_DIC_PROTOCOL (USB_CDC_NO_CLASS_SPECIFIC_PROTOCOL)
/* ---- Alternate settings ------------------------------------------------ */
#define USB_CDC_VCOM_COMM_INTERFACE_ALTERNATE_COUNT (1U)
#define USB_CDC_VCOM_DATA_INTERFACE_ALTERNATE_COUNT (1U)
#define USB_CDC_VCOM_COMM_INTERFACE_ALTERNATE_0 (0U)
#define USB_CDC_VCOM_DATA_INTERFACE_ALTERNATE_0 (0U)
/* ---- String descriptor lengths (computed from arrays) ------------------ */
#define USB_DESCRIPTOR_LENGTH_STRING0 (sizeof(g_UsbDeviceString0))
#define USB_DESCRIPTOR_LENGTH_STRING1 (sizeof(g_UsbDeviceString1))
#define USB_DESCRIPTOR_LENGTH_STRING2 (sizeof(g_UsbDeviceString2))
#define USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL (sizeof(g_UsbDeviceConfigurationDescriptor))
/* ---- Прототипы (реализация в usb_cdc.c) -------------------------------- */
/**
* @brief Обработка USB device событий (bus reset, set config и т.д.).
*/
extern usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param);
/**
* @brief Обновление дескрипторов при смене скорости HS/FS.
*/
extern usb_status_t USB_DeviceSetSpeed(usb_device_handle handle, uint8_t speed);
#endif /* USB_DEVICE_DESCRIPTOR_H_ */

View file

@ -18,11 +18,9 @@ target_link_libraries(
PRIVATE bsp_board
bsp_led
bsp_tick
bsp_can
bsp_button
bsp_uart_host
bsp_boot_xip
bsp_opto
bsp_usb_cdc
port_log_uart
lib_external # SEGGER RTT если включён через SEGGER_RTT_ENABLED
)

View file

@ -3,65 +3,12 @@
#include "bsp/led.h"
#include "bsp/tick.h"
#include "bsp/uart_host.h"
#include "fsl_common.h"
#include "bsp/usb_cdc.h"
#include "log/log.h"
#include "port/log_uart.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
/* --------------------------------------------------------------------------
* Проверка non-cacheable региона
* --------------------------------------------------------------------------
* Буфер размещён в секции NonCacheable OCRAM @ 0x20200000.
* MPU Region 9 настраивает эту область как Normal non-cacheable,
* поэтому записи CPU сразу видны DMA без SCB_CleanDCache().
* -------------------------------------------------------------------------- */
#define NCACHE_TEST_BUF_SIZE 64U
#define NCACHE_REGION_BASE 0x20200000U
#define NCACHE_REGION_END 0x20202000U /* 8 KB — размер из линкер-скрипта */
AT_NONCACHEABLE_SECTION_ALIGN(static uint8_t s_ncache_buf[NCACHE_TEST_BUF_SIZE], 4U);
static bool ncache_test_run(void)
{
uint32_t buf_addr = (uint32_t) s_ncache_buf;
/* Проверяем что буфер физически лежит в ожидаемом ncache регионе */
if (buf_addr < NCACHE_REGION_BASE || buf_addr >= NCACHE_REGION_END)
{
LOG_E("NCACHE", "buf addr 0x%08lx outside ncache region [0x%08x..0x%08x)",
(unsigned long) buf_addr, NCACHE_REGION_BASE, NCACHE_REGION_END);
return false;
}
/* Записываем паттерн */
for (uint32_t i = 0U; i < NCACHE_TEST_BUF_SIZE; i++)
{
s_ncache_buf[i] = (uint8_t) (i ^ 0xA5U);
}
/* Для non-cacheable памяти flush не нужен — данные уже когерентны.
* Вызываем CleanDCache чтобы убедиться что он не ломает данные. */
SCB_CleanDCache();
/* Читаем обратно и сравниваем */
for (uint32_t i = 0U; i < NCACHE_TEST_BUF_SIZE; i++)
{
uint8_t expected = (uint8_t) (i ^ 0xA5U);
if (s_ncache_buf[i] != expected)
{
LOG_E("NCACHE", "mismatch at [%lu]: got 0x%02x expected 0x%02x", (unsigned long) i,
s_ncache_buf[i], expected);
return false;
}
}
return true;
}
int main(void)
{
@ -76,20 +23,22 @@ int main(void)
LOG_I("BOOT", "firmware_test started, tick=%lu", (unsigned long) bsp_tick_get_ms());
if (ncache_test_run())
if (bsp_usb_cdc_init() == BSP_OK)
{
LOG_I("NCACHE", "OK addr=0x%08lx size=%u", (unsigned long) (uint32_t) s_ncache_buf,
NCACHE_TEST_BUF_SIZE);
}
else
{
LOG_E("NCACHE", "FAIL");
LOG_I("BOOT", "USB CDC ACM initialized");
}
bsp_led_on(LED_APP);
bool is_connection_established = false;
while (1)
{
if (bsp_usb_cdc_is_ready() == true && is_connection_established == false)
{
is_connection_established = true;
LOG_I("BOOT", "USB CDC ACM ready");
}
bsp_usb_cdc_poll();
bsp_led_toggle(LED_HEARTBEAT);
bsp_delay(DELAY_MS);
}

View file

@ -1,317 +0,0 @@
.
├── CMakeLists.txt
├── CMakePresets.json
├── Justfile
├── README.md
├── bootstrap.sh
├── bsp
│   ├── CMakeLists.txt
│   ├── README.md
│   ├── button
│   │   ├── CMakeLists.txt
│   │   ├── README.md
│   │   ├── include
│   │   └── src
│   ├── can
│   │   ├── CMakeLists.txt
│   │   ├── README.md
│   │   ├── include
│   │   ├── mocks
│   │   └── src
│   ├── common
│   │   ├── CMakeLists.txt
│   │   └── include
│   ├── generated
│   │   ├── README.md
│   │   ├── TFT_Board.mex
│   │   ├── board
│   │   ├── board.c
│   │   ├── board.h
│   │   ├── clock_config.c
│   │   ├── clock_config.h
│   │   ├── pin_mux.c
│   │   ├── pin_mux.h
│   │   ├── startup
│   │   └── syscalls.c
│   ├── led
│   │   ├── CMakeLists.txt
│   │   ├── README.md
│   │   ├── include
│   │   └── src
│   ├── opto
│   │   ├── CMakeLists.txt
│   │   ├── README.md
│   │   ├── include
│   │   └── src
│   ├── sdram
│   │   ├── README.md
│   │   ├── include
│   │   └── src
│   ├── tick
│   │   ├── CMakeLists.txt
│   │   ├── README.md
│   │   ├── include
│   │   └── src
│   ├── uart_host
│   │   ├── CMakeLists.txt
│   │   ├── README.md
│   │   ├── include
│   │   ├── mocks
│   │   └── src
│   └── usb_cdc
│   ├── CMakeLists.txt
│   ├── README.md
│   ├── include
│   └── src
├── build
│   ├── Debug
│   │   ├── CMakeCache.txt
│   │   ├── CMakeFiles
│   │   ├── bsp
│   │   ├── build.ninja
│   │   ├── cmake_install.cmake
│   │   ├── compile_commands.json
│   │   ├── firmware
│   │   ├── firmware_test.bin
│   │   ├── firmware_test.elf
│   │   ├── firmware_test.map
│   │   ├── firmware_test_hab.bin
│   │   ├── lib
│   │   ├── port
│   │   ├── sdk
│   │   └── utils
│   ├── host-debug
│   │   ├── CMakeCache.txt
│   │   ├── CMakeFiles
│   │   ├── CTestTestfile.cmake
│   │   ├── Testing
│   │   ├── bsp
│   │   ├── build.ninja
│   │   ├── cmake_install.cmake
│   │   ├── compile_commands.json
│   │   ├── lib
│   │   ├── port
│   │   ├── sdk
│   │   ├── tests
│   │   └── utils
│   └── host-release
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── CTestTestfile.cmake
│   ├── Testing
│   ├── bsp
│   ├── build.ninja
│   ├── cmake_install.cmake
│   ├── compile_commands.json
│   ├── lib
│   ├── port
│   ├── sdk
│   ├── tests
│   └── utils
├── cmake
│   ├── linker
│   │   ├── MIMXRT1052xxxxx_flexspi_nor.ld
│   │   ├── MIMXRT1052xxxxx_flexspi_nor_sdram.ld
│   │   ├── MIMXRT1052xxxxx_ram.ld
│   │   ├── MIMXRT1052xxxxx_sdram.ld
│   │   └── MIMXRT1052xxxxx_sdram_txt.ld
│   ├── toolchain_arm.cmake
│   └── toolchain_host.cmake
├── docs
│   ├── DEV_ARCH.md
│   ├── HOW_TO_DEBUG.md
│   ├── HOW_TO_FLASH.md
│   ├── hardware
│   │   ├── MCULINKINSERT.pdf
│   │   ├── board
│   │   └── m5stamPLC
│   ├── mimxrt1052
│   │   ├── BOOT_FLAGS.md
│   │   ├── HAB_GUIDE.md
│   │   ├── manufacturing_user's_guide.pdf
│   │   └── mcu_rm.pdf
│   └── testing
│   ├── hil
│   └── host
├── firmware
│   ├── bootloader
│   ├── test
│   │   ├── CMakeLists.txt
│   │   ├── README.md
│   │   ├── arch.svg
│   │   └── main.c
│   └── tft_app
├── just
│   ├── build.just
│   ├── ci.just
│   └── host.just
├── lib
│   ├── CMakeLists.txt
│   ├── SEGGER
│   │   ├── RTT
│   │   └── wrapper
│   ├── Unity
│   │   ├── CMakeLists.txt
│   │   ├── LICENSE.txt
│   │   ├── README.md
│   │   ├── auto
│   │   ├── docs
│   │   ├── examples
│   │   ├── extras
│   │   ├── library.json
│   │   ├── meson.build
│   │   ├── meson_options.txt
│   │   ├── platformio-build.py
│   │   ├── src
│   │   ├── test
│   │   └── unityConfig.cmake
│   └── fff
│   ├── CMakeLists.txt
│   ├── LICENSE
│   ├── README.md
│   ├── buildandtest
│   ├── examples
│   ├── fakegen.rb
│   ├── fff.h
│   └── test
├── port
│   ├── CMakeLists.txt
│   ├── README.md
│   └── log
│   ├── CMakeLists.txt
│   ├── README.md
│   ├── include
│   └── src
├── project_tree.txt
├── pyocd.yaml
├── pyocd_debug.yaml
├── sdk
│   ├── CMSIS
│   │   ├── Core
│   │   ├── DSP
│   │   ├── Driver
│   │   ├── LICENSE.txt
│   │   ├── NN
│   │   └── RTOS2
│   ├── CMakeLists.txt
│   ├── COPYING-BSD-3
│   ├── LA_OPT_NXP_Software_License.txt
│   ├── MIMXRT1052xxxxB_manifest_v3_15.xml
│   ├── README.md
│   ├── SW-Content-Register.txt
│   ├── boards
│   │   └── evkbimxrt1050
│   ├── components
│   │   ├── audio
│   │   ├── button
│   │   ├── codec
│   │   ├── common_task
│   │   ├── crc
│   │   ├── display
│   │   ├── exception_handling
│   │   ├── flash
│   │   ├── gpio
│   │   ├── i2c
│   │   ├── internal_flash
│   │   ├── led
│   │   ├── lists
│   │   ├── log
│   │   ├── mem_manager
│   │   ├── messaging
│   │   ├── mx25r_flash
│   │   ├── osa
│   │   ├── panic
│   │   ├── phy
│   │   ├── pmic
│   │   ├── reset
│   │   ├── rng
│   │   ├── rtt
│   │   ├── sensor
│   │   ├── serial_manager
│   │   ├── silicon_id
│   │   ├── spi
│   │   ├── timer
│   │   ├── timer_manager
│   │   ├── touch
│   │   ├── uart
│   │   ├── video
│   │   └── wifi_bt_module
│   ├── devices
│   │   └── MIMXRT1052
│   ├── docs
│   │   └── readme.md
│   ├── middleware
│   │   ├── audio_voice
│   │   ├── cjson
│   │   ├── dhara
│   │   ├── fatfs
│   │   ├── freemaster
│   │   ├── libjpeg
│   │   ├── littlefs
│   │   ├── mcuboot_opensource
│   │   ├── pkcs11
│   │   ├── pngdec
│   │   ├── sdmmc
│   │   ├── tfm
│   │   ├── tinycbor
│   │   └── usb
│   ├── rtos
│   │   └── freertos
│   └── tools
│   └── cmake_toolchain_files
├── tests
│   ├── CMakeLists.txt
│   ├── host
│   │   ├── CMakeLists.txt
│   │   ├── README.md
│   │   ├── button
│   │   ├── can
│   │   ├── led
│   │   ├── log
│   │   ├── mocks
│   │   ├── opto
│   │   ├── ring_buffer
│   │   ├── timeout
│   │   └── uart_host
│   └── target
│   ├── CMakeLists.txt
│   ├── hil_button
│   ├── hil_can
│   ├── hil_opto
│   └── host_uart
├── tools
│   ├── hil
│   │   ├── 01_test_uart.py
│   │   ├── 02_test_opto.py
│   │   ├── 03_test_can.py
│   │   ├── 04_test_button.py
│   │   ├── README.md
│   │   ├── __pycache__
│   │   ├── conftest.py
│   │   ├── env_config.py
│   │   ├── load_and_run.py
│   │   ├── m5
│   │   ├── pyocd_utils.py
│   │   ├── pyproject.toml
│   │   └── uv.lock
│   └── host
│   ├── README.md
│   ├── dcd
│   ├── flash_swd.py
│   ├── flash_usb.py
│   ├── hab
│   ├── pyproject.toml
│   └── uv.lock
└── utils
├── CMakeLists.txt
├── README.md
├── log
│   ├── README.md
│   ├── log.c
│   └── log.h
└── ring_buffer
├── README.md
├── ring_buffer.c
└── ring_buffer.h
185 directories, 130 files

View file

@ -67,3 +67,47 @@ add_sdk_driver(flexspi fsl_flexspi.c)
target_link_libraries(sdk_semc PUBLIC sdk_clock)
target_link_libraries(sdk_flexspi PUBLIC sdk_clock)
# -----------------------------------------------------------------------------
# USB middleware — ручные таргеты (middleware/usb/, не drivers/)
# -----------------------------------------------------------------------------
# --- sdk_osa_bm: OS Abstraction Layer (bare-metal) ---
# Объявлен первым — от него зависят USB таргеты через fsl_os_abstraction.h
add_library(sdk_osa_bm STATIC components/osa/fsl_os_abstraction_bm.c
components/lists/fsl_component_generic_list.c)
target_include_directories(sdk_osa_bm PUBLIC components/osa components/lists)
target_link_libraries(sdk_osa_bm PUBLIC sdk_device sdk_common sdk_usb_config)
target_compile_options(sdk_osa_bm PRIVATE -w)
# --- sdk_usb_common: заголовки USB стека ---
add_library(sdk_usb_common INTERFACE)
target_include_directories(sdk_usb_common SYSTEM
INTERFACE middleware/usb/include)
# --- sdk_usb_config: application-specific конфиги ---
add_library(sdk_usb_config INTERFACE)
target_include_directories(sdk_usb_config SYSTEM
INTERFACE ${CMAKE_SOURCE_DIR}/bsp/usb_cdc/src)
# --- sdk_usb_device_ehci: EHCI контроллер + DCI абстракция ---
add_library(sdk_usb_device_ehci STATIC middleware/usb/device/usb_device_dci.c
middleware/usb/device/usb_device_ehci.c)
target_include_directories(sdk_usb_device_ehci PUBLIC middleware/usb/device)
target_link_libraries(
sdk_usb_device_ehci PUBLIC sdk_device sdk_common sdk_usb_common
sdk_usb_config sdk_osa_bm)
target_compile_options(sdk_usb_device_ehci PRIVATE -w)
# --- sdk_usb_device_ch9: Chapter 9 standard requests ---
# add_library(sdk_usb_device_ch9 STATIC middleware/usb/device/usb_device_ch9.c)
# target_include_directories( sdk_usb_device_ch9 PUBLIC middleware/usb/device
# middleware/usb/device/class) target_link_libraries(sdk_usb_device_ch9 PUBLIC
# sdk_usb_device_ehci) target_compile_options(sdk_usb_device_ch9 PRIVATE -w)
# --- sdk_usb_phy: USB PHY ---
add_library(sdk_usb_phy STATIC middleware/usb/phy/usb_phy.c)
target_include_directories(sdk_usb_phy PUBLIC middleware/usb/phy)
target_link_libraries(sdk_usb_phy PUBLIC sdk_device sdk_common sdk_usb_common
sdk_usb_config sdk_osa_bm)
target_compile_options(sdk_usb_phy PRIVATE -w)