We have a number of drivers implemented in FreeRTOS but I am a little confused as to whether we are doing things correctly as my expectations of what the “standard” pattern is don’t seem to match the FreeRTOS API.
In general, we have many drivers which are primarily driven by a state machine in the ISR. For example, the ISR may transmit the next data byte through a peripheral. To do so it would take the next byte from a buffer. If the transmission is completed then it would take the next buffer from a pending queue. If the pending queue is empty then it would stop.
When a request is made for transmission, the driver must therefore determine whether there is already a transmission in progress. If so, the buffer can be added to the pending queue and it will get handled by the driver. If there is not a transmission in progress then simply adding the buffer to the pending queue will do nothing because the ISR will never go off (as the hardware has stalled). It is therefore necessary to “kick” the hardware to, for example, transmit the first byte from the buffer. After that the processing will continue in the ISR.
Obviously, the detection of the current driver state (in progress or not) and the decision as to whether to kick the hardware, or simply queue the buffer, must be taken atomically, from the perspective of the ISR. It is therefore necessary to ensure that the peripheral interrupt is masked during this decision. If we only mask the one hardware interrupt then there is the potential for a task switch to take place whilst the interrupt is disabled, which would be bad as it may leave the interrupt disabled for a long time. It seems to me, then, that the best thing would be to have a short critical section, in which it is guaranteed that a task switch cannot take place and I understand that FreeRTOS provides taskENTER_CRITICAL and taskEXIT_CRITICAL for this sort of situation. However, one of the operations which must take place within the critical section is the insertion of the buffer onto the queue. If this does not happen inthe critical section then the driver could potentially stall. The API reference for taskENTER_CRITICAL and taskEXIT_CRITICAL clearly states that FreeRTOS API calls must not be made in a critical section. If this is the case, then I do not understand how to implement this simple driver pattern.
Is it really the case that no FreeRTOS API calls can be made inside a critical section, or could I call the xxxFromISR variant? (As I only want to insert an item into a queue). If the documentation is correct, and I cannot make FreeRTOS calls at all, then my overall pattern must be wrong. How should I be implementing this simple driver pattern in FreeRTOS?
Many thanks in advance,