Author Topic: Modern AVR bootloader with XC8: How do I? (the most technical stuff)  (Read 1000 times)

0 Members and 1 Guest are viewing this topic.

Offline igendelTopic starter

  • Frequent Contributor
  • **
  • Posts: 377
  • Country: il
    • It's Every Bit For Itself (Programming & MCU blog)
Hi all,

My ultimate goal is to develop custom bootloaders for AVR DA/DB MCUs, probably ATmega4809 too. My development environment is MPLAB X IDE with the XC8 compiler. Yes, I know Microchip are pushing a transition to VS Code for the IDE, but one thing at a time.

While I believe I understand the concept of bootloading quite well, it is the smallest technical details surrounding it which I can't find/figure out. The examples on the web are, at best, for AVR GCC and/or Atmel Studio; AI oracles tell me to use project options which do not exist; and the app notes are silent on these critical points.

Let's start with the bootloader code:
1. How do I tell the toolchain that this program should reside in the BOOT section? Is there a setting I can use in the bootloader's C code itself?
2. Once the bootloader finished its job, how do I jump to the "regular" program, while making sure it will behave normally (e.g. set all registers to defaults, automatically zero-fill variables at startup)?

And the main code:
1. Here too, how do I tell the toolchain that this goes to the program code segment of the FLASH? Or is that the default?
2. How do I set up and refer to different interrupt vector tables for the bootloader vs. the main code? The IVSEL bit in the CPUINT's CTRLA register supposedly selects the vector table, but surely the tables themselves are created at compile time, not in runtime as I change IVSEL - so how do I know the ISRs that I wrote go to the right place?

Any additional info will be, of course, welcome too.
thanks,
Maker projects, tutorials etc. on my Youtube channel: https://www.youtube.com/user/idogendel/
 

Offline dobsonr741

  • Frequent Contributor
  • **
  • Posts: 970
  • Country: us
Re: Modern AVR bootloader with XC8: How do I? (the most technical stuff)
« Reply #1 on: January 28, 2026, 02:32:49 pm »
I would study https://github.com/askn37/euboot

And surrender to the more modern tools after seeing any obstacles with XC8. It’s an undocumented relic in my experience.
 

Online voltsandjolts

  • Supporter
  • ****
  • Posts: 3773
  • Country: gb
Re: Modern AVR bootloader with XC8: How do I? (the most technical stuff)
« Reply #2 on: January 28, 2026, 07:54:01 pm »
The examples on the web are, at best, for AVR GCC and/or Atmel Studio

XC8 is a brand name which encompasses two compilers; the original proprietary XC8 for smaller PICs, and now since they bought Atmel it has the added avr-gcc for AVR.

So, in short, you're using avr-gcc.
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 4650
  • Country: us
Re: Modern AVR bootloader with XC8: How do I? (the most technical stuff)
« Reply #3 on: January 29, 2026, 11:33:49 pm »
Quote
goal is to develop custom bootloaders for AVR DA/DB MCUs, probably ATmega4809 too. My development environment is MPLAB X IDE with the XC8 compiler.
Quote
XC8 is a brand name which ... since they bought Atmel it has the added avr-gcc for AVR.
So, in short, you're using avr-gcc.
Unfortunately, if you set the compiler to XC8, microchip wraps their own code around the linker and compiler, and the "options" that you need to set for bootloader use move, disappear, or don't work.  :-(

Note that there are some pretty significant differences between the NVMCTRL stuff between the AVR-xxx chips and the ATmega4809 and "xTiny" chips.

Quote
Let's start with the bootloader code:
1. How do I tell the toolchain that this program should reside in the BOOT section? Is there a setting I can use in the bootloader's C code itself?
For these newer AVRs, the bootloader section starts at 0x0, which is the same as the default compile/link destination, so you don't need to do anything special.
In theory, for clarity in your source code you could put all your bootloader functions in a bootloader "section", but it's unnecessary.

Quote

2. Once the bootloader finished its job, how do I jump to the "regular" program, while making sure it will behave normally (e.g. set all registers to defaults, automatically zero-fill variables at startup)?
The usual method is to do a software reset (on newer chips) or a wdt reset (on older avrs), which sets all the IO registers and such to their defaults.   Then the bootloader should detect this reset cause and do a simple jmp to the start vector in the application section (at relative address 0x0 in the application section.)
Note that zero-filling variables is part of the C startup code, which should still be present in your application.

Quote
And the main code:
1. Here too, how do I tell the toolchain that this goes to the program code segment of the FLASH? Or is that the default?
You have to move the application to the start of the application section.  Normally, you'd either modify the linker script, fill in a field in the ld options, or specify an "extra link option" like "-Wl,--section-start=.text=0x1000"
Unfortunately:
  • setting up an XC8 project does not copy a linker script into your project, or easily allow you to specify a custom linker script.  (Maybe it's an MPLABX think rather than an XC8 thing.)
  • The nice "program offset" option that exists for avr-gcc builds is not present for XC8.
  • The "--section-start" option (which is what the xc8 manual says to use, BTW) doesn't seem to work right (the command line generate works fine if you repace the "xc8-ld" with "avr-gcc", so I'm not sure what's wrong.)
There is a "legacy" form "-Ttext=0x1000" that does the same thing as section-start, and that DOES seem to work, so that's what I'd try in the short term.  (Maybe it's been fixed in 6.3; my experiments have been with 6.25)

Quote
2. How do I set up and refer to different interrupt vector tables for the bootloader vs. the main code?
The vectors get relocated along with the .text segment, so you don't need anything further to adjust the addresses of ISRs.  The vector table location defaults to the beginning of the application section, so if your bootloader wants to use interrupts, it MUST change IVSEL in its startup code (before enabling interrupts.)

There are several examples you can look at:
https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/optiboot_x.c bootloader for ATmega4809 and xTiny.
https://github.com/SpenceKonde/DxCore/tree/master/megaavr/bootloaders/optiboot_dx bootloader for AVR-D*
(These are both based on "optiboot", but optiboot_x is more of a re-write, and optiboot_dx is more of a modification.  Because of the differences in NVMCTRL, I think.)
 
The following users thanked this post: igendel


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

-->