IPC problem xQueueSend, xSemaphoreTake, ExitCriticalSection

valeriv wrote on Monday, December 11, 2017:

Hello all
I need your advices and opinion about IPC.

The project run on STM32, in IAR with FreeRTOS.

I have 2 tasks (there are a lot of tasks in the project but I speak about two) : ModbusMasterTask with priority 5 and IOTask with priority 7.

When IO task want to get any information from modbus, it connect TransmitCallbackFunction to modbusMasterObject and wait for message on xQueueReceive method from modbusMasterTask.

IOTask:
ReadInputRegisters:
SetTransmitCallbackFunction
if xQueueReceive
return true;
return false;
Delay(30)

ModbusMasterTask a little more complicated : it checks TransmitCallbackFunction if it is NULL task does nothing.

IF ( NULL != TransmitCallbackFunction )
{
EnterCriticalSection;
Send request
Get answer from slave
SetTransmitCallbackFunction to NULL
xQueueSend transmitEndMessage to IOTask
ExitCriticalSection
}
Delay(30)

So, here is the FIRST question: It works good but I don’t understand how it works. The priority of the IOTask higher than ModbusMasterTask and I think that on xQueueSend OS immediately try to make run IOTask but it cann’t because the code in critical section. Probably after ExitCriticalSection OS make run IOTask ???
AM I RIGHT ?

And now I need change existing code. Actually ModbusMasterTask always knows about start and end of transmission, so it doesn’t need to run always, but IOTask can trigger it and after ModbusMasterTask GetsAnswer from slave it can go to blocking state. I tryed to do this with Notify functions and BinarySemaphore, but it doesn’t work and I think that it is because of critical section.
So, my pseudocode is

IOTask:
ReadInputRegisters:
SetTransmitCallbackFunction
xSemaphoreGive – new row PROBLEM !!!
if xQueueReceive
return true;
return false;
Delay(30)

ModbusMasterTask:
EnterCriticalSection;
Send request
Get answer from slave
SetTransmitCallbackFunction to NULL
xQueueSend transmitEndMessage to IOTask
xSemaphoreTake with MAX DELAY – new row PROBLEM !!!
ExitCriticalSection
NO DELAY – PROBLEM !!!

It is the SECOND question- problem
Both of tasks enters there loops several times and stuck on ModbusMasterTask forever.
Please help me to resolve this problem

Thanks a lot for your time and consideration

Valerie

rtel wrote on Monday, December 11, 2017:

IOTask:
ReadInputRegisters:
SetTransmitCallbackFunction
if xQueueReceive
return true;
return false;
Delay(30)

What does it do with the data obtained by the xQueueReceive() call?
Can it block on the queue for 30 ticks, rather than calling delay for 30
ticks?

ModbusMasterTask a little more complicated : it checks
TransmitCallbackFunction if it is NULL task does nothing.

IF ( NULL != TransmitCallbackFunction )
{
EnterCriticalSection;
Send request
Get answer from slave
SetTransmitCallbackFunction to NULL
xQueueSend transmitEndMessage to IOTask
ExitCriticalSection
}
Delay(30)

I assume the critical section here is used to prevent a race condition
on TransmitCallbackFunction, but FreeRTOS API functions (queue send and
receive etc.) should not be performed in a critical section as to do so
would generate logic errors if using the API unblocks a task but a
switch to that task cannot be performed [some FreeRTOS ports can, and
other can’t, the STM32 can’t].

Also, this critical section looks very long if it is sending something
and then waiting for the answer.

Where is the critical section actually required? By which I mean, other
than when TransmitCallbackFunction is tested and reset, what else needs
protecting? Try and come out of the critical section as soon as possible.

I suspect a simpler (to structure, not to code) solution might be to
make the Modbus comms interrupt driven.

So, here is the FIRST question: It works good but I don’t understand how
it works. The priority of the IOTask higher than ModbusMasterTask and I
think that on xQueueSend OS immediately try to make run IOTask but it
cann’t because the code in critical section. Probably after
ExitCriticalSection OS make run IOTask ???
AM I RIGHT ?

As per my comments above. It actually depends on the FreeRTOS port
being used, and the STM32, being a Cortex-M, cannot context switch in a
critical section. Try to restructure, then you can try the semaphore
(or other signalling scheme) again.

valeriv wrote on Wednesday, December 13, 2017:

Many many thanks to you !!!