STM32F429Discovery with STM32Cube, USB, fatfs and FreeRTOS

thyanger wrote on Wednesday, September 09, 2015:

Hi,

I am developping an application to write something in a file over an USB key connected to the discovery board. A very basic example without FreeRTOS works well. This example is one of those provided by ST within Cube (STM32Cube_FW_F4_V1.5.0\Projects\STM32F429I-Discovery\Applications\FatFs\FatFs_USBDisk), which I rearranged to make it work with eclipse mars. This example, and also my application, uses the USB middleware provided within Cube. The USB is configured in HS as a host mass storage class (MSC) device.

Now, I have rearranged the code to use FreeRTOS but in this case it does not work. I am really confused by the USB middleware layer which I tried to investigate for debug purposes, so I know that also my help request is unclear. The code is organized as follow: there are one task and one queue. The task, namely userTask, is that which is in charge to write the file. The drivers are adapted to the use with an RTOS, being enough to check the flag USBH_USE_OS == 1 in a configuration file. By means of the driver initialization procedure, another task is created by the driver at startup, namely driverTask, which is in charge to detect the events occurring about the USB peripheral (i.e. connection, disconnection and so on). The userTask and the dirverTask communicates via the queue I have mentioned before. The driverTask communicates with the low level driver with other queues (by code inspection you can see this).

As an example I also gave a look at the code written for the evaluation board and provided within Cube (for the discovery there is no example with freertos+usbkey+fatfs).

So, the microcontroller starts with the USB key attached. During debug I noticed that both tasks are in blocking state, like they are waiting for something to happen. So I put a breakpoint to the IRQHanlder call and I have noticed that by repeatedly pressing the “play” button in eclipse, it always enters that piece of code as the interrupt is never served. However I checked the interrupt priority and everything looks ok.

At this point I really don’t know what to check since my lack of knowledge of this middleware (which I deem awful). Any help will be really appreciated.

Thank you and regards.

edwards3 wrote on Wednesday, September 09, 2015:

Sounds like the problem is not directly a freeRTOS one, but the interrupt being executed repeatedly might be the right behavior for USB. How often does the interrupt run in the working code?

thyanger wrote on Thursday, September 10, 2015:

Dear MEdwards,

thank you for the reply!

However I just found the problem. It seems that with heap_4.c my code does not work. I changed heap_4.c with heap_3.c, clean and build and it works indeed. For doublecheck I tried again with heap_4.c (clean and build) and it does not work.

Basicly I took a previous code I wrote which I knew it was working and then I started to compare with the non working one. Going further I copied all the code from the working one to the non working one and I finally end up with two folders with only one difference: the memory management scheme.

I am not an expert, really, so I don’t know if this is a bug or if some memory management schemes are not suited this particular purpose. What I know is that this worked for me.

I hope that this can help somebody else.

Regards.

heinbali01 wrote on Thursday, September 10, 2015:

Hi Valerio,

As you probably know:

heap_3 uses the standard malloc()/free() couple.

heap_4 uses a fixed block of heap space, statically declared as:

uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];

heap_5 uses a series of non-contiguous memory blocks. It allows e.g. to use both internal SRAM as well as external SDRAM.

When using heap_4 or heap_5, make sure that malloc() and free() are not being called. Some library calls (sprintf(), localtime()) may use them.

Sometimes I declare them as follows, so that the linker will issue an error whenever they are called:

    /* Define a non-existent function. */
    extern void malloc_is_called( void );
    extern void free_is_called( void );
    void* malloc( size_t xWantedSize )
    {
        /* Call a non-existent function. */
        malloc_is_called();
        return NULL;
    }
    void free( void* pv )
    {
        /* Call a non-existent function. */
        free_is_called();
    }

Other developer redefine malloc()/free() as follows:

    /* Make a wrapper for malloc() and free().
    You can put breaks in a debugger here.
    Do not use this in combination with heap_3 :-) */
    void* malloc( size_t xWantedSize )
    {
        return pvPortMalloc( xWantedSize );
    }
    void free( void* pv )
    {
        vPortFree( pv );
    }

For C++ users, make sure that the above declarations get an extern "C" linking.

( I’m not sure if I like that mix of malloc() and pvPortMalloc(). */

Keep on using heap_3 that calls malloc()/free() ? That is OK.

I tend to prefer heap_4 and heap_5 because they are:

  • very fast
  • they are easy to inspect while debugging
  • easy to monitor ( xPortGetMinimumEverFreeHeapSize() / xPortGetFreeHeapSize() )
  • easy to configure ( configTOTAL_HEAP_SIZE or vPortDefineHeapRegions() )

I once wrote a test for these two modules: allocating and freeing random amounts of memory. They both passed the test more than well.

Regards.

thyanger wrote on Thursday, September 10, 2015:

Thank you!