USB Host stack and driver for STM32

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderators: RoccoMarco, barthess

dismirlian
Posts: 65
Joined: Fri Dec 20, 2013 3:59 pm
Location: Buenos Aires, Argentina
Has thanked: 1 time
Been thanked: 16 times

USB Host stack and driver for STM32

Postby dismirlian » Tue Nov 03, 2015 11:47 pm

Hello all,

I've been working on a USB host stack and driver for ChibiOS for the last couple of weeks. The code quality is ultra-beta for now (especially the low level driver), but it works with the (few) devices I've tested.

The driver is split in two (as the rest of the ChibiOS HAL):

1) a high level driver which handles:
* port connection/disconnection detection
* enumeration
* class driver loading by Class/Subclass/Protocol and VID/PID (TODO)

2) a driver for the STM32 OTG IP:
* full-speed only
* Slave-mode only (no DMA)
* MUCH room for improvement/optimization yet, the driver has to be tested thoroughly.
* Support for all the transfer types, but only tested Control SETUP/IN/OUT, Bulk IN/OUT, Interrupt IN.
* I will test Isochronous IN with the USB Video Class driver; I don't have other devices to test INT/ISO OUT...

On top of the high level driver, we can write class drivers. For now, there are only:
- Mass Storage driver, which exposes a ChibiOS Block Device (to connect, for instance, to FATFS).
- HUB driver, tightly integrated with the high level driver, to connect multiple devices to the USB port.
- Interface Association driver (dummy driver which loads drivers for interface groups - necessary for USB Video Class and USB Audio Class)
- UVC class skeleton (no code yet).

The high level driver API is inspired in various hosts/libraries including Linux and libUSB. I think the driver is basic but quite complete (for example, it supports multiple devices at the same time, and a clean asyncrhonous API). The high level driver exposes two kinds of APIs to perform transfers:

- Synchronous API, for Control and Bulk only, which send a message while blocking the thread for the answer:
See example in usbh_msd.c. The synchronous API is built upon the asyncrhonous API.

Code: Select all

   ...
   stat =  usbhBulkTransfer(ep, data, len, &actual_len, timeout);
   //Here, the transfer is done (or an error ocurred)
   ...


- Asynchronous API, for any transfer type, which can be used in interrupts:
See example in usbh_hub.c

Code: Select all

func() {
   ...
   osalSysLock();
   usbhURBSubmitI(&urb);
   osalSysUnlock();
   ...
}

static void _urb_complete_callback(usbh_urb_t *urb) {
   switch (urb->status) {
   case USBH_URBSTATUS_TIMEOUT:
      ...
      break;
   case USBH_URBSTATUS_OK:
      ...
      break;
   case USBH_URBSTATUS_CANCELLED:
      ...
      break;
   default:
      ...
      break;
   }

   usbhURBObjectResetI(urb);
   usbhURBSubmitI(urb);
}


The low level driver is inspired primarily in the Linux source code for the DesignWare OTG driver (much cleaner than the ST implementation, which is quite buggy). The code should be adaptable to any OCHI/ECHI implementation (for instance, I think the NXP LPCxxxx are OHCI/ECHI), because the basic idea is similar: when you submit an URB, the driver queues it in the endpoint, and queues the endpoint for processing in the host scheduler.

Thus, it is possible to push ahead of time some URBs, to maximize USB bandwidth. For example, a possible UVC (USB Video Class) camera driver could do something like this:

Code: Select all

init() {
    initialize a mailbox
    reserve a memory pool of 10 buffers
    initialize two URBs

    mempool alloc & submit URB to ISO IN endpoint
    mempool alloc & submit URB to ISO IN endpoint
}

callback() {
    push full buffer to mailbox
    reset URB
    mempool alloc & submit URB to ISO IN endpoint
}

reading thread() {
    while(1) {
        wait for mailbox
        do something with the full buffer
        mempool free the buffer
    }
}



For the high level driver to work, the function usbhMainLoop has to be called periodically. This function polls the connected hubs (including the root hub) for port status changes (connect/disconnect, etc), and enumerates devices and loads appropriate drivers. The poll rate and priority are not critical (the example provided uses 100ms).

The provided example enumerates the connected devices and prints device/configuration details. Also, if the device is a mass storage device, then loads the Mass Storage Driver. The MSD then loads one block driver for each Logical Unit (LUN). The TestThread detects the BLK_READY state, and begins a quick test (read/write/file listing), using the FATFS library. This works also through USB hubs.

All the devices I have lying around get enumerated ok:
- 3 pendrives
- 1 USB hard drive
- 2 mice
- 1 keyboard
- 4 webcams
- 1 MIDI interface
- 2 hubs
- 3 FTDI USB/serial converters
- 1 Jlink debug pod

Some details:
1) Sources:
src/usbh.c: The high level driver
src/usbh_lld.c: The low level driver for STM32 OTG
src/usbh_debug.c: Debug functions
src/usbh_desciter.c: Configuration descriptor iterator routines (see example in usbhDevicePrintConfiguration)
src/usbh_hub.c: HUB class driver
src/usbh_msd.c: Mass Storage class driver
src/usbh_uvc.c: UVC driver (skeleton)

2) Headers:
include/usbh_conf.h: Configurations (Tune this file)
include/usbh.h: Main driver header (API)
include/usbh_msd.h: Header for usbh_msd.c
include/usbh_hub.h: Header for usbh_hub.c
include/usbh_desciter.h: Header for usbh_desciter.c


To test:
1. I use the SVN version of ChibiOS
2. The stm32_otg.h file is a modified version of the one distributed with ChibiOS (one bug correction, and some additions). You should replace the ChibiOS (in hal/ports/STM32/LLD/OTGv1/) version with the one provided.
3. Configure your MCU in mcuconf.h, board.h, Makefile. Currently, I use a custom board with the STM32F207.
4. Configure the IOs in main(), especially the SD1 UART pins, the VBUS enable pin (if any), and the USB pins (note that the driver doesn't work with external PHYs yet, only with the internal Low/Full Speed PHY).
5. Configure the usbh driver in usbh_conf.h, especially STM32_USBH_USE_OTG: 1 = OTG_FS, 2 = OTG_HS (in Full speed mode)
6. Connect a PC's serial port using 230400bps 8N1; the example uses serial driver SD1 (UART1_TX/RX).
7. Plug a pendrive (best if there's nothing critical in there!).

Future improvements might include (also, see TODOs in all files):
- High level: Event sources for connection, disconnection, etc.
- High level: More class drivers (HID, UVC)
- High level: Suspend/Resume support
- LLD: Cleaner code
- LLD: DMA and High speed support (don't have a board with HS phy)
- LLD: Suspend/Resume support
- General: more options to compile-out portions of code to reduce flash/RAM usage.

One important detail: The driver makes use of the Linux Kernel list.h header (renamed as usbh_list.h). See http://github.com/torvalds/linux/blob/m ... nux/list.h. This file will have to be rewritten. It shouldn't be a big job, because not many functions are used.

Any comments are welcome!

Diego.
Attachments
test.zip
USB Host stack for ChibiOS
(122.54 KiB) Downloaded 640 times

User avatar
Giovanni
Site Admin
Posts: 14457
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: USB Host stack and driver for STM32

Postby Giovanni » Wed Nov 04, 2015 9:16 am

Hi,

Great work, I am sure a lot of people will appreciate this, lets collect feedback. I will post my suggestions after reviewing it, I still have a lot of pending bugs and tasks in queue.

Giovanni

dismirlian
Posts: 65
Joined: Fri Dec 20, 2013 3:59 pm
Location: Buenos Aires, Argentina
Has thanked: 1 time
Been thanked: 16 times

Re: USB Host stack and driver for STM32

Postby dismirlian » Wed Nov 04, 2015 3:27 pm

Hi Giovanni,

While I wait for your feedback, I'll be posting updates/bug fixes.

Thanks!!

Diego.

User avatar
Giovanni
Site Admin
Posts: 14457
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: USB Host stack and driver for STM32

Postby Giovanni » Wed Nov 04, 2015 3:39 pm

Thanks, let's keep this post updated.

Giovanni

chibby
Posts: 66
Joined: Wed Oct 22, 2014 11:20 am

Re: USB Host stack and driver for STM32

Postby chibby » Wed Nov 04, 2015 9:35 pm

Excellent work.

I'm not up to speed on using Chibios yet but this may be time to get stuck in. I have two F4 discovery boards

Is there a simple ready to build example that I can flash to the device to help test this?

dismirlian
Posts: 65
Joined: Fri Dec 20, 2013 3:59 pm
Location: Buenos Aires, Argentina
Has thanked: 1 time
Been thanked: 16 times

Re: USB Host stack and driver for STM32

Postby dismirlian » Thu Nov 05, 2015 7:29 pm

Hi Chibby,

The code does not support the high-speed PHY yet (it even has some bugs as-is!). I'm still trying to track down a problem with the low level driver: when two host channels are scheduled in the hardware queue, strange things happen, and the communication ceases to work. For now, I've implemented a work-around that works, but I'd like to correct this issue when I can.

I don't have a F4 Discovery board, but I prepared an example for you to test (don't know if it works...). The example writes a file to a pendrive and then reads the file back. To use it, plug a pendrive to the OTG port in the F4 Discovery, and a TTL serial port to UART2 in the discovery - PA2(TX) and PA3(RX) to see the output (115200, 8N1).

Diego.
Attachments
RT-STM32F407-DISCOVERY-usbh.zip
USB Host stack (F407 Discovery test)
(122.55 KiB) Downloaded 459 times

chibby
Posts: 66
Joined: Wed Oct 22, 2014 11:20 am

Re: USB Host stack and driver for STM32

Postby chibby » Sun Nov 08, 2015 11:07 am

Thanks, I've built the demo provided above. However, I don't have a TTL serial driver and did not want to start breadboarding this ST board yet.

This config is the obvious choice for debugging the driver but is it possible to simply redirect the output to the ST-link for testing OTG?

dismirlian
Posts: 65
Joined: Fri Dec 20, 2013 3:59 pm
Location: Buenos Aires, Argentina
Has thanked: 1 time
Been thanked: 16 times

Re: USB Host stack and driver for STM32

Postby dismirlian » Sun Nov 08, 2015 7:43 pm

Yes, it should be possible to redirect the output to the SWO pin.

You can modify the file usbh_debug.c to "print" directly to SWO using ITM_SendChar; check the uses of USBH_DEBUG_SD in that file and replace them with appropriate calls.

Maybe you could wrap the ITM in a BaseSequentialStream, it shouldn't be very complex. I don't have SWO connected in my board, that's why I use the serial port for debugging, sorry!

Diego.

dismirlian
Posts: 65
Joined: Fri Dec 20, 2013 3:59 pm
Location: Buenos Aires, Argentina
Has thanked: 1 time
Been thanked: 16 times

Re: USB Host stack and driver for STM32

Postby dismirlian » Wed Nov 18, 2015 1:01 am

Hi,

I attach a new version of the USB host stack (+ STM32 low level driver), included in an (untested) F407 Discovery demo.

The code is much cleaner (especially the low level driver); it took me some time to clean up the bugs and work around some errata. I don't know of any bugs currently.

The stack and driver has been tested using two custom boards: one F207 and one F411; it works quite well in both. Currently, there is a mass storage driver, and a video class driver (for webcams, which I am not yet allowed to share, but is working).

The Mass Storage driver saturates the USB Full speed bus, at 1.159MB/s (raw blocks read speed), which is exactly the theoretical limit for Full Speed Bulk (1,216,000 B/s). Through FATFS, the write speed is ~630kB/s (limited by the storage device), and the read speed is 860kB/s. These tests were done with the F207, running at 120MHz, with -O2 and ChibiOS checks enabled. I couldn't test the raw block write speed limit (the flash devices I have limit the speed).

It is also now possible to use simultaneously the OTG_FS and the OTG_HS peripherals, which map to the USBHD1 and USBHD2 ChibiOS drivers (although the OTG_HS only in Full Speed mode, with internal PHY), so you can have two independent USB ports. Also, it is possible to connect the devices through USB hubs, if the hub driver is enabled.

I hope someone finds this useful. Any comments/suggestions are welcome!

Thanks,
Diego.
Attachments
RT-STM32F407-DISCOVERY-usbh.zip
USB Host stack (F407 Discovery test)
(121.12 KiB) Downloaded 598 times

User avatar
Giovanni
Site Admin
Posts: 14457
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: USB Host stack and driver for STM32

Postby Giovanni » Wed Nov 18, 2015 8:46 am

Great work :)

Giovanni


Return to “STM32 Support”

Who is online

Users browsing this forum: No registered users and 50 guests