• AVR Freaks

Hot!Issues with SD Card Initialisation

Author
AKJ
Starting Member
  • Total Posts : 49
  • Reward points : 0
  • Joined: 2019/05/27 06:55:52
  • Location: 0
  • Status: offline
2019/08/12 06:16:42 (permalink)
0

Issues with SD Card Initialisation

Hello,
 
i am trying to set up an SPI communication between my dsPIC33EP512GM706 and some SD card.
(Please note that i have already written Sd card libraries for the Arduino Platform (using the already provided SPI library, which made things easier)).
The issue that i have, is that the card doesn't return an R1 response, as i followed the example mentioned on this website: https://buildbrighton.com...ith-an-sd-card/ . My code fails in the sdInit() at "if(v != 1){fatal(2);} " (near the bottom of the page).
I initialized the SPI module like so:

 
void SPI2_init(void)
{
    SPI2_remap();
    SPI2STATbits.SPIEN = 0;
    SPI2STATbits.SPISIDL = 1;
    SPI2CON1bits.DISSCK = 0;
    SPI2CON1bits.DISSDO = 0;
    SPI2CON1bits.MODE16 = 0;
    SPI2CON1bits.SMP = 0;
    SPI2CON1bits.CKE = 0;
    SPI2CON1bits.SSEN = 0;
    SPI2CON1bits.CKP = 0;
    SPI2CON1bits.MSTEN = 1;
    SPI2STATbits.SPIROV = 0;
    SPI2CON1bits.SPRE = 0b010; // Prescaler: 6:1
    SPI2CON1bits.PPRE = 0b0; // Prescaler 64:1 // just for the initialization process
    SPI2CON2bits.FRMEN = 0;
    SPI2CON2bits.SPIFSD = 0;
    SPI2CON2bits.SPIBEN = 0;
    SPI2STATbits.SPIEN = 1;

    TRISGbits.TRISG7 = 1;
    TRISGbits.TRISG8 = 0;
    TRISGbits.TRISG6 = 0;
    TRISGbits.TRISG9 = 0;
}

 
and the transfer goes as so:

uint8_t SPI2_transfer(uint8_t value)
{
    uint8_t temp;
    temp = SPI2BUF;
    SPI2BUF = value;
    while (!SPI2STATbits.SPIRBF);
    return SPI2BUF;
}

The test code:

 
static uint8_t sdCrc7(uint8_t* chr, uint8_t cnt, uint8_t crc)
{
uint8_t i = 0, a = 0;
uint8_t data;
for (a = 0; a < cnt; a++){
data = chr[a];
for (i = 0; i < 8; i++)
{
crc <<= 1;
if ((data & 0x80) ^ (crc & 0x80)){
crc ^= 0x09;
}
data <<= 1;
}
}
return crc & 0x7F;
}
 
static inline void sdSendCommand(unsigned char cmd, uint32_t param)
{
uint8_t send[6];
send[0] = cmd | 0x40;
send[1] = param >> 24;
send[2] = param >> 16;
send[3] = param >> 8;
send[4] = param;
send[5] = (sdCrc7(send, 5, 0) << 1) | 1;
for (cmd = 0; cmd < sizeof(send); cmd++)
{
SPI2_transfer(send[cmd]);
}
}
 
static inline uint8_t sdReadResp(void)
{
uint8_t v = 0, i = 0;
PORTGbits.RG8 = 0;
do {
v = SPI2_transfer(0xFF);
} while ((i++ < 128) && (v == 0xFF));
return v;
}
 
static uint8_t sdCommandAndResponse(uint8_t cmd, uint32_t param)
{
uint8_t ret = 0;
SPI2_transfer(0xFF);
sdSendCommand(cmd, param);
ret = sdReadResp();
return ret;
}
 
uint8_t sdInit()
{
uint8_t v, tries = 0;
uint8_t sd;
sd = 0;
SPI2_init();
PORTGbits.RG8 = 1;
for (v = 0; v < 20; v++)
SPI2_transfer(0xFF);
PORTGbits.RG8 = 0;
v = sdCommandAndResponse(0, 0);
if (v != 1)
return 0;
v = sdCommandAndResponse(1, 0);
int i = 0;
for (i = 0; v != 0 && i < 50; i++)
{
int l = 0;
for (l = 0; l < 100; l++);
v = sdCommandAndResponse(1, 0);
}
if (v)
return 0; 
return 1;
}
 

 
So ... my questions are:
1. Did i set the clock rates right? The documentation states that the rate get calculated from the prescalers, which i have set to (64:1 and 6:1) to stay between 100 kHz and 400 kHz (for the initialization phase) from the formula: Fsck = (Fcy / (primary_prescaler * secondary_prescaler))
 
2. Am i doing something else wrong here?
 
Sorry for the long post and thank you.
post edited by AKJ - 2019/08/12 06:25:48
#1

5 Replies Related Threads

    Aussie Susan
    Super Member
    • Total Posts : 3618
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: Issues with SD Card Initialisation 2019/08/12 19:55:08 (permalink)
    5 (1)
    Don't write to the PORT, write to the LAT register.
    How have you set the analog/digital registers?
    How are you mapping the PPS registers? I assume that is in the 'SPI2_map()' function that you don't show us? On these devices, the SCK line must be mapped as both input and output (see the SPI FRM document for this MCU, Section 3.1).
    I cannot see any line in 'sdInit()' that calls the 'fatal()' function. It really does not help if you don't show us your real code.
    Did you set the clock right? Who knows as you have told us nothing about the oscillator setup. Also there is more to setting up the 'clock' than the SCK frequency. You need to check the data sheet for the SD Card interface to make sure that you are reading and writing on the correct clock edges.
    Are you doing something else wrong? - see above.
    I'm not clear if you have ever received anything on the SPI module. If not then that is one set of problems (possibly one of the above). If you have then it is probably a logical error in your code or a timing issue perhaps.
    Susan
    #2
    AKJ
    Starting Member
    • Total Posts : 49
    • Reward points : 0
    • Joined: 2019/05/27 06:55:52
    • Location: 0
    • Status: offline
    Re: Issues with SD Card Initialisation 2019/08/13 05:38:56 (permalink)
    0
    Aussie Susan,
     
    thanks for the reply.
    I have set the analog/digital registers in the SPI2_remap() function (see first code block) like so:

    void SPI2_remap(void)
    {
        OSCCONbits.IOLOCK = 0;
        RPINR22bits.SDI2R = 0x77;   //RG7->SPI2:SDI2
        RPINR22bits.SCK2R = 0x76;  //RG6->SPI2:SCK2OUT
        RPOR10bits.RP118R = 0x9;    //RG6->SPI2:SCK2OUT
        RPOR11bits.RP120R = 0x8;    //RG8->SPI2:SDO2
        ANSELG = 0;
        OSCCONbits.IOLOCK = 1;
    }

     
    I don't suppose, i have to modify the oscillator registers, like OSCCON.
    The fatal function from the tutorial, simply blinks an LED, prints a message via UART and goes into an infinite while loop. I decided to rather return 0 for failure;
     
    #3
    Aussie Susan
    Super Member
    • Total Posts : 3618
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: Issues with SD Card Initialisation 2019/08/13 19:29:05 (permalink)
    0
    Please read the data sheet about how to (un)lock the PPS registers - you cannot simply set/clear the IOLOCK bit. If you are using XC16 then look at the '__builtin_xxx' macros for how to write to the OSCCON register. Please do not try to code the unlock sequence in C.
    Also, the default settings are that the IOLOCK bit is no set which means the PPS registers are unlocked. However the default for the IOL1WAY config bit (whcih you also don't show) is to only allow the PPS registers to be unlocked once. My advice is to leave the PPS registers unlocked until right near the end of the development of your app.
    I repeat: have you ever received anything with this SPI? Try connecting SDI and SDO and send a known value and see what you receive.
    Have you put a scope on the SCK and SDO lines to check that the signals are correct?
    Susan
    #4
    AKJ
    Starting Member
    • Total Posts : 49
    • Reward points : 0
    • Joined: 2019/05/27 06:55:52
    • Location: 0
    • Status: offline
    Re: Issues with SD Card Initialisation 2019/08/14 01:52:35 (permalink)
    0
    Aussie Susan,
     
    thanks for your reply. I connected the SDI to the SDO and used the following code:

     
     
     
    int main(void)
     
     
     
    {
     
     
     
        pin_config();
        spi2_init(); 
     
     
     
        unsigned i, returned;
     
     
     
       for ( i = 0; i < 255; i++)
     
     
     
       {
     
     
     
             returned = spi2_exchangeByte(i);
     
     
     
       }
     
     
     
       return 0;
     
     
     
    }
     
     
     

    whereby

     
     
     
    void pin_config(void)
    {
    // // Output Latch Configuration
    LATG = 0x0;

    // Input/Output Configuration
    TRISGbits.TRISG6 = 0;
    TRISGbits.TRISG7 = 1; // MISO
    TRISGbits.TRISG8 = 0;
    TRISGbits.TRISG9 = 0; // SS

    // Analog / Digital Configuration
    ANSELG = 0;
     
     
     

    // SPI2 Pins remap (PPS)
    // __builtin_write_OSCCONL(OSCCON & 0xBF); // Unlock PPS
    RPOR11bits.RP120R = 0x08;
    RPINR22bits.SDI2R = 0x0077;
    RPINR22bits.SCK2R = 0x0076;
    RPOR10bits.RP118R = 0x09;
    // __builtin_write_OSCCONL(OSCCON | 0x40); // Lock PPS
    }
     
     
     

     
    and 
     

     
     
     
    bool spi2_init(void)
    {
        SPI2CON1bits.DISSCK = 0;
        SPI2CON1bits.DISSDO = 0;  
        SPI2CON1bits.MODE16 = 0;
        SPI2CON1bits.SMP = 0;
        SPI2CON1bits.CKE = 0; 
        SPI2CON1bits.SSEN = 0;
        SPI2CON1bits.CKP = 0;
        SPI2CON1bits.MSTEN = 1;
        SPI2CON1bits.SPRE = 0b010; // 6:1
        SPI2CON1bits.PPRE = 0b10; // 4:1
        SPI2CON2 = 0x00;
       SPI2STATbits.SPIEN = 1;
       return true;
    }
     
     
     

    Setting a breakpoint after 'returned'. I also tried it with the SD card connected. 
    Conclusion, the variable 'returned' and 'i' were the same, which means, that the SPI protocol was sucessfully implemented.
    This means that the issues lie between the clock speed, which i have according to the MCC, set to around 130kHz and the SD card initialization itself.
    I reread the SD card specification and see what i have missed.
     
    Thank you.
     
     
    Thanks.
    post edited by AKJ - 2019/08/14 03:34:38
    #5
    AKJ
    Starting Member
    • Total Posts : 49
    • Reward points : 0
    • Joined: 2019/05/27 06:55:52
    • Location: 0
    • Status: offline
    Re: Issues with SD Card Initialisation 2019/08/16 01:55:30 (permalink)
    4 (1)
    Aussie Susan,
     
    i managed to solve it. The issues where:
     
    1. Like you mentioned, changing the prescaler and the postscaler is not quite enough to manage the baud rate of the SPI module. I fetched the Oscillator documentation and configured the clock registers (cough cough ... by cheating a bit from Mplab Code configurator).
    2. This led to an invalid spi slow mode for the initialization
    3. The delays were incorrect, (cough cough ... by cheating from the SD card library of the Mplab Code Configurator) i needed to add proper delays for the controller i am using.
    4. Moreover, i need to add in the sendCommand() function, after sending the cmd | 0x40 and the argument, the following lines:

    timeout = (uint16_t)20;
    do
    {
         response = spi2_exchangeByte(0xFF);
        timeout--;
    } while ((response == 0xFF) && (timeout != 0));

     
    For all those in the future, stuck here. Just download the MCC plugin, set it up. Test the sd card initialization of the sd card library, then implement it into your code, if it returns true.
     
    Thanks for the help.
    #6
    Jump to:
    © 2019 APG vNext Commercial Version 4.5