# Best way to stop the scheduler when leaving bootloader to go to main application?

**URL:** <https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120>\
**Category:** Kernel\
**Created:** [December 9, 2015, 11:50am UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120 "2015-12-09T11:50:36Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [December 9, 2015, 11:50am UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/1 "2015-12-09T11:50:36Z")

</div>

**[dibosco](https://sourceforge.net/u/dibosco/)** wrote on [Wednesday, December 09, 2015](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#9c84):

Folks,

I have a FreeRTOS bootloader on a SAM4S that programs new code into the flash from 0x420000. This works just fine, but when I then jump from the bootloader to the new code, as it’s going through all the usual initialisation in SAM4S\_Startup, it tries to change another task and then I get a hard fault error.

If I jump to the new app before vTaskStartScheduler() is called, it’s all OK. I assume, therefore, I need to completely stop the scheduler.

vTaskEndScheduler seems only to be implemented on x86 and vTaskSuspendAll doesn’t help.

I have seen another thread that seems to suggest I need to stop the tick interrupt. Is that correct? Is there a FreeRTOS call to do that, or do I need to create my own function to do this?

Or is there another way altogether to solve this?

Thanks!

Rob

---

<div class="post-metadata">

**Author:** ![rtel](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/rtel/32/31_2.png) [@rtel](https://forums.freertos.org/u/rtel)\
**Post date:** [December 9, 2015, 4:58pm UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/2 "2015-12-09T16:58:45Z")

</div>

**[rtel](https://sourceforge.net/u/rtel/)** wrote on [Wednesday, December 09, 2015](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#b7e8):

Probably the easiest way to do this would be to simply call taskENTER\_CRITICAL(), and then never call taskEXIT\_CRITICAL(). That will leave the BASEPRI register set such that the tick interrupt is masked. I think it will work as long as your start up code or boot loader do not clear the BASEPRI register. Interrupts will be enabled again the next time you start the scheduler.

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [December 9, 2015, 5:00pm UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/3 "2015-12-09T17:00:31Z")

</div>

**[dibosco](https://sourceforge.net/u/dibosco/)** wrote on [Wednesday, December 09, 2015](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#eb43):

Smashing, thanks very much!

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [January 22, 2016, 5:49pm UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/4 "2016-01-22T17:49:21Z")

</div>

**[ppotts](https://sourceforge.net/u/ppotts/)** wrote on [Friday, January 22, 2016](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#e4a4):

I am having the same trouble. I am running FreeRTOS 8.2.3 on a Atmel SAM4E16E, building with the Keil toolchain. I have a bootloader app and a main app, both built with FreeRTOS. If I jump from the bootloader app before starting the FreeRTOS scheduler, it works fine. I tried using the taskENTER\_CRITICAL() trick and it seemed to work with one build of my application, but with the next revision, it stopped working. I’m seeing a bus fault shortly after making the jump. The application image has been loaded into flash, checksum-verified, etc. and the application executes fine if I start it from boot.

It would be really great if I could get my tasks to exit and get vTaskStartScheduler() to exit, and then do the jump after that. Barring that, any other ideas for what I need to do, in order to make this jump safely from a task?

If it is really impossible I will have to rewrite a big chunk of the bootloader code so that it runs without any FreeRTOS scheduling calls, but that would be a huge pain, because I have (for example) an EEPROM driver that uses a mutex, semaphore, waits, etc.

I can’t tell for sure, but it appears this could be becauase the sys tick is running at priority 0, and this can’t be masked with BASPRIO?

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [January 22, 2016, 7:09pm UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/5 "2016-01-22T19:09:33Z")

</div>

**[edwards3](https://sourceforge.net/u/edwards3/)** wrote on [Friday, January 22, 2016](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#3b3b):

Is this what you are doing:

set up VTOR for the boot loader  
run boot loader  
disable interrupts completely in the core (cpsid i instruction)  
set up VTOR for the application code  
jump to start up routine for the application to configure the C run time (dont enable interrupts here)  
jump to application main()

Interrupts will be enabled when the scheduler starts.

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [January 22, 2016, 8:03pm UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/6 "2016-01-22T20:03:52Z")

</div>

**[ppotts](https://sourceforge.net/u/ppotts/)** wrote on [Friday, January 22, 2016](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#eb99):

Thanks for your note MEdwards.

It looks like I was disabling interrupts after setting VTOR for the application code. That probably means a tick interrupt was getting in a few instructions after setting VTOR and thus off into space (?)

I am not sure I understand the Cortex interrupts and how the FreeRTOS port uses them completely, although I have read over the docs repeatedly and I understand that I have 4 priority bits, they are acutally the high 4 bits of the priority value, and they are inverted (0 is highest).

The taskENTER\_CRITICAL seems to set BASEPRIO to 0x10 (the 4 high bits are significant). I think that means it should disable everything with lower priority than the highest priority 0, right?

It appears that the system timer tick is running at priority zero (actually 0xF, but only the high bits are signfiicant) in my port, which would mean that it can’t be masked with BASEPRIO. I think that means that taskENTER\_CRITICAL() is necessary but not sufficient in this case. (Maybe? This is all buried in port macros and somewhat confusing; if I look at the NVIC peripheral with my debugger, it shows system tick timer at priority 15, and TWIO at 253, which is confusing because I called NVIC\_SetPriority(TWI0\_IRQn, 1) so I would expect it to be a value like 0x1N, decimal 31 or less.

I am using priority 1 for my own peripheral interrupts and 5…15 for my FreeRTOS tasks. I don’t think any of my own interrupts are firing and causing this crash during the transfer of control between applications.

What does seem to work is to disable the timer tick before setting VTOR like so:

```
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;

```

although I am nervous that there is not a better-supported way to do this – nervous that it will not continue to work across code changes, for example.

---

<div class="post-metadata">

**Author:** ![rtel](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/rtel/32/31_2.png) [@rtel](https://forums.freertos.org/u/rtel)\
**Post date:** [January 23, 2016, 6:27pm UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/7 "2016-01-23T18:27:09Z")

</div>

**[rtel](https://sourceforge.net/u/rtel/)** wrote on [Saturday, January 23, 2016](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#eb99/e9e2):

> I am not sure I understand the Cortex interrupts and how the FreeRTOS  
> port uses them completely,

You are not the only one, which is why we provide the following page:  
[RTOS for ARM Cortex-M](http://www.freertos.org/RTOS-Cortex-M3-M4.html) … but the more you try  
and explain it the more complex it becomes ;o)

FreeRTOS never disables interrupts completely, it only masks them up to  
a user defined priority. The difference is:

- The “cpsid i” instruction globally disables all interrupts within the  
processor core itself.

- taskDISABLE\_INTERRUPTS masks interrupts up to the user defined  
priority, but does not globally disable all interrupts, so some  
interrupts remain enabled.

> The taskENTER\_CRITICAL seems to set BASEPRIO to 0x10 (the 4 high bits  
> are significant). I think that means it should disable everything  
> with lower priority than the highest priority 0, right?

No, it disables everything with the priority 0x10 and lower. Remember,  
on the ARM Cortex-M, the lower the numeric priority the higher the  
logical priority. So, setting BASEPRI to 0x10 does not disable  
interrupt priority 0 (or 1, 2, etc.) because those priorities have a  
lower numeric value and therefore a HIGHER logical priority. This is  
why it is so confusing for people.

> It appears that the system timer tick is running at priority zero

It shouldn’t be, it should be running at the lowest possible priority.  
As above, 0 is the highest possible priority, not the lowest, and the  
tick definitely must not run at priority 0.

If you are using a recent version of FreeRTOS then ensure [configASSERT()](http://www.freertos.org/a00110.html#configASSERT)  
is defined, because that will automatically check the interrupt priority  
settings for you, and the assert will fail if they are wrong.

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [January 29, 2016, 7:30pm UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/8 "2016-01-29T19:30:50Z")

</div>

**[ppotts](https://sourceforge.net/u/ppotts/)** wrote on [Friday, January 29, 2016](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#e435):

Thank you for taking the time to explain. If you are willing to take a little longer I think I am just about there. I have read that document you linked to yet again. This must be the fifth time… I also read this: [http://embeddedgurus.com/state-space/2014/02/cutting-through-the-confusion-with-arm-cortex-m-interrupt-priorities/](http://embeddedgurus.com/state-space/2014/02/cutting-through-the-confusion-with-arm-cortex-m-interrupt-priorities/)

I think there is further confusion due not only to the reversed counting of priorities, but to the use of a subset of bits that is shifted towards the high bits.

So,

In my build, \_\_NVIC\_PRIO\_BITS is 4

configLIBRARY\_LOWEST\_INTERRUPT\_PRIORITY is 0xF  
configLIBRARY\_MAX\_SYSCALL\_INTERRUPT\_PRIORITY is 0x1

I take this to mean that 1 is the next-to-highest priority (not numerically highest, but logically highest).

The document says “The RTOS interrupt nesting scheme splits the available interrupt priorities into two groups - those that will get masked by RTOS critical sections, and those that are never masked by RTOS critical sections and are therefore always enabled. The configMAX\_SYSCALL\_INTERRUPT\_PRIORITY setting in FreeRTOSConfig.h defines the boundary between the two groups.”

However, I don’t find this to be perfectly clear. “Defines the boundary” could be read as either “this value and logically higher values are not masked,” or “values logically higher than this value are not masked.” So I am not clear whether priority 1 can be masked by FreeRTOS critical sections.

There are two more macros, configKERNEL\_INTERRUPT\_PRIORITY and configMAX\_SYSCALL\_INTERRUPT\_PRIORITY that are based on the previous two macros but take into account the number of priority bits, to shift them into the high bits.

So in this case configKERNEL\_INTERRUPT\_PRIORITY becomes 0xF \<\< 4 = 0xF0

That should be the logically lowest priority ready to put into BASEPRI

The other one is configMAX\_SYSCALL\_INTERRUPT\_PRIORITY and that turns into 1 \<\< 4 = 0x10

That should be the logically next-to-highest priority ready to put into BASEPRI

Trying to figure out the actual priority used for the system clock is buried under more layers of macros. It looks like my port defines #define portNVIC\_SYSTICK\_PRI ( ( ( uint32\_t ) configKERNEL\_INTERRUPT\_PRIORITY ) \<\< 24UL )

Which should mean that is 0xF0000000

It looks like that is formatted to be placed in portNVIC\_SYSPRI2\_REG

That is defined as ( \* ( ( volatile uint32\_t \* ) 0xe000ed20 ) ) but I don’t find that address in any of the chip headers so I’m not certain what that is, but I’ll take it as a given that the lowest available priority setting is assigned to the system tick.

But I’m still unclear on why taskENTER\_CRITICAL could not disable that. We seem to have a chain of definitions, taskENTER\_CRITICAL -\> portENTER\_CRITICAL -\> vPortEnterCritical() which calls portDISABLE\_INTERRUPTS -\> vPortRaiseBASEPRI -\> which sets BASEPRI to configMAX\_SYSCALL\_INTERRUPT\_PRIORITY which is 0x10 (next-to-highest logical priority, shifted into the high bits).

That should have blocked the timer tick, which has the the lowest logical priority, right? (But it did not seem to in my case, because disabling the timer tick fixed the crash problem, while calling taskENTER\_CRITICAL only did not).

You wrote “No, it disables everything with the priority 0x10 and lower. Remember,  
on the ARM Cortex-M, the lower the numeric priority the higher the  
logical priority. So, setting BASEPRI to 0x10 does not disable  
interrupt priority 0 (or 1, 2, etc.) because those priorities have a  
lower numeric value and therefore a HIGHER logical priority. This is  
why it is so confusing for people.”

But I think putting 0x10 in BASEPRI should allow interrupts with numeric priority 0 and disable interrupts with numeric priority 1 or greater (lower logical priority). (Remember, the bits are shifted up by 4).

If that is not the case… then it seems like the port is not defining things sensibly, with its definitions of configKERNEL\_INTERRUPT\_PRIORITY and configMAX\_SYSCALL\_INTERRUPT\_PRIORITY, because using those values would never disable _any_ of the actual 16 interrupt priority levels used on this chip? I think if that was the case, the port would not work right.

Thanks for any clarification.

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [January 29, 2016, 7:49pm UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/9 "2016-01-29T19:49:07Z")

</div>

**[edwards3](https://sourceforge.net/u/edwards3/)** wrote on [Friday, January 29, 2016](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#f2a0):

configMAX\_SYSCALL\_INTERRUPT\_PRIORITY is the highest logical priority that can use the API, so the highest priority that is masked by a critical section. If configLIBRARY\_MAX\_SYSCALL\_INTERRUPT\_PRIORITY is 1 then a critical section will mask priority 1 interrupts, but not priority 0 interrupts. I think it might be impossible to mask priority 0 interrupts actually because writing 0 to BASEPRI enables all interrupts.

The system clock has to have the lowest priority so it looks like 0xF0 is right for that here, and yes I think the same the BASEPRI of 0x10 should block that.

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [January 29, 2016, 9:00pm UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/10 "2016-01-29T21:00:09Z")

</div>

**[ppotts](https://sourceforge.net/u/ppotts/)** wrote on [Friday, January 29, 2016](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#c691):

OK, thanks a lot MEdwards. It makes me wonder, then, why my original approach to vectoring from one app to another was crashing. In any case it seems like disabling the clock fixed that, but I wish I was clearer on what was going wrong without it.

All I know is that I was getting a hard fault (bus) in the startup code of the new app. I have not tried that hard to debug it. It’s like the aftermath of a car crash. It’s possible I might be able to use the trace buffer features of the DLink Pro to try to see what actually happened.

---

<div class="post-metadata">

**Author:** ![McuOnEclipse](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/mcuoneclipse/32/32_2.png) [@McuOnEclipse](https://forums.freertos.org/u/McuOnEclipse)\
**Post date:** [January 20, 2019, 9:55am UTC](https://forums.freertos.org/t/best-way-to-stop-the-scheduler-when-leaving-bootloader-to-go-to-main-application/2120/11 "2019-01-20T09:55:11Z")

</div>

**[xz8987f](https://sourceforge.net/u/xz8987f/)** wrote on [Sunday, January 20, 2019](https://sourceforge.net/p/freertos/discussion/382005/thread/5db393e3/#d777):

If you are still looking for a way to end the scheduler on ARM Cortex-M and return to main() or the point where you have started it, see [https://mcuoneclipse.com/2019/01/20/freertos-how-to-end-and-restart-the-scheduler/](https://mcuoneclipse.com/2019/01/20/freertos-how-to-end-and-restart-the-scheduler/)

I hope this helps,  
Erich
