USBX移植(X是eXtended的意思)
1. 添加Class layer, 添加含有“ ux_device_class_cdc_acm_"前缀的C文件,其中,cdc是Communication Device Class 的缩写,acm是Abstract Control Model的缩写。
2. 添加stack layer,添加含有ux_device_stack_, ux_utility_, ux_system_前缀的C文件。
3. 添加Controller layer, 添加含有ux_dcd_stm32_前缀的C文件。其中dcd是Device Controller Driver的缩写。
4.添加app文件夹下的ux_device_cdc_acm.c, ux_device_descriptors.c, app_usbx_device.c
修改usb.c, 添加如下代码:
MX_USBX_Device_Init();
//使能usb控制器的电源 /* HAL_PWREx_EnableVddUSB()是给USB模块本身供电,有些STM32的USB模块有独立的电源域,需要特别开启。HAL_PWREx_EnableUSBVoltageDetector()则是启用电压检测器,确保USB工作在稳定的电压下,这对可靠性至关重要。 */ HAL_PWREx_EnableVddUSB(); HAL_PWREx_EnableUSBVoltageDetector();
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x00, PCD_SNG_BUF, 0x14); HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x80, PCD_SNG_BUF, 0x54); HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_CDCACM_EPINCMD_ADDR, PCD_SNG_BUF, 0x94); HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_CDCACM_EPOUT_ADDR, PCD_SNG_BUF, 0xD4); HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_CDCACM_EPIN_ADDR, PCD_SNG_BUF, 0x114);
/*将初始化好的STM32 HAL库的USB设备句柄 (hpcd_USB_DRD_FS) 传递给USBX设备栈的STM32设备控制器驱动层(DCD),完成两层软件之间的对接。*/ ux_dcd_stm32_initialize((ULONG)USB_DRD_FS, (ULONG)&hpcd_USB_DRD_FS);//启动USB控制器 HAL_PCD_Start(&hpcd_USB_DRD_FS);/**************************** PCD: Peripheral Controller Driver DRD: Dual Role Device FS: Full Speed****************************/
在默认任务里调用如下函数:
ux_system_tasks_run();
app_freertos.c
ux_device_cdc_acm_send((uint8_t *)buf, strlen(buf), 1000);
当 USB 串口收到数据后,ux_device_class_cdc_acm_read_callback 函数被调用。
4.8 源码分析与改造
ux_device_cdc_acm_send会调用
/* 启动发送 */ UINT ux_device_class_cdc_acm_write_with_callback(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, ULONG requested_length);
/* 发送完毕的回调函数 */ static UINT ux_device_class_cdc_acm_write_callback(struct UX_SLAVE_CLASS_CDC_ACM_STRUCT *cdc_acm, UINT status, ULONG length);
发送函数改造:
static SemaphoreHandle_t g_xUSBUARTSend;......VOID USBD_CDC_ACM_Activate(VOID *cdc_acm_instance)函数中创建信号量:{ ......if(!g_xUSBUARTSend){g_xUSBUARTSend = xSemaphoreCreateBinary(void);g_xUSBUART_RX_Queue = xQueueCreate(200,1);}...... }int ux_device_cdc_acm_send(uint8_t *datas, uint32_t len, uint32_t timeout) {if (cdc_acm){//启动发送if (UX_SUCCESS == ux_device_class_cdc_acm_write_with_callback(cdc_acm, datas, len)){/* 等待发送完成*/if(pdTRUE == xSemaphoreTake(g_xUSBUARTSend, timeout)){return 0;}else{return -1; //timeout}}else{return -1;}}else{return -1;}return 0; }//发送完成的回调函数 static UINT ux_device_class_cdc_acm_write_callback(struct UX_SLAVE_CLASS_CDC_ACM_STRUCT *cdc_acm, UINT status, ULONG length) {xSemaphoreGive(g_xUSBUARTSend);return 0; }
接收函数改造:
static QueueHandle_t g_USBUART_RX_Queue;static UINT ux_device_class_cdc_acm_read_callback(struct UX_SLAVE_CLASS_CDC_ACM_STRUCT *cdc_acm, UINT status, UCHAR *data_pointer, ULONG length) {for(int i=0; i<length; ++i){xQueueSendFromISR(g_USBUART_RX_Queue, (const void*)&data_pointer[i], 0);}return 0; }
int ux_device_cdc_acm_getchar(uint8_t* pData, uint32_t timeout){if(g_xUSBUART_RX_Queue){if(pdPASS == xQueueReceive(g_xUSBUART_RX_Queue, pData, timeout))return 0;elsereturn -1;}else{return -1;} }在CH2_UART4_RxTaskFunction(void* pvParameter)中调用该函数,验证接收的数据并打印出来
同UART,发送时使用信号量,接收数据时使用队列;