Всем привет! Сегодня будем поднимать 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.