November 27, 2021, 04:19:26 pm

[STM32-P405] - SD card issue

Started by narko38, November 15, 2015, 08:36:07 pm

Previous topic - Next topic

narko38

November 15, 2015, 08:36:07 pm Last Edit: November 15, 2015, 08:41:04 pm by narko38
Hello everyone,

I'm running through some issues trying to initialize a SD card on the STM32-P405 Olimex board.

I'm using STM32 HAL library. And I write my code adapting the STM32-P405 example downloadable on the product page.

I've read a lot of doc (http://elm-chan.org/docs/mmc/mmc_e.html) and the simplified SD card spec (https://www.sdcard.org/downloads/pls/part1_410.pdf).

I'm using a SDHC Nikon 4GB SD card.

I went through the init process until the command ACMD41, this command is suppose to return 0x00 at a certain point but I can't get this response, the command is always responding 0x01.

You will find the main parts of my code below.

SPI initialization

Spi2Handle.Instance = SPI2;
Spi2Handle.Init.Direction = SPI_DIRECTION_2LINES;
Spi2Handle.Init.Mode = SPI_MODE_MASTER;
Spi2Handle.Init.DataSize = SPI_DATASIZE_8BIT;
Spi2Handle.Init.CLKPolarity = SPI_POLARITY_HIGH;
Spi2Handle.Init.CLKPhase = SPI_PHASE_2EDGE;
Spi2Handle.Init.NSS = SPI_NSS_SOFT;
Spi2Handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
Spi2Handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
Spi2Handle.Init.CRCPolynomial = 7;
Spi2Handle.Init.TIMode = SPI_TIMODE_DISABLE;
HAL_SPI_Init(&Spi2Handle);


Init function

#define CS_LOW()  SET_BIT(GPIOB->BSRR,GPIO_BSRR_BR_12);  // Card Select
#define CS_HIGH() SET_BIT(GPIOB->BSRR,GPIO_BSRR_BS_12);  // Card Deselect

unsigned char ucInitCard(void)
{
   CS_HIGH();
   // Send 80 dummy clock
   for(i=0;i<=9;i++)
   {
      spiSendByte(0xFF);
   }
   CS_LOW();

   //Send Command 0 to put MMC in SPI mode
   ucSendCmd(0x00,0,0x95);
   //Now wait for READY RESPONSE
   if(ucGetResponse()!=0x01) // Idle state
   {
      trace_printf("Debug : SD card No response\n");
      return 0;
   }

   ucSendCmd(0x08,0x000001AA,0x86);
   if((response = ucGetResponse()) != 0x01)
   {
      trace_printf("Debug : SD card Not initialized | response = %d\n",response);
      return 0;
   }
   else // Read R7 (response to CMD8)
   {
      uint8_t r7Buf[4];
      int8_t y;

      for(y=3; y>=0; y--)
      {
         r7Buf[y] = ucGetResponse();
      }

      if( (r7Buf[0] == 0xAA) && (r7Buf[1] == 0x01)) // Check pattern OK and Voltage Ok
      {
         int timeout = 0xFFF;
         while( (response != 0x00) && (timeout>=0)) // repeat sequence until response = 0x00
         {
            ucSendCmd(0x37,0x0000,0x00); // CMD55
            if((response = ucGetResponse()) != 0x01)
            {
               trace_printf("Debug : SD card CMD55 error | response = %d\n",response);
               return 0;
            }
            else
            {
               ucSendCmd(0x29,0x4000,0x00); // ACMD41 (HCS (bit 30) = 1)

               if((response = ucGetResponse())==0x00) break;
               timeout--;
            }
         }
         if(timeout <= 0)
         {
            trace_printf("Debug : SD card ACMD41 timeout\n");
            return 0;
         }
         else
         {
            trace_printf("Debug : SD card ACMD41 OK (%d)\n",timeout);
         }
      }
      else
      {
         trace_printf("Debug : SD card CMD8 pattern or voltage dismatch\n");
         return 0;         
      }
   }
}


ucSendCmd function :

void ucSendCmd (const unsigned char cmd, unsigned long data, const unsigned char crc)
{
unsigned char frame[6];
unsigned char temp;
int i;

frame[0]=(cmd|0x40);
for(i=3;i>=0;i--){
temp=(unsigned char)(data>>(8*i));
frame[4-i]=(temp);
}
frame[5]=((crc | 0x01));
for(i=0;i<6;i++)
spiSendByte(frame[i]);
}


ucGetResponse function :

unsigned char ucGetResponse(void)
{
//Response comes 1-8bytes after command
//the first bit will be a 0
//followed by an error code
//data will be 0xff until response

unsigned char response = 0xFF ;

while(response == 0xFF)
{
response=spiSendByte(0xFF);
}
return response;
}


spiSendByte function :

unsigned char spiSendByte(unsigned char data)
{
uint8_t result = 0;

HAL_SPI_TransmitReceive(&Spi2Handle,&data,&result,1,1000);

return result;
}


I think my SPI peripheral is well configured because all the commands are responding. I can use CMD59 to turn CRC ON of OFF, when CRC is ON and CRC is invalid the card is responding correctly : 0b00001001 (bit0 means idle state = 1 and bit3 means invalid CRC).

I've seen somewhere that during the init process, SPI frequency has to be between 100-400 KHz then when the init process is down SPI frequency can be turn high. But in my case I've tried every option of the SPI baudrate prescaler.

Last point, all examples I've found so far seems to be executing with SD card capacity <= 2GB, I've only tested my code with 4 GB and 8 GB SD card. So I'm wondering : do every SD HC cards are compatible with SPI ? Might need a hardware modification on the board to be compatible ?

What do you think about that guys ?

Thanks for your help.

P.S : sorry for my english, it's not my mother tongue.