Offsetting the FreeRTOS to a new start adress

tjohansen wrote on Tuesday, February 15, 2011:


Im using FreeRTOS v5.1.2 and currently trying to use it with a bootloader.

I have search the forums but I cant find an solution for my problem.

I must realocate the FreeRTOS app to 0x5100 in flash. But I guess I also have to move all the exception vectore in my startup.s file??

From my S file:

IMPORT vPortYieldProcessor

Vectors         LDR     PC, Reset_Addr        
                LDR     PC, Undef_Addr
                LDR     PC, SWI_Addr
                LDR     PC, PAbt_Addr
                LDR     PC, DAbt_Addr
                NOP                            ; Reserved Vector
                LDR     PC, IRQ_Addr
;               LDR     PC,      ; Vector from VicVectAddr
                LDR     PC, FIQ_Addr

Reset_Addr      DCD     Reset_Handler
Undef_Addr      DCD     0x5104
SWI_Addr        DCD     vPortYieldProcessor
;SWI_Addr        DCD     SWI_Handler
PAbt_Addr       DCD     0x510C
DAbt_Addr       DCD     0x5110
                DCD     0                      ; Reserved Address
IRQ_Addr        DCD     0x5118
FIQ_Addr        DCD     0x511C

But it seems to crash somewhere in my init code.
I get to my main.c function, but suddenly its stucked at adress 0x0000004c??

Have I missed something else todo???

Im using an LPC2478…


richard_damon wrote on Tuesday, February 15, 2011:

Just because you moved the location in flash where you put the vectors doesn’t mean you have changed where the processor looks for the vectors. I haven’t used the LPC series of parts, but they are obviously ARM based. Some of these provide a means to relocate the vectors to some other location (or map some other location into the place of the vectors). If not, then the boot loader needs to define a way for the program to link into the vectors.

tjohansen wrote on Wednesday, February 16, 2011:

It seems to be related to the following IRQ handler from the startup file:

LDR     PC,  

Nom the user app has been offset with 0x5100 so jumping relative to the SP will not worm (Jump to the adress VicVectAddr will not work)

So any ARM guru, who knows how to use another instruction??


richard_damon wrote on Wednesday, February 16, 2011:

I haven’t worked with this chip, but have used other ARM processors. Taking a quick peek at the datasheet it looks like this processor does not have the ability to map the interrupt vectors to other addresses, but can map several different locations to appear at the low memory interrupt vectors (and the memory immediately following).

It looks like you can map into this area the contents of the flash at that location, the contents of flash at the beginning of the boot block, the contents of the beginning of the internal static ram, or the contents of the beginning of external memory space. Since the instruction will be executed at the standard vector address, that instruction still should work to read the contents of the VicVectAddr at its high memory address. If you have placed you application at 0x5100, the machine will NOT use your vectors, as I see no way to map this address to the vector table. If the contents you showed at 0 were from the boot loader, then you can just load your program at 0 and then turn off the boot loader mapping. If there is a second level of boot loader that is using up location 0 in flash, then you need to put your vectors in ram and map those in.

tjohansen wrote on Thursday, February 17, 2011:

Not sure I understand

So on a interrupt the IRQ vector (0x0000 0018) which is defined by the bootloader? So the LDR     PC,  would actually resolve to the address set in the VivVector and jump to the right ISR, event though the freeRTOS app has been build with offset 0x5100.
So the problem really could be the SWI handler. Its set to vPortYieldProcessor as address in the FreeRTOS port. But the SWI handler set by the bootloader is called instead, which isn’t set to anything??

So if the bootloader then would define the SWI handler to 0x5108, would it go to the SWI handler defined in the application startup.s file and hit the vPortYieldProcessor??

rtel wrote on Thursday, February 17, 2011:

This is my understanding or which richard_damon wrote, which richard_damon might want to correct.

The ARM7 will always look at address 0 for the vectors.  That is what the core does, but you can map different physical memory to appear at address 0.

Therefore, you can write you bootloader in the bootloader memory, and map that memory to address 0.  Then the LDR     PC,   instruction will work because the bootloader memory appears to the MCU as being address 0. 

Once the bootloader has completed and switches the application the physical memory mapped to address 0 is changed (by your bootloader) to the start of the application code, and the vector table defined by the application code appears to the MCU as being at address 0.  Therefore the instruction LDR     PC,    will still work, because the vector table always appears to the MCU as if it is at address 0 no matter where it is actually programmed into the flash (or RAM, for that matter).


richard_damon wrote on Thursday, February 17, 2011:

The ARM (and in fact many processors) have fixed addresses for the interrupt vectors, as that is the way the hardware is built. When a given interrupt occurs, the processor goes to the fixed address to start the processing.

In the case of the LPC family, the way they handle the desire for pointing the vectors at different places is to allow several different data sources to provide the contents for the very bottom piece of address space, where the vectors are.

By default, at power up, the processor maps “boot flash”, which is a piece of flash memory at the end of the flash to location 0, and the rest into a higher address section (so on all variants, it can appear at the same address, even though the definition of “end of flash” may change). Other locations that can be mapped include the real beginning of flash, and the beginning of the ram blocks. As far as I can see, there is no way to tell things that 0x5100 is a source of the interrupt vectors, and there is no way to try and convince the hardware that it is, regardless of what the source says.

Now the good part of the way that vectored interrupts work on the ARM with the vectored interrupt module is that you load the address of the routine to go to into hardware registers, and the general vectored interrupt routine just needs to read that address and go there (which is what the LDR PC, does), in the variety I am using it isn’t quite so convenient, the vector interrupt routine typically does the common state save, and then reads the address and jumps to it.

As was said, the other interrupts are more of an issue, including the SWI. If you haven’t done what is needed to put your vectors where the hardware will look at them, the SWI will not find the FreeRTOS handler.

I note that I am a bit puzzled by the need to relocate your program up to get around the boot loader, as the boot loader should NOT be in low flash to begin with on the LPC family. If the issue is that your boot loader isn’t using the boot loader capability of the LPC, you really should do so if possible, and in fact, you must have a real boot loader of some sort as that IS what the processor starts with,

My guess is that for some reason you are actually using a second level of boot loader (something the real boot loader validates and transfer control to), and this would of course be using the flash vectors at the bottom of flash. This means that your application program (now the 3rd program in memory) can’t use those vectors. You have a couple of options:

1) Move the 2nd level boot loader into the real boot loader location, thus your application becomes the 2nd program and can use the lower flash memory for its use.

2) You application can setup its vectors in the bottom of ram and map those addresses into the interrupt vector.

3) You write your 2nd level boot loader to understand the need to revector the interrupts, and reserves some ram locations (which it preloads) for the address of the interrupt routines, the various interrupts that need revectoring then use those locations to get the address to go to. This would NOT be needed for the Vectored Interrupts, as the single instruction routine stored goes to the correct address anyway, so doesn’t need to be overridden. This is by far the most complicated option.