100 microseconds interval
Hi,
I am a relatively new OpenRTOS user and so far I’m amazed by the possibilities it offer you when dealing with a larger embedded project. However, I got into a problem and would like to ask for some advice on the best way to handle it.
I am trying to implement a CAN based communication protocol and part of it is to send streams of CAN messages separated by time intervals of 100uS. It is ok if the interval is a bit longer, but it should never be shorter than 100uS. I am running an ARM Cortex M4F at 120MHz and my OS ticks are set to 1000Hz.
One of the first solutions I thought about was to increase the tick rate to 10kHz and use vTaskDelay(1) to create the intervals, while giving the other tasks a chance to run. However, I’ve read that it’s best to avoid such high tick rates, due to the context switching delays.
A second solution would be to give my task a higher priority and use a while loop to wait for the 100uS interval. However, this would prevent other tasks from running and this could be a real problem if the message sequence is longer.
The third option would be to block the task with a semaphore as soon as it finishes sending a message. The semaphore would be released in a hardware timer ISR after 100uS. However, I wasn’t able to get the task to wake up multiple times during a tick period. I tried using the xSemaphoreGiveFromISR function follwed by a taskYIELD if the woken parameter gets set, but my task was still executed only once per milisecond.
Do you have any ideas about this problem? I feel like there should be a way to get it done nicely, but I am missing something.
Thank you!
Max
100 microseconds interval
If you are an OpenRTOS customer then you, or one of your colleages, should have a login to the support ticketing system where you can get private support. I would suggest posting your question there.
100 microseconds interval
Thanks for the suggestion. We are in the phase of considering if FreeRTOS would fulfill our needs, which is why we do not have a membership yet. It occured to me that the dilema I have might be a limitation of the OS, so I was trying to figure that out first.
Any feedback or ideas would be greatly appreciated.
100 microseconds interval
Hi Max,
OpenRTOS is outside my expertise, but if you were to implement the above task in FreeRTOS:
I would go for the third option: program one of the TC’s (Timer-Clock).
I tried using the xSemaphoreGiveFromISR function followed by a taskYIELDShouldn’t you use a
FromISR
variant of taskYIELD ? Something like portYIELD_FROM_ISR()
?
if the woken parameter gets set, but my task was still executed only once per millisecondStrange, it should be able to wake-up much more often between 2 clock ticks. It sounds like the
YIELD_FROM_ISR()
has not succeeded.
Here is a solution which uses the (cheaper) task notification (although it should work equally well using a semaphore).
~~~~~
void tcinterrupt()
{
BaseTypet xHigherPriorityTaskWoken = psFALSE;
/* Stop further interrupts to avoid time period shorter than 100 us. */
tc_stop_interrupt();
vTaskNotifyGiveFromISR( xCANTaskHandle, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
void vCANTask( void pvParameter )
{
tc_initialise();
for( ;; )
{
/ Program the TC to issue an interrupt after 100 uS. /
tc_start_interrupt( 100 );
/ Will be woken-up by the timer-counter.
ulTaskNotifyTake( pdTRUE, portMAXDELAY );
cansend_message();
}
}
~~~~~
Regards.
100 microseconds interval
Hi Hein,
Thanks for your message, that worked like a charm!
I was indeed using the regular taskYIELD instead of its ISR specific version (portENDSWITCHINGISR in my case).
Is there a way to rank up your answer?
Max
100 microseconds interval
that worked like a charm!Great
Is there a way to rank up your answer?Haha, there is not. Remember that most FreeRTOS API calls can not be called from an ISR. That has to do with locking / critical sections, and certain assumptions that the code makes. Quite often your application will just crash if you forget to add the ‘FromISR’ addition. Look at these couples: A. xSemaphoreGive( xSemaphore ); B. xSemaphoreGiveFromISR ( xSemaphore, &xHigherPriorityTaskWoken ); A. xTaskNotifyGive( pvTaskHandle ); B. vTaskNotifyGiveFromISR( pvTaskHandle, &xHigherPriorityTaskWoken ); The normal versions will call
taskYIELD()
. If the API unblocks a higher-priority task, that task will start running before the API call finishes.
The xxxGiveFromISR()
functions will never yield. It would be meaningless to yield because they are called from an interrupt. Normally an ISR ends with a short instruction like “iret”. This pops the registers from stack, including the program counter PC, and it returns to the task that was active just before the ISR was called.
Now your ISR makes a task ‘runnable’ and in stead of just returning, it wants the scheduler to check if another task should start running now. That is the function of portYIELD_FROM_ISR()
.
Regards.
100 microseconds interval
Hein,
I was actually wondering about the difference between the regular and ISR calls, so thanks a lot for clearing it up for me.
Have a great day
Max