Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem


Loading

vTaskEndScheduler not working as stated

Posted by Bernardo Marques on January 6, 2010
Hi there,
I'm using FreeRTOS on a project of my own with a custom board and an AT90USB647 uController. At some point I need to jump to the USB boot loader code and before I do it I stop the scheduler with
vTaskEndScheduler
function.
Problem is:
- in the documentation it is stated that execution will return to the instruction after the call to
vTaskStartScheduler
just as if it had returned (see http://www.freertos.org/a00133.html). The code does not behave that way. After some time trying to make it work I checked the source code and
vTaskEndScheduler
has only 3 lines of code that I pasted below.

void vTaskEndScheduler( void )
{
/* Stop the scheduler interrupts and call the portable scheduler end
routine so the original ISRs can be restored if necessary. The port
layer must ensure interrupts enablebit is left in the correct state. */
portDISABLE_INTERRUPTS();
xSchedulerRunning = pdFALSE;
vPortEndScheduler();
}


this means that unless somehow i make code on
vPortEndScheduler
to return to the instruction after
vTaskStartScheduler
the return will be to the instruction after
vTaskEndScheduler
.

Can someone please tell me how to make it return to the statement after
vTaskStartScheduler
??
Or does the documentation need to be changed?
Anyway, this is a either a bug or an unimplemented feature on FreeRTOS isn't it?

Regards,
Bernardo Marques.

RE: vTaskEndScheduler not working as stated

Posted by Bernardo Marques on January 6, 2010
This is the same question but readable, i did not now that the 'code' tag would do that and i do not know how to edit the post.

Hi there,
I'm using FreeRTOS on a project of my own with a custom board and an AT90USB647 uController. At some point I need to jump to the USB boot loader code and before I do it I stop the scheduler with vTaskEndScheduler function.
Problem is:
- in the documentation it is stated that execution will return to the instruction after the call to vTaskStartScheduler just as if it had returned (see http://www.freertos.org/a00133.html).
- The code does not behave that way. After some time trying to make it work I checked the source code and vTaskEndScheduler has only 3 lines of code that I pasted below.

void vTaskEndScheduler( void )
{
/* Stop the scheduler interrupts and call the portable scheduler end
routine so the original ISRs can be restored if necessary. The port
layer must ensure interrupts enablebit is left in the correct state. */
portDISABLE_INTERRUPTS();
xSchedulerRunning = pdFALSE;
vPortEndScheduler();
}


this means that unless somehow i make code on vPortEndScheduler to return to the instruction after vTaskStartScheduler the return will be to the instruction after vTaskEndScheduler.

Can someone please tell me how to make it return to the statement after vTaskStartScheduler??
Or does the documentation need to be changed?
Anyway, this is a either a bug or an unimplemented feature on FreeRTOS isn't it?

Regards,
Bernardo Marques.

RE: vTaskEndScheduler not working as stated

Posted by Richard on January 7, 2010
I think that function is only implemented for the PC port, where ending the scheduler allows you to return to DOS. The implementation uses setjmp(), take a look at the OpenWatcom PC port implementation of the function.

Regards.

RE: vTaskEndScheduler not working as stated

Posted by Bernardo Marques on January 7, 2010
Shouldn't the documentation be changed to say that the function returns as expected unless using the PC port where it'll return to the instruction after vTaskStartScheduler?

Thanks for your help Richard.

Regards,
Bernardo Marques.

RE: vTaskEndScheduler not working as stated

Posted by JBlackArty on August 1, 2012
I fallen into the same trap. Agree. Documentation should be corrected (it's still unclear).

RE: vTaskEndScheduler not working as stated

Posted by Richard Damon on August 1, 2012
Rather than putting in the documentation differing behavior baed on the port, it might be better to document that this function is only fully implemented on the PC port, thus opening the door to implementing it on other ports later if desired without "breaking" the documentation.

I would also think a different "default implementation" for the ports which don't really implement the function, maybe vPortEndScheduler() should do something like a while(1); stall loop which is at least closer to documented behavior and puts up a nice big flag when debugging that makes it clear what wasn't working.

RE: vTaskEndScheduler not working as stated

Posted by Richard on August 1, 2012
I updated the online documentation page to say it was only implemented on the PC port a couple of hours ago - when the last page came in. The reference manual already has the text "At the time of writing, vTaskEndScheduler() is only implemented for the real mode x86 OpenRTOS port.".

Regards.

RE: vTaskEndScheduler not working as stated

Posted by JBlackArty on August 2, 2012
Thank you, Richard.
I've implemented this behavior for GCC ARM Cortex-M3 MPU port. Following is diff applied to original FreeRTOS V7.1.0 port:

diff --git a/FreeRTOSV7.1.0/Source/portable/GCC/ARM_CM3_MPU/port.c b/FreeRTOSV7.1.0/Source/portable/GCC/ARM_CM3_MPU/port.c
--- a/FreeRTOSV7.1.0/Source/portable/GCC/ARM_CM3_MPU/port.c
+++ b/FreeRTOSV7.1.0/Source/portable/GCC/ARM_CM3_MPU/port.c
@@ -316,8 +316,11 @@ static void prvRestoreContextOfFirstTask( void )
/*
* See header file for description.
*/
+volatile char sh_stop_request = 0; // indicates whether xPortStartScheduler() called from vPortEndScheduler() to stop sheduler
+volatile unsigned long sh_context[4]; // stores context of vTaskEndScheduler() call to restore it when sheduler being requested to stop
portBASE_TYPE xPortStartScheduler( void )
{
+if (!sh_stop_request) {
/* Make PendSV and SysTick the same priroity as the kernel. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;
@@ -332,19 +335,49 @@ portBASE_TYPE xPortStartScheduler( void )
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;

+/* Save context to return from vTaskEndScheduler() */
+__asm volatile
+(
+"push {r0-r12,lr}\n"
+"mrs %[basepri_val], basepri\n"
+"mrs %[control_val], control\n"
+"mrs %[psp_val], psp\n"
+"mrs %[msp_val], msp\n"
+: [basepri_val]"=r" (sh_context[0]), [psp_val]"=r" (sh_context[1]), [msp_val]"=r" (sh_context[2]), [control_val]"=r" (sh_context[3])
+);
+
/* Start the first task. */
__asm volatile( "svc %0\n"
:: "i" (portSVC_START_SCHEDULER) );
+} else {
+sh_stop_request = 0;
+
+/* Cancel most important system changes made when sheduler started */
+*(portNVIC_SYSTICK_CTRL) &= ~(portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE);
+*portMPU_CTRL &= ~portMPU_ENABLE;
+/* Restore context to return back to vTaskStartScheduler() */
+__asm volatile
+(
+"msr basepri, %[basepri_val]\n"
+"msr control, %[control_val]\n"
+"msr psp, %[psp_val]\n"
+"msr msp, %[msp_val]\n"
+"isb\n"
+"pop {r0-r12,lr}\n"
+:: [basepri_val]"r" (sh_context[0]), [psp_val]"r" (sh_context[1]), [msp_val]"r" (sh_context[2]), [control_val]"r" (sh_context[3])
+: "sp"
+);
+}

-/* Should not get here! */
-return 0;
+return pdFALSE;
}
/*-----------------------------------------------------------*/

void vPortEndScheduler( void )
{
-/* It is unlikely that the CM3 port will require this function as there
-is nothing to return to. */
+/* Restore point where sheduler started with tricky change of control flow */
+sh_stop_request = 1;
+xPortStartScheduler();
}
/*-----------------------------------------------------------*/

It works as expected but I didn't tested heavily.
It must work also on non-MPU port if you remove
*portMPU_CTRL &= ~portMPU_ENABLE;
line.

RE: vTaskEndScheduler not working as stated

Posted by JBlackArty on August 2, 2012
Oops. It's wrong solution. I found that prvRestoreContextOfFirstTask() unwinds main stack which corrupts saved "context" needed to return back to vTaskStartScheduler(). Why ???
P.S. It's very strange that it worked for me very first time.

RE: vTaskEndScheduler not working as stated

Posted by JBlackArty on August 2, 2012
I didn't found any reason to unwind stack and removed few assembler instructions as useless (and destructive). Now it works perfectly. A final patch as follows:

diff -u -r FreeRTOSV7.1.0/Source/portable/GCC/ARM_CM3_MPU/port.c FreeRTOSV7.1.0_improved/Source/portable/GCC/ARM_CM3_MPU/port.c
--- FreeRTOSV7.1.0/Source/portable/GCC/ARM_CM3_MPU/port.c2011-12-13 22:38:23.906250000 +0700
+++ FreeRTOSV7.1.0_improved/Source/portable/GCC/ARM_CM3_MPU/port.c2012-08-02 19:20:05.640625000 +0700
@@ -288,10 +288,6 @@
{
__asm volatile
(
-"ldr r0, =0xE000ED08\n" /* Use the NVIC offset register to locate the stack. */
-"ldr r0, [r0]\n"
-"ldr r0, [r0]\n"
-"msr msp, r0\n" /* Set the msp back to the start of the stack. */
"ldrr3, pxCurrentTCBConst2\n" /* Restore the context. */
"ldr r1, [r3]\n"
"ldr r0, [r1]\n" /* The first item in the TCB is the task top of stack. */
@@ -316,8 +312,11 @@
/*
* See header file for description.
*/
+static volatile char sh_stop_request = 0; // indicates whether xPortStartScheduler() called from vPortEndScheduler() to stop sheduler
+static volatile unsigned long sh_context[4]; // stores context of vTaskEndScheduler() call to restore it when sheduler being requested to stop
portBASE_TYPE xPortStartScheduler( void )
{
+if (!sh_stop_request) {
/* Make PendSV and SysTick the same priroity as the kernel. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;
@@ -332,19 +331,49 @@
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;

+/* Save context to return from vTaskEndScheduler() */
+__asm volatile
+(
+"push {r0-r12,lr}\n"
+"mrs %[basepri_val], basepri\n"
+"mrs %[control_val], control\n"
+"mrs %[psp_val], psp\n"
+"mrs %[msp_val], msp\n"
+: [basepri_val]"=r" (sh_context[0]), [psp_val]"=r" (sh_context[1]), [msp_val]"=r" (sh_context[2]), [control_val]"=r" (sh_context[3])
+);
+
/* Start the first task. */
__asm volatile( "svc %0\n"
:: "i" (portSVC_START_SCHEDULER) );
+} else {
+sh_stop_request = 0;

-/* Should not get here! */
-return 0;
+/* Cancel most important system changes made when sheduler started */
+*(portNVIC_SYSTICK_CTRL) &= ~(portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE);
+*portMPU_CTRL &= ~portMPU_ENABLE;
+/* Restore context to return back to vTaskStartScheduler() */
+__asm volatile
+(
+"msr basepri, %[basepri_val]\n"
+"msr control, %[control_val]\n"
+"msr psp, %[psp_val]\n"
+"msr msp, %[msp_val]\n"
+"isb\n"
+"pop {r0-r12,lr}\n"
+:: [basepri_val]"r" (sh_context[0]), [psp_val]"r" (sh_context[1]), [msp_val]"r" (sh_context[2]), [control_val]"r" (sh_context[3])
+: "sp"
+);
+}
+
+return pdFALSE;
}
/*-----------------------------------------------------------*/

void vPortEndScheduler( void )
{
-/* It is unlikely that the CM3 port will require this function as there
-is nothing to return to. */
+/* Restore point where sheduler started with tricky change of control flow */
+sh_stop_request = 1;
+xPortStartScheduler();
}
/*-----------------------------------------------------------*/


[ Back to the top ]    [ About FreeRTOS ]    [ Privacy ]    [ Sitemap ]    [ ]


Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

NXP tweet showing LPC5500 (ARMv8-M Cortex-M33) running FreeRTOS.

Meet Richard Barry and learn about running FreeRTOS on RISC-V at FOSDEM 2019

Version 10.1.1 of the FreeRTOS kernel is available for immediate download. MIT licensed.

View a recording of the "OTA Update Security and Reliability" webinar, presented by TI and AWS.


Careers

FreeRTOS and other embedded software careers at AWS.



FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Espressif ESP32

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Renesas

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS

Xilinx Microblaze and Zynq partner