Mutex to access same function from a task and ISR

Hi guys,

I’m writing a code for an STM32 with an external flash where I use a FAT file system and a mass storage USB accessing the memory at the same time. A normal task calls the FatFS functions whereas the USB accesses the memory from interrupt calls. Both ways end up calling the same Mem_Write() and Mem_Read() functions that access the memory using an SPI.

I’ve unsuccessfully tried using a mutex to arbitrate the memory access because the xSemaphoreTakeFromISR() returns immediately if the mutex’s taken. I read in this post that I shouldn’t block the interrupt anyway:

I’ve observed that the computer waits for the usb to respond, but it crashes if the memory read/write fails because it’s being used by a task. So somehow blocking the USB interrupt sounds acceptable.

My plan is disabling only the USB interrupt while I’m accessing the memory from a task but I wondered if is there any smarter (more efficient) way of tackling this problem?

What I have done for that sort of action is the ISR stores the data in a RAM buffer and triggers a task to write the data at a task level, not try to do the write inside the ISR.

Disabling the USB interrupt will have the danger that you may not respond to USB requests in time and the Host disconnects you from the bus. USB IS a “Real-Time” interface and is very sensitive to delays in response, but does allow responding “Not-Ready yet” to requests, so the ISR can put off new requests until the previous one is completed.

That’s a good way to do it, but it only solves the writing. If the USB tries to read the memory when another task is reading/writing it would fail again.

And that’s exactly what happened. Disabling the interrupt works fine for reading but but when I tried to save a file from the pc it crashed.

I’m now thinking having some thread safe function that would give priority always to the usb, and if any other task was in a middle of read/writing process, it would detect that the usb took over and would re-try later maybe?

Do you really have to reply with the data inside the ISR during a USB interrupt?

Youre probably better off with some kind of queue based scheme where a request comes in via USB, and gets queued with a task via the ISR, that task can then do the arbitration along with all other tasks for any resources it needs, and once it has done what it needs to do it can generate a response back to the host. This will be so much more maintainable, and easier to sequence and structure in your code.

Trying to do some kind of priority scheme where you interrupt some other transfer to give the ISR priority to read/write sounds like a nightmare in the making. Not to mention spending a lot of time inside the ISR. Get in and get out ASAP, and let non-ISR code take care of the bulk of processing.

Theres probably also a use case for something like a NAK or STALL (USB protocol) that you can generate to tell the host that the data isnt available right now, but will be soon.

That can be generated by the USB task, which can have a higher priority so that it will start executing ASAP after an interrupt. It can attempt to take the mutex and if it is already in use then it can NAK to the host which will then idle for a little bit before attempting again. If the USB task got the mutex is can read/write the data and respond with an DATAx packet to the host. As is my understanding.

As @tomstorey says, that is what the STALL response is for, you get the request, you tell the host, I don’t have the data yet, but will likely soon, and you kick a task to get the data into a buffer to send on a later repeated request for that data.

That is the expected behavior of a USB device, you get a request, and if it not immediately available, you stall and get it for a future repeat of the request.

1 Like

Dear @Litan,

It’s been a long time since I worked on STM32’s but my biggest observation was the Cube/HAL stuff provided by the manufacturer gave me many headaches and eventually I went bare-metal!

That aside, I have recently done a USB Host implementation on a different hardware platform with FreeRTOS and I found that a doctored version of the tinyusb stack to work very well and it takes care of all the issues you are struggling with now, as the author has made some steps to integrate it with FreeRTOS deferred processing methods already… There appears to be a number of STM32 example on github might be worth a look… I don’t know the details for your application so probably won’t be much further help but I know the tinyusb code is basically sound :wink: You may be able to use the code directly or take some inspiration from it.

This is just a suggestion please feel free to dismiss it :slight_smile:

I hope that helps.

Kind Regards,

Pete

I agree with @tomstorey that stopping any processes in order to give way to the ISR is a terrible idea.

The reason why I was looking for a workaround is because I’m not really familiar with the low level USB protocol and wasn’t aware of the STALL response, that actually may be the way to go. Thanks for the explanation.

I’m usually pretty comfortable working with the HAL functions. I know they have some limitations and some times I need to dig a little deeper in the code but they are fine for me most of the time. I’ll have a look at that library though, it sounds like it may be a good alternative to the HAL drivers. Thanks for sharing.

A real big reason that “taking” a resource from another task, and telling it that it no longer has it, generally doesn’t work, is because there is still a good possibility that it will still do something with that resource before it can notice that it was taken.