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
turboscrew
Senior III
Posted on January 08, 2014 at 00:19

''You'd better to ask, how to reach to the ''SW'' on your phone ;-)''

That is one of my worries...

I have a funny feeling that the phone SW uses sockets. I wondet if TCP/USB is enough...

Or maybe I have to go with Remote NDIS of which I know absolutely nothing yet.

On the other hand, 3 of weeks ago I knew absolutely nothing about STM32s or USB - well I'm not exactly guru now either...

I also have a funny feeling that I'm going to need the links you gave even if I don't quite get their purpose yet ... :)

turboscrew
Senior III
Posted on January 08, 2014 at 13:05

Has there been some changes or why usb.org lists:

0xE0, 0x01, 0x03 as RNDIS, but in the MS RNDIS documents there is nothing about 0xE0.

Instead they talk about classes 0x02 and 0x0A.

Is 0x02 replaced with 0xE0 or something?

I'm also a bit confused about the use of 0x02 and 0x0A.

If I have to take the RNDIS-way, do I also need TCP/IP stack on top of the RNDIS host (my first guess is ''yes'')? I understand that the RNDIS host is not very large task (I had a glimpse on the Linux sources)? I wonder if the device  side is?

[edit]

Aha, looks like there are more descriptors than the library reads:

Without tethering there are interfaces:

0x02    bInterfaceClass   (Communication Device Class)

0x02    bInterfaceSubClass   (Abstract Control Model)

0x01    bInterfaceProtocol   (ITU-T V.250)

0x06    iInterface   ''CDC Abstract Control Model (ACM)''

and

0x0A    bInterfaceClass   (CDC Data)

0x00    bInterfaceSubClass   

0x00    bInterfaceProtocol   

0x07    iInterface   ''CDC ACM Data''

With tethering only:

0xE0    bInterfaceClass   (Wireless Controller)

0x01    bInterfaceSubClass   

0x03    bInterfaceProtocol   

0x05    iInterface   ''RNDIS Communications Control''

and

0x0A    bInterfaceClass   (CDC Data)

0x00    bInterfaceSubClass   

0x00    bInterfaceProtocol   

0x06    iInterface   ''RNDIS Ethernet Data''

I understand that CDC (and RNDIS) take pairs of interfaces?

Looks like RNDIS is my only option?

tsuneo
Senior
Posted on January 08, 2014 at 16:31

I picked up above Intel site, because it well summarises the common way to expose each USB interface on Android phone. Your phone seems not to expose CDC(-ACM) interface yet. Following to the Intel site, you have to connect to the phone over ADB (Android Debug Bridge) with a PC, and then type in the commond on the page. The command for GB (GingerBread, Android 2.3) and ICS (Ice Cream Sandwich, Android 4.0) are shown.

- Over the CDC-ACM interface, Android phone works as an AT modem. Your firmware dials up to connect to a sever over the phone. ie. you should have a target dial-up server to connect to. Your firmware requires PPP (or SLIP) and TCP/IP stack.

- Over the RNDIS interface, Android phone works as an Ethernet MAC-PHY, which connects to WAN. Your firmware requires just TCP/IP stack.

Which one do you like?

> Has there been some changes

MS had applied (0x02, 0x02, 0xFF) and (0x0A, 0x00, 0x00) for RNDIS in their first implementation on USB1.1. It means a vendor-specific subclass of CDC.

USB Remote NDIS Devices and Windows

http://msdn.microsoft.com/en-us/library/windows/hardware/gg463298.aspx#ESG

Recently MS register Wireless RNDIS class, (0xE0, 0x01, 0x03) (and (0x0A, 0x00, 0x00)), to USB.org.

Tsuneo

turboscrew
Senior III
Posted on January 09, 2014 at 05:31

I guess I have to go with RNDIS.

You cleared a LOT with your RNDIS description.

BTW,where do you get the energy to help all with such a dedication? :)

turboscrew
Senior III
Posted on January 09, 2014 at 16:21

Yes, I'm heading towards RNDIS (even if I think I'm sticking my hands into ''it''). ;)

Any idea what the ''Unknown descriptors'' are?

(From a listing by Thesyscon USB Descriptor Dumper)

[edit]

 Forget the ''unknown descriptors''. I found them in communications device specific

USB specs (

CDC120-20101103-track.pdf).

I'll leave them here still for now in case someone else is wondering the same.

[/edit]

Interface Descriptor:

------------------------------

0x09 bLength

0x04 bDescriptorType

0x00 bInterfaceNumber

0x00 bAlternateSetting

0x01 bNumEndPoints

0xE0 bInterfaceClass   (Wireless Controller)

0x01 bInterfaceSubClass   

0x03 bInterfaceProtocol   

0x05 iInterface   ''RNDIS Communications Control''

Unknown Descriptor:

------------------------------

0x05 bLength

0x24 bDescriptorType

Hex dump: 

0x05 0x24 0x00 0x10 0x01 

Unknown Descriptor:

------------------------------

0x05 bLength

0x24 bDescriptorType

Hex dump: 

0x05 0x24 0x01 0x00 0x01 

Unknown Descriptor:

------------------------------

0x04 bLength

0x24 bDescriptorType

Hex dump: 

0x04 0x24 0x02 0x00 

Unknown Descriptor:

------------------------------

0x05 bLength

0x24 bDescriptorType

Hex dump: 

0x05 0x24 0x06 0x00 0x01 

Endpoint Descriptor:

------------------------------

0x07 bLength

0x05 bDescriptorType

0x83 bEndpointAddress   (IN Endpoint)

0x03 bmAttributes (Transfer: Interrupt / Synch: None / Usage: Data)

0x0008 wMaxPacketSize   (8 Bytes) 

0x09 bInterval

turboscrew
Senior III
Posted on January 10, 2014 at 13:55

A couple of questions still...

  1. Is it necessary to handle the CDC-specific descriptors and interface association descriptor too? (My first guess is: no, maybe later.)
  2. Do I need to be prepared for different order of interface descriptors?
  3. The address 0 is for the USB host itself, and the RNDIS-device could be address 1?The address id the same for both interfaces and the EP numbering continues from the first interface to the second? In the library, the EP ''numbers'' are just indices to interface specific table of actual USB endpoints? So in which endpoint are the RNDIS requests sent: hosts EP 0 (the address 0 EP 0) or class E0 interface? (But if it only has interrupt IN EP?)
  4. ''USBH_CtlReceiveData Issues a control data IN stage transaction.'' Does the ''stage'' here mean a request put together and the state machine ''notified'' so that the request will be sent (in the background)?
I guess the encapsulated command handling (maybe all RNDIS command handling?) should be implemented by rewriting the USBH_MSC_Handle? A (request) state machine there, and adding some request initiation subroutines (staging?), something like USBH_MSC_GETMaxLUN in the MSC example?

(Looks like the SCSI commands are also handled as encapsulated requests?)

Also the whole usbh_usr seems to need an RNDIS state machine (RNDIS counterpart of  HOST_State)?

turboscrew
Senior III
Posted on January 10, 2014 at 15:17

Sorry all.

The editing here works funny. It changes the original order of postings.

tsuneo
Senior
Posted on January 10, 2014 at 20:10

Android applies Linux RNDIS gadget as it is.

You'll find the descriptors in Linux source code.

http://lxr.free-electrons.com/source/drivers/usb/gadget/f_rndis.c#L214
214 static struct usb_descriptor_header *eth_fs_function[] = {
215 (struct usb_descriptor_header *) &rndis_iad_descriptor,
216
217 /* control interface matches ACM, not Ethernet */
218 (struct usb_descriptor_header *) &rndis_control_intf,
219 (struct usb_descriptor_header *) &header_desc,
220 (struct usb_descriptor_header *) &call_mgmt_descriptor,
221 (struct usb_descriptor_header *) &rndis_acm_descriptor,
222 (struct usb_descriptor_header *) &rndis_union_desc,
223 (struct usb_descriptor_header *) &fs_notify_desc,
224
225 /* data interface has no altsetting */
226 (struct usb_descriptor_header *) &rndis_data_intf,
227 (struct usb_descriptor_header *) &fs_in_desc,
228 (struct usb_descriptor_header *) &fs_out_desc,
229 NULL,
230 };

Also, the body of RNDIS gadget process is here,

http://lxr.free-electrons.com/source/drivers/usb/gadget/rndis.c

> 1. Is it necessary to handle the CDC-specific descriptors and interface association descriptor too? (My first guess is: no, maybe later.) Not necessarily. > 2. Do I need to be prepared for different order of interface descriptors? In the Linux source, the order of the interfaces are fixed. But you'd better traverse the interfaces, and pick up (0xE0, 0x01, 0x03) and (0x0A, 0x00, 0x00) > 3. The address 0 is for the USB host itself, and the RNDIS-device could be address 1? By the bus reset at the entry of enumeration, the device starts with address 0. The STM32 host assigns USBH_DEVICE_ADDRESS (1) to the device, using Set_Address on the enumeration. Anyway, you don't need worry about the device address, because the ST host stack (v2.1.0) supports just single device. > the EP numbering continues from the first interface to the second? Not always. > In the library, the EP ''numbers'' are just indices to interface specific table of actual USB endpoints?

for (if_index = 0;
if_index < 
pphost-
>device_prop.Cfg_Desc.bNumInterfaces;
if_index++ ) {
// check
// pphost->device_prop.Itf_Desc[if_index].bInterfaceClass
// pphost->device_prop.Itf_Desc[if_index].bInterfaceSubClass
// pphost->device_prop.Itf_Desc[if_index].bInterfaceProtocol
// if (0xE0, 0x01, 0x03)
// confirm pphost->device_prop.Ep_Desc[if_index][0].bEndpointAddress & 0x80 != 0 // IN EP
// confirm pphost->device_prop.Ep_Desc[if_index][0].bmAttributes == 0x03 // interrupt
// keep .bEndpointAddress and .wMaxPacketSize in your RNDIS object for the interrupt EP
// if (0xE0, 0x01, 0x03)
// pick up bulk IN and OUT EPs, like the original USBH_MSC_InterfaceInit()
}

> So in which endpoint are the RNDIS requests sent: hosts EP 0 (the address 0 EP 0) or class E0 interface? ''Request'' (Control transfer) should be sent to the default EP (EP0) > ''USBH_CtlReceiveData Issues a control data IN stage transaction.'' Does the ''stage'' here mean a request put together and the state machine ''notified'' so that the request will be sent (in the background)? Instead of USBH_CtlReceiveData(), USBH_CtlReq() is repeatedly called, until it returns USBH_OK To send a message to a RNDIS device, - Host sends a message block using Send_Encapsulated_Commnad - Host polls the interrupt endpoint for ''ResponseAvailable notification'' from the device - Host reads the reply block using Get_Encapsulated_Response RNDIS Control Channel Characteristics

http://msdn.microsoft.com/en-us/library/ff546aspx

These Requests are written as follows,

#define USB_REQ_CDC_SEND_ENCAPSULATED 0x00
#define USB_REQ_CDC_GET_ENCAPSULATED 0x01
USBH_Status USBH_RNDIS_Send_Encapsulated_Commnad(
USB_OTG_CORE_HANDLE *pdev,
USBH_HOST *phost,
uint8_t messageLen,
uint8_t* messageBuff)
{
phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \
USB_REQ_RECIPIENT_INTERFACE;
phost->Control.setup.b.bRequest = USB_REQ_CDC_SEND_ENCAPSULATED;
phost->Control.setup.b.wValue.w = 0;
phost->Control.setup.b.wIndex.w = 0; // interface number of the Communication Class IF
phost->Control.setup.b.wLength.w = messageLen;
return USBH_CtlReq(pdev, phost, messageBuff, messageLen );
}
USBH_Status USBH_RNDIS_Get_Encapsulated_Response(
USB_OTG_CORE_HANDLE *pdev,
USBH_HOST *phost,
uint8_t messageLen,
uint8_t* messageBuff)
{
phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \
USB_REQ_RECIPIENT_INTERFACE;
phost->Control.setup.b.bRequest = USB_REQ_CDC_GET_ENCAPSULATED;
phost->Control.setup.b.wValue.w = 0;
phost->Control.setup.b.wIndex.w = 0; // interface number of the Communication Class IF
phost->Control.setup.b.wLength.w = messageLen;
return USBH_CtlReq(pdev, phost, messageBuff, messageLen );
}

USBH_RNDIS_Send_Encapsulated_Commnad() and USBH_RNDIS_Get_Encapsulated_Response() are repeatedly called until they return USBH_OK As of the interrupt IN EP, refer to these states of USBH_HID_Handle() (usbh_hid_core.c) case HID_GET_DATA: case HID_POLL: (Send_Encapsulated_Commnad - ResponseAvailable notification - Get_Encapsulated_Response) sequence is used in both of our USBH_MSC_ClassRequest() and USBH_MSC_Handle(). You'll implement this sequence in a state machine on a separate routine. Tsuneo
turboscrew
Senior III
Posted on January 10, 2014 at 21:49

>Also, the body of RNDIS gadget process is here,

>

http://lxr.free-electrons.com/source/drivers/usb/gadget/rndis.c

I tried to read that some time ago (except I'm more familiar with 

lxr.

linux

.no) but

couldn't get much out of it, because i

Linux code is full of macros these days and the rndis.c stuff is called from rndis_host.c whose stuff is used from...

But I'll check that rndis.c again. Maybe I have learned more enough to figure oyt the rndis-part.

>> 2. Do I need to be prepared for different order of interface descriptors?

 

>In the Linux source, the order of the interfaces are fixed.

>But you'd better traverse the interfaces, and pick up (0xE0, 0x01, 0x03) and (0x0A, 0x00, 0x00)

Pretty much that way I did it. I managed to get the descriptors for both interfaces and

(I guess) to initialize the endpoints. And the deinit (I think) works too.

The EPs are just not used for anything yet., so can't be sure.

>> the EP numbering continues from the first interface to the second?

 

>Not always.

What I meant is that the numbering needs to be unique over all the interfaces?

And loads of thanks again. I think I'll be busy for a while with all that info. ;)

I even think that the overall picture is forming...

Arigato gozaimasu, Sensei. ;)

turboscrew
Senior III
Posted on January 13, 2014 at 10:31

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

>REMOTE_NDIS_INITIALIZE_MSG

You first send the configuration value to tell the device which configuration is taken into use, and then

REMOTE_NDIS_INITIALIZE_MSG

 (to the active configuration of the device)?