Interfacing PIC16F877A with SD card
In this post we'll see how to read raw data from MMC or SD card using PIC16F877A microcontroller. Reading raw data is just the reading of bytes and sectors of the SD card. UART protocol is used to display the data.SD card driver for CCS C compiler is used in this example, so download the driver from the following topic and put it in the project folder:
MMC/SD Card driver for CCS PIC C compiler
The microcontroller PIC16F877A has only 368 bytes of data RAM which means that it is not possible to load an entire sector which contains 512 bytes. That means we can't write byte or sector correctly with this microcontroller unless an external component is added to the circuit such as external EEPROM which of course slows the writing process. But reading is not like writing, we can read all the SD card data byte by byte.
In this topic we will just read data from the SD card and send it to PC via UART protocol.
The following topic shows a simple example for the UART protocol and PIC16F877A microcontroller:
PIC16F877A UART example
Required components:
- PIC16F877A microcontroller
- SD Card
- AMS1117 3.3V voltage regulator
- 8MHz crystal
- 2 x 22pF ceramic capacitors
- 3 x 3.3K ohm resistor
- 3 x 2.2K ohm resistor
- 2 x 10K ohm resistor
- 5 x 10uF polarized capacitor
- 100nF ceramic capacitor
- MAX232 chip
- Female COM port
- 5V Power source
- Breadboard
- Jumper wires
In this project the PIC16F877A runs with 8MHz crystal oscillator and for higher data transfer rate use crystal with higher frequency up to 20MHz.
The AMS1117 3.3V voltage regulator is used to supply the SD card with 3.3V. Also 3 voltage dividers are used to step down the 5V which comes from the microcontroller to about 3V which is sufficient for the SD card. Each voltage divider consists of 2K2 and 3K3 resistors.
MAX232 integrated circuit is used to interface the microcontroller with the PC, I connected just one wire (RD2) because I need to transmit data from the SD card to the microcontroller and then from the microcontroller to the PC, there is no need to connect the second wire because I don't have to send data from the PC to the microcontroller.
Hardware SPI is used by the microcontroller to read data from the SD card, the SPI pins of the PIC16F877A are:
- SCK (RC3): connected to pin SCK of the SD card
- SDI (RC4): connected to pin MISO of the SD card
- SD0 (RC5): connected to pin MOSI of the SD card
SD Card raw data read using PIC16F877A CCS C code:
The code used for this example is shown below. It was tested with CCS PIC C compiler versions 5.051 and 5.070.
There are two functions in the code: sdcard_read_byte and sdcard_read_data. I used the first function to read byte with address 0 and I used the second function to read sector number 0. Since the PIC16F877A has only 368 bytes of RAM and I can not upload all the sector data (512 bytes) in one time, I divided the sector into 16 32-byte parts, so 16 x 32 = 512. The sdcard_read_data function allows us to read data from the SD card starting from any address with any size we want.
The functions sdcard_init , sdcard_read_byte and sdcard_read_data return 0 if OK and non-zero if an error has been occurred.
// Interfacing PIC16F877A microcontroller with SD card CCS C code. // This example shows raw data read of the SD card. // 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 #include <16F877A.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock = 8000000) #use fast_io(D) #use rs232(xmit = PIN_D2, rcv = PIN_D1, baud = 9600) #include <sdcard.c> // SD card diver source code int8 i, j, one_byte, _data[32], size = 32; void main(){ set_tris_d(0); // Configure PORTD pins as outputs delay_ms(2000); printf("\n\r"); // Start new line printf("*** Interfacing PIC16F877A 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:"); // Sector 0 from address 0 to 511 (512 bytes) printf("\n\r"); // Start new line delay_ms(2000); for( i = 0; i < 16; i++){ if(sdcard_read_data((int32)i * size, size, _data) == 0){ for(j = 0; j < 32; j++) printf("%X", _data[j]); // Print 32 byte of data } } } // End printf("\n\r"); // Start new line printf("*** END ***"); while(TRUE) ; // Endless loop }After compiling the code and burning the HEX file into the microcontroller and with the help of the Serial Monitor of the CCS C IDE I got the result shown in the image below (I used a SD card with 4 GB ==> SDHC card).