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.

[参考译文] TM4C123FH6PM:USB 主机 CDC 函数

Guru**** 1812430 points
Other Parts Discussed in Thread: TM4C1294NCPDT
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1030030/tm4c123fh6pm-usb-host-cdc-function

器件型号:TM4C123FH6PM
主题中讨论的其他器件:TM4C1294NCPDT

您好!

我需要制作一个器件、该器件通过 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

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢!

    它非常有用!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我今天已经为主机创建了 CP210x 器件的驱动程序。 顺便说一下、在所示的示例中发现了一些问题。

    CP210x 的问题在于它不报告器件2级、而是报告 FF 级、特定于供应商、并且它不使用中断端点、 因此它需要通过 TX 请求进行轮询。 此外、控制命令与标准 CDC 器件不兼容。

    稍后、我将附上我的代码。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 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个驱动程序。 以下是库:

    usbhserial @ google 驱动器

    和简单的示例 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、配置端口、发送采样命令并打印响应。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您可以看到、使用此库可以很容易地添加其他 USB-2串行芯片。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Oleg、

    感谢您分享此代码! 我想其他社区成员会觉得这对未来很有帮助。 我还将在处理 USB 主机 CDC 项目时进行回顾、以了解可以对我之前所做的工作进行哪些改进。

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    刚刚 在 GitHub 上共享了库项目- https://github.com/kiabrin/usbhserial

    我会在短期内对图书馆作出一些改变和改进。