Go Down

Topic: Building custom bootloader? (Read 4867 times) previous topic - next topic

Claghorn

What is the best place to start if I want to build a custom bootloader for my Uno R3? (Where do I find the source, for one thing, and which source version do I want?)

I'd like to be able to use a watchdog timer to do a reset and have the bootloader go ahead and wait for avrdude to talk to it rather than jumping directly to the sketch.

This way, I'll be able to upload new microcode over bluetooth without having to physically press the reset button (as long as the old microcode can recognize a command that tells it to reset itself, that is).
http://home.comcast.net/~tomhorsley/hardware/arduino/arduino.html

Nick Gammon

The source for existing bootloaders is here:

https://github.com/arduino/Arduino/tree/master/hardware/arduino/bootloaders

In your shoes I would take one of them and modify it - I think the Uno comes with Optiboot.

You might be able to do it anyway with some sort of (external) timer connected to the reset pin, but the bootloader is an interesting idea.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Claghorn

Thanks. I took a quick look at the optiboot source and it will be trickier than I thought to do what I want. The only way it ever gets to the sketch it loaded is via a watchdog interrupt, so it will take more work than just removing the check for watchdog to change it - I may need to understand more of the code than I want to :-).
http://home.comcast.net/~tomhorsley/hardware/arduino/arduino.html

tim7

Wireless upload via XBee modules can be done by transmitting the RTS or DTR signals on a spare communication channel, so that Avrdude can trigger a hardware reset as normal.  Note that this does not use the RTS pin on the RF modules, which is for flow control between the XBee and whatever it is electrically connected to.

Can your bluetooth connection carry the RTS or DTR signals in this way?

An alternative (and a controversial one) is to make your sketch issue a hardware self-reset when instructed.  This is not officially recommended without some kind of pulse-stretching hardware between the digital-output and the reset pins.  For me it works without, but this is not absolutely guaranteed.

Claghorn

After looking at the bootloader code some more I'm wondering if this is workable:

Modify the code at the top that detects a watchdog reset and instead of always calling appStart(), check a flag in the eeprom instead.

If the flag is set, clear it and fall through to the bootloader code. If the flag is clear, then do the normal thing and call appStart().

This would allow my sketch to set the flag and trigger a watchdog interrupt when it wanted to allow a firmware update.

My big question would be if eeprom_read_byte() and eeprom_write_byte() will work properly if I call them at the start of the bootloader. Anyone know if there are any implications there I'd need to worry about?
http://home.comcast.net/~tomhorsley/hardware/arduino/arduino.html

tim7

I don't see anything wrong with the logic, but the bootloader binary grows in size somewhat.  The AVR Libc eeprom function calls occupy ~20 bytes each.  If you can tolerate a 1k boot sector there should be no problem.

Claghorn

A 1k bootloader is no real problem, I'm not short of space in flash.

I have just gotten this to build, but it was a struggle. If I remove the  -nostdlib LDFLAGS setting it can reference the eeprom routines, but the linker also includes all sorts of .ctor and .bss nonsense.

I finally had to track down the right copy of libc.a, extract the eerd_byte_atmega328p.o and eewr_byte_atmega328p.o
files from the archive and explicitly link them in to get the read/write routines without dragging in all sorts of other nonsense.

Now it is time to see if I can use an Uno to load the bootloader into another Uno (I think I'll see if I can reload the standard bootloader first before I try my new one :-).
http://home.comcast.net/~tomhorsley/hardware/arduino/arduino.html

Claghorn

More questions: I think I discovered that the linker command line options for the location of the .version section in the bootloader needs to be changed to store the version in the last two bytes of a 1K image rather than the last two bytes of a 512 byte image, but now I wonder if anyone else needs changes to take a 1K versus 512 bootloader into account? Does something in the avrdude conf file need to be changed to reflect the reduced size of available flash?
http://home.comcast.net/~tomhorsley/hardware/arduino/arduino.html

westfw

The .version section should stay in the same place (last two bytes of flash memory in the chip), but the .text segment address will change for a longer bootloader.  For a 1K bootloader on atmega328, you'd want to start at the 31k mark:

atmega328: LDSECTIONS  = -Wl,--section-start=.text=0x7c00 -Wl,--section-start=.version=0x7ffe

Instead of:

atmega328: LDSECTIONS  = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe

BTW, I didn't have any problem adding EEPROM support (under BIG_BOOT for atmega1284, just by including <avr/eeprom.h> and using eeprom_write_byte() and eeprom_read_byte() (which are macros, so they shouldn't result in any special library requirements.)


tim7

Claghorn, do you have Arduino IDE v1.0?  This comes with Optiboot v4.4, which should compile as-is using the IDE tool chain.  I could add the eeprom code and recompile with no problem.  You'll need to adjust the fuses for the 1k bootsector of course - either in the optiboot makefile or in boards.txt, depending on how you're uploading the new bootloader.  You'll also need to set the maximum_size line in boards.txt.

Aside from the segment addresses already mentioned, I can't think of anything else.

Claghorn


The .version section should stay in the same place (last two bytes of flash memory in the chip), but the .text segment address will change for a longer bootloader.  For a 1K bootloader on atmega328, you'd want to start at the 31k mark


Yea, that occurred to me later :-).

Quote
BTW, I didn't have any problem adding EEPROM support (under BIG_BOOT for atmega1284, just by including <avr/eeprom.h> and using eeprom_write_byte() and eeprom_read_byte() (which are macros, so they shouldn't result in any special library requirements.)


I know I've seen copies of eeprom.h where they are macros, but in the avr-libc I have (downloaded from the fedora repos), they are real external routines (actually there are a gazillion versions of them with different names disguised by macro definitions for just the name of the routine).

In fact the whole avr toolchain in the fedora repos seems to be somewhat different since if I don't modify anything in the optiboot source, it doesn't build the same (or even a similar) .hex file. For one thing, the unmodified version built out of the box is already bigger than 512 bytes.
http://home.comcast.net/~tomhorsley/hardware/arduino/arduino.html

tim7

You mean it's easier to compile something under Windows than Linux?  My world is being turned upside down!

I think it's important to have the "right" version of the AVR libs, and possibly GCC too.  This may actually be harder to ensure on a Linux box.  It seems perverse to recommend running Gnu software on Windows, but it may be the quickest way to achieve your goal.

Claghorn

I just took a look at the latest 1.8.0 avr-libc from the official avr-libc site, and it looks the same as the fedora version (no macros for eeprom routines), so I guess the fedora repos are too new :-).

I was also reading about fuses and bootloaders in the atmel datasheet, and got really confused till I got it through my head that all the tables were giving addresses and offsets in 2 byte word units rather than byte units.

Anyway, I think I may have gathered enough info to take a real stab at making this work. Thanks to everyone for all the pointers. Now I need to find a big capacitor to disable reset on the R3 I'm going to try to use as an ISP...
http://home.comcast.net/~tomhorsley/hardware/arduino/arduino.html

tim7

Check the bootloader version in your Uno (see instructions here http://arduino.cc/forum/index.php/topic,64105.msg468453.html#msg468453).  Thanks to Westfw's work on optiboot, recent versions >=4.3 don't require reset to be disabled when running ArduinoISP.

westfw

Quote
the whole avr toolchain in the fedora repos seems to be somewhat different

Yes, this is part of the reason that I added support to optiboot to compile using the exact toolchain that ships with the Mac/Windows Arduino IDE, rather than (or "in addition to") the one that happens to be on your system.  Especially since changes in compiler version can drastically change the code size, making source that compiled fine with 4.3.2 be many bytes too large with 4.6.

Confirmed that eeprom.h has changed drastically between the Arduino version and the "current" latest version.  Rats; that's annoying...

Go Up