After calling xQueueSendToBackFromISR() my task changes state and gets READY.
If i call portEND_SWITCHING_ISR() in the end of the USART1_IRQHandler, that my task gives CPU, changes state and gets RUNNING. My task continue works.
But if i don’t call portEND_SWITCHING_ISR(), my task must gets CPU in the end of system tick. In the hendler of the system timer must call scheduler. But scheduler does call and switch context no occur. Why? My singular task is ready and only IDLE running all times. Why?
Where in the hendler of the system timer calling scheduler and where checking for tasks ready?
The same code works with FreeRTOS v7.2.0 and early.
Please confirm that all the RTOS code you are running is from the V7.6.0 distribution. What I think you are describing could be the case if you updated the core files found in FreeRTOS/source from V7.2.0 to V7.6.0, but left the port layer files found in FreeRTOS/source/portable/IAR/ARM_CM3 at V7.2.0.
Please ensure you report back even if that is your problem so we can be assured there are no issues.
I am sure the files from V7.2.0 use in project with V7.2.0, and the files from V7.6.0 use in project with V7.6.0.
Initially, i was doing project with V7.6.0. By accident i detected that one of my task with highest priority didn’t work. Its state was READY. I studied of rtos source code and found out that the scheduler isn’t calling from the hendler of the system timer.
Then i downdated FreeRTOS/source from V7.6.0 to V7.2.0 and my task worked.
You can see and compare hendler V7.6.0 ( FreeRTOSV7.6.0\FreeRTOS\Source\portable\IAR\ARM_CM3\port.c )
void xPortSysTickHandler( void )
{
/* The SysTick runs at the lowest interrupt priority, so when this interrupt
executes all interrupts must be unmasked. There is therefore no need to
save and then restore the interrupt mask value as its value is already
known. /
( void ) portSET_INTERRUPT_MASK_FROM_ISR();
{
/ Increment the RTOS tick. /
if( xTaskIncrementTick() != pdFALSE )
{
/ A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );
}
…compare with hendler V7.2.0 ( FreeRTOSV7.2.0\FreeRTOS\Source\portable\IAR\ARM_CM3\port.c )
void xPortSysTickHandler( void )
{
unsigned long ulDummy;
/* If using preemption, also force a context switch. */
#if configUSE_PREEMPTION == 1
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
#endif
ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
{
vTaskIncrementTick();
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
}
Where calling scheduler in V7.6.0?
Also i studied of rtos source code another ports. For example ATMega323:
V7.2.0
vPortYieldFromTick:
portSAVE_CONTEXT ; Save the context of the current task.
call vTaskIncrementTick ; Call the timer tick function.
call vTaskSwitchContext ; Call the scheduler.
portRESTORE_CONTEXT ; Restore the context of whichever task the …
ret ; … scheduler decided should run.
V7.6.0
vPortYieldFromTick:
portSAVE_CONTEXT ; Save the context of the current task.
call xTaskIncrementTick ; Call the timer tick function.
tst r16
breq SkipTaskSwitch
call vTaskSwitchContext ; Call the scheduler.
SkipTaskSwitch:
portRESTORE_CONTEXT ; Restore the context of whichever task the …
ret ; … scheduler decided should run.
Please try the following sequence when you build with portEND_SWITCHING_ISR() commented out, and report back where you think the problem occurs.
Put a break point on your call to xQueueSendToBackFromISR(), then run the code until the break point is hit.
In the debugger, step into the xQueueSendToBackFromISR() function, you should enter the xQueueGenericSendFromISR() function, from which xTaskRemoveFromEventList() is called. Step into xTaskRemoveFromEventList().
Inside cTaskRemoveFromEventList() there is the line of code:
which, if there is a task waiting on the queue, and the task's priority is above the idle priority, should evaluate to true, which in turn will cause xYieldPending to be set to pdTRUE.
When you get to the line that sets xYieldPending to pdTRUE, put a break point on the first line of xTaskIncrementTick() which is in tasks.c. Run the code again until the new break point is hit.
At the very end of xTaskIncrementTick() you will find the following lines of code:
Step out of xTaskIncrementTick() and you will end up in the code you posted in your previous post.
if( xTaskIncrementTick() != pdFALSE )
{
/ A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. /
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
As xTaskIncrementTick() returns pdTRUE (because xSwitchRequired equaled pdTRUE) the PendSV interrupt is pended to request a context switch.
So the logic shows a context switch should happen. At which point do you see the actual behaviour deviate from this sequence? Please ensure to report back as it is very important to know if you think there is an error somewhere.
Hello. Thank you for replay and help.
I try you steps in the debbug mode and … and make several screenshort… step-by-step. You can see them in attach.
I don’t understand… where and when xYieldPending must be set to pdTRUE?
Thanks for such detailed screen shots. I can see in image 9 that this is not FreeRTOS V7.6.0, as V7.6.0 contains the following code:
if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* Return true if the task removed from the event list has
a higher priority than the calling task. This allows
the calling task to know if it should force a context
switch now. */
xReturn = pdTRUE;
/* Mark that a yield is pending in case the user is not using the
"xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
xYieldPending = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
The lines in red are missing in your code.
Regards.
[edit the red didn’t come out - but it is the code with the comment “mark that a yield…” that is missing in your code - this forum is hard to post code too!]
Thank you for you help. I deleted all source of FreeRTOS and load V7.6.0 again. My task works. Thank yo very match and i’m sorry for my mistake made through lack of attention.
But happiness was short. I was sending bytes whit period 1 sec to my programm. For the short haul my task worked, than it hang.
I stoped running and begin step in the debag mode. My task was READY, queue was full and xYieldPending == 0. Something was wrong, and context doesn’t switch to my task. In the handler of system timer no check tasks for ready. Why?
If this happened after it has been running for a while then the most likely cause is a bad interrupt priority assignment. Do you have configASSERT() defined?
I will rephrase that. If you don’t have configASSERT() defined then define it because it will help trap bad interrupt priority assignments. http://www.freertos.org/FAQHelp.html