主题中讨论的其他器件:TM4C1294NCPDT
您好!
我需要制作一个器件、该器件通过 CP2102 USB-2-UART 桥接器连接到电路板、并通过虚拟 UART 与电路板进行通信。 我在 usblib 中没有看到 CDC 主机函数、如何实现它?
谢谢。
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
您好!
我需要制作一个器件、该器件通过 CP2102 USB-2-UART 桥接器连接到电路板、并通过虚拟 UART 与电路板进行通信。 我在 usblib 中没有看到 CDC 主机函数、如何实现它?
谢谢。
您好 Oleg、
我有一个适用于 TM4C1294NCPDT 的 USB 主机 CDC 示例。 同样的也应该能够被移植到 TM4C123x。 请参阅以下 E2E 帖子、其中包含该项目以及有关如何安装该项目及其工作原理的详细说明: https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/1017323/tm4c129x-and-bulk-transfer-and-device/3774058#3774058
我们希望在不久的将来为 TM4C123x 创建相同的器件、但现在不提供。
此致、
Ralph Jacobi
您好 Oleg、
[引用 userid="140078" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1030030/tm4c123fh6pm-usb-host-cdc-function/3810000 #3810000"]它不报告器件类别2,而是 FF 类别,供应商特定这是一个特定于应用的元素、是的。 您是否需要修改主机 CDC 库文件以解决此问题? 如果是、我将了解可以采取哪些措施来提高灵活性、从而仅在应用程序代码中实现。
[引用 userid="140078" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1030030/tm4c123fh6pm-usb-host-cdc-function/3810000 #3810000"]它不使用中断端点, 因此它需要使用 TX 请求进行轮询您觉得在 CDC 器件中这是非常标准的吗? CP210x 是一款 UART 转 USB 转换器、因此我认为它的要求可能与往常不同?
[引用 userid="140078" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1030030/tm4c123fh6pm-usb-host-cdc-function/3810000 #3810000"]同时控制命令与标准 CDC 器件不兼容。不过、这些可以很容易地从应用程序代码中排除、对吧?
我很感谢这一反馈、因为我们正在考虑在不久的将来在应用报告中发布此示例、因此、如果存在可以解决的缺点、我想更好地理解这些缺点。 目标是使其尽可能广泛应用、但我认为、由于 CDC 作为接口的使用范围非常广泛、因此覆盖每个单一用例都非常困难。
此致、
Ralph Jacobi
我刚刚创建了驱动程序、它使用了 usbhcdc 驱动程序中的大多数功能。
实际上、我在 Linux 中看到有两个不同的器件类-一个是创建 ttyUSBx 器件条目(例如 CP210x 和 FTDI)、另一个是创建 ttyACMx 器件条目(对于 Tiva usblib CDC 器件、也对于 MSP430FET 和 XDS100 JTAG 探针)。 第二个问题看起来更像标准投诉。 正如我看到的、这些二级器件可由 USBhcdc 等通用驱动器驱动、但常用的 CP210x、FTDI、Prolic 等器件需要一些定制。 是的、对于较旧的器件、轮询是正常现象。
我认为、最好为这类器件编写一些框架驱动程序、以便为其轻松派生驱动程序。 我可以做一些工作。
您好 Oleg、
嗯、当你这样解释时、这是有道理的。 是的、ACM 或 抽象控制模型是使用最广泛的器件类别。 因此、如果 CP210x 不是 ACM、这一点很有意义。
我介绍了一些 USB 规范、0x80及以上的代码是特定于供应商的。 因此、我不确定我们是否会做很多工作来适应示例。 ACM 和直接线路控制模型是可行的选择、具有我们期望的广泛用途。 因此、我认为重要的是在文件和文档中强调代码仅限于特定 CDC 类、必须扩展进一步的支持。
虽然支持 CP210x 和 FTDI 的范围相当广泛、但它会使我们面临一种对其他广泛定制协议的请求越来越多、并且会使 USB 堆栈卷积(...比现在更多)的情况。
此致、
Ralph Jacobi
从现实角度来看、最常见的任务是通过基于 Tiva 的设备和电路板与某些第三方设备和电路板进行通信、因为在大多数情况下、嵌入式 Linux 盒并不是一个好主意、 由于任务通常相当简单-通过 CAN 等总线转换协议或集中几个器件(在我的情况下-我有一组器件、由第三方软件支持、 我需要构建一个简单的解决方案、通过一根电缆将它们连接到 PC、而无需更改器件和软件)。
目前我正在编写框架、它将具有如下结构:
usbhserial | +- usbhserialdriver | +- usbhserialcdc +- usbhserialcp210x +- ...
其中 usbhserial 是 HAL 层、定义了标准函数:
extern uint32_t USBHostSerialInit(tUSBCallback pfnCallback); extern uint32_t USBHostSerialSetupInstance(tSerialInstance *psSerialInstance, tUSBCallback pfnCallback, void *pvRxBuffer); extern void USBHostSerialClose(tSerialInstance *psSerialInstance); extern uint32_t USBHostSerialReadData(tSerialInstance *psSerialInstance, uint8_t *pui8Data, uint32_t ui32Size); extern uint32_t USBHostSerialWriteData(tSerialInstance *psSerialInstance, uint8_t *pui8Data, uint32_t ui32Size); extern void USBHostSerialScheduleWrite(tSerialInstance *psSerialInstance, uint8_t *pui8Data, uint32_t ui32Size); extern uint32_t USBHostSerialInitNewDevice(tSerialInstance *psSerialInstance); extern uint32_t USBHostSerialSetLineConfig(tSerialInstance *psSerialInstance, uint32_t ui32Baud, uint32_t ui32Coding); extern uint32_t USBHostSerialGetBaud(tSerialInstance *psSerialInstance); extern uint32_t USBHostSerialGetCoding(tSerialInstance *psSerialInstance); extern uint32_t USBHostSerialSetControlLineState(tSerialInstance *psSerialInstance, uint32_t ui32Control); extern uint32_t USBHostSerialGetControlLineState(tSerialInstance *psSerialInstance); extern uint32_t USBHostSerialBreakSet(tSerialInstance *psSerialInstance); extern uint32_t USBHostSerialBreakClear(tSerialInstance *psSerialInstance);
在不知道底层驱动程序工作原理的情况下、可以从应用层调用这些函数、
usbhserialdriver 定义驱动程序接口,声明驱动程序定义结构:
//***************************************************************************** // //! This is the structure that holds all of the data for a given driver of //! a serial device. // //***************************************************************************** typedef struct { // //! The interface class that this device class driver supports. // uint32_t ui32InterfaceClass; // //! Vendor ID of device (0 - do not care) // uint16_t ui16VID; // //! Product ID of device (0 - do not care) // uint16_t ui16PID; // //! Polling mode flag // bool bPolling; // //! Polling interval // uint32_t ui32Interval; // //! Init function pointer // uint32_t (* pfnInit)(tSerialInstance *psSerialInstance); // //! Baud set function pointer // uint32_t (* pfnSetBaud)(tSerialInstance *psSerialInstance, uint32_t ui32Baud); // //! Baud get function pointer // uint32_t (* pfnGetBaud)(tSerialInstance *psSerialInstance); // //! Line coding set function pointer // uint32_t (* pfnSetBaud)(tSerialInstance *psSerialInstance, uint32_t ui32Coding); // //! Line coding get function pointer // uint32_t (* pfnGetCoding)(tSerialInstance *psSerialInstance); // //! Control line set function pointer // uint32_t (* pfnSetControlLineState)(tSerialInstance *psSerialInstance, uint32_t ui32Control); // //! Control line set function pointer // uint32_t (* pfnGetControlLineState)(tSerialInstance *psSerialInstance); // //! Break set function pointer // uint32_t (* pfnBreakSet)(tSerialInstance *psSerialInstance); // //! Break clear function pointer // uint32_t (* pfnBreakClear)(tSerialInstance *psSerialInstance); } tUSBSerialDriver;
这种方法可轻松创建其他驱动程序。 最初、我将提供两个具有代码的驱动程序:CDC 1和 CP210x、正如我所拥有的、它们可以实现和测试。
另一个注意事项:提供的示例不能与多个器件或多通道器件配合使用、我希望使其完全基于实例。
完成了框架草案和2个驱动程序。 以下是库:
和简单的示例 main.c:
#include <stdint.h> #include <stdbool.h> #include <string.h> #include <stdio.h> #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "driverlib/debug.h" #include "driverlib/gpio.h" #include "driverlib/pin_map.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/sysctl.h" #include "driverlib/uart.h" #include "driverlib/udma.h" #include "usblib/usblib.h" #include "usblib/usbcdc.h" #include "usblib/host/usbhost.h" #include "usbhserial.h" #include "usbhserialdriver.h" #include "usbhserialcdc.h" #include "usbhserialcp210x.h" //***************************************************************************** // // The number of SysTick ticks per second. // //***************************************************************************** #define TICKS_PER_SECOND 100 #define MS_PER_SYSTICK (1000 / TICKS_PER_SECOND) //***************************************************************************** // // Our running system tick counter and a global used to determine the time // elapsed since last call to GetTickms(). // //***************************************************************************** uint32_t g_ui32SysTickCount; uint32_t g_ui32LastTick; uint8_t g_pUSBPipeBuffer[USB_TRANSFER_SIZE]; tUSBSerialDriver g_psDrivers[] = { DECLARE_USB_SERIAL_CDC_DRIVER, DECLARE_USB_SERIAL_CP210X_DRIVER }; uint8_t g_ui8NumDrivers = 2; //***************************************************************************** // // This is the handler for this SysTick interrupt. // //***************************************************************************** void SysTickIntHandler(void) { // // Update our tick counter. // g_ui32SysTickCount++; } //***************************************************************************** // // This function returns the number of ticks since the last time this function // was called. // //***************************************************************************** uint32_t GetTickms(void) { uint32_t ui32RetVal; uint32_t ui32Saved; ui32RetVal = g_ui32SysTickCount; ui32Saved = ui32RetVal; if(ui32Saved > g_ui32LastTick) { ui32RetVal = ui32Saved - g_ui32LastTick; } else { ui32RetVal = g_ui32LastTick - ui32Saved; } // // This could miss a few milliseconds but the timings here are on a // much larger scale. // g_ui32LastTick = ui32Saved; // // Return the number of milliseconds since the last time this was called. // return(ui32RetVal * MS_PER_SYSTICK); } uint32_t CDCSerialCallback(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgParam, void *pvMsgData) { tSerialInstance *psInstance = (tSerialInstance *)pvCBData; uint32_t ui32Count; uint32_t ui16BytesReceived; switch(ui32Event) { // // Data was detected. // case USB_EVENT_RX_AVAILABLE: { ui16BytesReceived = USBHostSerialReadDataCount(psInstance); printf("Data received: "); for (ui32Count = 0; ui32Count < ui16BytesReceived; ui32Count++) { printf("%02X ", g_pUSBPipeBuffer[ui32Count]); } printf("\n"); break; } case USB_EVENT_TX_COMPLETE: { break; } } return 0; } bool bConnected = false; bool bSent = false; tSerialInstance *psInstance = 0; uint32_t CDCSerialGlobalCallback(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgParam, void *pvMsgData) { if(ui32Event == USB_EVENT_CONNECTED) { psInstance = (tSerialInstance *)pvCBData; USBHostSerialSetupInstance(psInstance, CDCSerialCallback, g_pUSBPipeBuffer); USBHostSerialInitNewDevice(psInstance); USBHostSerialSetLineConfig(psInstance, 19200, USBHS_CONF_STOP_1 | USBHS_CONF_PAR_NONE | USBHS_CONF_DATA_8); printf("Connected serial device, driver = %d\n", (int)psInstance->ui8Driver); bConnected = true; return 0; } if(ui32Event == USB_EVENT_UNKNOWN_CONNECTED) { printf("Unknown device connected\n"); } } #define HCD_MEMORY_SIZE 128 uint8_t g_pHCDPool[HCD_MEMORY_SIZE]; /** * main.c */ int main(void) { SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); uint32_t ui32SysClock = 80000000; SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_5 | GPIO_PIN_4); // // Configure SysTick for a 100Hz interrupt. // SysTickPeriodSet(ui32SysClock / TICKS_PER_SECOND); SysTickEnable(); SysTickIntEnable(); // // Initialize the USB stack in host mode. No callback is needed at this // time. // USBStackModeSet(0, eUSBModeHost, 0); USBHostSerialInit(CDCSerialGlobalCallback); // // Initialize the power configuration. This sets the power enable signal // to be active high and does not enable the power fault. // USBHCDPowerConfigInit(0, USBHCD_VBUS_AUTO_HIGH | USBHCD_VBUS_FILTER); USBHCDFeatureSet(0, USBLIB_FEATURE_CPUCLK, &ui32SysClock); // // Initialize the USB controller for host operation. // USBHCDInit(0, g_pHCDPool, HCD_MEMORY_SIZE); printf("USB host initialized\n"); while(1) { // // Tell the OTG library code how much time has passed in // milliseconds since the last call. // USBOTGMain(GetTickms()); if(bConnected && !bSent) { uint8_t Out[7] = {0x70, 0x01, 0, 0, 0, 0, 0x71}; USBHostSerialScheduleWrite(psInstance, Out, 7); bSent = true; } } return 0; }
示例连接到器件、确定其 cp210x、配置端口、发送采样命令并打印响应。
刚刚 在 GitHub 上共享了库项目- https://github.com/kiabrin/usbhserial
我会在短期内对图书馆作出一些改变和改进。