SD memory card access from an Atmel AVR microcontroller using sd-reader

I’ve recently had a need to access SD memory cards from an Atmel AVR microcontroller. There are plenty of libraries out there which can do it, which saved me a lot of time, but choosing the right one and getting it to work wasn’t entirely straightforward.

DSC_1025

I looked at sdfatlib, which is intended for use with the Arduino. The Arduino also uses an AVR microcontroller but the code is mostly written in C++. My project (using Atmel Studio) was set up to build a lot of complex code in C, and I didn’t fancy trying to convince it to build C++ and link successfully. The compiler balked at the first mention of the word ‘class’, so I decided not to pursue it.

Next in the candidate list there was FatFs, which is written in C but targeted at all sorts of microcontrollers including the AVR. It looked more generic than I needed, and I didn’t want to spend too much time dealing with the low-level SPI stuff to talk to an SD card, so I moved on. I would certainly consider it for future projects though.

The final choice was sd-reader, written and released by Roland Riegel. This was the answer to my wishes: all written in C and well tested, specifically targeted at SD cards on AVR microcontrollers. It compiled as part of my project without a problem. However, there were some issues to deal with.

Firstly, it’s set up assuming that it has sole control of the SPI interface. My project already used SPI for another peripheral, so I had to do some trickery in sd_raw_config.h and my existing code to dynamically reconfigure the SPI port for each peripheral each time it was selected. I replaced the macro:

#define select_card() PORTB &= ~(1 << PORTB0)

with

#define select_card() ({SPCR=0x50; nSD_CS_PORT &= ~nSD_CS_MASK;})

which forced SPCR, the SPI control register, to the right value for the SD card. I had to do something similar in my other peripheral code. This all worked fine but a small change to sd_raw_init() in sd_raw.c was needed because the initialisation of the card takes place with a very slow clock speed, so that accesses SPCR as well.

I wanted to enable access time stamping in my application, so I set

#define FAT_DATETIME_SUPPORT 1

in fat_config.h. The documentation indicates that functions fat_set_file_modification_date() and fat_set_file_documentation_time() are available, but in fact they’re not. They’re declared static and used internally by the sd-reader code. The way to get time stamps to work is to define a function:

void get_datetime(uint16_t* year, uint8_t* month, uint8_t* day, uint8_t* hour, uint8_t* min, uint8_t* sec)

which gets called by the sd-reader code. You write this function so that your timekeeping code fills in the values. It worked fine once I’d discovered this.

The final wrinkle was that the function to create a directory:

uint8_t fat_create_dir(struct fat_dir_struct* parent, const char* dir, struct fat_dir_entry_struct* dir_entry)

is claimed by the documentation to leave dir_entry filled in with the directory’s details if the directory already exists. It does, but returns 0 indicating an error, so there’s no way to tell if it was impossible to get the directory or it just already existed. I worked round this by attempting to open the directory first, and only if that failed, attempting to create it.

Caveats: I may not have been using the most up-to-date version of the software, or I may have misinterpreted the documentation, or these things might have changed since I wrote this text.

Advertisements

One thought on “SD memory card access from an Atmel AVR microcontroller using sd-reader

  1. Pingback: Project Reference: A “Modern Day” Z80 Hardware Emulator – Z80 Project with AVR system controller

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s