Interfacing a (micro)SD card with an Atmega328 microcontroller
Interfacing a microSD card with an Atmega328 microcontroller
Hooking up an SD card (or microSD card) to your AVR project will seriously increase the amount of data storage you can access. I wanted to stream WAV files from an SD card for an audio project I was working on. I'm not going to delve into FAT16/FAT32 architecture or the SD card SPI interface in this post, but working on the principle that Life's too short to reinvent the wheel, there are libraries available for reading and writing to SD cards with Atmel microcontrollers. First things first, we need to physically connect our SD card to the controller. I'm actually using a microSD card to save space on my PCB, but I'm using a microSD card adapter so this will apply to SD cards equally. Grab a soldering iron, your SD card (/microSD card adapter) and a 7 pin header and solder like so:
Tin the header pins and be careful not to melt the plastic and bridge the connections. Using a putty like "Blu-Tac" is useful here to keep the header still while you're tacking the first connections in place. Next we need to connect things up, following this wonderful schematic.
We want the SD card pin out in this case. CS (#1) is "chip select", which can in theory be any pin, but is usually chosen as PB2 (SS), DI is connected to PB3 (MOSI), VSS1 and VSS2 are connected to GND, SCLK to PB5 and DO to PB4 (MISO). VDD is V+.
Getting the Atmega328 to talk to the SD card (actually a microSD card) was remarkably easy, thanks to the fantastic libraries out there. I used the SD card library from Roland Riegel. I used a high capacity microSD card, greater than 2 Gb. Therefore I had to modify "sd_raw_config.h" so that:
Getting the Atmega328 to talk to the SD card (actually a microSD card) was remarkably easy, thanks to the fantastic libraries out there. I used the SD card library from Roland Riegel. I used a high capacity microSD card, greater than 2 Gb. Therefore I had to modify "sd_raw_config.h" so that:
#define SD_RAW_SDHC 0
is changed to:
#define SD_RAW_SDHC 1
Also if we want to write to the SD card we've got to change (as I didn't have anything hooked up to these pins):
#define configure_pin_available() DDRC &= ~(1 << DDC4)
#define configure_pin_locked() DDRC &= ~(1 << DDC5)
#define get_pin_available() (PINC & (1 << PINC4))
#define get_pin_locked() (PINC & (1 << PINC5))
is changed to:#define configure_pin_available() //Do nothing
#define configure_pin_locked() //Do nothing
#define get_pin_available() (0) //Emulate that the card is present
#define get_pin_locked() (1) //Emulate that the card is always unlocked
And that's it. Almost too easy...NOTE: If you choose to use any other pin than the 'default' pin on your Atmega328 microcontroller (pin 16, PB2) , you'll need to do something that tripped me up for a while: YOU MUST STILL CONFIGURE THE CHIP SELECT PIN PB2 WHEN YOU SET UP SPI COMMUNICATION EVEN IF YOU DON'T THEN USE IT FOR CHIP SELECT! I thought I was being clever, and changed 'configure_pin_ss' in sd_raw_config.h from:
#define configure_pin_ss() DDRB |= (1 << DDB2)
to the pin I was using:#define configure_pin_ss() DDRC |= (1 << DDC1)
DON'T DO THIS! Keep this as it is, but change the chip select and unselect macros as necessary:#define select_card() PORTC &= ~(1 << PORTC1)
#define unselect_card() PORTC |= (1 << PORTC1)
Make sure you setup your alternative Chip Select pin as an output and you're ready to go. DON'T change the configure_pin_ss though! Maybe this is obvious to you, it wasn't to me. If you just want to use pin PB2 as the Chip Select pin, you can ignore this bit. Otherwise, I suffered so you don't have to, and heed my advice!
Make sure you have formatted your SD card to FAT32/16. It has been recommended that some operating systems cannot be trusted to do this in the required manner and "SDformatter" is a safe way to do this.
Debugging mode is enabled by default, which outputs to UART (RX/TX). This output (and input) can be interacted with. Thus using a USB USART converter and Putty, it's possible to navigate the file system using the low-level interface in the example code (see my blog post on communicating with an AVR chip and PC via UART)
Interested in Arduino and AVR programming? You might also enjoy:
- ATtinyMario
- Adding LCD character display to Attiny85
- Decoding and sending IR signals with an Arduino Nano
- Controlling quadcopter with PS2 controller
- PS2 radio controller - NEW!
This comment has been removed by a blog administrator.
ReplyDelete