Hi all, I'd like to better understand the Arduino bootloader, so I've read the source code (ATmegaBOOT_168.c).
First of all, I've understood that the bootloader is an optional piece of code that make possible uploading a sketch without the need of an external programmer.
Now, in the source code, I see a function pointer "void (*app_start)(void) = 0x0000;" that made me wonder if is our code (sketch) really written at 0x0000 in the MCU? and if yes, at which address is the bootloader written ?
Look at the datasheet, page 265 for a pictoral view of the addresses, and page 275 for the actual addresses for the various chips (ATmega48A/PA/88A/PA/168A/PA/328/P).
is our code (sketch) really written at 0x0000 in the MCU?
Yep. Actually, the "vector table" starts at 0, with the first vector being the "reset vector." But vectors are actually AVR instructions, so... you do wind up with actual code at 0.
Chips with "bootloader support" have options that can be set to have reset cause the execution to start at an alternate address (near the end of flash.)
Luca-91:
Hi all, I'd like to better understand the Arduino bootloader, so I've read the source code (ATmegaBOOT_168.c).
First of all, I've understood that the bootloader is an optional piece of code that make possible uploading a sketch without the need of an external programmer.
Now, in the source code, I see a function pointer "void (*app_start)(void) = 0x0000;" that made me wonder if is our code (sketch) really written at 0x0000 in the MCU? and if yes, at which address is the bootloader written ?
Many thanks
To get a better understanding of the bootloader code, read Section 27 of the Atmel DataSheet (Atmel 8271).
the function pointer that is initialized to 0x0000 points to the nominal Reset vector. That memory location contains an JMP instruction to the start of your application code. Normally this jump instruction at address 0x0000 is executed whenever one of these events happen: Reset, Power-on, Brown-out or Watchdog.
But, this standard operation is overridden by the BootFlag fuse. If the BootFlag fuse is set, the Reset vector is moved to the start of the BootPage. So any hardware reset is directed to this address. The standard UNO bootloader uses a 1k bootpage, since the UNO has 32k of program space, this means the effective Reset vector is at 0x7C00. Which is were the 'BootLoader' is actually located in memory.
calling app_start(resetReason); jumps to 0x0000 and starts executing code from that location.
0x0000 contains a JMP main instruction.
When you upload your Arduino sketch code, it fills flash with the HEX image of your compiled sketch. 0x0000 is actually filled with a jump to the main(); function of your sketch.
chucktodd:
ToThe standard UNO bootloader uses a 1k bootpage, since the UNO has 32k of program space, this means the effective Reset vector is at 0x7C00. Which is were the 'BootLoader' is actually located in memory.
I think it's 512 bytes for the Uno.
From boards.txt: "uno.upload.maximum_size=32256"
A tempting plum to pluck if you're running out of space.
A tempting plum to pluck if you're running out of space.
That sounds good, I thought they were still using the 1k bootcode, and that you had to manually replace it with Optiboot if you wanted to reduce the memory usage?
Atmega8 has/had a 1k bootloader.
ATmega168 and early 328 boards had the 2k atmegaboot bootloader, because optiboot didn't exist when they first came out.
Uno, being a brand-new board type, made a clean switch to the 512 byte Optiboot. There's no reason that older boards can't use optiboot as well, other than a desire not to change boot process of an existing product.
(The whole point of OptiLoader was to be able to take it to a get-together and put optiboot on everyone's old boards, saving them 512 to 1.5k bytes of space.)
Okay, just another question.. I've followed a tutorial on how to write a blink led in pure C with avr-libc, and i was able to produce an .hex file. Since flashing this .hex file would write it starting from 0x0000 I assume that the first istruction would be a jump to the main function (as stated by chucktodd), so I've run avr-objdump on the .hex and I've got:
The very first instruction is jump to program prolog which must be executed before the main function. It ensures setting the registers, initialize and clear global variables etc. In your case on address ACh is EOR R1,R1 instruction. It clears R1 register. It is a rule to have R1=0.
BTW: You can use avr-objdump with -S switch to intermix the source code with ASM. It could be interesting reading for you.
The first instruction is a jump at [to] 0xac! and 0xAC is where I think the main() is! (Please correct me if I'm wrong...)
Correct, except for the typo.
That make sense, but why there are all those jmp to 0xC0 (that jump again to 0x0)
Those are the other vectors in the "vector table" that I mentioned; they are jumps to the routines that handle the other interrupts that are possible on your chip. 0xC0 is the "unused interrupt" vector; if you don't define an ISR for a particular interrupt, the compiler will point it at the (rather useless) "reset the chip, sort of" code that you noticed.
You can use avr-objdump with switch to intermix the source code with ASM.
To get the mixed output (with "-S"), you'll have to use the .elf file rather than the .hex file as input.
Where can I read about the other interrupts? and what kind of interrupts are there? I imagine that there is something like the PIT (programmable interval timer) on x86.
Luca-91
If you are trying to understand to all "magic behind the curtain" before the main(), try to debug the program in AtmelStudio.
Just you have to put somewhere in your code the jump to zero address or null function call to reach the beginning and you can trace it per instruction.