cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 USB On-The-Go Host and Device Library: structure?

turboscrew
Senior III
Posted on December 29, 2013 at 17:48

I'm in a process of trying to write an USB Host CDC program (Full Speed only).

This is my first encounter with USB-internals and STM32-chips.

I still haven't figured out what should go into which file / directory or what interrupt to use for waking the end point data transfer code to check whether there is something to move or not.

It's hard to follow the examples without knowing where the actions get initiated.

I don't have much time, and the right stuff is hard to find in the documents (the library and chip).

The files whose contents I'm wondering especially about, are:

...\STM32_USB_HOST_Library\Class\CDC\inc\usbh_cdc_core.h

...\STM32_USB_HOST_Library\Class\CDC\src\usbh_cdc_core.c

...\USB_Host_Examples\CDC\inc\usbh_usr.h

...\USB_Host_Examples\CDC\src\usbh_usr.c

(maybe some other VCP-files?)

I have been trying to put the SW together by editing the MSC example looking into VCP-device example on the side.

I understand that in the device example it's periodic transfer interrupt that is used for triggering the ''situation check'' for USB EP transfers, while RS-side minds its own business using rx/tx interrupts?

That is: what is supposed to be the interface to the library, and what should be left in the application side. The catch is that I shoud add a protocol (in between the USB and Serial) later when I get the raw bytes flowing through. I'm using STM3240G-EVAL.

At the moment I'm using Eclipse, but the stuff should eventually be brought into a commercial IDE.

(Quite a lot of work putting together an Eclipse project...)

#usb #fs
28 REPLIES 28
chen
Associate II
Posted on January 03, 2014 at 12:55

Hi

''I'm in a process of trying to write an USB Host CDC program''

and

''I have been trying to put the SW together by editing the MSC example looking into VCP-device example on the side.''

If by 'the other side' you mean a PC then you cannot connect a USB host to a USB host.

The VCP driver makes the PC a USB host.

The STM32 must be made a USB device.

If you want to make the STM32 a USB host - you will need another USB device (maybe another STM32 dev board or something like a 'FTDI USB to RS232' or a sub20)

It has been months since I did USB work. The files you list look familiar, all I can say is look at the sample projects. The files that need to be modified are NOT in the STM_USB_xxxx directories.

turboscrew
Senior III
Posted on January 04, 2014 at 01:31

''editing the MSC example looking into VCP-device example on the side.''

That means that I have been editing the MSC-example, with the VCP-device example code open for reference.

And the the CDC-device side is handled by an Android phone (interface 0x0a, 0x00, 0x00 - got it enumerated).

Also, the directory STM32_USB_HOST_Library\Class\CDC is my addition - there was no such. It's more or less the copy of  STM32_USB_HOST_Library\Class\MSC that I've been editing.

tsuneo
Senior
Posted on January 05, 2014 at 20:22

Hi turboscrew,

You are making a CDC host based on the MSC host example in STSW-STM32046 (STM32_USB-Host-Device_Lib_V2.1.0) http://www.st.com/web/en/catalog/tools/PF257882 I've briefly explained the structure of ST's host stack on this post. http://www.keil.com/forum/20569/ Here is a little more detailed summary of CDC implementation. 1) main.c

main.c
#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_cb;
int main(void)
{
/* Init Host Stack */
USBH_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USB_Host, &USBH_MSC_cb, &USR_cb);
while (1)
{
/* Host Task handler */
USBH_Process(&USB_OTG_Core, &USB_Host);
}
}

- main() initializes the host stack by USBH_Init(), with the class driver object (USBH_MSC_cb) and the application object (USR_cb). - USBH_Process(), which runs the host stack, is repeatedly called in the main loop. 2) Class driver (usbh_msc_core.c) This file gives a class driver object (USBH_MSC_cb), ie. class-specific callbacks.

usbh_msc_core.c
#include ''usbh_core.h''
USBH_Class_cb_TypeDef USBH_MSC_cb =
{
USBH_MSC_InterfaceInit,
USBH_MSC_InterfaceDeInit,
USBH_MSC_ClassRequest,
USBH_MSC_Handle,
};

2-1) USBH_MSC_InterfaceInit() This callback is called just after enumeration of plugged-in device by the host stack. At the entry of this routine, you should confirm if the device is really your target device or not. a) Check the interface triad (class, subclass, protocol) on the interface descriptors. If you would support ANY CDC-ACM device, this one should be the way. CDC-ACM has two interfaces (IFs), - Communication Class IF (0x02, 0x02, 0x01) - Data Class IF (0x0A, 0x00, 0x00) You should check both of interfaces. At this point, the stack has already read out the descriptors on its internal array. You may accesses to each field of the descriptors over this array. The triad of the first interface is referred by, pphost->device_prop.Itf_Desc[0].bInterfaceClass pphost->device_prop.Itf_Desc[0].bInterfaceSubClass pphost->device_prop.Itf_Desc[0].bInterfaceProtocol OR b) Check the VID/PID on the Device Descriptor If you would support just a specific device, you could take this way. You may refer to VID/PID using, pphost->device_prop.Dev_Desc.idVendor pphost->device_prop.Dev_Desc.idProduct If the target device doesn't satisfy above criteria, call pphost->usr_cb->DeviceNotSupported() As the next step, USBH_MSC_InterfaceInit() identifies the address of each endpoint. CDC-ACM has three endpoints, Communication Class IF - interrupt IN Data Class IF - bulk IN - bulk OUT The first endpoint descriptor on the first interface (usually, it's interrupt IN) is referred as, pphost->device_prop.Ep_Desc[0][0].bEndpointAddress (IN:bit7=1, OUT:bit7=0) pphost->device_prop.Ep_Desc[0][0].bmAttributes (interrupt:0x03, bulk:0x02) pphost->device_prop.Ep_Desc[0][0].wMaxPacketSize The endpoint address and its size are stored in a target device object. CDC_Machine .CDCIntInEp .CDCIntInEpSize .CDCBulkInEp .CDCBulkInEpSize .CDCBulkOutEp .CDCBulkOutEpSize USBH_Alloc_Channel() assigns a pipe (channel) to each endpoint Lastly, open channel for each endpoint (USBH_Open_Channel()) This routine always returns USBH_OK, even if the device is not supported. 2-2) USBH_MSC_InterfaceDeInit() In this callback, close the channels, opened in USBH_MSC_InterfaceInit(), using USB_OTG_HC_Halt() and USBH_Free_Channel() 2-3) USBH_MSC_ClassRequest() This callback is supposed to initializes the target device and the context (variables and flags) of next USBH_MSC_Handle() for start up. For CDC implementation, you'll need nothing. Just return USBH_OK Or, if your target device requires Set_Line_Coding / Set_Control_Line_State requests at the start up, here is the place where these control transfers (requests) are issued. As of the implementation of control transfers, refer to the HID host stack (usbh_hid_core.c, USBH_HID_ClassRequest()) 2-4) USBH_MSC_Handle() This callback is supposed to run class-specific protocol. - interrupt IN endpoint The interrupt IN EP returns Serial_State notification (DSR, DCD, break, parity error, etc) If your application requires these status, run this EP. Refer to usbh_hid_core.c, USBH_HID_Handle() for the handling of interrupt IN EP. Put a transfer using USBH_InterruptReceiveData() Poll the transfer completion using if(HCD_GetURB_State(pdev , HID_Machine.hc_num_in) == URB_DONE) - bulk IN/OUT endpoints You may run the bulk IN/OUT EPs here, to pass data over RX/TX buffers, or you may run these endpoints directly in your application object (USBH_USR_MSC_Application()). USBH_BulkReceiveData(), USBH_BulkSendData() are used to receive/send a transaction. When HCD_GetURB_State() returns URB_DONE, the transaction completes. When HCD_GetURB_State() returns URB_NOTREADY, the endpoint is NAKing. Refer to usbh_msc_bot.c, USBH_MSC_HandleBOTXfer(), USBH_MSC_BOT_DATAIN_STATE / USBH_MSC_BOT_DATAOUT_STATE Lastly, USBH_MSC_Handle() calls pphost->usr_cb->UserApplication() to run the application object. 3) Application object (usbh_usr.c) This file gives an application object, USR_cb

USBH_Usr_cb_TypeDef USR_cb =
{
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_MSC_Application,
USBH_USR_DeviceNotSupported,
USBH_USR_UnrecoveredError
};

You may leave most of these callbacks as they are. Just USBH_USR_MSC_Application() is the target of modification. If you would implement RX/TX buffer on USBH_MSC_Handle(), this routine runs the other end of the buffers. In this routine, your application code processes / exchanges data over the bulk EPs. As of the details of the host stack, ''7 USB host library'' section of the library user manunal. http://www.st.com/st-web-ui/static/active/en/resource/technical/document/user_manual/CD00289pdf Tsuneo
turboscrew
Senior III
Posted on January 06, 2014 at 02:32

Trainload of thanks. You really have put effort in making it clear.

Considering other questions about CDC hosts, maybe this could be made sticky?

''

You are making a CDC host based on the MSC host example in STSW-STM32046 (STM32_USB-Host-Device_Lib_V2.1.0)''

Yes.

''

I've briefly explained the structure of ST's host stack on this post.

http://www.keil.com/forum/20569/'';

Unfortunately it was a bit too briefly for me. 😉

Anyway, that's why I decided to start from the MSC host.

I could get the enumeration right:

''

And the the CDC-device side is handled by an Android phone (interface 0x0a, 0x00, 0x00 - got it enumerated).''

Here the 0x0a, 0x00, 0x00 meant ''

Data Class IF (0x0A, 0x00, 0x00)''

In the ''InterfaceInit'' I found that interface as the second one:

 

pphost->device_prop.Itf_Desc[1].bInterfaceClass

The explanation of the idea of the class callback functions (what should go inside them) was good and really welcome - at least by me.

tsuneo
Senior
Posted on January 06, 2014 at 05:00

> ''And the the CDC-device side is handled by an Android phone (interface 0x0a, 0x00, 0x00 - got it enumerated).''

Does the Android phone tether over USB?

Android tethering is based on RNDIS protocol (subclass of CDC, by MS)

[MS-RNDIS]: Remote Network Driver Interface Specification (RNDIS) Protocol

http://msdn.microsoft.com/en-us/library/ee524902.aspx

[MS-RNDIS].pdf

http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5bMS-RNDIS%5d.pdf

RNDIS protocol is more complicated than simple CDC-ACM.

- RNDIS exchanges control and status messages over (Send_Encapsulated_Commnad - ResponseAvailable notification - Get_Encapsulated_Response) sequence.

Send_Encapsulated_Commnad and Get_Encapsulated_Response are carried over control transfer.

ResponseAvailable notification comes from the interrupt IN EP

- After enumeration (Set_Config), host initializes the device using,

REMOTE_NDIS_INITIALIZE_MSG

And host asks the properties of the device,

REMOTE_NDIS_QUERY_MSG

- OID_GEN_SUPPORTED_LIST

- OID_GEN_VENDOR_DRIVER_VERSION

- OID_GEN_MAXIMUM_FRAME_SIZE

- OID_802_3_MAXIMUM_LIST_SIZE

- OID_802_3_CURRENT_ADDRESS

- OID_GEN_PHYSICAL_MEDIUM

- OID_GEN_MAXIMUM_TOTAL_SIZE

etc.

- Host regularly checks the link (media) status

REMOTE_NDIS_QUERY_MSG

- OID_GEN_MEDIA_CONNECT_STATUS

- OID_GEN_LINK_SPEED

- OID_GEN_XMIT_OK

- OID_GEN_RCV_OK

- OID_GEN_XMIT_ERROR

- OID_GEN_RCV_ERROR

Ethernet ''frames'' are exchaged over bulk IN/OUT EPs, tagged with REMOTE_NDIS_PACKET_MSG

Tsuneo

turboscrew
Senior III
Posted on January 06, 2014 at 15:45

''Does the Android phone tether over USB?

Android tethering is based on RNDIS protocol (subclass of CDC, by MS)''

Yes it does: 

pphost->device_prop.Itf_Desc[0] has 0xE0, 0x01, 0x03

but there is a second interface 

pphost->device_prop.Itf_Desc[1]: 0x0A, 0x00, 0x00.

Those are found when USB tethering is enabled. Otherwise there is only

 

pphost->device_prop.Itf_Desc[0] has 0x06, 0x01, 0x01

At least those were what I found when I debugged the enumeration and checked the descriptors.

tsuneo
Senior
Posted on January 06, 2014 at 20:18

> Yes it does: pphost->device_prop.Itf_Desc[0] has 0xE0, 0x01, 0x03

 

> but there is a second interface pphost->device_prop.Itf_Desc[1]: 0x0A, 0x00, 0x00.

 

Ah, both are RNDIS (Remote NDIS) interfaces. RNDIS consists of two interfaces, as usual of CDC subclasses.

 

> pphost->device_prop.Itf_Desc[0] has 0x06, 0x01, 0x01

This interface gives (old version of) MTP, stands on Still-image class.

USB Class Codes

http://www.usb.org/developers/defined_class

Now that I believe you have enough information to finish these callbacks,

USBH_MSC_InterfaceInit() and USBH_MSC_InterfaceDeInit()

Ah, you'll need these numbers to parse the descriptors.

pphost->device_prop.Cfg_Desc.bNumInterfaces - number of interfaces in this configuration set

pphost->device_prop.Itf_Desc[0].bNumEndpoints - number of endpoints under the first interface

When you finish above callbacks, we'll move to USBH_MSC_InterfaceInit()

1) inplementation of (Send_Encapsulated_Commnad - ResponseAvailable notification - Get_Encapsulated_Response) sequence.

2) send REMOTE_NDIS_INITIALIZE_MSG message

3) put REMOTE_NDIS_QUERY_MSG to know

- OID_GEN_SUPPORTED_LIST

- OID_GEN_VENDOR_DRIVER_VERSION

- OID_GEN_MAXIMUM_FRAME_SIZE

- OID_802_3_MAXIMUM_LIST_SIZE

- OID_802_3_CURRENT_ADDRESS

- OID_GEN_PHYSICAL_MEDIUM

- OID_GEN_MAXIMUM_TOTAL_SIZE

etc.

Tsuneo

turboscrew
Senior III
Posted on January 07, 2014 at 10:58

I've been told that the phone will hace SW to get the stuff. The data will not be tethered, so I guess Remote NDIS is not needed.

tsuneo
Senior
Posted on January 07, 2014 at 23:03

> I've been told that the phone will hace SW to get the stuff.

You'd better to ask, how to reach to the ''SW'' on your phone 😉

Installation Instructions for Intel® Android* USB Driver

 

http://software.intel.com/en-us/articles/installation-instructions-for-intel-android-usb-driver

 

 

CDC Serial (Modem AT Proxy): This functionality provides the link to Modem to allow to use AT commands through a virtual com port:

 

 

GB: Start adb shell. (http://developer.android.com/guide/developing/tools/adb.html#shellcommands)

 

Enable: setprop persist.ril-daemon.disable 0

 

Disable: setprop persist.ril-daemon.disable 1

 

 

ICS: Start adb shell. (http://developer.android.com/guide/developing/tools/adb.html#shellcommands)

 

Enable: setprop persist.system.at-proxy.mode 1

 

Disable: setprop persist.system.at-proxy.mode 0

Tsuneo