Problems with SPI and SD Card

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problems with SPI and SD Card

13,505 Views
JulianP
Contributor I
Hi,
 
I have a problem with the SPI Bus which should communicate with a SD Card.
If I send for example a 9(0x09) to the SD Card i dont get an answer. But the SD Card should answer something.
 
I think that the problem is caused by my init() function. Maybe someone here can have a look on the code an help me.
 
void vfnSPI_Init(void)

 
    DDRS_DDRS4 = 0; //Miso
    DDRS_DDRS5 = 1; //Mosi
    DDRS_DDRS6 = 1; //Sck
    DDRS_DDRS7 = 1; //CS
     
     
    // Chip Select auf High
    PTS_PTS7 =0;
   
    SPI0CR1_SPE = 1;    /* SPI module enabled */ 
    // SD - Karte an SPI0                
    SPI0CR2 = 0x00;
       
    (void)SPI0SR;       /* Read the status register and */
    (void)SPI0DR;       /* read the data register to clear the status flags*/
   
    /* Desired SPI baud rate = 12kHz   */   
    SPI0BR_SPPR = 0x07; 
    SPI0BR_SPR = 0x07;                                                            
   
    SPI0CR2_MODFEN = 1; /* Slave select output pin used by SPI module */ 
    SPI0CR1_CPHA = 1;   /* Data sampling at falling edges */
    SPI0CR1_SSOE = 1;   /* Slave select output enable */
    SPI0CR1_MSTR = 1;   /* SPI in Master mode */
   
    SPI0CR1_SPE = 1;    /* SPI module enabled */

    /* Desired SPI baud rate = 4MHz, baud rate divider = (40MHz/2.5MHz) = 16   */   
    SPI0BR_SPPR = 0x03;  /* Baud rate divider = (SPPR+1)*2^(SPR+1) = (4)*(2^2) */
    SPI0BR_SPR = 0x01;
   */
    
  }
 
void vfnSPI_Send_Byte(unsigned char u8DataByte)

   
    while (!SPI0SR_SPTEF)   /* Wait for empty data register */  
        ;
   
    SPI0DR = u8DataByte;    /* Load byte in data transmission register */
}
 
unsigned char u8SPI_Receive_Byte(void)
{
    while (SPI0SR_SPIF == 0)//(SPI0SR & SPI0SR_SPIF_MASK))  /* Wait for data in the receive buffer */
        ; 
                       
    return SPI0DR;     /* Return received data */
}
 
Labels (1)
0 Kudos
19 Replies

2,969 Views
JulianP
Contributor I
Hi,
 
I am very happy the SPI works :smileywink: The problem were the transistors.
 
But now i have a different Problem.
 
Iam trying to implement the FatFS written by Chan.
Has anybody implemented this Code? If i want to open a File i always get the NO_Filesystem error. But the Card is formatted FAT16 correctly. I am using the mmc.c file from JimDon posted in this thread. In my opinion it normally should work.
 
Anybody an idea?
0 Kudos

2,969 Views
JimDon
Senior Contributor III
I did get to work, but I am not near that machine right now and you need to do this first.

Get sector read/write to work first.
First of all read sector 0 in. Get the FAT16 spec, there are certain magic values that should be in this sector. Also from the fat16 spec you should be able to decode some of the fields to convince yourself are reading a valid sector 0. There is a certain value in sector 0 that I alway read and confirm first in my code before I declare the card as online.

Then pick a random starting sector and r/w "sector in sector". For example, all 0's in the first sector 1 in the next on up to 0xff, then read them back and verify this is working. The code should write 256 sectors, then read them back verifying no error.


Until you get this to work, chans code will not work.

0 Kudos

2,969 Views
JulianP
Contributor I
Hi
 
For testing iam now using disk_read(0,buf,0,1);
 
This function sends command 17 to the SD Card. It should return 0 but it returns 0x05 which means(i think) Illegal command. Have I used wrong parameters for the function? or is the still something Wrong with the SPI?
0 Kudos

2,969 Views
JimDon
Senior Contributor III
Hard to say from my point of view. But, obvioulsy if you can not read a sector, you sure can't read a file.
You should look at the SD card spec again in the spi section to see what that error means. It could still be hardware. Carfully read it. I know it makes your head pound, but there is no easy way around understanding this.


Perhaps you should go  back to the initialization code.
There is a command that will get an ID packet from th card. If you look in my code I belive I do that. You should see a string in there that should have some letters and the size of the card.

For what it's worth, I spent a lot of time getting mine to work.

0 Kudos

2,969 Views
JulianP
Contributor I
Ok sometimes it gives back Illegal Command. But sometimes it gives that failure and sometimes not.
If iam using disk_ioctl for getting CSD for example it works. But if i execute after that ioctl command for example send_cmd((0x40+17),512); it does notwork. If i am not executing ioctl before send_cmd. It works. Maybe its caused by the Debugger because iam setting an breakpoint between these two commands.
 
The code is for an Datalogging system. I need the Fat system because i have to write a logfile which must be readable in windows.
 
 
0 Kudos

2,969 Views
JimDon
Senior Contributor III
I this for a product?
0 Kudos

2,969 Views
Ganryu
Contributor I
Hi, I was reading this post and I got the FatFS module working. But I made a routine to write a txt for a datalogger, and when my archive get in the range of 2Kb (sometimes early), my f_write command returns FR_RW_ERROR and set FIL->flag to an unknow value. Anione got this module working and writing files and got this problem or can help me?
 
Thx,
Horacio
0 Kudos

2,969 Views
OlivierL
Contributor I
Hi,

I've been using a HSC12X microcontroller for a couple months now and after setting up most of the basic functions, I am stuck with a stupid error with the SD card that I can't seem to understand and overcome. I am using a HCS12X development board (http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=EVB9S12XDP512&fsrch=1) and I soldered a connector to plug in a Microchip PicTail SD Card board (http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en537238). I decided to implement with that board because I had it working in the past so I could rely on it.

I am using the SPI1 port on pins 2,3,4 and Port B (pin 0 at pin 32) for the /SS.

I use the code posted above in this post by Jim to implement the SD card basic functionality. I have also tested with other codes, such as the one provided on http://elm-chan.org/fsw/ff/00index_e.html with the same result.

Here is my issue:
I have checked with a scope that the signals are sent as follow:
Wait ~1 ms
Send 80 CLK with /SS High and 0xFF on MOSI, (CLK idle low)
then taking /SS low, wait ~1 ms
Send CMD0 (0x40, 0x00, 0x00, 0x00, 0x00, 0x95)
Send 0xFF until receiving an answer
(MOSI and MISO are both Idle high)

The answer is ALWAYS 0x03 which means SD card is IDLE but "Erase RESET" flag is set. The card won't listen to future commands and the answer is the same no matter how often I send CMD0. I have tried with different SD cards (SD 512MB, SD 1GB, MMC 16MB), all with the same result.

If I put the same PicTail board on the microchip Explorer 16 board, it works perfectly and even writes empty data files on the FAT16 file system. The connector used to connect to the Explorer 16 is different than the one used on the HCS12X eval board since it is 3.3V instead of 5V but the conversion is done properly on the PicTail board, and the signals all look perfect on the scope.

also important to note, I have tried SPI CLK speed from 125kHz to 2 MHz without better success.

Has anybody ever had this issue? Any hints?

Thank you,

Olivier


Message Edited by OlivierL on 2009-02-11 12:17 AM
0 Kudos

2,969 Views
JimDon
Senior Contributor III
Here is some code that  will initialize and SD card and r/w sectors.

I wouldn't waste time with the SS as there are certain times you must assert and deassert the select.
Please examine this code.
Please also download and read the specifications, as it is important to understand these.





Message Edited by JimDon on 2008-02-27 09:55 AM
0 Kudos

2,969 Views
JulianP
Contributor I
Hi, thanks a lot for your help.
 

 // CMD0 Forces the card to SPI mode.
 // All types of cards accept CMD0
 do
 {
  status = send_cmd(CMD0, 0);
  // fail and return
  if(n++ > 50)
  {
      return RES_INITFAILED;
  }
 } while( status != 1 ); // Wait for idle state.
 
in this loop after these 50 tries i get the RES_INITFAILED error.
 
I the attachment you can find the shematic hwo mosi etc. is connected to the SD Card. I also have slowed down the baud rate because of the transitors which block the signal if its too fast. 
 
Message Edited by t.dowe on 2009-10-20 11:18 PM
0 Kudos

2,969 Views
JeffS_
Contributor I
Well, for one think you need a pull up on the data out, like 10K. Thats in the SD spec.
When the card first starts up, it floats.

Try that and see if it gets initalized.
Also, you can break poin on the if statement and see what gets returned.
What is status equal to?
0 Kudos

2,969 Views
JulianP
Contributor I
Thanks a lot for the code. But I have still the same Problem.
Code:
static BYTE rcvr_spi (void){  while(!(SPI0SR & SPI0SR_SPTEF_MASK) )// Wait for write to end.        ;          // Send FF as the SD card wants to see highs...   SPI0DR =0xff;                         // Trigger 8 SCLK clocks    while(!(SPI0SR & SPI0SR_SPIF_MASK)  )// Wait for write to complete    ;  return SPI0DR;}

 
This is the receive function you send me. But if the disk_initialize function calls rcvr_spi the function gets stuck in the second while loop because SPIF is not 1 at anytime. Normally it should work i have no idea why it does not. I have checked the Hardware but it seems to be OK.


Message Edited by JulianP on 2008-02-28 08:28 AM
0 Kudos

2,969 Views
bigmac
Specialist III
Hello,
 
Keep in mind that, for the SPI master, the SPIF flag becoming set has nothing to do with any data returned from the slave, or whether pullups are present or not, or whether a slave device is actually connected.  The flag becoming set indicates that the master has completed the SPI transaction, and that the return data (if any exists) may be read.  So the flag should always become set.
 
One possibility, assuming you are using the debugger, is that your monitoring conditions during debug provide the flag clearing mechanism, between the flag becoming set and the while loop.  Do not monitor either SPI0SR, or SPI0DR, during the debug process, nor single step that part of the code.
 
Regards,
Mac
 
0 Kudos

2,969 Views
JimDon
Senior Contributor III
Mac,
I guess I was not clear.
The code waits for 0xFF to be returned from the SD Card, and I am not at all saying that the data returned has anything to do with the flag, but the code loops on sending a certain command until FF comes back.
A properly designed interface will return FF, so the code expects to get this, even there is no card it will get FF.

Of course if your had been looking at the code what I said might of been clearer, but I suppose a better explanation is in order.

If the input is stuck at 0, it will seem as though it is hung waiting at this point because it is a fairly tight loop and when you start off the SPI clock is slow only like 100K so it is in this routine often. When you click break there is a very high probability it will be on this line of code, but it seems the debugger will steal the status and you can never seem to step out of it so you conclude that it is hung at this point. Well,  it is and you will have to reset to get out of it, but is is not the problem you are looking for.

I say all this because I had a bug in the hardware where this would happen, and I thought the same thing, that it was not sending properly and it was stuck waiting for status, when it was not the case. In fact, if the SPI is properly set up and you code is right, it can't really ever fail to complete sending the byte.

0 Kudos

2,969 Views
JimDon
Senior Contributor III
Does the data out from the card line have a pullup on it?
At some point the code expects FF, but the SDCARD may be tristated and the input to the SPI port in stuck low, having floated there.
What happens is when you trace into the code to see what is up, the debugger steals the bit by reading the port and you think that it is stuck, but it really is not. Well it is stuck but for another reason.

Check that the data out line from the card has a pull up on it.
I had this problem. I may have changed to code to ignore 0 until that first command is sent, which makes the card start driving the line.







Message Edited by JimDon on 2008-02-28 10:04 AM
0 Kudos

2,969 Views
JulianP
Contributor I
Hi,
 
the problem is still existing. You are right it seems the the debugger is stealing the bit if is dont look in that part of the code it does not get stuck, but there is now a different problem. I have used the code from JimDon but it gives an diskinitialisation error. In the Attachment you will finde the whole project maybe you will find the problem. I am really becoming desperate with this SPI
 
Message Edited by t.dowe on 2009-10-20 11:14 PM
0 Kudos

2,969 Views
JimDon
Senior Contributor III
Since your hardware is different then mine, you are going to have to tell exactly what error you are getting from disk_initialize, since I can not run your code on your hardware. Obviously, it works on my hardware.

It would also be helpful to see how the card is connected to your board, as in a schematic.

0 Kudos

2,969 Views
bigmac
Specialist III
Hello, and welcome to the forum.
 
I am not familiar with the specific SD card requirements, and whether the SS line is raised after each byte is sent, or should remain low for more than one byte transaction.  This will determine whether you can utilise the automatic SS output operation, or not.
 
I wonder if there might be some misunderstanding about the operation of the SPI.  For each SPI transaction, this is a two-way process.  When the master sends a byte value, the slave will simultaneously respond with a return value.  This value must be read by the master, whether or not the data is valid,.in order to clear the SPIF flag.
 
If you are expecting a response from a command byte, this will actually involve two byte transactions, the first one to send the command, and the second to receive the response.
 
unsigned char response;
 
vfnSPI_Send_Byte(command);  // Send command byte
u8SPI_Receive_Byte();       // Discard return value
vfnSPI_Send_Byte(0);        // Send dummy byte
response = u8SPI_Receive_Byte(); // Read response
 
Is the code sequence you are using anything like the above?
 
Regards,
Mac
 
0 Kudos

2,969 Views
JulianP
Contributor I
It was not like that but i tried it and it also does not work. Whats about the configuration? Anything wrong there? I have got an example of a configuration but it is written for an Atmel Chip. Maybe someone can see what difference between the Configs may cause the Problem
 
unselect/selectcard switches the CS input from the SD Card on and of
 
Code:
/* enable outputs for MOSI, SCK, SS, input for MISO */    configure_pin_mosi();    configure_pin_sck();    configure_pin_ss();    configure_pin_miso();    unselect_card();    /* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */           (1 << SPE)  | /* SPI Enable */           (0 << DORD) | /* Data Order: MSB first */           (1 << MSTR) | /* Master mode */           (0 << CPOL) | /* Clock Polarity: SCK low when idle */           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */           (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */           (1 << SPR0);    SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */

 
0 Kudos