Other Parts Discussed in Thread: TM4C1294NCPDT
主题中讨论的其他器件: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.
Other Parts Discussed in Thread: 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
您好 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
我会在短期内对图书馆作出一些改变和改进。