Hi !
I have to implement an USB CDC Host driver for STM32F4 controller. Has anyone an idea/example how to do that. I only found examples for CDC Device.
Thanks
Marc
Here is a brief summary of ST Micro's host stack, which is common to STM32F105/107,F2xx,F4xx
STM32F105/7 and STM32F2xx USB on-the-go Host and device library (UM1021) v2.0.0 www.st.com/.../stm32_f105-07_f2xx_usb-host-device_lib.zip
To implement CDC, modify usbh_msc_core.c Your application over CDC is written in usbh_usr.c, USBH_USR_Application()
// Summary of ST Micro host stack // STM32_F105-07_F2xx_USB-Host-Device_Lib_V2.0.0 // STM32F4-Discovery_FW_V1.1.0 // -- STM32_USB_Device/Host/OTG_Library are identical with above library // // Host stack Framework // #include "usbh_core.h" #include "usbh_usr.h" USB_OTG_CORE_HANDLE USB_OTG_Core; USBH_HOST USB_Host; extern USBH_Class_cb_TypeDef USBH_MSC_cb; extern USBH_Usr_cb_TypeDef USR_Callbacks; int main(void) { /* Init Host Library */ USBH_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USB_Host, &USBH_MSC_cb, &USR_Callbacks); while (1) { /* Host Task handler */ USBH_Process(&USB_OTG_Core, &USB_Host); } }
// // Class driver - refer to usbh_msc_core.c for typical implementation // #include "usbh_core.h" // callbacks from USBH_Process() in main loop USBH_Class_cb_TypeDef USBH_MSC_cb = { USBH_ClassDrv_InterfaceInit, USBH_ClassDrv_InterfaceDeInit, USBH_ClassDrv_ClassRequest, USBH_ClassDrv_Handle, }; static USBH_Status USBH_ClassDrv_InterfaceInit( USB_OTG_CORE_HANDLE *pdev, void *phost ) { USBH_HOST *pphost = phost; // check interface/endpoint descriptors, if the target interface is supported or not pphost->device_prop.Itf_Desc[0].bInterfaceClass pphost->device_prop.Itf_Desc[0].bInterfaceProtocol pphost->device_prop.Ep_Desc[0][0].bEndpointAddress // open pipes using USBH_Alloc_Channel() / USBH_Open_Channel() if ( not_supported ) pphost->usr_cb->USBH_USR_DeviceNotSupported(); return USBH_OK; } static void USBH_ClassDrv_InterfaceDeInit (USB_OTG_CORE_HANDLE *pdev, void *phost) { // close pipes USB_OTG_HC_Halt() / USBH_Free_Channel() } static USBH_Status USBH_ClassDrv_ClassRequest(USB_OTG_CORE_HANDLE *pdev, void *phost) { // initialization of USBH_ClassDrv_Handle() return USBH_OK; } static USBH_Status USBH_ClassDrv_Handle(USB_OTG_CORE_HANDLE *pdev, void *phost) { // state machine to run this class // first, put class specific requests, if required // run class-specific protocol over USB while in idle, call ((USBH_HOST *)phost)->usr_cb->USBH_USR_Application() return USBH_OK; }
// // Callbacks from host stack -- usbh_usr.c // #include "usbh_usr.h" USBH_Usr_cb_TypeDef USR_Callbacks = { USBH_USR_Init, USBH_USR_DeInit, USBH_USR_DeviceAttached, USBH_USR_ResetDevice, USBH_USR_DeviceDisconnected, USBH_USR_OverCurrentDetected, USBH_USR_DeviceSpeedDetected, USBH_USR_Device_DescAvailable, USBH_USR_DeviceAddressAssigned, USBH_USR_Configuration_DescAvailable, USBH_USR_Manufacturer_String, USBH_USR_Product_String, USBH_USR_SerialNum_String, USBH_USR_EnumerationDone, USBH_USR_UserInput, USBH_USR_Application, USBH_USR_DeviceNotSupported, USBH_USR_UnrecoveredError }; Most of callbacks are copied as is from existing usbh_usr.c int USBH_USR_Application(void) { // // application-specific state machine // called from USBH_Process() -> USBH_ClassDrv_Handle() // return 0; }
// control transfer // fill setup packet phost->Control.setup.b.bmRequestType phost->Control.setup.b.bRequest phost->Control.setup.b.wValue.w phost->Control.setup.b.wIndex.w phost->Control.setup.b.wLength.w Call USBH_CtlReq() repeatedly while it returns USBH_BUSY when finishes, it returns USBH_OK / USBH_FAIL / USBH_NOT_SUPPORTED (got STALL from device) // bulk transfer OUT 1) call USBH_BulkSendData() 2) poll HCD_GetURB_State() while it returns USBH_BUSY when finishes, HCD_GetURB_State() returns URB_DONE IN 1) call USBH_BulkReceiveData() 2) same as above // interrupt transfer OUT USBH_InterruptSendData() IN USBH_InterruptReceiveData() same as above bulk transfer
Tsuneo
Hi Tsuneo !
Thank you very much for reply. I will test your advice, but unfortunately I am not very firm in USB Classes. If you have (written) such a file/stack please let me know.
In most cases, you don't need to realize CDC spec in depth. I believe your target device doesn't require full-spec CDC host.
To make it sure, examine your target CDC device on a PC using a terminal application. Does your target device need any of these serial port features? 1) Baudrate, data bits and parity setting 2) DSR/DTR, CTS, RI, DCD handshake 3) Detection of parity, overrun and frame errors 4) Break signaling
If none of them is required, you may simplify the host code so much. Just take care of bulk IN and OUT endpoints.
When I attach the CDC device to my CDC host and I put a breakpoint at the following function the value of pphost->device_prop.Itf_Desc[0].bInterfaceClass is 0xFF but it should be 0x02 for CDC_CLASS
static USBH_Status USBH_ClassDrv_InterfaceInit( USB_OTG_CORE_HANDLE *pdev, void *phost ) { USBH_HOST *pphost = phost; // check interface/endpoint descriptors, if the target interface is supported or not pphost->device_prop.Itf_Desc[0].bInterfaceClass pphost->device_prop.Itf_Desc[0].bInterfaceProtocol pphost->device_prop.Ep_Desc[0][0].bEndpointAddress
When I attach the CDC device to PC I get two virtual COM-Ports which I can use with Terminal.
> When I attach the CDC device to PC I get two virtual COM-Ports which I can use with Terminal.
For confirmation, did you read out the descriptors of the target device on a PC? Virtual COM ports may derive from a vendor specific device using a custom PC driver. For example, FTDI and SiLabs apply vendor specific devices for their USB-UART chips.
UVCView is a handy utility to see USB descriptors on PC. (Maybe, USBView can't display such a complicated descriptor set by its bug) I attached UVCView to this post. " href= "http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=11800"> www.microsoft.com/.../details.aspx
Please post the descriptors of the target device, to make our discussion forward ;-)
The output of UVCView shows:
[Port3] : USB-Verbundgerät ---===>Device Information<===--- English product name: "Motorola Tetra Radio" ConnectionStatus: Current Config Value: 0x01 -> Device Bus Speed: High Device Address: 0x01 Open Pipes: 4 ===>Endpoint Descriptor<=== bLength: 0x07 bDescriptorType: 0x05 bEndpointAddress: 0x81 -> Direction: IN - EndpointID: 1 bmAttributes: 0x02 -> Bulk Transfer Type wMaxPacketSize: 0x0200 = 0x200 max bytes bInterval: 0x00 ===>Endpoint Descriptor<=== bLength: 0x07 bDescriptorType: 0x05 bEndpointAddress: 0x01 -> Direction: OUT - EndpointID: 1 bmAttributes: 0x02 -> Bulk Transfer Type wMaxPacketSize: 0x0200 = 0x200 max bytes bInterval: 0x00 ===>Endpoint Descriptor<=== bLength: 0x07 bDescriptorType: 0x05 bEndpointAddress: 0x82 -> Direction: IN - EndpointID: 2 bmAttributes: 0x02 -> Bulk Transfer Type wMaxPacketSize: 0x0200 = 0x200 max bytes bInterval: 0x00 ===>Endpoint Descriptor<=== bLength: 0x07 bDescriptorType: 0x05 bEndpointAddress: 0x02 -> Direction: OUT - EndpointID: 2 bmAttributes: 0x02 -> Bulk Transfer Type wMaxPacketSize: 0x0200 = 0x200 max bytes bInterval: 0x00 ===>Device Descriptor<=== bLength: 0x12 bDescriptorType: 0x01 bcdUSB: 0x0200 bDeviceClass: 0x00 -> This is an Interface Class Defined Device bDeviceSubClass: 0x00 bDeviceProtocol: 0x00 bMaxPacketSize0: 0x40 = (64) Bytes idVendor: 0x0CAD = Motorola GEMS idProduct: 0x9011 bcdDevice: 0x2416 iManufacturer: 0x01 English (United States) "Motorola" iProduct: 0x02 English (United States) "Motorola Tetra Radio" iSerialNumber: 0x00 bNumConfigurations: 0x01 ===>Configuration Descriptor<=== bLength: 0x09 bDescriptorType: 0x02 wTotalLength: 0x0037 -> Validated bNumInterfaces: 0x02 bConfigurationValue: 0x01 iConfiguration: 0x03 English (United States) "Generic Serial config" bmAttributes: 0xC0 -> Bus Powered MaxPower: 0x00 = 0 mA ===>Interface Descriptor<=== bLength: 0x09 bDescriptorType: 0x04 bInterfaceNumber: 0x00 bAlternateSetting: 0x00 bNumEndpoints: 0x02 bInterfaceClass: 0xFF -> Vendor Specific Device bInterfaceSubClass: 0x00 *!*CAUTION: This appears to be an invalid bInterfaceSubClass bInterfaceProtocol: 0x00 iInterface: 0x00 *!*CAUTION: 0xFF is a prerelease Class ID ===>Endpoint Descriptor<=== bLength: 0x07 bDescriptorType: 0x05 bEndpointAddress: 0x81 -> Direction: IN - EndpointID: 1 bmAttributes: 0x02 -> Bulk Transfer Type wMaxPacketSize: 0x0200 = 0x200 max bytes bInterval: 0x00 ===>Endpoint Descriptor<=== bLength: 0x07 bDescriptorType: 0x05 bEndpointAddress: 0x01 -> Direction: OUT - EndpointID: 1 bmAttributes: 0x02 -> Bulk Transfer Type wMaxPacketSize: 0x0200 = 0x200 max bytes bInterval: 0x00 ===>Interface Descriptor<=== bLength: 0x09 bDescriptorType: 0x04 bInterfaceNumber: 0x01 bAlternateSetting: 0x00 bNumEndpoints: 0x02 bInterfaceClass: 0xFF -> Vendor Specific Device bInterfaceSubClass: 0x00 *!*CAUTION: This appears to be an invalid bInterfaceSubClass bInterfaceProtocol: 0x00 iInterface: 0x00 *!*CAUTION: 0xFF is a prerelease Class ID ===>Endpoint Descriptor<=== bLength: 0x07 bDescriptorType: 0x05 bEndpointAddress: 0x82 -> Direction: IN - EndpointID: 2 bmAttributes: 0x02 -> Bulk Transfer Type wMaxPacketSize: 0x0200 = 0x200 max bytes bInterval: 0x00 ===>Endpoint Descriptor<=== bLength: 0x07 bDescriptorType: 0x05 bEndpointAddress: 0x02 -> Direction: OUT - EndpointID: 2 bmAttributes: 0x02 -> Bulk Transfer Type wMaxPacketSize: 0x0200 = 0x200 max bytes bInterval: 0x00
The device actually sends 0xFF for InterfaceClass. I would expect 0x02 for CDC.
Surely, the device has two interfaces (composite device). Both of interfaces belong to vendor specific class (bInterfaceClass: 0xFF).
The Vendor ID (VID: idVendor) shows it's a Motorola device. Is it an Android phone or pad?
Android phone swaps its USB interface, when USB tethering is enabled on Setting. RNDIS (derivative of CDC) interface appears.
Hi, Marc!
I wolud like to know if you have figured out some way to develop your CDC USB host driver;
What did you do? Have you edited the USB MSD's files to adapt to a CDC like Tsuneo did recommend?
Thank you in advance;
Marcel.