How to (successfully) apply mutex for queueing SPI jobs?
- March 8, 2021
- 1 reply
- 1659 views
I'm trying to implement a queue system for external storage attached to the SPI.
I have three parts:
Add an item to the queue
Process an item from the queue
HAL_SPI_RxCpltCallback (my implementation to override the weak default implementation)
In doing so I've found that I have a need to stop the interrupts when I update the queue and then enable; this is some six 'C' instructions; four to update the structure in the current array element, one to move the pointer to the next array element; we'll call this the job index and one to determine the workload remaining. The process item function is called when the current element pointer has value '1' to start the process.
The process item has a separate pointer indicating the job it is working on; we'll call this the current index. This part sends out the address to the SPI via HAL_SPI_Transmit and then calls HAL_SPI_Receive_IT to receive the corresponding number of bytes from the SPI, triggering the appropriate interrupt when complete.
The call back updates the current index and if the same, resets both to zero to avoid overloading the array - the array is plenty big enough and I can see from the traffic that it no where gets near to the actual size of it. If the two index pointers are different, ie. job index > current index then the next process item is initiated.
Sometimes, everything goes a little wrong - the process stops reading while in the middle of HAL_SPI_Receive_IT transaction, for example I know that the job was 96x 16-bit words and hspi->Instance->RxXferSize == 96, hspi->Instance->RxXferCount == 72, 42 bytes have been read (or 21x 16-bit words) or I change the prescaler and I get clock stretching on the transmit read command on the address.
I'm pretty certain that the __disable_irq() and __enable_irq() calls are the culprits that surround the five operations in my job adding function and I would like to know suggestions for a better way to do this. The global interrupt handling was added as I was fairly confident that a completion interrupt was being triggered whilst the control was within this block, causing the processIndex to be reset while the jobIndex retained value. However, this method is probably overkill and is likely the cause to the SPI transaction stalling.
