Helpful ReplyHot!SDC/SDHC/MMC in SPI problem

Page: 12 > Showing page 1 of 2
Author
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
2013/03/11 03:03:26 (permalink)
0

SDC/SDHC/MMC in SPI problem

Hello everyone!
 
I'm new to this forum due to the fact that I don't usually register for forums and I don't ask for help until I really, really need it.
 
I've been stuck with my project for quite some time now and frankly I'm almost on the edge since my professor is pressuring me to complete this project but isn't giving me any info or help. So now I had to turn to you guys and ask for your help.
 
First off, I have to make a PIC16F88 microcontroller work with the above mentioned cards. I'm not using MPLABX IDE because we have access to and we have to use MikroC for PIC (and PIC32) compilers but I think you should not have any difficulties understanding my code:
 
char counter_1 = 0;
char counter_2 = 0;
char response_1 = 255;
char response_2 = 255;
char response_3 = 255;
char response_4 = 255;
 
char out_high = 255;
char out_low = 0;
 
void main() 
{
        //Set PORTB to output
        TRISB = 0;
        
        //Set RB0 to low
        PORTB.B0 = 0;
 
        //Initialize SPI interface
        SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV64, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH, _SPI_LOW_2_HIGH);
 
        //Wait for boot-up
        Delay_ms(10);
        
        while (1)
        {
                //Reset counter_1
                counter_1 = 0;
                
                //Reset response_1
                response_1 = 255;
                
                //Initialization routine - Send (and retry) reset + CMD0 command
                while (response_1 != 1)
                {
                        //Set CS high
                        PORTB.B3 = 1;
 
                        //Reset response_1
                        response_1 = 255;
 
                        //Send 80 dummy clocks
                        SPI1_Write(out_high);
                        SPI1_Write(out_high);
                        SPI1_Write(out_high);
                        SPI1_Write(out_high);
                        SPI1_Write(out_high);
                        SPI1_Write(out_high);
                        SPI1_Write(out_high);
                        SPI1_Write(out_high);
                        SPI1_Write(out_high);
                        SPI1_Write(out_high);
 
                        //Set CS low
                        PORTB.B3 = 0;
 
                        //Send 0x40
                        SPI1_Write(64);
 
                        //Send argument 0x00000000
                        SPI1_Write(out_low);
                        SPI1_Write(out_low);
                        SPI1_Write(out_low);
                        SPI1_Write(out_low);
 
                        //Send 0x95 as CRC value
                        SPI1_Write(149);
 
                        //Get response 0x01
                        response_1 = SPI1_Read(out_high);
                        response_1 = SPI1_Read(out_high);
                }
                
                //Reset response_1
                response_1 = 255;
                
                //Send CMD8 command
                        //Reset response_1
                        response_1 = 255;
                        
                        //Send 0x40 + 8
                        SPI1_Write(72);
                        
                        //Send argument 0x000001AA
                        SPI1_Write(out_low);
                        SPI1_Write(out_low);
                        SPI1_Write(1);
                        SPI1_Write(170);
                        
                        //Send 0x87 as CRC
                        SPI1_Write(135);
                        
                        //Get response
                        response_1 = SPI1_Read(out_high);
                        response_1 = SPI1_Read(out_high);
 
                        //If response_1 == 1 => SDHC (v2) else response_1 != 1 => SDC (v1) or MMC (v3)
                        if (response_1 == 1)
                        {
                                //Check for required response
                                response_1 = SPI1_Read(out_high);
                                response_2 = SPI1_Read(out_high);
                                response_1 = SPI1_Read(out_high);
                                response_2 = SPI1_Read(out_high);
                                
                                if (response_1 == 1 && response_2 == 170)
                                {
                                        //Reset response_1 and response_2
                                        response_1 = 255;
                                        response_2 = 255;
                                        
                                        //Send ACMD41 to support SDHC cards (ACMD41 is CMD55 + CMD41)
                                        while (response_2 != 0)
                                        {
                                                //Reset response_1 and response_2
                                                response_1 = 255;
                                                response_2 = 255;
                                        
                                                //Send CMD55
                                                        //Send 0x40 + 55
                                                        SPI1_Write(119);
 
                                                        //Send argument 0x00000000
                                                        SPI1_Write(out_low);
                                                        SPI1_Write(out_low);
                                                        SPI1_Write(out_low);
                                                        SPI1_Write(out_low);
 
                                                        //Send 0xFF as CRC
                                                        SPI1_Write(out_high);
 
                                                        //Get response
                                                        response_1 = SPI1_Read(out_high);
                                                        response_1 = SPI1_Read(out_high);
                                                        
                                                //Send CMD41
                                                        //Send 0x40 + 41
                                                        SPI1_Write(105);
                                                        
                                                        //Send argument 0x40000000
                                                        SPI1_Write(64);
                                                        SPI1_Write(out_low);
                                                        SPI1_Write(out_low);
                                                        SPI1_Write(out_low);
                                                        
                                                        //Send 0xFF as CRC
                                                        SPI1_Write(out_high);
                                                        
                                                        //Get response
                                                        response_2 = SPI1_Read(out_high);
                                                        response_2 = SPI1_Read(out_high);
                                        }
                                        
                                        //Reset response_1 and response_2
                                        response_1 = 255;
                                        response_2 = 255;                                        
                                        //Flash CS line
                                        PORTB.B3 = 1;
                                        SPI1_Write(out_high);
                                        PORTB.B3 = 0;
                                        
                                        //Send CMD58 and check if card is SDHC  PROBLEM
                                                //Send 0x40 + 58
                                                SPI1_Write(122);
                                                
                                                //Send argument 0x00000000
                                                SPI1_Write(out_low);
                                                SPI1_Write(out_low);
                                                SPI1_Write(out_low);
                                                SPI1_Write(out_low);
                                                
                                                //Get response
                                                response_1 = SPI1_Read(out_high);
                                                response_1 = SPI1_Read(out_high);
                                                
                                                //Get response
                                                response_1 = SPI1_Read(out_high);
                                                response_2 = SPI1_Read(out_high);
                                                response_3 = SPI1_Read(out_high);
                                                response_4 = SPI1_Read(out_high);
                                                
                                                //Read OCR and if CCS bit is not set force block size - not needed due to problem with CMD58
                                                if (response_1.B7 == 0)
                                                {
                                                        //Reset response_1 and response_2
                                                        response_1 = 255;
                                                        response_2 = 255;
                                        
                                                        //Send CMD16 and force 512 byte block size
                                                               //Send 0x40 + 16
                                                               SPI1_Write(80);
                                                               
                                                               //Send argument 0x00000200
                                                               SPI1_Write(out_low);
                                                               SPI1_Write(out_low);
                                                               SPI1_Write(2);
                                                               SPI1_Write(out_low);
 
                                                               //Get response
                                                               response_1 = SPI1_Read(out_high);
                                                               response_1 = SPI1_Read(out_high);
                                                }
                                }
                        }
                        else
                        {
                                //Send ACMD41 - this is where the program should check if the card is SD v1 or MMC (not yet needed)
                        }
                        
                //Reset response_1 and response_2
                response_1 = 255;
                response_2 = 255;
                        
                //Send CMD17 - not finished due to problems with CMD58
                        //Send 0x40 + 17
                        SPI1_Write(81);
 
                        //Send argument 0x00000000
                        SPI1_Write(out_low);
                        SPI1_Write(out_low);
                        SPI1_Write(out_low);
                        SPI1_Write(out_low);
 
                        //Get response
 
        }
}
 
To help you help me :) when the program starts running on the microcontroller I set the PORTB to output and then i initialize the SPI interface. Then I send the required 80 dummy clocks and CMD0 to reset the card and I get the required response of 0x01.
 
The next thing that comes is the painful process of CMD8 and ACMD41 (CMD1 for SD v1 cards) as shown in this flowchart: http://elm-chan.org/docs/mmc/sdinit.png
 
I use these lines of code:
                        //Get response
                        response_1 = SPI1_Read(out_high);
                        response_1 = SPI1_Read(out_high);
because I found out that my card gives responses after a byte of delay (the first line scraps the response and the second is what I need). At this point I'm not going for general usage, just this specific card.
 
I get the required responses from CMD8 and ACMD41 (my card is a Kingston microSDCH 4GB card) but when I try to send the CMD58 command the response I get is all zeroes and this is where I'm stuck. No CMD58 => can't continue the initialization.
 
I hope you can help me diagnose the problem.
 
Thank you all in advance.
 
P.S.
The counter_1 and counter_2 variables were used for testing. Don't mind them.
post edited by yoninno - 2013/03/11 03:06:01
#1
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/03/15 05:41:20 (permalink)
0
PLS, people. I really need the help.
#2
sasa72
Super Member
  • Total Posts : 418
  • Reward points : 0
  • Joined: 2011/08/09 05:17:18
  • Location: 0
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/03/16 00:35:18 (permalink)
+2 (1)
No body will do your homework for you. You have first to understand yourselves exactly how SD/MMC card works and what is the difference between many SD spec. revisions.
 
Quite messy code...
 
Advice:
 
1. Make functions for each command, you will locate easier the cause of the problem and logic follow the flowcharts in SD  specification, not other sources.
 
2. Look at the Smart Card section at this forum, there is few long threads about SD card and similar issue.
 
3. Notice there is a few main differences between SD Standard and SD HC during initialization and reading/writing blocks. Be sure you understand it.
 
4. MicroSD cards are not required to support SPI mode, even many card manufacturers support it. Suggestion is that first experiment on Standard size SD under 2GB.
#3
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/03/16 03:27:49 (permalink)
0
First off, thanks for the reply.
 
I'm not looking for anyone to do my homework for me, I'm asking for help in understanding why does CMD58 return all zeroes after I use ACMD41. I tried sending CMD58 before ACMD41 and the code is accepted, but sending it once again after ACMD41 (as per this flowchart http://www.chlazza.net/im...nitFlowchart_3.01.png) still returns all zeroes.
 
The code itself is messy 'cause it's still a draft code and not the final version and its easier to read the code like the initialization sequence (at least to me).
#4
sasa72
Super Member
  • Total Posts : 418
  • Reward points : 0
  • Joined: 2011/08/09 05:17:18
  • Location: 0
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/03/16 06:10:54 (permalink)
+2 (1)
From the code you posted, I can see you do not understand fully the SD SPI init procedure, command responds and also do not respect SD card to finish began CMD process, etc.
 
1. First of all, are you sure SPI is correctly initialized in Mode 0 and speed less than 400KHz? I would not trust any function I have no source code (mikroElektronika does not supply it). If have no oscilloscope to confirm, why not ensure and set SPI SFRs directly?
 
2. Why sending dummy sequence all over again to put card in SPI mode? That is require by SD spec. to do once, after power-on (and delay time to stabilize voltage). When card goes to SPI mode then cannot be returned in SD Bus state without reset.
 
3. The whole init process may last even whole second or more, usually very shortly. However, after CMD0 you do not let the card to finish processing command. And if you check all bytes of response, you will probably notice that card still processing request - it is not enough to test only bit 0 (idle state bit) of response!
 
Etc.. My advice is to go to www.sdcard.org and download at least latest available  SD Simplified Specifications and closely study each basic step: init sequence, commands responses etc.
#5
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/03/16 14:20:24 (permalink)
0
Now that's the kind of reply I'm looking for. Just to point me in some direction.
 
Thanks friend.
 
BTW 
Sorry If  behaved somewhat like an ass but the whole thing was just frustrating and with the lack of concrete info on the procedure your reply was just what I needed.
#6
cushyprinting
New Member
  • Total Posts : 3
  • Reward points : 0
  • Joined: 2013/05/23 01:08:55
  • Location: China
  • Status: offline
Flagged as Spam (2)
Re:SDC/SDHC/MMC in SPI problem 2013/05/24 01:30:53 (permalink)
0
Hi,
It's too difficult for me. I have learned more from here.
#7
markp
Super Member
  • Total Posts : 397
  • Reward points : 0
  • Joined: 2006/01/26 13:54:56
  • Location: 0
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/05/24 15:50:30 (permalink)
+2 (1)
My advice is do what engineers do in the real world when confronted by things like this: Try to find some open source software on the net that is known to work, look through each of the steps they use, understand exactly what each step does and why, then write your own version. The learning time is vastly reduced from trying to write it all from scratch using a datasheet or spec. The key is understanding, by reading the specs, exactly what that code does.
 
Here's a really good implentation to get you going:
http://elm-chan.org/fsw/ff/00index_p.html
 
Mark.
#8
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/07/28 11:57:05 (permalink)
0
OK people. I have finally fixed the problem I was having concerning interfacing SD cards with microcontrolers.
 
To be honest, I don't have enough time to review my faulty code and the new one that works to find out what was causing my problems so I'll just say it's has been fixed.
 
I won't post the code right now since it needs more refining and breaking up into specific functions but I'll try to make the improvements as soon as possible since this was a part of a project using PIC16F88. So please, just wait a little bit more.
#9
katela
Super Member
  • Total Posts : 921
  • Reward points : 0
  • Joined: 2013/06/11 05:25:18
  • Location: South Africa
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/07/29 02:53:45 (permalink)
+2 (1)
I' m not sure whether the PIC16F88 has enough resources to support the memory requirement of an SD card, but most PIC18F series can.
Check out this post using XC8 compiler: Interfacing SD Card With PIC Microcontroller
post edited by katela - 2017/07/05 05:50:02
#10
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/07/29 05:55:12 (permalink)
+4 (2)
Sadly, that is one part of the project. Making SD cards work with less memory than required in normal operation.
 
It is a pain in the a**, but we still have to do it :)
post edited by yoninno - 2013/07/29 05:58:18
#11
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/07/29 12:20:17 (permalink) ☄ Helpfulby RogerRowland 2015/07/26 09:30:47
0
Ok, here is the deal. I won't pack up my code into specific functions because I use a specific C development environment and it might get even more confusing for some people and above all this code is open to modification by everyone (just make sure to mention me, at least in a footnote :). As always I'm opened to suggestions, so if you have any suggestions, comments, criticism, feel free to express them.
 
Here we go.
First of all, when working with SD cards you need to physically connect your SD card (socket) to the microcontroller. I used a socket as it was simpler and I followed an Arduino suggestion to connect the socket to my PIC16F88.
 

 
On this image you can see the proper way of connecting your SD card socket to your microcontroller. If you do not have a socket with an integrated 3.3V voltage regulator DO NOT, and i repeat DO NOT CONNECT the 5V pin to your card because it'll go up in smoke.
The MISO pin on the image must be connected to the SDI pin on the microcontroller (pin 7 on PIC16F88)
The MOSI pin must be connected to the SDO pin on the microcontroller (pin 8 on PIC16F88)
The SCK pin must be connected to the SCK pin on the microcontroller (pin 10 on PIC16F88)
The CS pin can be connected to any digital I/O pin on the microcontroller (I used pin 9 on PIC16F88, RB3)
This is the basic physical setup.
 
Now all that is left is to program the microcontroller.
When you want to communicate with the SD card through your microcontroller you need to use SPI mode. That means you have  to set up your SSP module correctly and enable it.
 
//SPI interface setup
     TRISB.B1 = 1;     //SPI input pin            - in
     TRISB.B2 = 0;     //SPI output pin          - out
     TRISB.B3 = 0;     //SPI CS pin                - out
     TRISB.B4 = 0;     //SPI CLK pin              - out

     SSPSTAT.B6 = 1;   //Data transmission occurs on transition from active to idle clock state
     SSPSTAT.B7 = 0;   //SPI data sampling at middle of interval

     SSPCON.B0 = 1;    //SCK frequency is OSC / 16
     SSPCON.B1 = 0;    //SCK frequency is OSC / 16
     SSPCON.B2 = 0;    //SCK frequency is OSC / 16
     SSPCON.B3 = 0;    //SCK frequency is OSC / 16
     SSPCON.B4 = 0;    //Clock idle state is low
     SSPCON.B5 = 1;    //SPI interface enable
 
I set up the SPI interface bit by bit so that you know exactly what i did. First define the data direction on specific pins using the appropriate TRIS register. Then set up communication in mode 0, 0: CKP and CKE bits must be set to 0 and 1 respectively (bits SSPCON.B4 i SSPSTAT.B6 in my case). We are almost finished with the interface. The only things left are to select the clock frequency divider to get a clock frequency between 100kHz and 500kHz (when you initialize the card you can increase the frequency) and enable the interface (SSPCON.B5 = 1 in my case).
 
We have come to the hard part now, actually initializing a card and then reading and/or writing data to it.
By the general specification of SD card, you need to set your CS line high (logic 1). After you set the CS line high you need to apply 74+ clock pulses to the card. The pulses are needed to tell the card at which speed are you going to begin communication. I sent 80 pulses and it worked just fine. After that you need to pull the CS line low (logic 0) and you can forget about your CS unless you need to manage it for some reason. In this example we wont need to change it anymore.
 
//Set CS line high
PORTB.B3 = 1;
Delay_ms(1);
//Send 80 dummy clocks
SPI1_Write(0xFF);
SPI1_Write(0xFF);
SPI1_Write(0xFF);
SPI1_Write(0xFF);
SPI1_Write(0xFF);
SPI1_Write(0xFF);
SPI1_Write(0xFF);
SPI1_Write(0xFF);
SPI1_Write(0xFF);
SPI1_Write(0xFF);
              
//Set CS line low
 PORTB.B3 = 0;
 
If you asked yourself why I sent 0xFF ten time to the card, the answer is simple. The SCK pin won't generate pulses if the is no data in the SPI I/O buffer and 0xFF is just junk data which means nothing to the card at this point.
 
Continuing the initialization routine by specs, we need to send the CMD0 or GO_IDLE_STATE command to the card.
 
//Reset counter_1
counter_1 = 0x00;
                   
//Delay before sending command
SPI1_Read(0xFF);

do
{
          //Reset counter_2
          counter_2 = 0x00;

          //Send CMD0
          SPI1_Write(0x40);     //Foundation byte of every CMD command
          SPI1_Write(0x00);     //Four byte argument of CMD0 command
          SPI1_Write(0x00);     //Four byte argument of CMD0 command
          SPI1_Write(0x00);     //Four byte argument of CMD0 command
          SPI1_Write(0x00);     //Four byte argument of CMD0 command
          SPI1_Write(0x95);     //CRC value for CMD0
                        
          //Reset card_response_1
          card_response_1 = 0xFF;

          //Wait for response
          do
          {
                    card_response_1 = SPI1_Read(0xFF);

                    counter_2++;
          }
          while (card_response_1 != 0x01 && counter_2 < 10);

          //Increase counter_1
          counter_1++;
}
while (card_response_1 != 0x01 && counter_1 < 10);
 
NOTE: Before sending each command it is good practice to send a byte of 0xFF to let the card prepare. This is not required but should be used. I used SPI1_Read(0xFF) to generate the required clock because if you do not send clock pulses to the card, the card thinks that "time has stopped"  for her. Just remember, if you want to delay the card you need to generate clock pulses with junk data.
 
I used two counters counter_1 and counter_2 where counter_1 controls how many time i send the command and counter_2 controls how many times I check for my SD card's response when sending the command.
Every CMD<n> command is composed of 6 BYTES of data. The first byte is the start byte and it is different for every command (obviously) and it is calculated very easily:
for CMD0   -> 0x40 (hex) + 0 (decimal) = 64 (decimal) + 0 (decimal) = 64 (decimal) = 0x40 (hex)
for CMD8   -> 0x40 + 8 = 64 + 8 = 72 = 0x48
for CMD24 -> 0x40 + 24 = 64 + 24 = 88 = 0x58
and so on
The next four bytes are the argument of the of the command.
The last byte is the CRC byte. It is necessary for some command in SPI mode and for others if you enable the feature. Be aware that some cards (but only  a few) require that the CRC value of each command be correct even if you do not enable the CRC feature.
For CMD0 the start byte is 0x40, the argument is 0x00 0x00 0x00 0x00 and the CRC byte is 0x95. After sending the command you need to check for the response. The correct response for CMD0 is 0x01.
 
If your card is good and you received a nice 0x01 in one or two tries, then continue.
 
Next, per specs, is the CMD8 (SEND_IF_COND) command.
You can analyze this command the same way as I did for CMD0. The differences are in the start byte (0x48), the argument (0x00 0x00 0x01 0xAA), the CRC value (0x87) and the required response. This command is very important because based on the response you can know if you have a version 1 SD or MMC card or version 2 SD, SDHC or SDXC card. That is why we look for two distinct responses 0x01 and 0x05.
 
In my code I first checked for 0x01. If you get this response that means you have a version 2 or later SD card. After the response 0x01 you will have to check the next four bytes that the card will send. The value of these bytes in order is 0x00 0x00 0x01 0xAA just like the command argument. If you get these that means your card is OK to use, everything is as it should be. These bytes do not appear if the first response is not 0x01 but 0x05 (illegal command). I wont post all of these command since  they have the same structure  and you can look them up in the .txt file I'll attach.
 
Next comes the CMD58 command. This command is optional for both version 1 and version 2 cards, but it is recommended to send this command to check if the working voltage of the card is correct.
Keep in mind that this command also gives 4 bytes of additional information.
 
The work we have done so far concerning version 2 SD cards (we will come back to version 1 later) has almost come to an end. What is left is to actually initialize the card in SPI mode using ACMD41. ACMD41 is a compound command, meaning it is composed of more than one command. Actually ACMD<n> commands are always composed of CMD55 + CMD<n> and when you have to resend the ACMD<n> during the process you need to continuously send CMD55 + CMD<n>. So following the rule the ACMD41 command is actually CMD55 + CMD41 command and it looks something like this.
 
                //Delay before sending command
                         SPI1_Read(0xFF);

                         do
                         {
                              //Reset counter_2
                              counter_2 = 0x00;

                              //Send CMD55
                              SPI1_Write(0x77);     //Foundation byte of every CMD command
                              SPI1_Write(0x00);     //Four byte argument of CMD55 command
                              SPI1_Write(0x00);     //Four byte argument of CMD55 command
                              SPI1_Write(0x00);     //Four byte argument of CMD55 command
                              SPI1_Write(0x00);     //Four byte argument of CMD55 command
                              SPI1_Write(0xFF);     //CRC value is irrelevant

                              //Reset card_response_1
                              card_response_1 = 0xFF;

                              //Wait for response
                              do
                              {
                                   card_response_1 = SPI1_Read(0xFF);

                                   counter_2++;
                              }
                              while (card_response_1 != 0x01 && counter_2 < 10);

                              //Delay before sending command
                              SPI1_Read(0xFF);

                              //Reset counter_2
                              counter_2 = 0x00;

                              //Send CMD41
                              SPI1_Write(0x69);     //Foundation byte of every CMD command
                              SPI1_Write(0x40);     //Four byte argument of CMD41 command
                              SPI1_Write(0x00);     //Four byte argument of CMD41 command
                              SPI1_Write(0x00);     //Four byte argument of CMD41 command
                              SPI1_Write(0x00);     //Four byte argument of CMD41 command
                              SPI1_Write(0xFF);     //CRC value is irrelevant

                              //Reset card_response_1
                              card_response_1 = 0xFF;

                              //Wait for response
                              do
                              {
                                   card_response_1 = SPI1_Read(0xFF);

                                   counter_2++;
                              }
                              while (card_response_1 != 0x00 && counter_2 < 10);
                         }
                         while (card_response_1 != 0x00);
 
In essence the initialization process for SD version 2 cards is finished. You can ultimately send one more CMD58 command to check bit CCS in the additional response. This bit is bit 30 (when counting from 0) or bit 6 in the first byte of the additional  4 byte response. This bit will tell you if the card is version 2 standard SD or version 2 SDHC/SDXC card. I haven't yet tested he system with SDHC/SDXC cards because i dont own one, yet :)
 
So we have come almost to the end. Whats left is to explain the initialization process of version 1 SD and MMC cards. The process is, of course, the same up to and including CMD8. The difference begins with the response of CMD8. For version 1 of SD cards the response to CMD8 is 0x05 (it means illegal command and in idle state).
 
After CMD8 for v1 SD's you continue the process with CMD58 (which is in this case also optional). The response is still the same as with v2 cards.
 
After CMD58 you send the famous ACMD41 command. The command here is a bit different in my code only, i think, because some or most v1 SD's and MMC cards, that's why they are called v1, do not support ACMD41 (CMD55 + CMD41) and they give 0x05 as the response for CMD55 instead of the usual 0x01 response if the card supports ACMD41. If you get 0x05 as a response to CMD55 you have to skip the CMD41 and break the loop of ACMD41. This means that you have to use CMD1 to initialize the card.
 
We have finally come to an end of this "tutorial". I know this is short and maybe not the best written tutorial but I hope it will help those in need of an explanation as to how to initialize SD cards.
 
I used only a few web resources to make this work, though it took a while. These resources are:
http://elm-chan.org/docs/mmc/mmc_e.html - Here you will find explanations of some commands and the early process of initialization.
 
https://www.sdcard.org/do.../pls/simplified_specs/ - Here you will find the latest simplified physical layer specification of SD cards which has the correct initialization diagram you need to follow.
 
http://www.microchip.com/forums/m452739.aspx - This thread has some useful info on commands and responses if you find my code to hard to read.
 
http://mfb.nopdesign.sk/d...at_d/MMC/spitiming.pdf - Timing diagram for some commands. Could prove useful.  
I hope you find this useful and if you do please keep it alive and share for other to see.
 
NOTE: The example code I uploaded also has some code written to use PORTA. This is not needed for the example to work since I used it for testing purposes. There is also an implementation of CMD17 (Read) and CMD24 (Write) commands and the code is well crude so have fun.
 
BTW I used MikroC for pic as my dev environment.
post edited by yoninno - 2013/07/29 15:20:45
#12
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/08/10 08:54:03 (permalink)
0
I would really appreciate any feedback to make the article I wrote better and easier to understand.
 
Thank you in advance.
#13
Mafia
New Member
  • Total Posts : 1
  • Reward points : 0
  • Joined: 2013/12/11 22:19:42
  • Location: 0
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2013/12/11 22:23:40 (permalink)
-2 (1)
I found your post incredibly useful, thank you.
#14
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2014/01/19 04:58:46 (permalink)
0
You're welcome.
#15
Miroslav Segvic
Senior Member
  • Total Posts : 167
  • Reward points : 0
  • Joined: 2013/05/27 06:53:43
  • Location: Zagreb, Croatia
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2014/11/29 16:00:14 (permalink)
0
Hi guys, i know this is an old topic but since everything is written here already i would just like to check some things.
 
I'm planing on using memory card reader with dspic30f6012A which is a 5V chip.
I've recently purchased SPI memory card reader for Arduino  and it has 5v regulator on board. Here is the picture: http://s3.tupianku.com/view/large/5531/T00197.jpg
as i can see it has some resistors also on the lines 4 of them, and i cant figure out are these for level shifting between 5V chip and 3.3V card or do i still have to make level shifter like one shown in this topic earlier? the fourth one is puzzling if this is for level shifting?
 
I've found various information that 3.3V on MISO wont be enough for the chip and that resistor dividing is only good for slow connection so just want to clear things out which is simplest reliable way to go here?
 
Thanks for help.
 
#16
Miroslav Segvic
Senior Member
  • Total Posts : 167
  • Reward points : 0
  • Joined: 2013/05/27 06:53:43
  • Location: Zagreb, Croatia
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2014/11/29 16:14:31 (permalink)
0
one more thing, why are there different value resistors on SCK line divider?
#17
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2014/11/29 16:29:40 (permalink) ☄ Helpfulby miroslav.segvic@hotmail.com 2014/11/29 17:09:45
+3 (2)
Well, here is to reviving my old topic :D
 
After some work on the matter I found that this setup works quite well despite the info you suggested (BTW I found none).
 
First off, logically resistor dividing is the fastest form of level shifting you could hope for. You know, passive elements and all that ...
Second, that regulator you spoke of - not 5V, but 3.3V - and it is used to power the card and also give you a convenient 3.3V rail if you need it. Just make sure that you check the connections ON YOUR OWN despite the comments on the internet cause each module can have slightly different setups.
Third, the 3.3V MISO line wont cause you problems at lower speeds 300kHz - 500kHz which is more than enough. As I remember it, these speeds are required for card initialization anyway. 3.3V would cause you problems at extremely high speeds only because at those speeds even small capacities of lines and/or the pins themselves become significant. At very high speeds it takes more time to get to the required logic level with lower voltages. (I could write an entire article about this - just remember low voltage level => lower communication speed => no problems if speed is not an issue)
And last but not least, your question about the different values of resistors. I'm not sure cause I can't see the values, but I assume that the values are lower. If so, then its the same thing as with the MISO pin. Lower resistor values mean that you will get less signal distortion  at higher speeds. The SCK line probably has a higher capacitance that the other lines.
post edited by yoninno - 2014/11/29 16:31:04
#18
Miroslav Segvic
Senior Member
  • Total Posts : 167
  • Reward points : 0
  • Joined: 2013/05/27 06:53:43
  • Location: Zagreb, Croatia
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2014/11/29 17:19:16 (permalink)
0
Thanks you very much for saving me some time with your experience.
 
Yes that 5v regulator was a typo. I meant 3.3V regulator.
 
He drew 1k8 + 3k3 on CS and MOSI and 1K + 2K2 on MISO and that gives 3.43V. Since i've found similar shifters online with all the same values on MOSI MISO and CS, i'll put 1K8 or 2K3 + 3K3 an all three lines that gives me round 3.23 to 3.0V depending which resistors i find,  with enough room till 3.3V maximum specified.
I've found disinformation on some post suggesting maxim and 74.. series 5-3V shifters and that trash about 3.3 not enough for the chip. Never mind.
 
Thanks and regards.
 
 
 
 
#19
yoninno
Junior Member
  • Total Posts : 82
  • Reward points : 0
  • Joined: 2013/03/11 02:33:15
  • Location: Normandy SR-2
  • Status: offline
Re:SDC/SDHC/MMC in SPI problem 2014/11/29 17:44:44 (permalink)
0 (1)
Glad to have helped you neighbour ;)
 
Pozdrav iz Sarajeva.
#20
Page: 12 > Showing page 1 of 2
Jump to:
© 2018 APG vNext Commercial Version 4.5