Quality RTOS & Embedded Software

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




Loading

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

Posted by dibosco on December 9, 2015

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


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

Posted by rtel on December 9, 2015

Probably the easiest way to do this would be to simply call taskENTERCRITICAL(), and then never call taskEXITCRITICAL(). 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.


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

Posted by dibosco on December 9, 2015

Smashing, thanks very much!


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

Posted by ppotts on January 22, 2016

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?


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

Posted by edwards3 on January 22, 2016

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.


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

Posted by ppotts on January 22, 2016

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 taskENTERCRITICAL() 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 NVICSetPriority(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.


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

Posted by rtel on January 23, 2016

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: 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() is defined, because that will automatically check the interrupt priority settings for you, and the assert will fail if they are wrong.


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

Posted by ppotts on January 29, 2016

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/

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, _NVICPRIO_BITS is 4

configLIBRARYLOWESTINTERRUPTPRIORITY is 0xF configLIBRARYMAXSYSCALLINTERRUPT_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 configMAXSYSCALLINTERRUPT_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, configKERNELINTERRUPTPRIORITY and configMAXSYSCALLINTERRUPT_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 configKERNELINTERRUPTPRIORITY becomes 0xF << 4 = 0xF0

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

The other one is configMAXSYSCALLINTERRUPT_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 portNVICSYSTICKPRI ( ( ( uint32t ) configKERNELINTERRUPT_PRIORITY ) << 24UL )

Which should mean that is 0xF0000000

It looks like that is formatted to be placed in portNVICSYSPRI2REG

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 taskENTERCRITICAL could not disable that. We seem to have a chain of definitions, taskENTERCRITICAL -> portENTERCRITICAL -> vPortEnterCritical() which calls portDISABLEINTERRUPTS -> vPortRaiseBASEPRI -> which sets BASEPRI to configMAXSYSCALLINTERRUPT_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 configKERNELINTERRUPTPRIORITY and configMAXSYSCALLINTERRUPTPRIORITY, 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.


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

Posted by edwards3 on January 29, 2016

configMAXSYSCALLINTERRUPTPRIORITY is the highest logical priority that can use the API, so the highest priority that is masked by a critical section. If configLIBRARYMAXSYSCALLINTERRUPT_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.


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

Posted by ppotts on January 29, 2016

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.


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




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

Latest News

FreeRTOS kernel V10 is available for immediate download. Now MIT licensed.


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

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