Tag Archives: sd

PetitFatFs SD card bootloader for ATmega2560 / Arduino Mega 2560

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)

FatFs with Arduino Mega 2560 and EthernetShield micro SD card

This is based on FatFs 0.8b, the latest release at the time of writing. We wanted to use the SD card slot on the standard arduino ethernet shield, and there’s a standard arduino provided SD library for working the sd card slot. However, despite the claims in the arduino FAQ, where it says, “… the C/C++ microcontroller libraries are under the LGPL” and “Using the Arduino core and libraries for the firmware of a commercial product does not require you to release the source code for the firmware. The LGPL does, however, require you to make available object files that allow for the relinking of the firmware against updated versions of the Arduino core and libraries. Any modifications to the core and libraries must be released under the LGPL.” this is actually untrue. Even on the SD card library reference page or Notes on using SD cards no mention is made of the fact that the SD library is actually GPLv3. Because the library is based on the GPLv3 sdfatlib

This is a pretty glaring omission, and a rather rude piece of code to just slip in.

Fortunately, there is also FatFs, and it’s tiny sister, PetiteFs, which are both under a BSD style license. They’re also plain C, and a lot more portable, with the sample code working on not just AVR, but ARM, i386, h8, and on and on.

So, I thought it should be possible to get that working with our mutant arduino here. Two websites were very useful in getting me started in the right direction, (in addition to the FatFs documentation)

What did I actually have to do?

  1. Download FatFs sample, and grab diskio.h, ff.c, ff.h, ffconf.h, integer.h and mmc.c and put them in my project
  2. Replace allll instances of BYTE with BYTEF (or anything else you want) in those files. BYTE is already defined (and differently) by the Arduino codebase
  3. In diskio.h, I had to add the following c++ wrapper
    #ifdef	__cplusplus
    extern "C" {
    #endif

    at the start, and close it at the end.

  4. Edited the ffconf.h to suit, (This is up to you…)
  5. in mmc.c, I added #include "WProgram.h"
  6. in mmc.c, I replaced the #defines for CS_LOW and CS_HIGH with digitalWrite(4, LOW/HIGH). For the Arduino Ethernet shield, chip select is on pin 4.
  7. in mmc.c, the three power_* functions were stubbed out. The ethernet shield doesn’t support this.
  8. in mmc.c, the disk_timerproc function had the write detect and card inserted logic removed, again, the ethernet shield doesn’t support this.
  9. in mmc.c, because I wanted write support, I had to provide a function, DWORD get_fattime(), which simply returns 1. This is the file create time, and if you don’t really care what timestamp you get, a fixed value is fine. You would normally hook this up to an RTC or something.

    That’s about it. Then, just be careful to make sure that SPI is set up properly (taken care of if you’re using the ethernet on the ethernet shield) and, very importantly, make sure to include pinMode(4, OUTPUT) to make sure that the SD cards chip select pin is actually an output. If you forget this, it will sometimes work, and sometimes fail, and be very very very unpredictable.

    Oh, And you need to set up a timer to call disk_timerproc() every 10ms. The circleofcurrent page shows how to work around this with fixed loops if you’d prefer, but I just set up Timer2 to do this. This list of arduino resources used seems to imply that Timer2 is safe for us, but your mileage may vary. Here’s how we set up Timer2

            TCCR2A = _BV(WGM21);  // CTC MODE
    	TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); // clkdiv 1024
    	TIMSK2 = _BV(OCIE2A);			/* Output compare match interrupt */
    	OCR2A  = 156;         // 156 ticks at 16Mhz/1024 = ~10ms
            // Needs to be turned on before we start trying to wake up the sd card!
    	sei();
            // fatfs disk init code below...

    This was all done on an Arduino Mega 2560 board.