I tested out the code I had already written and found out that the power up sequence was not working as expected. After consulting with my supervisor he advised me to enable pull-up resistors in port B and test the input and outputs for the each pin. By setting the INTCON2bits.NOT_RBPU to 0, I was able to enable the pull up resistors. I then set my port B as output and checked to see the voltage across the pins when set to high and when set to low. There were no unexpected results, moreover after setting port B as an input and setting the port to high, I found that pins 4-7 behaved differently. At this point the PICDEM2.NET was tested using a UART to debug port B using a resistor. From the results it was established that port B was working fine and all physical connections were working.
I ran my codes again and I was still not able to proceed with power_on at that time I checked the software SPI library that MPLAB was using for compiling and found that it was the unmodified initial one. The compiler was confused since both include directories had the file with the same name. Hence I renamed the file and added it to the compiler. At this point I also added a delay in between the clock pulses and after compilation I found that my power_on sequence was successful.
I then moved on to the mode_select function and tested it out, the function was at a halt after sending CMD0, I modified my code to show the lower bits of output R1 which was 0x0F showing that the card was in idle state although erase reset, illegal command, and command CRC error was also set. At this point I checked the CRC for command 0 from the SD documentation and from another sample code obtained from the Internet and I found that my CRC was right. I then changed my code to input a real value; a value other than 0x00 when obtaining the R1 response and somehow this time I was able to get the card in idle state and proceed to the next command. I then was able to get the card’s voltage range and check pattern and hence proceeded to the function card_init. When I ran this function there were hitches and I found that the card I had was an extended / high capacity card.
I faced no problems during that part of testing and hence I proceeded to writing a function for reading and writing. At first I wanted to perform writing and therefore wrote a function “sd_write”. In order to write to the card the host has to send CMD 24 (WRITE_BLOCK), with the address as the argument, wait for R1 response, check if there were no errors and then send the start token and the data to the card. During this time the Chip Select (CS) is set to low. When the data is received the card responds with a data_response token and gives busy signal while write is in progress.
The card writes data in blocks and the sd_write function has 5 inputs; 4 bytes of write start address and the data. Initially I wanted to write just one byte hence the input data was also one byte. The function then sends out CMD24, checks R1 response and is R1 is 0x00 the start token which is 0xFE is sent along with data and a dummy CRC. I then checked the response token. There are 3 response tokens 0x05 for data accepted, 0x0B for CRC error and 0x0D for write error. When the function was tested out I kept getting errors and then my supervisor suggested trying to read from the card first.
The card was then plugged into a PC to test if there was any data on it. When plugged back into the board and the initialization was run I kept getting errors at the initialization stage. I didn’t know what was happening and therefore went back to the documentation. I found that after power up sequence I had to send CMD0 , check for response send CMD8 and check for response to identify the version of the card. There are 2 versions of the card each having a specific initialization sequence and I had not taken that into consideration.
Hence I modified my codes to follow the sequence shown in the figures 1-3 below. I also changed my function prototypes to have a separate function for each command. These functions return a value according to the response received, and the details for outputs are shown in Table 3 below.
After running all the function prototypes I was getting the result that the card enters idle state, is a version 1 card and error when sending CMD08. I then obtained byte 5 of R7 response and output it to the UART to check out the flags and found that the last 4 bits (bit 0-3) is set high, indicating errors in erase reset, illegal command and CRC. I have not yet been able to figure out what the problem is.
Figure 1: Sequence of commands to determine version of card
Figure 2: Version 1 card Initialization sequence
Figure 2: Version 2 Card Initialization Sequence.
Table1: PIN connections from the SD card to PIC18F97J60
SD Card Contact Surface |
PIC Port B PIN |
CS (Chip Select) |
RB0 |
DIN (Data In) |
RB1 |
DOUT (Data Out) |
RB6 |
SCK (Clock) |
RB4 |
Table 2: Command Index, Arguments and Responses
Index |
Name |
Value |
Argument |
Response |
CMD0 |
GO_IDLE_STATE |
0x00 |
0x00000000 |
R1 |
CMD8 |
SEND_IF_COND |
0x08 |
0x000001AA |
R7 |
CMD16 |
SET_BLOCKLEN |
0x10 |
0x00000200 |
R1 |
CMD55 |
APP_CMD |
0x37 |
0x00000000 |
R1 |
CMD58 |
READ_OCR |
0x3A |
0x00000000 |
R3 |
ACMD41 |
SD_SEND_OP_COND |
0x29 |
0x00000000 |
R1 |
Table 3: Function Prototypes Input/Output and Description
Function |
Input |
Output |
Description |
power_on |
No input |
No output |
Provides the power on sequence with 1 ms delay and more than 74 clock pulses |
sd_command_tx |
Command index, argument bytes 1 – 4 |
No output |
Sends the command index after masking bit 47 and bit 46 to 0 and 1 respectively, send the argument bytes and CRC with bit 0 set to 1. The CRC is set to a definite value which is valid for CMD0. |
cmd00_tx |
No input |
R1 = 1 (if in idle state) R1 = 0 (if not in idle state) |
Sends CMD0, obtains the response R1 and outputs a value of 1/0 according to received response. |
cmd08_tx |
No input |
R1 = 1 (if version 1) R1 = 2 (if version 2) |
Sends CMD8, wait for response R7, check to see if command was legal or illegal. If command received was legal its a version 2 card, hence check for operating voltage and check pattern. If command was illegal its a version one card and return the response 1. |
cmd16_tx |
No input |
No output |
Sets block length to 512 bytes if its a version 2 SCSD card. |
cmd55_acmd41_tx |
No input |
R1 = 1 (if not in idle state) |
Sends CMD55, check R1 response to see if command was received without any errors, send ACMD41, obtain R1 response to see if in idle state. This sequence loops until R1 response for ACMD41 is 0x00 or if it timeouts. |
cmd58_tx |
No input |
R1 = 1 (if voltage range is accepted) R1 = 0 (Error in voltage range) |
Sends CMD58 and waits for R3 response, checks the first byte to see if there are any errors in command receive, then obtains byte 4 to check for the end of power up (bit 31 set to 1 if end of power up) and the type of card (Card capacity status from bit 30, set to 1 if it is HC/EC). These results are printed on the UART according to response. The function then checks for voltage range found in byte 3 and 2 of R3 and outputs a value according to result. |
0 Comments