Hi,
I am working on LPC2368 microcontroller. I need to develop two codes. One for bootloader and other is the actual application code.
The bootloader resides at 0x0000 and the application code is at 0x2000 The bootloader RAM is from 0x40000000 to 0x40000BFF and the application code RAM is from 0x40000C00 onwards.
I am using a flag in the bootloader to identify if there is a firmware upgrade. If this flag is set then the new firmware stored at a location other than actual application will be loaded into the application location i.e., 0x2000 and hence the firmware had been upgraded.
Now my problem is when my actual application code is running the interrupts are being called from the IVT of the Bootloader. Since i am using the VIC Vector Table for interrupts so both the IVT from Bootloader and application code are pointing to the same location. So i am not having any trouble with the IRQs.
Now i need to add a Data Abort handler which calls a function in the application code for handling data abort instructions.
This handling i have added in the IVT of the application code. But since the interrupts are being called from the IVT of the bootloader i couldnt write handling for Data Abort from application code.
I had seen many threads and all suggest to remap the interrupt vectors to RAM Mode. But if i did so the IVT of the application code will be mapped to 0x40000000.
But my bootloader is using the RAM from 0x40000000 so should i leave the first 64 bytes of RAM for application IVT and then allocate my Bootloader RAM and after that allocate my Application RAM??
Please do suggest me how i need to achieve this.
Thanks in advance
Think again about your RAM allocation.
First off - the boot loader could use the first RAM. Or it could use the last RAM. It really doesn't matter much.
Next thing - the boot loader and application can never run at the same time. So why do you even need to have them use different RAM regions? I normally save a tiny 16-byte range of RAM that I exclude from the normal RAM range, which means that the normal zero-initialization code doesn't overwrite it. So these 16 bytes can be used for sending messages between boot loader and application - the application stores a magic value there before taking a watchdog reset, to inform the bootloader to switch application.
In your case, you are wasting a huge amount of RAM that can never be used.
So you say that i leave 64bytes for the IVT of the Application code i.e., 0x40000000 to 0x40000040
Then i share a common RAM memory for Boot loader and Application code???
I have a doubt with this point. When the application code starts executing does the RAM assigned to this code will be initialized to 0's??
If not so then i will run into trouble.
I wont leave any RAM for indication to application code/ bootloader code since i am using the flash memory for indication.
The application should really be built with a full startup file. So it will perform a normal C runtime initialization including clearing the memory specified in the project settings (graphical dialog fields or specified in a scatter file) before main() of the application gets started.
When the application is running, then there is no reason for having much RAM dedicated to the boot loader because with your replaced interrupt table, there is no way for the boot loader to be called again until the processor gets reset.
And in the same way - while the boot loader is running, there is no reason for having any memory reserved for the application because the application can't make use of any RAM until it gets started - i.e. until the time when the boot loader ends and so no longer needs any RAM.
So that means that if you want to send information between boot loader and application, it will be enough with reserving a tiny bit of RAM just large enough for your message.
An example: Application writes magic "please reprogram" or "please switch to alternative application copy" into RAM and takes a watchdog reset. The boot loader checks if it finds any known magic value - in that case it performs as instructed, else it might perform the same operation as after a cold start.
Somewhere, you might want to store some counter or "uptime" to keep track of a newly programmed application that multiple times hangs (watchdog reset) without also sending any message to the boot loader - so the boot loader might decide "application version A has higher version, but have now failed multiple times - let's roll back to older application version B and wait for the over-the-air update to retrieve a better working version A++".
In the same way, the boot loader might store a magic value inside this small reserved RAM region: "Firmware reprogramming aborted - incorrect checksum" or "Firmware reprogramming successful" or "Third reactivation after unexpected watchdog reset - please enter reduced functionality mode and report issues to server."
But there really are NO reason to split your RAM and use half the RAM for a boot loader and half the RAM for an application - there are no magical multi-tasking OS that will run the boot loader and the application concurrently and so require both bootloader and application to concurrently need to access any RAM.
Bootloader -> Application is a transfer that can't be undone with less than a (watchdog) reset. There shouldn't be any Application -> Bootloader calls. Because then it isn't a bootloader anymore but have suddenly become a full BIOS which means that you get lots of dependencies that you suddenly also needs to care about. With calls Application -> Bootloader, you must suddenly test your new application versions against every released version of boot loader to test that the different versions of the bootloader code can correctly handle all made requests or that the application code will correctly notice which calls that aren't implemented (or which takes a different signature) in some bootloader/BIOS versions.
The only things you need to think twice about, when it comes to RAM allocation is: 1) That you need to consume a bit of hard-coded RAM for the application interrupt vector table remapping. 2) That if boot loader or application performs any IAP, then the NXP-supplied IAP code does require a bit of RAM - the user manual for the processor describes this requirement if you read the section about IAP.
The application code will have a full startup file. And as per the RAM i got your point.
I will leave 64 Bytes of RAM for IVT of Application Code i.e., 0x40000000 to 0x40000040. I will then assaign the RAM location for Bootloader from 0x40000040 to 0x40000400 i.e., 1024 bytes for the bootloader. And the remaining RAM will be assigned to the actual application code.
So to remap to the IVT of the application code to the RAM i had done the following settings in the IDE
Right click on the startup file. Go to 'Options for File"LPC2300.s"' Asm -> Conditional Assembly control symbols RAM_INTVEC REMAP RAM_MODE
Now the following gets executed in the startup code of the Application. ; Copy Exception Vectors to Internal RAM ---------------------------------------
IF :DEF:RAM_INTVEC ADR R8, Vectors ; Source LDR R9, =RAM_BASE ; Destination LDMIA R8!, {R0-R7} ; Load Vectors STMIA R9!, {R0-R7} ; Store Vectors LDMIA R8!, {R0-R7} ; Load Handler Addresses STMIA R9!, {R0-R7} ; Store Handler Addresses ENDIF
; Memory Mapping (when Interrupt Vectors are in RAM) ---------------------------
MEMMAP EQU 0xE01FC040 ; Memory Mapping Control IF :DEF:REMAP LDR R0, =MEMMAP IF :DEF:EXTMEM_MODE MOV R1, #3 ELIF :DEF:RAM_MODE MOV R1, #2 ELSE MOV R1, #1 ENDIF STR R1, [R0] ENDIF
Now i have another doubt regarding the mapping of IVT to RAM.
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, [PC, #-0x0120] ; Vector from VicVectAddr LDR PC, FIQ_Addr
For IRQ's it is as LDR PC, [PC, #-0x0120] ; Vector from VicVectAddr
Previously when IRQ interrupt arises PC is loaded from PC - 0x120 to get the VIC Vector Address. But now the PC will contain an address near to RAM location (0x40000000 + IRQ handler location)
Now if minus 0x120 from PC how can IRQ handling takes place?
The interrupt vector code is identical.
The processor remaps the interrupt vector table, so it will take a block of RAM and map on top of the lowest addresses of the flash. So the processor will still think that the interrupt vector table starts from address 0 - just as it did before.
The only difference is that your application (which starts at address 0x2000) will be linked with an interrupt vector table at address 0x2000. And the startup code will copy these bytes from address 0x2000 into RAM. And then map that RAM block on top of address 0x0000.
But back to the bootloader use of RAM again.
You write: "I will then assaign the RAM location for Bootloader from 0x40000040 to 0x40000400 i.e., 1024 bytes for the bootloader. And the remaining RAM will be assigned to the actual application code."
Why not map 0x40000040 .. whatever you feel you need (only matters how much memory to zero-init on boot).
And map 0x40000040 .. max to the application, where max represents all RAM supported by the chip.
There is zero reason for the application to leave the RAM that the boot loader used. The boot loader doesn't need it anymore at the same moment the processor enters the startup file of the application. So the startup code for the application is free to initialize all ram but the bytes reserved for the interrupt vector table. No reason to waste 1kB RAM for the boot loader, if the interrupt vector table remapping only requires 64 bytes. The other 1024-64 bytes will just be wasted by your configuration.