2014-08-28 01:23 PM
I'm new to USB programming, and am having some trouble getting my head around the concepts involved. Hopefully someone can have a look at what I think I need to do to meet my goals and tell me where I'm right and where I'm horribly wrong.
First, my goal is to replace an STM32F103 series CPU on a board that uses all five serial ports available on the CPU, plus four more implemented via a quad UART via the FSMC, with an STM32F417 series CPU. In the process, I want to be able to connect to some of those serial devices via USB instead, as USB versions of them exist (some are also dual interface), eliminating the need for the quad UART. These devices include a pinpad, receipt printer, and cellular modem. I'd also like to be able to insert a USB flash drive to perform software updates.To do this, I know I'll have to add a USB hub chip to my board, but this doesn't seem to hard from a hardware standpoint. Where things look difficult is with the software to handle all of this. It's not simple like RS-232 serial ports.Here's what I've managed to learn by going through the various demo code available via the STM32Cube package for the F4.1. For devices that can be controlled via a class driver, I can use USBH_RegisterClass to allow the USB stack to recognize that class. This should be sufficient for the flash drive by using the MSC class from the examples.2. Most of my devices are VENDOR SPECIFIC, and so I will have to write a new class driver for this, that will in turn have to handle the individual devices based on their VID/PID values. Hopefully I can use the HID example that determines whether a mouse or keyboard is attached as an example of figuring out which devices I have attached. I do not know how to handle this via the VID/PID however, because the HID example uses subclass to determine mouse vs keyboard, and my subclasses are the same on the vendor specific devices.3. USBH_Process will handle the high level USB functions such as enumeration, and pass any lower level things to the class driver(s).4. USBH_BulkSendData and USBH_BulkReceiveData will be used to send and receive data from my devices. These work by setting flags in the state machine for the device handle, which the state machine then processes.Obviously I'm missing quite a lot here. I'm trying to work on modifying one of the examples (CDC in this case, as it is similar to the cellular modem in terms of function) to handle the Vendor Specific class that my device uses. I can get it as far as recognizing that this is a vendor specific class, but crash trying to execute the state machine in the HOST_CLASS_REQUEST state.I've done a lot of searching, and I haven't really found much useful about interfacing to a vendor specific class device, and nothing about integrating a hub and supporting more than one of them.Any pointers would be greatly appreciated.Thanks, Jeff2014-08-28 04:22 PM
How much hair do you have?
Have you considered something with more nuts that can actually run Linux, and has drivers?2014-08-29 05:17 AM
> 2. .. I will have to write a new class driver for this, that will in turn have to handle the individual devices based on their VID/PID values.
You have to rewrite USBH_Process() (usbh_core.c) itself, instead of each class driver, because the host stack picks up just bInterfaceClass field on the interface descriptor, to bind a device (first interface) to a class driver on the list (phost->pClass[]).\STM32Cube_FW_F4_V1.3.0\Middlewares\ST\STM32_USB_Host_Library\Core\Src\usbh_core.c
USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost)
{
..
case HOST_CHECK_CLASS:
..
phost->pActiveClass = NULL;
for (idx = 0; idx <
USBH_MAX_NUM_SUPPORTED_CLASS
; idx ++)
{
if(phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass)
{
phost->pActiveClass = phost->pClass[idx];
}
}
This part of code is replaced, as follows,
phost->pActiveClass = NULL;
// first, identify the device by VID/PID
for (idx = 0; idx <
USBH_MAX_NUM_SUPPORTED_CLASS
; idx ++)
{
if( (phost->pClass[idx]->idVendor == phost->device.DevDesc.idVendor)
&& (phost->pClass[idx]->idProduct == phost->device.DevDesc.idProduct)
)
{
phost->pActiveClass = phost->pClass[idx];
break;
}
}
if ( phost->pActiveClass == NULL )
{ // identify the interface by class code
for (idx = 0; idx <
USBH_MAX_NUM_SUPPORTED_CLASS
; idx ++)
{
if(phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass)
{
phost->pActiveClass = phost->pClass[idx];
break;
}
}
}
\STM32Cube_FW_F4_V1.3.0\Middlewares\ST\STM32_USB_Host_Library\Core\Inc\usbh_def.h
typedef struct
{
const char *Name;
uint8_t ClassCode;
uint16_t idVendor; // <- add these lines
uint16_t idProduct;
USBH_StatusTypeDef (*Init) (struct _USBH_HandleTypeDef *phost);
USBH_StatusTypeDef (*DeInit) (struct _USBH_HandleTypeDef *phost);
USBH_StatusTypeDef (*Requests) (struct _USBH_HandleTypeDef *phost);
USBH_StatusTypeDef (*BgndProcess) (struct _USBH_HandleTypeDef *phost);
USBH_StatusTypeDef (*SOFProcess) (struct _USBH_HandleTypeDef *phost);
void* pData;
} USBH_ClassTypeDef;
idVendor and idProduct fields of each USBH_ClassTypeDef instance should be initialized.
- for your vendor device, they hold specific VID/PID
- for existing class driver like mass-storage, they are filled with 0
> but crash trying to execute the state machine in the HOST_CLASS_REQUEST state.
In this state, USBH_***_ClassRequest() of your class driver is called.
- Initialize the ''global'' variables of your class
- Initialize the target device, by putting Class Requests, if required.
Anyway, it’s bad naming sense ;)
> and nothing about integrating a hub and supporting more than one of them.
Hub support on current STM32Cube (v1.3.0) is really hard.
We have to touch to more than 10% of source code lines on everywhere of the original host stack.
- Establish Hub class - which abstracts hub enumeration and operation, like other device class.
- Establish Root hub - root hub operation is scattered around the source. To redirect the operation to new hub class, root hub operation is abstracted.
- support of multi device
This stack assumes just single device on the bus.
- The host stack should maintain a list of connected device handles, which hold all of device specific member in USBH_HandleTypeDef for each device.
- USBH_Process() runs just single state machine for single device. Each device needs its own state machine.
- Each class driver runs on single class driver instance, phost->pActiveClass. class driver API should take driver instance as its parameter.
etc. etc.
Without clear perspective, how the host stack should be, you would be lost in magic spells.
Tsuneo
2014-08-29 08:01 AM
Wow, I hadn't realized that the stack was limited to a single device. That really puts a damper on my enthusiasm for this project. Fortunately, there is only one device that I absolutely need USB host support for. But I'd hoped to be able to convert several others as well.
I've considered embedded Linux, but that is yet another learning curve beyond just USB support. At that point, I'd have several other drivers to write as well, bootloaders to learn to use, etc. and that's too much work for a small group to get done in a reasonable time frame. Not to mention the higher cost of the components needed to run Linux (more RAM/ROM).2014-08-29 08:46 AM
Embedded Linux boards are coming down, you just have to look at things like the Raspberry Pi, Beagle, Galileo.
If you need a lot of USART you could consider satellite STM32 (low cost, small memory ones) to consolidate multiple serial streams, or implement something like CMUX Doing the USB stuff you propose on the STM32 will be a nightmare. It has very limited end-point support, and aimed at much simpler solutions. The prospects of supporting a generic hub (single chip multi-port), and available open source drivers in Linux is a lot more promising.2014-08-29 09:26 AM
2014-09-02 05:11 AM
Hello Clive: what type of board is that? (manuf / pn?). Thank you.
2014-09-02 07:45 AM
http://www.janus-rc.com/Documentation/JA17-PB_Terminus_Cend.pdf
400 MHz ARM9, 128 MB DDR3, 48 MB SPI FLASH, 1x or 2x 10/100 ETHERNET I also have other devices usinghttp://www.janus-rc.com/T2Terminus.html
, and more recently STM32F4 (1MB, and 2MB capable) using ahttp://www.janus-rc.com/terminuscf.html
.2014-09-02 08:46 AM
Clive1,
Thanks for the info. I've looked at BeagleBone Black (bought one for evaluation) but still haven't figured out how to strip off all the extra stuff and load just my application, or how to support the display we use. Granted I haven't spent tons of time on it, but it certainly is not trivial. Just getting a build system set up to allow remote debugging was not easy. Eclipse/GDB is much clunkier than the IAR setup I'm using for STM32 work, anyway. What is more intriguing to me is the CDMA910CF module on the page you linked. This was not something that I found when looking for cell boards. I had moved to looking at USB because the Mini PCIe form factor was the only affordable removable form factor I could find (Multitech's SocketModem compatible boards are way too expensive, and I believe they are based on the same obsolete chipset that I'm having to replace). I also liked Mini PCIe because multiple vendors build Mini PCIe modems to a somewhat stable standard, which would keep me from being vendor locked (yes, I'd have to change software and recertify if I changed vendors, but that's a lot easier than redesigning all the hardware). But if this device is readily available, affordable, and gets its Verizon certification, I could use it with a much smaller redesign, as I wouldn't need USB at all. I'd still need to jump from the STM32F103 to a part with more RAM/ROM/Speed, as I will need to implement SSL on my processor (the CE910 does not have SSL, unlike the older C24 that this would replace). But that's a much smaller effort.That said, I'm also looking at third party USB stack vendors who have USB hub support and at least one has indicated they will work with me to support any other devices we might need. It is certainly good to have options.Jeff.2015-09-09 02:20 AM
Hello Tsuneo,
I am trying to add support for Silicon Labs'CP210x devices as host class to STM32F4 USB stack. Following your advise I succeeded to recognize connected device by VID/PID using modified (only VID/PID was added in CDC_Class structure) CDC implementation from STM32Cube_FW_F4_V1.7.0. These are debug messages when device is connected: USBH_UserProcess: HOST_USER_CONNECTION USB Device Attached PID: ea60h VID: 10c4h Address (#1) assigned. Manufacturer : Silicon Labs Product : CP2102 USB to UART Bridge Controller Serial Number : 0001 Enumeration done. This device has only 1 configuration. Default configuration set. DEBUG : Cannot Find the interface for Communication Interface Class. Device not supporting CDC class. Of course, without casting whole support staff to vendor specifics I will get to nowhere. Unfortunately, I am not enough competent in USB stack internals to write required new class driver so any help in implementation of vendor specific host class driver for CP230x devices will be appreciated. I found such support only for Linux but it is not possible for me to use it as a reference at writing the class driver for ST USB stack. My final goal is to implement USB Host to Serial adapter FW or embedded in my FW of STM32 USB Host support for devices (already owned by customers) which communication is based on CP2102 Serial to USB adapter. Skipping or removing of CP2102 chip by the user is not an option. Third party USB host to Serial adapters supporting CP2102 are acceptable. Best regards Chris