I've written a bootloader application for NXP Kinetis microcontroller. Following are the things I did to do the same: 1. Created a bootloader application in CFlash addresses 0x0000 to 0x8000 2. Created my main application code from addresses 0x8000 to 0x1FFFF
This code is working fine. Now my doubt is, I have ISRs placed in both bootloader as well as main application code and didn't use any ISR vector relocation. Is it necessary to relocate the vector tables in main application?
PS: I may not be facing the issue just because the ISRs in both the apps are same.
On most modern MCUs the vector table relocation is not required, as the vector table base address can be specified as a parameter when compiling an application.
If your target's doesn't have such feature and the vector table is in the bootloader are 0x0000 to 0x8000 then you will need to relocate the vector table for the application so that an interrupt occurring in the application results in jumping to the correct handler.
Although I don't know the specifics of a Kinetis microcontroller, the following is based on general behavior of other Freescale/NXP controllers.
A bootloader is meant to allow you to update your firmware. (Otherwise, you don't need one.) And, a bootloader has to be kept in protected memory to prevent accidental erasures. By protecting the bootloader you also protect the vectors. So, you can't update the vectors anymore.
Unless you go to extremes to guarantee each firmware update will have the ISR code start at the exact same address as in the previous version(s), you'd rather be able to have ISRs move freely in the address space. That's where vector relocation or redirection comes in to play.
Currently, you have both bootloader and app use the same addresses in both sets of vectors, and everything works fine.
As soon as you update your firmware to another version where the ISR entry points most likely have moved address, your code will stop working because the MCU/bootloader will be sending the ISR events to the wrong addresses.
If you enable/implement vector relocation/redirection, the original bootloader vectors will effectively be ignored, and the relocated vectors will be used. Since these are updated along with your application, no problem.
There are two methods for vector relocation. One is hardware based (has the advantage of no ISR call overhead) and the other is software based (some minimal overhead but can be implemented even in microcontrollers that have no hardware vector redirection available).
Related
I am a bit confused about boot sequence of ARM Cortex-m processors. From many different resources, i read that upon reset, the cortex-m copies contents from 0x0 to stack pointer and copies reset handler address from 0x4 to PC...
My questions are:
1) how the cortex-m processor copies these two values to appropriate registers, I mean processor need LDR/STR instruction to do so, but here values are automatically copied??? How the processor know thats these two words need to be copied.
2) does cortex-m controller contains any builtin firmware that is executed initially?
3) Normally processors after reset, start execting from a specific memory location in reset vector where the jump instruction is placed to reset handler... but here in cortex-m the processors start by copying first two words into registers and then Program counter points to Reset Handler... No jump instruction no Specific memory location where processor jump on reset.!!! How is it possible??
2) does cortex-m controller contains any builtin firmware that is executed initially?
Depends highly on the model and make. Example: NXP LPC series Cortex-M chips (like LPC17xx) have some masked ROM instructions that are executed before the program in flash. Others may have no such memory build in.
1) how the cortex-m processor copies these two values to appropriate registers, I mean processor need LDR/STR instruction to do so
This happens in hardware before any code execution, so no LDR instructions needed.
Its ridiculously simple, if you know what a state machine is and how to implement one in a hardware description language like VHDL or Verilog.
I am not able to understand the concept of remapping Interrupt vectors or boot block. What is the use of remapping vector table? How it works with remap and without remap? Any links to good articles on this? I googled for this, but unable to get good answer. What is the advantage of mapping RAM to 0x0000 and mapping whatever existing in 0x0000 to elsewhere? Is it that execution is faster if executed from 0x0000?
It's a simple matter of practicality. The reset vector is at 0x0*, and when the system first powers up the core is going to start fetching instructions from there. Thus you have to have some code available there immediately from powerup - it's got to be some kind of ROM, since RAM would be uninitialised at this point. Now, once you've got through the initial boot process and started your application proper, you have a problem - your exception vectors, and the code to handle them, are in ROM! What if you want to install a different interrupt handler? What if you want to switch the reset vector for a warm-reset handler? By having the vector area remappable, the application is free to switch out the ROM boot firmware for the RAM area in which it's installed its own vectors and handler code.
Of course, this may not always be necessary - e.g. for a microcontroller running a single dedicated application which handles powerup itself - but as soon as you get into the more complex realm of separate bootloaders and application code it becomes more important. Performance is also a theoretical concern, at least - if you have slow flash but fast RAM you might benefit from copying your vectors and interrupt handlers into that RAM - but I think that's far less of an issue on modern micros.
Furthermore, if an application wants to be able to update the boot flash at runtime, then it absolutely needs a way of putting the vectors and handlers elsewhere. Otherwise, if an interrupt fires whilst the flash block is in programming mode, the device will lock up in a recursive hard fault due to not being able to read from the vectors, never finish the programming operation and brick itself.
Whilst most types of ARM core have some means to change their own vector base address, some (like Cortex-M0), not to mention plenty of non-ARM cores, do not, which necessitates this kind of non-architecture-specific system-level remapping functionality to achieve the same result. In the case of microcontrollers built around older cores like ARM7TDMI, it's also quite likely for there to be no RAM behind the fixed alternative "high vectors" address (more suited for use withg an MMU), rendering that option useless.
* Yeah, OK, 0x4 if we're talking Cortex-M, but you know what I mean... ;)
I have been researching ARM M3 bootloaders and most seem to work with the bootloader code sitting in low memory and the user code in higher memory. This requires the users application to be linked differently when used with the bootloader. That is some address above the bootloader code which is located at 0x00000000. I think this an inconvenience.
I would like to know if it is possible to have a bootloader which is located in high memory and yet still allow the users application to be linked normally so it starts at 0x00000000 in low memory ?
I have done this before with PIC bootloaders which also have reset & stack code at 0x0000 similar to ARM M3's NVIC table.
They way this has worked form me on the PIC is that bootloader is located in the top 1k of the flash. Reset vector and SP code which is at 0x0000 points to the start address of the bootloader code. Thus the bootloader starts after reset.
Now when the bootloaders is downloading the user code it puts it into low memory where the linker thinks it should go, the only exception being it does not allow overwriting of its own reset and SP vectors located at 0x0000. Instead it 'catches' these and stores them in flash within its high memory.
When the bootloader is ready for the users code to start it retrieves the initial reset and SP vectors it stored during the download and starts the user code using these.
At the next reset the bootloader will start and it can do a check to see if it should wait for a new user program or just start the users code using the vectors it has stored.
Could the above method be translated for use on the ARM M3 ?
I think the expression 'go with the flow' applies here. You are trying to do something that the ARM is not intended to do so I think you are making unnecessary problems for yourself. Putting the app above the bootloader just requires linking at a different address then setting the VTOR register to that address.
I am trying to understand how computer boots up in very detail.
I came across two things which made me more curious,
1. RAM is placed at the bottom of ROM, to avoid Memory Holes as in Z80 processor.
2. Reset Vector is used, which takes the processor to a memory location in ROM, whose contents point to the actual location (again ROM) from where processor would actually start executing instructions (POST instruction). Why so?
If you still can't understand me, this link will explain you briefly,
http://lateblt.tripod.com/bit68.txt
The processor logic is generally rigid and fixed, thus the term hardware. Software is something that can be changed, molded, etc. thus the term software.
The hardware needs to start some how, two basic methods,
1) an address, hardcoded in the logic, in the processors memory space is read and that value is an address to start executing code
2) an address, hardcoded in the logic, is where the processor starts executing code
When the processor itself is integrated with other hardware, anything can be mapped into any address space. You can put ram at address 0x1000 or 0x40000000 or both. You can map a peripheral to 0x1000 or 0x4000 or 0xF0000000 or all of the above. It is the choice of the system designers or a combination of the teams of engineers where things will go. One important factor is how the system will boot once reset is relesed. The booting of the processor is well known due to its architecture. The designers often choose two paths:
1) put a rom in the memory space that contains the reset vector or the entry point depending on the boot method of the processor (no matter what architecture there is a first address or first block of addresses that are read and their contents drive the booting of the processor). The software places code or a vector table or both in this rom so that the processor will boot and run.
2) put ram in the memory space, in such a way that some host can download a program into that ram, then release reset on the processor. The processor then follows its hardcoded boot procedure and the software is executed.
The first one is most common, the second is found in some peripherals, mice and network cards and things like that (Some of the firmware in /usr/lib/firmware/ is used for this for example).
The bottom line though is that the processor is usually designed with one boot method, a fixed method, so that all software written for that processor can conform to that one method and not have to keep changing. Also, the processor when designed doesnt know its target application so it needs a generic solution. The target application often defines the memory map, what is where in the processors memory space, and one of the tasks in that assignment is how that product will boot. From there the software is compiled and placed such that it conforms to the processors rules and the products hardware rules.
It completely varies by architecture. There are a few reasons why cores might want to do this though. Embedded cores (think along the lines of ARM and Microblaze) tend to be used within system-on-chip machines with a single address space. Such architectures can have multiple memories all over the place and tend to only dictate that the bottom area of memory (i.e. 0x00) contains the interrupt vectors. Then then allows the programmer to easily specify where to boot from. On Microblaze, you can attach memory wherever the hell you like in XPS.
In addition, it can be used to easily support bootloaders. These are typically used as a small program to do a bit of initialization, then fetch a larger program from a medium that can't be accessed simply (e.g. USB or Ethernet). In these cases, the bootloader typically copies itself to high memory, fetches below it and then jumps there. The reset vector simply allows the programmer to bypass the first step.
I am working with an embedded board , but i don't know the flow of the start up code(C/assembly) of the same.
Can we discuss the general modules/steps acted upon by the start up action in the case of an embedded system.
Just a high level overview(algorithmic) is enough.All examples are welcome.
/Kanu__
CPU gets a power on reset, and jumps to a defined point: the reset vector, beginning of flash, ROM, etc.
The startup code (crt - C runtime) is run. This is an important piece of code generated by your compiler/libc, which performs:
Configure and turn on any external memory (if absolutely required, otherwise left for later user code).
Establish a stack pointer
Clear the .bss segment (usually). .bss is the name for the uninitialized (or zeroed) global memory region. Global variables, arrays, etc which don't have an initializing value (beyond 0) are located here. The general practice on a microcontroller is to loop over this region and set all bytes to 0 at startup.
Copy from the end of .text the non-const .data. As most microcontrollers run from flash, they cannot store variable data there. For statements such as int thisGlobal = 5;, the value of thisGlobal must be copied from a persistent area (usually after the program in flash, as generated by your linker) to RAM. This applies to static values, and static values in functions. Values which are left undefined are not copied but instead cleared as part of step 2.
Perform other static initializers.
Call main()
From here, your code is run. Generally, the CPU is left in an interrupts-off state (platform dependent).
Pretty open-ended question, but here are a few things I have picked up.
For super simple processors, there is no true startup code. The cpu gets power and then starts running the first instruction in its memory: no muss no fuss.
A little further up we have mcu's like avr's and pic's. These have very little start up code. The only thing that really needs to be done is to set up the interrupt jump table with appropriate addresses. After that it is up to the application code (the only program) to do its thing. The good news is that you as the developer doesn't generally have to worry about these things: that's what libc is for.
After that we have things like simple arm based chips; more complicated than the avr's and pic's, but still pretty simple. These also have to setup the interrupt table, as well as make sure the clock is set correctly, and start any needed on chip components (basic interrupts etc.). Have a look at this pdf from Atmel, it details the start up procedure for an ARM 7 chip.
Farther up the food chain we have full-on PCs (x86, amd64, etc.). The startup code for these is really the BIOS, which are horrendously complicated.
The big question is whether or not your embedded system will be running an operating system. In general, you'll either want to run your operating system, start up some form of inversion of control (an example I remember from a school project was a telnet that would listen for requests using RL-ARM or an open source tcp/ip stack and then had callbacks that it would execute when connections were made/data was received), or enter your own control loop (maybe displaying a menu then looping until a key has been pressed).
Functions of Startup Code for C/C++
Disables all interrupts
Copies any initialized data from ROM to RAM
Uninitialized data area is set to zero.
Allocates space for and initializes the stack
Initializes the processor’s stack pointer
Creates and initializes the heap
Executes the constructors and initializers for all global variables (C++ only)
Enables interrupts
Calls main
Where is "BOOT LOADER" placed then? It should be placed before the start-up code right?
As per my understanding, from the reset vector the control goes to the boot loader. There the code waits for a small period of time during which it expects for data to be flashed/downloaded to the controller/processor. If it does not detect a data then the control gets transferred to the next step as specified by theatrus. But my doubt is whether the BOOT LOADER code can be re-written. Eg: Can a UART bootloader be changed to a ETHERNET/CAN bootloader or is it that data sent using any protocol are converted to UART using a gateway and then flashed.