ChaN’s PetitFatFs, is a pretty neat plain C library dealing with Fat file systems (like on SD cards) with as little code as possible. It even includes sample bootloader code for AVR, which tries to open a file on an SD card, and if it exists, write it to flash, before booting the user application.
It’s a pretty neat base, though you may/probably will want to add a little bit functionality. The directions that come with the code are pretty good for getting this working. [1] However, for boards based around the ATmega2560, or ATmega2561, which contain >128k program space, a couple of things just don’t work…
First, the code for jumping into the user code:
((void(*)(void))0)(); |
This is fairly commonly seen pattern, but least with GCC 4.3.3 (WinAVR 20100110) this generates incorrect code. It gets turned into an EICALL
, but without setting EIND
. This results in the bootloader continually resetting into itself. (And, if the file on the sd card exists, repeatedly overwriting flash as fast as possible, not really very good for your flash lifetime!)
The alternative, which correctly generates a jump to the real 0, (These big ATmega’s have a 22 bit Program Counter, not a 16 bit one) is simply:
asm volatile("jmp 0000"); |
The other required piece of the puzzle, is actually an AVR-libc FAQ item. You need to add -mrelax
to your linker options.
As best I can tell, both of these additions should actually “do no harm” for regular sized AVRs as well, but I don’t have any boards handy to try that out with.
By the way, if you’re using the SD card on an arduino ethernetshield, below is the the only change you need in asmfunc.S
. Just to save you from working out what the real name for “digital pin 4” is C land.
#define DDR_CS _SFR_IO_ADDR(DDRG), 5 // MMC CS pin (DDR, PORT) #define PORT_CS _SFR_IO_ADDR(PORTG), 5 |
Now, if only I could convince avrdude to erase all the flash, but only program the 4-8kb of bootloader, instead of insisting that it needs to program the entire 256k of flash each time I make a tweak to the bootloader. (139 seconds to program using a FabISP)
[1] The only thing I found unclear at first was setting up the “DI” and “DO” pins. Given that I was choosing pins that were on my mega2560, I assumed these were Data Out and Data In, when seen from the point of view of the mega2560. They are not, they are from the point of view of the SD card. (This is actually shown on the schematic image that comes with the PetitFatFs sample download)