Wednesday, December 3, 2014

STM32F4 USB HOST AND DEVICE

This post is a result of several hours of hard work, thinking, planning, trial-and-error, debugging, and searching the internet for working code in order to make the USB peripheral of a STM32 act as an USB device (mass storage) and HOST (mass storage too). I believe that (at least these days) you will not find another internet site with all the stuff I'm posting here in one place. Most of the codes you will find spread in other examples and libraries.

So, this post is about of programming a Nucleo-F401RE board to use the STM32F401RE USB peripheral as a DEVICE Mass Storage Class with SDCARD (connected with 4bit SDIO interface) as the media. That is, in DEVICE mode, your Nucleo will become a generic USB storage device when connected to the USB port of your computer.
The code also works as a HOST for Mass Storage Devices. That is, if you connect a USB flash drive, you can access its contents using the FATFS library.
You can also use the FATFS to access the SD card.

Overview of the breakout board with USB connector. Beneath the Nucleo board is the SD card socket.


Hardware

To use this demo with a Nucleo F401 board, you will need:

  1. An USB connector wired properly.
  2. An usb power switch, in order to provide 5V with enough current to your device when in HOST mode.
  3. A SD card connector wired properly with SDIO 4bit interface.
I use this wiring:
Schematic with the necessary connections (click to enlarge).
Some pictures of my F401 USB and SD "shield", click to enlarge:
Top view.

Top view without Nucleo board.


Bottom view.

The code


The USB library from ST is the "core" of this demo. Nevertheless, in order to make it work the way I wanted to, I merged several pieces of code from several places. All these resources where very helpful and I would like to thank the authors for sharing their knowledge:


  • Tilen Majerle FATFS and SDIO interface for SD card (link here). 
  • Tilen Majerle RTC library to use the internal RTC of the microcontroller (link here)
  • Clive1 stm32F4 discovery SDIO driver with modification to support cards with capacity larger than 4GB. His USB MSC device demo is posted in this forum.
  • The modification in USB host core state machine proposed by Michele in this forum. Without this modification the USB host lib never enumerate the connected flash drive.

The demo code

This demo is a Cocoox COIDE 1.7.7 project using ARM GCC. You will find the complete demo in my GitHub repository:

https://github.com/miguelmoreto/NucleoF401-USB-HOST-DEVICE


See the main.c file.

With this demo, you can use your Nucleo board as a Mass Storage Device that shows on your PC as a removable flash drive. The storage media is a SD (or microSD) card connected with SDIO peripheral.
You can also use it to read contents of a flash drive (thumb drive) connected to USB interface of the STM32F401RE. In this case the USB peripheral behaves as USB HOST. FATFS lib is used to read from the USB.

Demo description:

The behavior of this demo is configured by 3 defines, you have to enable only one of them:

  • DEMO_USB_HOST_ONLY    ==> enables only USB HOST
  • DEMO_USB_DEVICE_ONLY  ==> enables only USB DEVICE
  • DEMO_USB_BOTH         ==> enables both. User button changes between host and device.

In DEMO_USB_HOST_ONLY the program starts the USB HOST and after that it goes on with the rest of the program (showing date and time in USART2). When a USB mass storage is connected the enumeration and MSC process will begin. When the mass storage is ready, FATFS will be used to create a file and list the contents of the flash drive.

In DEMO_USB_DEVICE_ONLY the USB DEVICE starts and it enter in an infinite loop, waiting to cable connection. If the user press the Nucleo User Button the program escape from this loop and goes to the rest of the program (blink the led and print date and time in USART2). Be aware that USB DEVICE will be active during the rest of the program. Therefore, if you add your own code in the main loop, it can be interrupted by USB when transferring data.

To run the USB DEVICE demo, you will need a SD card connected in SDIO interface or SPI (check how to configure this in TM lib fatfs sdcard lib).

In DEMO_USB_BOTH the demo starts in USB HOST mode and when the user press the button, it changes to DEVICE mode and keeps trapped in a loop until the user press the button. In this case, the USB changes back to HOST mode. Another press in the button and it will goes back to DEVICE and so on.



14 comments:

  1. HI, I am trying to connect SD Card to my project and used your code to learn.
    I just want to understand why all he samples is with tm-XXXXX files and not with classic ST libraries. what is the difference?
    If I generated the project with cube and configured there fatfs and sdio I still should use tm-XXX files?
    I am very new in this field. Will very appreciate your help!
    Thanks
    Anna

    ReplyDelete
    Replies
    1. Hello Anna, thanks for your interest!

      The tm-XXXXX files are those from Tilen Majerle libraries. They are very good and useful. Please, check his site: http://stm32f4-discovery.com/ there you will find all his libraries and tutorials. If you generate the code with cube, it will not include these files. The cube will result in a very different code, as it uses a different ST library (ST HAL).
      Best regards,
      Miguel

      Delete
    2. Thanks for your replay!
      I tried the examples and tutorial from Tilen Majerle but didn't succeed to make them work... And I gone to CUBE but there to the card is not initialized.....
      Will continue to learn :)
      Thanks

      Delete
  2. Hi Miguel,
    I need some advise from expert with stm32f4.
    I am trying to add some Tilen Majerle projects to ST open source Microphone streaming application. (Both based on HAL lib) but as I try to add them I have Linker errors ( IAR).
    I learned the files very well and did`n saw there some places to conflict.
    for example : In TM RTC file it uses some funcs from stm32f4xx_hal_rtc.c and for this funks I get linker error in tm_stm32_rtc.o
    Have you ever solved this kind of errors?

    Thanks Anna

    ReplyDelete
    Replies
    1. Hello Anna, sorry for late response. Have you solved the problem? I don't know how to help you in this case. I never used IAR. And I'm not an expert either! :). Best regards.

      Delete
  3. Hi Miguel,
    I have two questions for you. I amusing an STM32F405 processor. (Same as 407, less pins)
    All I want to be able to do is plug in the USB flash drive, and when it's detected, I want to read data for a location and then write it to the USB drive.

    1 - Will it be connected the same as your diagram?
    2 - Which mode would the STM32F4 be running in to best do this? I'm not sure if it
    would be DEMO_USB_HOST_ONLY, or DEMO_USB_DEVICE_ONLY. Is it the program's job to "check" and see if there is a USB connected? This is the part I am not sure about. I am using FreeRTOS so I can commit a task to checking at a certain interval for a connected drive.

    Thank you!
    Gary

    ReplyDelete
    Replies
    1. Hello Gary,

      I will try to answer. If I understood right, you want to read some data from somewhere (like AD converter or other peripheral).

      1) Yes, the USB part at least. If you will not use de SD card, those connections are not needed.
      2) If you will write to the flash drive connected to the microcontroller USB, the microcontroller will act as a host, so DEMO_USB_HOST_ONLY is the option.
      3) The USB lib detect the insertion of an USB drive using the USB interrupt. After that, you need to run its state machine. Let me explain: the usb interrupt handler calls the external function USBH_ConnectEventCallback(), among doing a lot of other stuff. This user defined handler in my main program sets a flag (usb_host_connected_flag = 1;). When this flag is set, the loop "while(!USBH_USR_MSC_IsReady())" process the state machine (function USBH_Process). The loop is ended when de USB drive is ready to be used. The lines that follow the loop in my program gives you an example of how to read and write the usb drive using the fatfs driver. Short answer: the program job is to run the state machine USBH_Process when the usb device is inserted. Alternatively, you can continuously call USBH_Process until some usb device is connected.

      I use this lib also in a STM32F405 with a real time operational system (BRTOS). I created a task for USB. I used semaphores instead of the usb_host_connected_flag to signal the usb task. The usb task send signal to the main task to inform the USB is ready.

      Check also the user callbacks at the file usbh_msc_usr.c. You can modify them. In my rtos application, I used semaphores in those callbacks to signal the usb task, instead of printing messages.

      Best regards,

      Miguel

      Delete
  4. Miguel,
    Thank you for your good answer, and so quickly. 8-)

    Yes, it's just data I am writing to a FRAM chip on the PCB when the unit is in the field, and when unit comes back and the user inserts the USB it will write the data from the FRAM to the USB.

    Great idea about using the semaphore from the FreeRTOS! I haven't used sempahores, but will try. I have used interrupt-safe message queues and they work well too.

    By the way, thank you for this very good page, very helpful.

    Kind regards,
    Gary

    ReplyDelete
  5. Hello, this example is relay helpful,
    I want to ask if are you try to develop this in mbed.org platform, if yes, u can share the project?
    i never use Cocoox COIDE, mbed platform is more easy for me :)
    Thanks in advance

    ReplyDelete
    Replies
    1. Hello Cipri.C,

      unfortunately I don't use mbed and I never tried to develop this project there.

      Sorry,

      best regards.

      Miguel

      Delete
  6. Hello,
    Can you show me the changes you made to use RTOS?
    I am trying, but my program only works without RTOS. When I activate RTOS the program don't pass the USBH_Init routine.
    I used semaphores instead of the connect and disconnect flags to activate the USBH_Process in the usb task, but I can figure the problem.
    Can you help me?

    ReplyDelete
  7. Hi Miguel,

    Congratulations on the project. As you said there are few, if any, examples of an SMT32 F4 connected to a USB MSD using also FATFS with SDIO.

    I have exactly that configuration, USB as device, using cube-mx, and I wanted to learn from your example how to see theFATFS on the SD drive in my project from a connected PC.

    Since I did not replicated your example using the same hardware, I am just browsing your code using coocox.

    The problem is that I did not find in your code, configured with DEMO_USB_DEVICE_ONLY, where you connect the USB interface to FATFS.

    Can you point me in the right direction of where you connect the USB as device to the FATFS?

    Thanks!

    ReplyDelete
  8. Hi Miguel,

    Could I run this circuit without USB power switch?
    I have tried it, but My HID device can't turn on (Red LED in My optical mouse still light off).

    Thanks

    ReplyDelete
  9. USB VBUS to PA9 might exceed abs max rating of the STM32. It surprises me that wiring it this way don't fry the IC the moment you plug it in.

    ReplyDelete