Quality RTOS & Embedded Software

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


FreeRTOS Bootloader and external RAM

Posted by RaceMouse on August 8, 2007

I have the following setup :
AT91SAM7SE32 with a serial DataFlash and SDRAM on the external bus interface.
The startup is as follows:

1 - A BootStrapper written en FreeRTOS in internal Flash/Ram starts up and transfers an image from the serial dataflash to the external RAM. Then it sets the PC to address 0x20000000 which is the start address of the external RAM.

2 - The image loaded in external RAM is a FreeRTOS based BootLoader which starts with the normal boot.s to setup the new stacks etc. It has a file system and connectivity (USART, USB, Ethernet...). When this BootLoader exits it loads the Application Image from the serial flash into another place in external RAM. Right now it just blinks an LED on the evaluation kit.

3 - The application starts and runs from external RAM.

So far I have managed to stop the FreeRTOS like this :
vTaskEndScheduler ();
// Stop the PIT
// Load address 0x20000000 into the PC
asm volatile ( "LDR PC, =0x20000000");

The BootLoader now starts and runs from RAM BUT when the BootLoader calls taskENTER_CRITICAL()/taskEXIT_CRITICAL() the blinking LEDs now blinks erratically.

Do I need to do something extra before the jump to 0x2000000 in order to make sure that the OS is reset to a known state ?

Best Regards

RE: FreeRTOS Bootloader and external RAM

Posted by RaceMouse on August 8, 2007
I see in the PC/DOS examples that the processor state is restored to what it was before the OS started. If that is what I'm missing I'm very open to suggestions as to how to do that.


RE: FreeRTOS Bootloader and external RAM

Posted by Dave on August 8, 2007
I don't think restoring the processor state should be necessary. This is done for returning to DOS in the PC port.

So if I understand your application correctly, the bootloader runs FreeRTOS. Therefore when the bootloader executes the C start up code will execute, setting all your static variables to 0, and setting ulCriticalNesting to a negative value. Next you will create your tasks, during which time interrupts will most probably be disabled. Then start the scheduler which will configure the timer to start generating tick interrupts and some other peripherals are probably generating interrupts too.

Next you disable the PIT so no more ticks occur, and switch to your application which is now in RAM. This re-runs the start up code so your variables should get set back to their initial states, creates tasks, then reconfigures the PIT.

This would seem ok, but some things to check.

I think from your code you have only disabled the PIT. So other peripherals interrupts could remain enabled along with global interrupts. If such an interrupt occurred while the FreeRTOS was being initialized either in the startup code or in the FreeRTOS code and the interrupt used an API call then you could get a problem. Try calling portENTER_CRITICAL() a few times before jumping to 0x20000000. This should ensure interrupts do not occur until FreeRTOS starts again.

Also, check that when you are running the start up code from 0x20000000 that the variables are initialised correctly. After running the start up code you should see that ulCriticalNesting is set to 9999 (in port.c). This will check that the linker is setup correctly for executing this code from RAM. The tick could should likewise get set to 0.

If you use your debugger to load the application image to 0x20000000 directly and start running it via the debugger rather than bootloader, does the application behave as expected?

RE: FreeRTOS Bootloader and external RAM

Posted by RaceMouse on August 8, 2007
First : Thanks for the effort. It is really appreciated !

If I call portENTER_CRITICAL() just before 'asm volatile ( "LDR PC, =0x20000000");', The result is the same. It still seems as if a timer tick occurs sporadically...

Using the debugger with a breakpoint at 'void main ()' I can veryfy that ulCriticalNesting is '9999'. As you said, that indicates that the linker sets it up correctly.

The software work as expected when loaded via SAM-BA. (It has to linked differently in order to put it into internal flash and RAM).

Any other thoughts ?


RE: FreeRTOS Bootloader and external RAM

Posted by sotd on August 8, 2007
This is just a wild guess.

I assume in your code you setup a PLL to generate the clock frequency you want.

When the bootload runs the clock will not yet have been configured so you configure it from 'clean'. When you app runs the clock will already have been configured so you are reconfiguring it but not from its start condition.

Maybe you have to unconfigure the clock before setting it up again? Stop the PLL before starting the PLL again? Maybe there is some guard in the processor that prevents you from unlocking the PLL once it is locked?

If the linker is getting all your startup code to initialize the variables correctly then I'm thinking it must be something to do with a register on the processor that is not in its initial condition when your app runs? Maybe I am just writing what is obvious here?

RE: FreeRTOS Bootloader and external RAM

Posted by RaceMouse on August 8, 2007
Hi soth,

Thanks for your input.

Yes it's true :
The BootStrapper : boot.s -> AT91F_LowLevelInit() -> main (start OS) -> upload BootLoader to external RAM -> stop OS -> jump to 0x20000000

The BootLoader (@ 0x20000000) : boot.s -> main (start OS) -> (right now just blinking LEDs)

This makes no difference :
The BootLoader (@ 0x20000000) : boot.s -> AT91F_LowLevelInit() -> main (start OS)
since AT91F_LowLevelInit() only sets up the PLL...

I agree with you that it must be som register not having the correct initial value but which one ?

Any hints ?


RE: FreeRTOS Bootloader and external RAM

Posted by RaceMouse on August 9, 2007
Hi again,

I have now tried manually reset all the periphials registers to the defaults before the jump to address 0x20000000, but still no go. More good ideas are more than welcome :-)


RE: FreeRTOS Bootloader and external RAM

Posted by Neil Bradley on August 9, 2007
Might be obvious things to try, but have you tried:

1) Disabling interrupts
2) Ensuring that whatever is running out of RAM initializes the interrupt controller properly
3) Doesn't attempt to reprogram the PLLs

Those things can really mess with you if you're not careful.

It's possible that there is some other peripheral hogging the interrupt (for whatever reason) that may get serviced and block your timer interrupts. What is your timer's interval set to currently?

RE: FreeRTOS Bootloader and external RAM

Posted by RaceMouse on August 9, 2007
Hi again,

1) The interrupts are all disabled before I jump to 0x20000000. This is how I do it:
void vStop (void)
unsigned char ucCount;

// Reset Controller Periphials one by one

// RTT
// Not used

// Stop the PIT

// WDT
// Can only be written once

// Not used

// MC
// Memory Controller. Configured to SDRAM. Do not touch

// EBI
// SDRAM sits here. Do not touch

// PDC
// Not used

// AIC
for (ucCount = 0; ucCount < 32; ucCount++)
AT91C_BASE_AIC->AIC_SMR[ucCount] = 0x00000000;
for (ucCount = 0; ucCount < 32; ucCount++)
AT91C_BASE_AIC->AIC_SVR[ucCount] = 0x00000000;
AT91C_BASE_AIC->AIC_SPU = 0x00000000;
AT91C_BASE_AIC->AIC_DCR = 0x00000000;

// PMC
// Setup via AT91F_LowLevelInit() and not touched again

// Not used

// PIO
// Only interrupts are disabled here

// SPI
AT91C_BASE_SPI->SPI_CR = 0x00000082;
AT91C_BASE_SPI->SPI_MR = 0x00000000;

// TWI
// Not used

AT91C_BASE_US0->US_CR = 0x0000E1AC;
AT91C_BASE_US1->US_CR = 0x0000E1AC;

// SSC
AT91C_BASE_SSC->SSC_CR = 0x00008000;

// TC
AT91C_BASE_TCB->TCB_BMR = 0x00000015;
AT91C_BASE_TCB->TCB_BCR = 0x00000002;

// PWM
AT91C_BASE_PWMC->PWMC_MR = 0x00000000;

// UDP
AT91C_BASE_UDP->UDP_GLBSTATE = 0x00000000;
AT91C_BASE_UDP->UDP_FADDR = 0x00000100;
AT91C_BASE_UDP->UDP_CSR[0] = 0x00000000;
AT91C_BASE_UDP->UDP_CSR[1] = 0x00000000;
AT91C_BASE_UDP->UDP_CSR[2] = 0x00000000;
AT91C_BASE_UDP->UDP_CSR[3] = 0x00000000;
AT91C_BASE_UDP->UDP_CSR[4] = 0x00000000;
AT91C_BASE_UDP->UDP_CSR[5] = 0x00000000;
AT91C_BASE_UDP->UDP_CSR[6] = 0x00000000;
AT91C_BASE_UDP->UDP_CSR[7] = 0x00000000;

// ADC
AT91C_BASE_ADC->ADC_CR = 0x00000001;
AT91C_BASE_ADC->ADC_CHDR = 0x000000FF;

// Bask to superviser mode
asm volatile ( "msr cpsr_c,#0xD3");
// Load address 0x20000000 into the PC
asm volatile ( "LDR PC, =0x20000000");

2: The same code initializes correctly when running fra Flash/internal RAM
3: The PLL's are left untouched.

Further info:
When only one task is running (blinking led) which looks like this :
for (;;)
vTaskDelay (50 / portTICK_RATE_MS);
AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, AT91C_PIO_PA1 ) ;
vTaskDelay (100 / portTICK_RATE_MS);
AT91F_PIO_SetOutput( AT91C_BASE_PIOA, AT91C_PIO_PA1 ) ;

I have checked on a scope and the timings are correct.

Introducing an other task that just blinks another LED completely screws up the timing. One of the LEDs starts to blink really fast. As if the task gets preempted all the time... Really hard to explain without pictures...

More ideas ?

RE: FreeRTOS Bootloader and external RAM

Posted by RaceMouse on August 9, 2007
Hi again,

As fair as I can decipher from its odd behavior I believe that it goes wrong when switching context. Could it be that something goes wrong when initializing the stack the second time. I mean : The first time the tasks stacks are initialized it happends in internal RAM. The next time it happends in external RAM.... Am I completely off here or ... ?


RE: FreeRTOS Bootloader and external RAM

Posted by Dave on August 9, 2007
I'm just making some guesses here.

If it works in internal RAM but not external RAM could there be a problem with the external bus interface configuration or timing?

Also, the code you gave showed the tasks writing to a port directly to set and clear an LED. Could there be some mutual exclusion problem there?

You say that the issue occurs when the first context switch happens. But when you have a single task it will still be switching between your task and the idle task. And this seems to work well you say.

RE: FreeRTOS Bootloader and external RAM

Posted by RaceMouse on August 9, 2007
Well, hmmm... It's true that the context switch still happends between the task and idle. Didn't think of that... My hair is getting thin...
I suppose that the timings on the external bus interface are OK. They have been taken from some sample code from IAR to this board (SAM7SE512-EK) and when using internal FLASH and external RAM there are no problems.

I'm fiddling around (more like frobnicating, actually) with the Re-map command. Could it be a re-map issue that is pulling my leg ?


RE: FreeRTOS Bootloader and external RAM

Posted by RaceMouse on August 10, 2007
Ok. This was the theory :

BootStrapper sets up the SWI interrupt vector to swi_handler in internal RAM. When the BootLoader in external ram interrupts it does not vector to the swi_handler in external RAM but to the swi_handler in internal RAM. I therefore needed to setup the correct interrupt vectors. I did it like this:

void main( void )
extern void swi_handler(void);

// Copy contents from Flash address 0x00 to 0x20 to RAM 0x00 to 0x20
memcpy ((int *)0x00200000, (int *)0x00100000, 128);

// Load the address of interrupt handlers into the correct places
dest_address = (int*)0x00200020;
*dest_address = (int*)0x20000034;
dest_address = (int*)0x00200024;
*dest_address = &swi_handler;
dest_address = (int*)0x00200028;
*dest_address = &Kernel_reboot;
dest_address = (int*)0x0020002C;
*dest_address = &Kernel_reboot;
dest_address = (int*)0x00200030;
*dest_address = (int*)0x2000004C;

// Remap so the RAM starts at address 0x00000000

vMainInit ();
vTaskStartScheduler ();

And now it works as it should :-)

Thanks for the help to those who helped and I hope someone else can use this.


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

Copyright (C) 2004-2010 Richard Barry. Copyright (C) 2010-2016 Real Time Engineers Ltd.
Any and all data, files, source code, html content and documentation included in the FreeRTOSTM distribution or available on this site are the exclusive property of Real Time Engineers Ltd.. See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Real Time Engineers Ltd.

Latest News:

FreeRTOS V9.0.0 is now available for download.

Free TCP/IP and file system demos for the RTOS

Sponsored Links

⇓ Now With No Code Size Limit! ⇓
⇑ Free Download Without Registering ⇑

FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Renesas Electronics Gold Alliance RTOS Partner.jpg

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Atmel RTOS partner supporting ARM Cortex-M3 and AVR32 microcontrollers

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

Xilinx Microblaze and Zynq partner

Silicon Labs low power RTOS partner

Altera RTOS partner for Nios II and Cortex-A9 SoC

Freescale Alliance RTOS Member supporting ARM and ColdFire microcontrollers

Infineon ARM Cortex-M microcontrollers

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

Cypress RTOS partner supporting ARM Cortex-M3

Fujitsu RTOS partner supporting ARM Cortex-M3 and FM3

Microsemi (previously Actel) RTOS partner supporting ARM Cortex-M3

Atollic Partner

IAR Partner

Keil ARM Partner

Embedded Artists