Всем привет! Сегодня будем поднимать USB CDC (VCP) на плате stm32f401c-disco.
USB communications device class (коммуникационный класс устройства) — является составным классом устройства Универсальной последовательной шины. Класс может включать один (или более) интерфейс, такой как интерфейс пользовательского элемента управления, интерфейс передачи данных, аудио или интерфейс запоминающего устройства.
VCP – Виртуальный COM-порт
Базовый класс 02h (Communications and CDC Control)
Этот базовый класс определен для устройств, которые относятся к классу устройств спецификации связи. Эта спецификация определяет используемый набор подкласса и Протокола значений. Значения за пределами определения спецификации защищены. Обратите внимание, что связи класса устройств спецификации требуется несколько значений Кода класса (три), которые будут использоваться в описания устройств, а некоторые, которые будут использоваться в интерфейсе дескрипторов.
Базовый класс 02h
Подкласс xxh
протокол xxh
смысл Communication device class
Базовый класс 0Ah (CDC-Data)
Этот базовый класс определен для устройств, которые относятся к классу устройств спецификации связи. Это спецификация определяет используемый набор подкласса и протокола значений. Значения за пределами определения спецификации защищены. Эти коды класса могут быть использованы только в интерфейсе дескрипторов.
Базовый класс 0Ah
Подкласс xxh
протокол xxh
смысл CDC data device
Дескриптор CDC
/* USB CDC device Configuration Descriptor */ __ALIGN_BEGIN uint8_t USBD_CDC_CfgHSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = { /*Configuration Descriptor*/ 0x09, /* bLength: Configuration Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */ 0x00, 0x02, /* bNumInterfaces: 2 interface */ 0x01, /* bConfigurationValue: Configuration value */ 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ 0xC0, /* bmAttributes: self powered */ 0x32, /* MaxPower 0 mA */ /*---------------------------------------------------------------------------*/ /*Interface Descriptor */ 0x09, /* bLength: Interface Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ /* Interface descriptor type */ 0x00, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x01, /* bNumEndpoints: One endpoints used */ 0x02, /* bInterfaceClass: Communication Interface Class */ 0x02, /* bInterfaceSubClass: Abstract Control Model */ 0x01, /* bInterfaceProtocol: Common AT commands */ 0x00, /* iInterface: */ /*Header Functional Descriptor*/ 0x05, /* bLength: Endpoint Descriptor size */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x00, /* bDescriptorSubtype: Header Func Desc */ 0x10, /* bcdCDC: spec release number */ 0x01, /*Call Management Functional Descriptor*/ 0x05, /* bFunctionLength */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x01, /* bDescriptorSubtype: Call Management Func Desc */ 0x00, /* bmCapabilities: D0+D1 */ 0x01, /* bDataInterface: 1 */ /*ACM Functional Descriptor*/ 0x04, /* bFunctionLength */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ 0x02, /* bmCapabilities */ /*Union Functional Descriptor*/ 0x05, /* bFunctionLength */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x06, /* bDescriptorSubtype: Union func desc */ 0x00, /* bMasterInterface: Communication class interface */ 0x01, /* bSlaveInterface0: Data Class Interface */ /*Endpoint 2 Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ CDC_CMD_EP, /* bEndpointAddress */ 0x03, /* bmAttributes: Interrupt */ LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_CMD_PACKET_SIZE), 0x10, /* bInterval: */ /*---------------------------------------------------------------------------*/ /*Data class interface descriptor*/ 0x09, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */ 0x01, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x02, /* bNumEndpoints: Two endpoints used */ 0x0A, /* bInterfaceClass: CDC */ 0x00, /* bInterfaceSubClass: */ 0x00, /* bInterfaceProtocol: */ 0x00, /* iInterface: */ /*Endpoint OUT Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ CDC_OUT_EP, /* bEndpointAddress */ 0x02, /* bmAttributes: Bulk */ LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), 0x00, /* bInterval: ignore for Bulk transfer */ /*Endpoint IN Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ CDC_IN_EP, /* bEndpointAddress */ 0x02, /* bmAttributes: Bulk */ LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), 0x00 /* bInterval: ignore for Bulk transfer */ } ;
1. Находим строку HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0); и меняем на HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
2. Находим строку #define CDC_DATA_HS_MAX_PACKET_SIZE 512 /* Endpoint IN & OUT Packet size */ и меняем на #define CDC_DATA_HS_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */
3. Производим изменения в usbd_cdc_if.c
static struct { uint8_t Buffer[CDC_DATA_HS_OUT_PACKET_SIZE]; int Position, Size; char ReadDone; } RxBuffer; char VCPInitialized; ... static int8_t CDC_Init_FS(void) { USBD_CDC_SetRxBuffer(&hUsbDeviceFS, RxBuffer.Buffer); VCPInitialized = 1; return (USBD_OK); } ... static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) { RxBuffer.Position = 0; RxBuffer.Size = *Len; RxBuffer.ReadDone = 1; return (USBD_OK); } ... int VCP_read(void *pBuffer, int size) { if (!RxBuffer.ReadDone) return 0; int remaining = RxBuffer.Size - RxBuffer.Position; int todo = MIN(remaining, size); if (todo <= 0) return 0; memcpy(pBuffer, RxBuffer.Buffer + RxBuffer.Position, todo); RxBuffer.Position += todo; if (RxBuffer.Position >= RxBuffer.Size) { RxBuffer.ReadDone = 0; USBD_CDC_ReceivePacket(&hUsbDeviceFS); } return todo; } int VCP_write(const void *pBuffer, int size) { if (size > CDC_DATA_HS_OUT_PACKET_SIZE) { int offset; for (offset = 0; offset < size; offset++) { int todo = MIN(CDC_DATA_HS_OUT_PACKET_SIZE, size - offset); int done = VCP_write(((char *)pBuffer) + offset, todo); if (done != todo) return offset + done; } return size; } USBD_CDC_HandleTypeDef *pCDC = (USBD_CDC_HandleTypeDef *)hUsbDeviceFS.pClassData; while(pCDC->TxState) { } //Wait for previous transfer USBD_CDC_SetTxBuffer(&hUsbDeviceFS, (uint8_t *)pBuffer, size); if (USBD_CDC_TransmitPacket(&hUsbDeviceFS) != USBD_OK) return 0; while(pCDC->TxState) { } //Wait until transfer is done return size; }
4. Теперь нужно добавить в usbd_cdc_if.h несколько строк кода
int VCP_read(void *pBuffer, int size); int VCP_write(const void *pBuffer, int size); extern char VCPInitialized;
5. Устраняем баг для USBD_CDC_TransmitPacket()
if(hcdc->TxState == 0) { hcdc->TxState = 1; USBD_LL_Transmit(pdev, CDC_IN_EP, hcdc->TxBuffer, hcdc->TxLength); return USBD_OK; }
6. И добавляем пример в main.c
#include "stm32f4xx_hal.h" #include "usb_device.h" #include "usbd_core.h" #include "usbd_desc.h" #include "usbd_cdc_if.h" /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* System interrupt init*/ /* Sets the priority grouping field */ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0); HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USB_DEVICE_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ char byte; /* USER CODE BEGIN 3 */ /* Infinite loop */ while(!VCPInitialized) {} while (1) { if (VCP_read(&byte, 1) != 1) continue; VCP_write("\r\nYou typed ", 12); VCP_write(&byte, 1); VCP_write("\r\n", 2); } /* USER CODE END 3 */ } ...
И все готова!, подключаем микро USB к плате, второй вывод к host-у и у нас появляется виртуальный com порт.
By!
6 thoughts on “Старт ARM. Поднимаем USB CDC.”
When i debbuged this code i found that for really big messages this doesn’t work right. There was some issue with size off offset. IT send multiple time the same think.
I corrected it with:
if (size > CDC_DATA_HS_OUT_PACKET_SIZE) {
int offset;
for (offset = 0; offset < size; offset += CDC_DATA_HS_OUT_PACKET_SIZE) {
int todo = MIN(CDC_DATA_HS_OUT_PACKET_SIZE, size - offset);
int done = VCP_write(((char *) pBuffer) + offset, todo);
if (done != todo)
return offset + done;
}
return size;
}
with large data is not working, thanks
Ну и зачем столько путанного кода. Всё это легко организуется средствами генерируемого STM32Cube проекта. Достаточно добавить несколько строчек в функцию ( CDC_Receive_FS (uint8_t* UserRxBufferFS, uint32_t *Len)) . И это доходчиво описано здесь: http://habrahabr.ru/post/249395/
Создается впечатление, что вы пытаетесь запутать, выложив обилие непонятной информации и кода.
Точно, спасибо за инфу.
Есть одна проблема. Не передаются пакеты более 64 байт. Кто-нибудь решил ее?
Передает, если у вас не FS USB, а HS USB
Comments are closed.