Hello freinds,
Having looked around for almost 2 days for getting some intro about the bootloading process, I would first elaborate a little about what I have understood about the entire thing.
Having referred to a plethora of forum threads, this is what I conclude.
Basically, the ARM7 executes in 3 different modes viz. boot mode, user flash mode and user ram mode. On reset, the core always is in boot mode and executes the boot loader.Now the boot block which is normally resident in the top 64 bytes in user flash gets remapped into the top 64 bytes of the onchip 2GB memory, if I understood correctly. Now heres my first question: If the boot block gets remapped to the top 64 bytes of on-chip memory, then does it mean that the reset vector is reset at location 0 relative to this address?..
If im correct on this one, does it mean that the 'LDR pc,reset_addr' which is usally the very first instruction in the startup file does(or is supposed to do) a short jump to reset addr which should be the very first word of my bootloader right?..the boot loeader should then do all the hardware initializations alongwith the allocation of various stacks for different operating modes including the user mode. It then does have to map the vectors back into the user RAM and load the OS image into the ram as well right? Now this is where things go haywire in my mind: 1. In one of the forum threads here, they said the startup file may use absolute addresses only whereas the manual says that once the MEMMAP register has been assigned a certain value, then based on this value, the core will automatically assume a certain base and accordingly calculate the addresses of the various interrupt vectors. Could someone please clarify what will it actually do?
2. Now how do I tell the linker that I would like to 'install' a given bootloader at a certain location. And how do I decidew where my bootloader should be. I plan to use U boot and while there is enough documentation to get started, I would be pleased if someone could get me straight on this one. I mean the bootloader should be able to boot the system automatically on startup. So I should be ideally placing it in non volatile flash right. Please give me some pointers on this one since these kind of things are bugging me a lot. The documentation on the UBoot website talks about the canyonlands board while I am using a local made board whch uses the LPC2129.If what I wrote above is indeed what it is actually done on the LPC2100s then I might have to specify an absolute address in the very first instruction which typically causes the jump to the reset handler. oh by the way im using uvision4
Keen to get things started, but Im still lost in this huge pile of information scattered in bits and pieces. May be I should get used to the real world now.
Keen to hear from you guys.
Note that the chip has a boot loader directly from factory - a boot loader that you will not replace.
That boot loader will do its magic on reset. It will then assume that you have a real program in flash with vectors in the start of the flash.
This may be your full application. Or it may be a secondary bootloader written by you.
If you do a secondary boot loader, this boot loader may then do whatever it does before calling your application. And your application can replace the vector table of the secondary boot loader by remapping a block of RAM into the vector address range.
The startup file has a REMAP define to control if you want to remap the vectors into RAM.
For the application (the third step in the boot sequence, in case you do add a secondary boot loader), you may either link the interrupt vectors into the reserved RAM area that gets remapped using the scatter file settings. Or you may link them anywhere you like, and have your secondary boot loader copy them to the reserved RAM area before remapping the memory.
So in the end, the processor can have several different memory areas that can be mapped into the specific location where the processor expects to find the interrupt vectors.
Hejsan kompis, Tack for din svar. Är du svensk?(so much for the swedish I gathered while being an exchange student there).
Nonetheless coming back to the topic, your replies have made quite a noticeable difference in the way I visualize the flow. It has raised some more interesting questions and here they are:
1. What is this primary bootloader I mean where exactly does it reside in the memory map?
2. Is it important for me to know more about it? I actually plan to install a firmware lile ARMBoot / Uboot later. This is part of my plan to later have Ucos or some other RT Linux like ARM Linux running on the core. So the Uboot in this case will be my secondary bootloader right?
3. The primary bootloader gets 'invoked' as a result of a reset vector branching to it right?
4.The manual also says that if the prim bootloader finds the signature at 0x14 to be valid, it will automatically program the MEMMAP register with 0x02 aka user flash mode wherein the vectors are again remapped to the start of the user flash. Is this correct?
5.You said that the primary bootloader will then relinquish control over to the secondary bootloader. Where should this secondary bootloader reside. If I want the secondary bootloader to be resumed everytime I start up the device, then it has to be in somekind of non volatile memory, it could be user flash or off chip flash. Could you offer some tips on this please?
6. Lastly, what happens to tbe interrupt vectors at the start of the on chip flash. I mean if I have my secondary bootloader at 0x0, then these vectors would be erased right. Is is then the duty of the sec. bootloader to remap them again somewhere where it could be accessed in case of runtime exceptions or resets? If yes then where could such a place be?
I hope that I have not been too buggy! I know I have been a lil though. But please don't mind as I am still starting out and all this stuff seems convoluted for a guy coming straight from 8 bit AVR. Hope to see u soon.
Vi ses kompis och tack for din hjälp! Can you suggest some reading besides the dense literature that I have encountered these past days. Like some blogs and stuff?
Yes, I'm from Sweden.
1) Not sure for your chip but most likely the flash is a couple of kB larger than what figure you see when you select a chip model.
2) No, in reality, you don't need to know much about the existing primary boot loader. This boot loader checks the copy protection bits to see if it may allow read/write/erase of the flash. It then checks if there is something that looks like a valid application (or secondary boot loader) in the chip or if it has to wait for you to transfer data to the chip. It finally checks an external pin to see if you want to force entry to the boot loader transfer functions.
3) Yes, there is nothing magic about this primary boot loader. The mapping of the vector table initially makes use of the vector table for the primary - factory-supplied - boot loader. This boot loader then remaps the vector table into the start of flash, where you are expected to place a secondary boot loader or a final application.
4) I would have to retrieve the manual for your specific chip and reread the relevant paragraphs a couple of times before saying an absolute yes or no to your question, but in essence, the factory-supplied boot loader has it's own vector table and then switches over to the vector table you are expected to store at the start of the flash. The primary boot loader do a checksum of the full vector table to guestimate if you have programmed the chip with an application or not.
5) Your secondary boot loader must start at the start of the flash - same as all Keil example applications do when compiled for flash. It will then be up to you to partition the flash sectors - which sectors (besides the first) to allocate for the secondary boot loader, and which sectors to allocate for one or more application copies.
6) You would not normally erase your secondary boot loader. Your secondary boot loader would make use of IAP to erase and reprogram other flash sectors with your application. And your secondary boot loader would deactivate all interrupts, copy the vectors from your application (wherever you have chosen to store them in flash) into a fixed RAM region defined in the datasheet. The secondary bootloader will then remap this RAM region to map on top of the vector table for your boot loader. So you may have multiple vector tables, but only one active at a time. And the remapping function will make the processor core see the current vector table at the same place all the time.
The reason why I avoid discussing absolute addresses is that I do most of my work with the LPC23xx chips. But the basic consept is very similar between the different NXP families, even if flash sector addresses etc will differ a bit.
I'm affraid that you will have to continue to suffer the dense reading :)
The NXP user manuals are normally quite good. And both NXP and Keil have a lot of sample code available. And a lot of features are quite similar between the different NXP families so you may be able to pick up pointers by looking at LPC23xx info too.
Hay there per,
Thanks for the answers. I have a few other questions based on your previous inputs. But first heres the specifics about the chip.
I have the LPC2129 on which the on chip flash is 256KB. So the on chip flash is between 0x0000 0000 - 0x0003 FFFF. It has 16KB on chip RAM from 0x4000 0000 - 0x4000 2FFF. The boot block is located in the topmost of the on chip flash and its size is 8KB i.e. from 0x0003 E000 to 0x0003 FFFF.
Moving on, I would like to clarify the exact concecpts of remapping hence I would like to quote the exact words of the manual UM10114 LPC21xx & LPC22xx: section 3.2: "The portion of memory that is re-mapped to allow interrupt processing in different modes includes the interrupt vector area (32 bytes) and an additional 32 bytes, for a total of 64 bytes. The re-mapped code locations overlay addresses 0x0000 0000 through 0x0000 003F. The vector contained in the SRAM, external memory,and boot block must contain branches to the actual interrupt handlers or to other instructions that accomplish the branch to the interrupt handlers."
section 5.1:"The boot block is 8 kB in size and resides in the top portion (starting from 0x0001 E000 for devices with 128 kB flash and from 0x0003 E000 for devices with 256 kB flash) of the on-chip flash memory. After any reset the entire boot block is also mapped to the top of the on-chip memory space. i.e. the boot block is also visible in the memory region starting from the address 0x7FFF E000. The flash boot loader is designed to run from this memory area, but both the ISP and IAP software use parts of the on-chip RAM. The RAM usage is described later in this chapter. The interrupt vectors residing in the boot block of the on-chip flash memory also become active after reset, i.e., the bottom 64 bytes of the boot block are also visible in the memory region starting from the address 0x0000 0000. The reset vector contains a jump instruction to the entry point of the flash boot loader software." There are quite a few things based on this that I would want to conclude from the above two paragraphs.
Fig. 72 is also interesting to look at although I m not so conversant with ASCII art.
1. Initially my bootloader is between 0x0003 E000 - 0x0003 FFFF.On reset it gets mapped to 0x7FFF E000 - 0x7FFF FFFF. And the vector table for the primary bootloader is not accessible or visible to me then right. These vectors perform functions before my application or secondary bootloader gets the "control" so to speak right? As in, the reset vector address in case of the primary bootloader would automatically redirect the control to the primary bootloader and this jump or branch is fairly invisible to me (unless i personally want to to tinker with it).
2. From answer number 4, I can fairly say that I can confidently place 'my' vector table at the start of the flash. The primary bootloader which has been remapped will do a checksum of all the entries in this table and compare it with the signature at location 0x0000 0014 to determine if I do have any valid application right? The philips flash utility will automatically insert the 'correct' entry at this location in flash right?
3. Is this second table the one I specify in the startup.S file which gets automatically included for any new project in keil's microvison software? If yes then I can have the reset vector in this secondary table point to the start of my secondary bootloader. Isn't it?
4. Well finally it means that the Uboot bootloader must be placed in a location such that the reset vector from the secondary table must be able to point to it.
5. Finally do u have any idea about getting started with the Uboot bootloader? I have downloaded the README, the DULG manual and also plan to get the source. However, I still need some quick start tips about configuring it to suit my board which I although hope would be answered in the above documents.
Keen to hear from you,
1) You can't tinker with this jump for the simple reason that it is performed before any single line of your code starts to run. And NXP hasn't officially informed how you can modify the 8kB that is part of their boot loader.
2) You have to place your interrupt table at the start of flash for the secondary boot loader - or the main applicaiton in case you don't have a secondary boot loader. This is assumed by the primary boot loader. It is only when running from RAM with the JTAG interface that the debugger can catch the processor and reprogram it to remap the interrupt vector table using any of the available alternatives. But that isn't applicable for live use - only for code developing with JTAG interface.
The primary boot loader will just compute the checksum of the interrupt vector table. The "signature" is just an adjustable value with the purpose that the checksum (summing 32-bit interrupt vector table entries) always becomes zero. Don't know what you mean by the "philips flash utility". But it isn't any loader program that initializes this signature. The signature is already available in the file you transfer to the chip. To my knowledge, it's something the linker does.
3) The startup file you use for your project contains the declaration of the interrupt vector table. This, together with a correct scatter file specifying address ranges to use, will make sure that you get an interrupt vector table starting at address 0, and where the reset vector points to the start location of your secondary boot loader.
4) The UBoot secondary boot loader should contain it's own interrupt vector table. With a correct scatter file when building the boot loader, this will take care of itself. Not sure if there already exists a usable scatter file for UBoot. If not, then you will have to create one. Maybe manually. Maybe a simplified form using the available project settings in the IDE. If UBoot isn't built using the Keil tools, then the other tools should contain similar functionality.
5) No. I have played with UBoot for other processor architectures, but not for any ARM chips.
Hi there per. A very happy new year to you. Thank you for being so explanatory to a beginner. As again I have some more questions. Each of these questions now becomes more specific as I (hopefully) move closer inch by inch to my goal of getting my own bootloader to work with the LPC2129 chip.
Here it goes: 1. You said that I need to place the interrupt table at the start of flash "for the secondary bootloader". So when the chip comes out of reset, the primary bootloader (is it what they call bootmonitor?) will cause the instruction at address 0x0 to be executed. Having read notes AN10254,AN10404 which describes the initial steps to be taken to execute a given interrupt, I have some specific questions about it. The note typically has 3 files, one for the table, one containing the startup code and the 3rd C file which contains the ISR for the timer interrupt. To me the 1st two are of interest. a)The 1st file,which should be linked to 0x0. It contains in the very first line,a jump to the start of the startup code.b)2nd file contains startup code which enables the interrupts and sets up the stack pointer for the various modes.Were the interrupts disabled to begin with? If yes, then how did the reset interrupt cause the jump to reset vector?
2. The note further explains the changes required to enable the code from SRAM. Now the manual says that the SRAM is mapped from 0x4000 0000.Thus in the words of the note, "linker should be linked such that the 1st file should be linked to 0x4000 0000.The relevant interrupt vectors should lie between 0x4000 003F.The other files are linked within the code itself and can lie in SRAM.Also the interrupt vectors have to be remapped to SRAM. Using the MEMAP register and configuring it for User RAM mode could achieve this.
int main() { ... . /* Initialize MEMAP */ MEMAP=0x2; ... . } " Now some more questions: Now when my processor comes out of reset, the 1st stage bootloader will again take the core to the address 0x0. a)Since I link the vector table to 0x4000 0000, does it mean that core will "automatically be taken to 0x4000 0000 without worrying about what might be present at 0x0?" b)we are actually writing to the MEMMAP register inside the C code here.I mean isn't the C code the very last in the complete sequence? Doesn't the C code already reside in the user ram due to the linking? So the mere fact that the C code is being executed automatically implies we are already running from the on chip ram isn't it? Then why do we need to explicitly write to MEMMAP in the C code?
3. A person on this forum asked a question regarding the place where the nxp bootloader resides (http://www.keil.com/forum/docs/thread14333.asp).He specifically wanted to know where exactly are the interrupts "copied to" when MEMMAP = 00.I think that the interrupts table for the nxp bootloader is distinct from the table which my stage 2 bootloader may use.It is what you told me in our earlier discussions, right?
4. In the thread http://www.keil.com/forum/docs/thread10212.asp, rodrigo describes problems he faced while remmapping the vectors to the application code once he jumps into the application.Now he has a secondary bootloader which he uses to load the application code from usb connection. Am I right to conclude that his secondary bootloader is at 0x4000? He has a codeinit.s file which he links at 0x0. This file is the one which will be "called upon" by the primary factory supplied bootloader after reset right? Then this file contains a direct jump to absolute address 0x4000 where the secondary bootloader is resident. am I right on that one?
5. Is it possible for code to be run directly from FLASH or do they need to be copied into RAM? Assuming my application (which could be an OS image for that matter) is to be run from RAM, then the bootloader has to run from FLASH or it will corrupt the RAM contents right? On a side note,I suppose one would need external RAM for running an OS as the onchip 16KB ram is not enough.
6. The thread 's not necessary to remappe the vectors in RAM.The bootloader and the firmware could init their VIC at the beginning of their execution to handle their ISR." Could you kindly explain?
7. I understand that scatter files are a way to let the linker (or is it the download tool rather?) know where to put a given section of the code written using say a typical IDE like Uvision from keil, isn't it? However to have the intended effect the "use memory from target dialog" checkbox must be de-selected. Could you elaborate a little on what effect does de-selecting this does?
8. Could you point me to a comprehensive review of all these mapping and remapping concepts? The material is so very scattered. Its rather a nightmarish situation. If I am allowed to ask, what strategy did u apply to get a grip on these concepts when u were just starting out?
Keen to hear from you and once again God Jul!!
Sorry, I don't have time to try and follow up all the links in your post, so I will have to assume/guess the contents of them :)
1) First off - there is no "reset interrupt". Reset isn't a normal interrupt. It is a hardcoded feature of the processor that sets processor registers etc in a known state. One of these registers is the PC.
When the processor boots, it will map in the interrupt table of the primary boot loader (caused by the reset of all registers - including the bits that defines interrupt table mapping).
When the NXP boot loader has done whatever it does, it will map back the original interrupt table stored at address 0, and then jump to the start address.
2) The flash memory can't be modified on the fly. And since the processor is always looking for the interrupt table at address 0 (which is flash) there has to be support for some type of mapping.
When your code starts (either a secondary boot loader or a main application) that interrupt table mapping is straight through, i.e. the interrupt table stored at address 0 of the flash will be visible at the same address. So when building a secondary boot loader, you would configure it similarly to a normal application that gets directly started from the NXP startup code.
If you do want a secondary boot loader, then the application (which is then step three in the startup sequence) must be able to replace the interrupt vectors at address 0. The way to do that, is to store the vectors at a suitable location in flash (basically wherever you want). You then copy these vectors to the dedicated RAM area mentioned (the copy should either be performed by the secondary boot loader, or by the application). When the vectors has been copied into RAM, the remap feature is used to "overlay" this RAM block on top of address 0 of the flash. So the ARM core will still think that there is an interrupt vector table at address 0. But in reality, this table is in RAM.
When building a project, you can specify two addresses for a code block. One address where the code/data is expected to be stored in flash. One address corresponding to the address where the code/data is expected to be found when running the application.
3) Yes, the chip can have three (or some variants four) different mappings for the interrupt vectors. But one of these mappings are unofficial, and not documented. It is the mapping used for the NXP boot loader. You do not need to know where that table is located, unles you are going to try to reverse-engineer their code.
4) No. His secondary boot loader starts from address 0. This seondary boot loader may then (since it is your code) locate the application wherever you want in the flash. But you must reserve the start of RAM for a copy of the interrupt vector table, since the ARM can not make use of a vector table at a random location.
5) If you do not use a secondary boot loader, then your application can run fully from flash. If you do use a secondary boot loader, then your appliation can run fully from flash, with the exception that you need to make use of the initial RAM addresses for copying and remapping the interrupt table, so that the ARM core can find the entry points to your application.
6) You should initialize the interrupt vector table. The vector table is needed as first step. The VIC is a second step to extend a single interrupt into multiple, prioritized, interrupt sources.
7) The scatter file is for the linker.
For simple memory configurations, you use the IDE to specify memory regions. Whenever you change the settings, the IDE will regenerate a scatter file. For more complex configurations, the IDE will not be able to let you specify the configuration. So you have to turn off the auto-generation of a scatter file, and create one by hand - or take one generated by the IDE, and extend it.
8) Sorry. No can help. I read everything I could find. Then did trial-and-error attempts. Keil should add more information and examples for their scatter-load functionality. Including information about situations when the scatter file will produce correct mappings, but the Keil startup code + RTL code will not be able to handle. If you need access to specific memory regions in the first part of the memory - close above the interrupt vector table - then the linker can create solutions that will fail to boot. The variable initialization code in the runtime library has limitations that are not fully (or at all?) documented. As long as all startup code is allowed to be stored directly after the vector table, all seems to be ok.
I don't know much about this. But would like to try to give you a short/simple answer.
1. You can always execute your codes from the 4G (32 bits) memory addresses. For X86, the 4G (32 bits) memory addresses are mainly for DRAM. For MCU, the 4G (32 bits) memory addresses can be Flash/ROM or SRAM. So, your code can be executed from the Internal (On Chip) Flash.
2. The ARM7TDMI processor has 7 operating modes, with 8 interrupt vectors (Exceptions). The addresses of the 8 interrupt vectors are fixed, can NOT be changed. But the memory addresses can be remapped.
3. After the On Chip (First) boot-loader finishes its work, and YOUR code start. It must start from address 0x0000-0000. And if you need to remap the memory addresses, Your code has to do the remapping work.
4. Every time an IRQ (ex: UART or Timer) happens, the ARM core goes to the address 0x0000-0018.
5. Every time an FIQ happens, the ARM core goes to the Address 0x0000-001C.
6. Your boot-loader (Second) starts from address 0x0000-0000, after Your boot-loader finished its work, your application starts from somewhere, so your application does not have its own interrupt vectors, because 0x0000-0000 is occupied by Your boot-loader. And YOUR code need to handle such a problem.
I didn't notice Per's latest post, until I finished my posting.
Imagine that, Your boot-loader (Second) does not support UART; but your application has to support UART.
When your application is running, and an UART IRQ happens, the ARM core goes to the address 0x0000-0018 looking for the UART support. So the content of 0x0000-0018 must point to the correct UART ISR.
About point 6. the secondary bootloader should run with memory mapping = User Flash Mode. The Application loaded by secondary bootloader should run with memory mapping = User RAM Mode: so the Interrupt vectors of application are re-mapped to Static RAM without conflict with the secondary bootloader Interrupt vectors; How described on manual ...interrupt vectors, continue to appear in their original location in addition to the re-mapped address (ram mode).