Interfacing PIC18F4550 with SD card
With the help of the small driver of the MMC/SD cards we can easily read and write any sector and any byte located in the media. First download the SD card driver from the topic below and after the download put the file sdcard.c in the project folder:MMC/SD Card driver for CCS PIC C compiler
In this project a 8 GB SDHC card is used (SD card capacity is not important), the SD card is connected to the PIC18F4550 microcontroller via hardware SPI and the microcontroller runs with a frequency of 48MHz (8MHz with PLL). Circuit schematic is shown below.
Hardware Required:
- PIC18F4550 microcontroller
- SD Card
- AMS1117 3.3V voltage regulator
- 8MHz crystal oscillator
- 2 x 22pF ceramic capacitor
- 3 x 3.3K ohm resistor
- 3 x 2.2K ohm resistor
- 10K ohm resistor
- 100nF ceramic capacitor
- MAX232
- 5 x 10uF polarized capacitor
- Female COM port
- 5V Power source
- Breadboard
- Jumper wires
The MAX232 is used to interface our microcontroller with PC via serial port as what was done in this topic:
CCS C UART example for PIC18F4550 microcontroller
I used just one wire (RD2) to transmit data from the microcontroller to the PC (there is no need for the MCU to receive data so the receiving wire is not connected).
The chip select pin of the SD card is connected to pin RD3 (the SD card chip select pin is active low).
It is recommended to use voltage level translator (level shifter) instead of the voltage divider if it is available. The level translator translates the 5V to 3.3V for CS (SS), SDO (MOSI), and SCK and translates the 3.3V of MISO to 5V (PIC18F4550 SDI is an input with Schmitt buffer which needs 0.8VDD for high input). For example we can use chips like 74LVC04 (hex NOT) or 74LVC125A (quadruple buffer) to go from 5V to 3.3V and 74HCT245 to go from 3.3V to 5V.
For my hardware circuit I used both the level translator using 74LVC04 and74HCT245 and also the voltage divider using resistors as shown in the circuit schematic above, both circuits worked very well.
SD Card byte/sector read and write with PIC18F4550 microcontroller CCS C code:
This is our example C code, this code was tested with versions 5.051 and 5.070.
The microcontroller runs at 48MHz (8MHz + PLL).
The MMC/SD card driver file must be added as mentioned above. This example is tested in real hardware circuit as well as simulation using Proteus ISIS. After writing sectors or bytes you can check it with some softwares like: Hex Workshop, HxD Hex editor......
Before you test your hardware circuit make sure that your MMC/SD card does not contain any important files!
// Interfacing PIC18F4550 microcontroller with SD card (SDHC) CCS C code. // This example shows read and write functions of a single byte and whole sector. // This example does not use any file system (FAT16, FAT32 ...). // MMC/SD card driver for CCS C compiler must be installed! // Use at your own risk! // http://ccspicc.blogspot.com/ // electronnote@gmail.com // SD Card module connections #define SDCARD_SPI_HW #define SDCARD_PIN_SELECT PIN_D3 // End SD card module connections #define SDCARD_WRITE // Enable write data to media functions #include <18F4550.h> #fuses NOMCLR HSPLL PLL2 CPUDIV1 #use delay(clock = 48MHz) #use fast_io(B) #use fast_io(D) #use rs232(xmit = PIN_D2, rcv = PIN_D1, baud = 9600) #include <sdcard.c> // SD card diver source code int8 one_byte, sector_data[512]; int16 i; void main(){ set_tris_b(1); // Configure RB0 pin as an input pin set_tris_d(0); // Configure PORTD pins as outputs delay_ms(2000); printf("\n\r"); // Start new line printf("*** Interfacing PIC18F4550 with SD card ***"); printf("\n\r"); // Start new line printf("Initializing the SD card..."); printf("\n\r"); // Start new line i = sdcard_init(); // Initialize the SD card module if(i == 0){ // If the SD card has been successfully initialized // Read 1 single byte printf("Read byte with address 0:"); printf("\n\r"); // Start new line delay_ms(2000); if(sdcard_read_byte(0, &one_byte) == 0) printf("%X\n\r", one_byte); // Print the value of 'one_byte' // Read 1 sector printf("Read sector 0:"); printf("\n\r"); // Start new line delay_ms(2000); if(sdcard_read_sector(0, sector_data) == 0) for(i = 0; i < 512; i++) printf("%X", sector_data[i]); // Print all sector bytes (512 bytes) // Write 1 sector printf("\n\r"); // Start new line printf("Write sector 3:"); printf("\n\r"); // Start new line delay_ms(2000); if(sdcard_write_sector(3, sector_data) == 0) printf("Write sector OK"); // Write 1 byte printf("\n\r"); // Start new line printf("Write byte 0x700:"); printf("\n\r"); // Start new line delay_ms(2000); if(sdcard_write_byte(0x700, one_byte) == 0) printf("Write byte OK"); // Read sector 3 (check the previous write sector and write byte functions) printf("\n\r"); // Start new line printf("Read sector 3:"); printf("\n\r"); // Start new line delay_ms(2000); if(sdcard_read_sector(3, sector_data) == 0) for(i = 0; i < 512; i++) printf("%X", sector_data[i]); // Print all sector bytes (512 bytes) // End printf("\n\r"); // Start new line printf("*** END ***"); } while(TRUE) ; // Endless loop }After building circuit and code I get a result as shown in this video:
This is sector 0:
And this is sector 3 where the underlined byte which has address 0x700 is caused by the write_byte function:
As we can see sector 0 and sector 3 data are the same except byte 0x700, so what I did is I read all sector 0 data (512 bytes) and then I wrote these data into sector 3 and finally I wrote byte 0x700 with the value of byte 0x00 which I read in the first function (read_byte).