SPI and SDCard problem

Page: 123 > Showing page 1 of 3
Post
c.dicaprio
Starting Member
2007/05/29 14:45:41
Hello to all,
I have a problem! I can read i file from an SDCard connected directly to the SPI, I mean no pullup or pulldown attached to the SDI, SDO and SCK lines. I can open a file and read all the content. The problem is that I can do that only at 250KHz! I can initialize the SDCard, at 250KHz right!, but when I switch to 500KHz or 1MHz the SPI clock, they stop to work. For example for the ReadCID command I receive 0x00 for the command but 0xFF forever instend of 0xFE.
I use the same hardware for different MCU with the same software with the same result. But I can't found the problem.
The MCU I use are: dsPIC4013, dsPIC33FJ128GGP306 and the PIC24FJGA002. The hardware is the same: the SPI pins attached directly to the SDCard connector. I use a separate power regulator for the SDCard to switch off the power before the initialization. This is the code I use to read, write the SPI, write a command and read a block: (thanks to k9spud.com site)


unsigned char InitSD()
{
    unsigned int i = 0;
    unsigned char status;
    unsigned int vStartUp=0;

    // SPI2 OFF
    SPI2STAT = 0x0000;

    SD_PowerOff();
    SD_PWR_DIR = 0;     // output
    SD_PowerOff();

    SD_Enable();    // CS = 0; No Vdd
    SD_CS_DIR = 0;    // output
    SD_Enable();

    SDI = 0; SCK = 0; SDO = 0;
    SDI_DIR = 0; // output
    SCK_DIR = 0;
    SDO_DIR = 0;
    //
    SD_CD = 0; SD_WR = 0;
    SD_CD_DIR = 0;
    SD_WR_DIR = 0;

    // Turn off SD Card
    SD_Enable();    // CS = 0; No Vdd
    SD_PowerOff();

    vStartUp = timer_ticks;
    // Wait for power to really go down
    do
    {
        Nop();
    }while( (timer_ticks-vStartUp) < 500);
   
    // Turn on SD Card
    SD_PowerOn();
    SD_Disable();

    vStartUp = timer_ticks;
    // Wait for power to really come up
    do
    {
        Nop();
    }while( (timer_ticks-vStartUp) < 5);

    //
    InitSPI();

    // We need to give SD Card about a hundred clock cycles to boot up
    for(i = 0; i < 16; ++i)
    {
        SPIWrite(0xFF); // write dummy data to pump clock signal line
    }   

    SD_Enable();

    vStartUp = timer_ticks;
    do
    {
        Nop();
    }while( (timer_ticks-vStartUp) < 10);
   
    // This is the only command required to have a valid CRC
    // After this command, CRC values are ignore unless explicitly enabled using CMD59
    unsigned char CMD0_GO_IDLE_STATE[] = {0x00,0x00,0x00,0x00,0x00,0x95};

    // Wait for the SD Card to go into IDLE state
    i = 0;
    do
    {
        status = SD_WriteCommand(CMD0_GO_IDLE_STATE);

        // fail and return
        if(i++ > 50)
        {
            return 1;
        }
    } while( status != 0x01 );

    // Wait for SD Card to initialize
    unsigned char CMD1_SEND_OP_COND[] = {0x01,0x00,0x00,0x00,0x00,0xFF};

    i = 0;
    do
    {
        status = SD_WriteCommand(CMD1_SEND_OP_COND);
        if(i++ > 250)
        {
            return 2;
        }
    } while( (status & R1_IN_IDLE_STATE) != 0 );

    // Send CMD55, required to precede all "application specific" commands
    unsigned char CMD55_APP_CMD[] = {55,0x00,0x00,0x00,0x00,0xFF};
    status = SD_WriteCommand(CMD55_APP_CMD); // Do not check response here

    // Send the ACMD41 command to initialize SD Card mode (not supported by MMC cards)
    i = 0;
    unsigned char ACMD41_SD_SEND_OP_COND[] = {41,0x00,0x00,0x00,0x00,0xFF};
    do
    {
        status = SD_WriteCommand(ACMD41_SD_SEND_OP_COND);
        // Might return 0x04 for Invalid Command if MMC card is connected

        if(i++ > 50)
        {
            return 3;
        }
    } while( (status & R1_IN_IDLE_STATE) != 0 );

    // Set the SPI bus to full speed now that SD Card is initialized in SPI mode
    SD_Disable();
    SPIFastClock();

    return 0;
}

void InitSPI(void)
{
   
    SDI_DIR = 1; // input
    SCK_DIR = 0;
    SDO_DIR = 0;
    //
    SD_CD_DIR = 1;
    SD_WR_DIR = 1;

    // SPI2 Off   
    SPI2STAT = 0x0000;
   
    //
    SPI2CON1 = 0x0000;
    SPI2CON1 |= SEC_PRESCAL_4_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // 250KHz
    SPI2CON1bits.MSTEN = 1;
    SPI2CON1bits.CKP = 1;
    SPI2CON1bits.CKE = 0;
    SPI2CON1bits.SMP = 0;

    SPI2CON2 = 0x0000;
    //
    SPI2STAT = 0x8000; // enable SPI port

}


void SPIWrite(unsigned char data)
{
    // DO NOT WAIT FOR SPITBF TO BE CLEAR HERE
    // (for some reason, it doesn't work on this side of the write data).


    // Write the data!
    SPI2BUF = data;

    // Wait until send buffer is ready for more data.
    while(SPI2STATbits.SPITBF);
    SPI2STATbits.SPIROV = 0;
}

unsigned char SPIRead(void)
{
    unsigned char data;

    if(SPI2STATbits.SPIRBF)
    {
        // already have some data to return, don't initiate a read
        data = SPI2BUF;

        SPI2STATbits.SPIROV = 0;
        return data;
    }

    // We don't have any data to read yet, so initiate a read
    SPI2BUF = 0xFF;  // write dummy data to initiate an SPI read
    while(SPI2STATbits.SPITBF);     // wait until the data is finished reading
   
    data = SPI2BUF;

    SPI2STATbits.SPIROV = 0;
    return data;
}

unsigned char SD_WriteCommand(unsigned char* cmd)
{
    unsigned int i;
    unsigned char response;
    unsigned char savedSD_CS = SD_CS;

    // SD Card Command Format
    // (from Section 5.2.1 of SanDisk SD Card Product Manual v1.9).
    // Frame 7 = 0
    // Frame 6 = 1
    // Command (6 bits)
    // Address (32 bits)
    // Frame 0 = 1

    // Set the framing bits correctly (never change)
    cmd[0] |= (1<<6);
    cmd[0] &= ~(1<<7);
    cmd[5] |= (1<<0);


    // Clem: 8 clocks to startup??
    SPIWrite(0xFF);
       
    // Send the 6 byte command
    SD_Enable();

   
    for(i = 0; i < 6; ++i)
    {
        SPIWrite(*cmd);
        cmd++;
    }
   
    // Wait for the response
    i = 0;
    do
    {
        response = SPIRead();

        if(i > 100)
        {
            Nop();
            break;
        }
        i++;
    } while(response == 0xFF);

    SD_Disable();

    // Following any command, the SD Card needs 8 clocks to finish up its work.
    // (from SanDisk SD Card Product Manual v1.9 section 5.1.8)
    SPIWrite(0xFF);

    SD_CS = savedSD_CS;
    return(response);
}


void SPIFastClock( void)
{
    // SPI2CON1 = 0x007B;
   
    SPI2STAT = 0x0000;    // disable SPI port
    SPI2CON1 = 0x0000;
    SPI2CON1 |= SEC_PRESCAL_4_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // it's OK @250KHz
    // SPI2CON1 |= SEC_PRESCAL_2_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // it's bad @500KHz
    SPI2CON1bits.MSTEN = 1;
    SPI2CON1bits.CKP = 1;
    SPI2CON1bits.CKE = 0;
    SPI2CON1bits.SMP = 0;

    SPI2CON2 = 0x0000;
    //
    SPI2STAT = 0x8000; // enable SPI port
}

unsigned char SD_ReadCID(unsigned char *buf)
{
    unsigned int i;
    unsigned char status;

    unsigned char CMD10_READ_SINGLE_BLOCK[] = {10,0x00,0x00,0x00,0x00,0xFF};

    SD_Enable();

    // Send the read command
    status = SD_WriteCommand(CMD10_READ_SINGLE_BLOCK);
    if(status != 0)
    {
        // ABORT: invalid response for read single command
        return 1;
    }
   
    // Now wait for the "Start Block" token    (0xFE)
    // (see SanDisk SD Card Product Manual v1.9 section 5.2.4. Data Tokens)
    do
    {
        status = SPIRead();
    } while(status != 0xFE);      // @500KHz the code loop forever...
       
    // Read off all the bytes
    for(i = 0; i < 16; ++i)
    {
        status = SPIRead();
        *buf = status;
        buf++;
    }
   
    // Read CRC bytes
    status = SPIRead();
    status = SPIRead();

    SD_Disable();

    // Following a read transaction, the SD Card needs 8 clocks after the end
    // bit of the last data block to finish up its work.
    // (from SanDisk SD Card Product Manual v1.9 section 5.1.8)
    SPIWrite(0xFF);

    return 0;
}



Which tests can I do? Any suggestions?
TIA
Clemente.
soman
Starting Member
SPI and SDCard problem 2007/05/30 01:07:53
u perform one sequence, check whether ur card will be able to do this or not
first u write one block then read it back with same 250 KHz frequency
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/05/30 07:59:27
ORIGINAL: soman

u perform one sequence, check whether ur card will be able to do this or not
first u write one block then read it back with same 250 KHz frequency

Hello soman, thanks for the replay.
I'm be able to read an entire file, circa 200KByte, from the SDCard without problem. I posted only the code about the low level access to the SPI. At 250KHz, the FAT16 code I use, is working well. After I call the SPIFastClock function, changing the SPI clock at 500KHz for example, I can't access the SDCard any more!
Is it possible that I'm using the wrong "SPI mode"?

Regards

Clemente.
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/05/30 10:16:29
Hello again,
I make some tests, trying to change from SPI mode 1,1 (CKP=1,CKE=0) to mode 0,0 (CKP=0,CKE=1) but the problem remain.
I add a pullup resistor to the SDI and SDO lines but without success.
Some ideas...

TIA
Clemente
isa.guru
Super Member
RE: SPI and SDCard problem 2007/05/30 10:20:41
Is the SDCard capable of working at 500kHz or 1 MHz?
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/05/30 10:36:00
ORIGINAL: isa.guru

Is the SDCard capable of working at 500kHz or 1 MHz?

Hello isa.guru, thanks for the replay.
Good question! I will try to read the CSD register for this information. By the way I'm using two cards: a 16MByte Toshiba, very old, and a 256MByte SanDisk more recent, 2 year old I think. But I have problem with both.
I will back soon with the result!

Bye
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/05/30 13:49:08
I read the CSD register, @250KHz of course, and this is the output:
00 2D 00 32 13 59 80 E3 76 D9 CF 80 16 40 00 9B
So the TRANS_SPEED field (the maximum data transfer rate) is 0x32 that is 25MHz.

Attached the schematic of the board. I hope can help...

TIA
Clemente

Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/05/30 14:26:16
Hi
In a quick view at your schematic sv1 i asume the numbers correspond to the sdcard. If so then double check if your cardholder is correctly hooked up. see my post here
http://forum.microchip.com/tm.aspx?m=240818&mpage=1&key=&#241146
No divider circuit will be needed of course but the first pin is number 9 from a sdcard holder: front view
-------------------------
|9 1 2 3 4 5 6 7 8 WP CD|
-------------------------
 | | | | | | | | | |  |   |
CD pullup 10K to 5V supply
WP pullup 10K to 5V supply
08  not connected
07  data out to SDI mcu
06  gnd to gnd
05  clk to SCL (divider) mcu
04  3.3V to 3.3V supply
03  gnd to gnd
02  data in to SDO (divider) mcu
01  cs to to RB3 (divider) mcu
09  not connected

c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/05/30 21:24:10
Hello Neiwiertz, thanks for the replay.
ORIGINAL: Neiwiertz
In a quick view at your schematic sv1 i asume the numbers correspond to the sdcard.

sv1 is a 10 pin connector to a little board with the sdcard holder.


see my post here
http://forum.microchip.com/tm.aspx?m=240818&mpage=1&key=&#241146

I can follow the Elm Chan's design and add the pullup and pulldown resistor. Which value of resistor is it correct? Elm use 100K resistors (http://elm-chan.org/works/glg/glg_sch.png), but in your post you tell about 50K resistors.

Thanks again
Clemente
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/05/31 09:59:19
Hello Clemente

when using 50K or 100K should make no difference it's just the purpose that unused pins of the sdcard holder are not floating -> 8 and 9 (but if no pullups are used it should also work)  actually the pulldown on the clock line i should leave it out and attach the clock line directly to the mcu spi sck. For more info have a look at appendix from appnote AN1003 where you can find a schematic also. There are ic used to do the level conversion instead of a resistor divider because 18F4550 runs at 5V.

I quess 10pin connenctor is a flatcable or something to a little board wich containing the sdcard holder am i right? Keep that flatcable as short as possible anyway. I assume the sdcard cardholder is correctly connected to sv1 now? Be aware the first pin of the sdcard cardholder is pin number 9.

Regards
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/05/31 10:45:43
Hello Neiwiertz,
ORIGINAL: Neiwiertz
I quess 10pin connenctor is a flatcable or something to a little board wich containing the sdcard holder am i right?

Yes, bingo!

Keep that flatcable as short as possible anyway. I assume the sdcard cardholder is correctly connected to sv1 now? Be aware the first pin of the sdcard cardholder is pin number 9.

The flatcable is 20cm long. No more. @500KHz, I think, there is no problem. And I have the same problem on a board, with a dsPIC33, with the card holder soldered. It is why I'm focused on a missed "pullup/down" problem or a software problem, like mode 1,1 for the SPI.
Any way I can change the flatcable for a test, but before to do that I want to make a test changing the "fast" SPI speed to a value small than 250KHz. Just a test...

Thanks.
Clemente
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/05/31 11:58:43
Hint
take a look here http://forum.microchip.com/tm.aspx?m=231763
I think the software is causing trouble too[8|]

Next will be to port over an1003 sdcard.c on your mcu and learn from the spi functions abovewink.
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/05/31 14:32:53
ORIGINAL: Neiwiertz

Hint
take a look here http://forum.microchip.com/tm.aspx?m=231763
I think the software is causing trouble too[8|]

Next will be to port over an1003 sdcard.c on your mcu and learn from the spi functions abovewink.

Thanks Neiwiertz.
I hope to came back with good news!

Clemente.
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/02 07:23:31
Hello again to all.
I follow the Neiwiertz's istruction but without success! Thanks again Neiwiertz.
The an1003 is a goot start point, and I use some tips for my code, but without success.

So now I'm focused on the SPIFastClock procedure.
The problem here is that if I change only the prescaler value the speed does not change.

//
#define  SEC_PRESCAL_1_1        0b0000000000011100  /* Secondary Prescale 1:1   */
#define  SEC_PRESCAL_2_1        0b0000000000011000  /* Secondary Prescale 2:1   */
#define  SEC_PRESCAL_3_1        0b0000000000010100  /* Secondary Prescale 3:1   */
#define  SEC_PRESCAL_4_1        0b0000000000010000  /* Secondary Prescale 4:1   */
#define  SEC_PRESCAL_5_1        0b0000000000001100  /* Secondary Prescale 5:1   */
#define  SEC_PRESCAL_6_1        0b0000000000001000  /* Secondary Prescale 6:1   */
#define  SEC_PRESCAL_7_1        0b0000000000000100  /* Secondary Prescale 7:1   */
#define  SEC_PRESCAL_8_1        0b0000000000000000  /* Secondary Prescale 8:1   */

#define  PRI_PRESCAL_1_1        0b0000000000000011  /* Primary Prescale 1:1     */
#define  PRI_PRESCAL_4_1        0b0000000000000010  /* Primary Prescale 4:1     */
#define  PRI_PRESCAL_16_1       0b0000000000000001  /* Primary Prescale 16:1    */
#define  PRI_PRESCAL_64_1       0b0000000000000000  /* Primary Prescale 64:1    */

void SPIFastClock( void)
{
    // SPI2CON1 = 0x007B;
   
//    SPI2STAT = 0x0000;    // disable SPI port
//    SPI2CON1 = 0x0000;
//    SPI2CON1 |= SEC_PRESCAL_4_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // 250KHz
    SPI2CON1 |= SEC_PRESCAL_2_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // 500KHz
//    SPI2CON1 |= SEC_PRESCAL_6_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // 167KHz
//    SPI2CON1 |= SEC_PRESCAL_4_1; SPI2CON1 |= PRI_PRESCAL_64_1;            // 64KHz
//    SPI2CON1bits.MSTEN = 1;
//    SPI2CON1bits.CKP = 1;
//    SPI2CON1bits.CKE = 0;
//    SPI2CON1bits.SMP = 0;
//
//    SPI2CON2 = 0x0000;
//   
//    SPI2STAT = 0x8000; // enable SPI port
   
}

To really change the speed I need to disable and then enable the SPI.
Is it a normal procedure? Is it possible that this "enable/disable" put the SDCard in a "wrong" state?
( I know, I'm climbing on a mirror) :-)

TIA
Clemente
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/02 10:54:26
Hi Clemente

from my other thread see the OpenSPI1 function, this function is used in the an1003 MediaInitialize function. sdcard init takes place below <400KHz then almost at the end of this function before sending the blocklen command the speed can be increased. For example i used this on explorer16

    SPI1CON1bits.SPRE2=1; //1:1  Fcy=32MHz DOZE 1:1 32000/1=32MHz
    SPI1CON1bits.SPRE1=1;
    SPI1CON1bits.SPRE0=1;
    SPI1CON1bits.PPRE1=1; //1:1
    SPI1CON1bits.PPRE0=1;

No need to enable or disable spi for changing spi speed!wink

I was wondering can you post your code (main with the ported an1003 sdcard) that will help us to fix your sdcard problem
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/02 16:04:20
ORIGINAL: Neiwiertz
No need to enable or disable spi for changing spi speed!wink
I was wondering can you post your code (main with the ported an1003 sdcard) that will help us to fix your sdcard problem

Hello Neiwiertz, thanks for your response.
I make a program for test, taking only the Init code and the change speed procedure. I run into problem with this small part too.
This is the code:


/*
*/
#include <p24fj64ga002.h>

/*
Prototype
*/
void InitModule( void);  // Peripheral pin select
void InitBoard( void);    // I/O pin setting
void InitSerial( void);    // Serial @57600
void InitTimer( void);    // 1 tick every 1ms
void InitSPI(void);        // first time @250KHz
void SPIFastClock( void);  // High speed @500KHz
// Misc function
void display_buffer(unsigned char * ptr, unsigned int size);
int write(int handle, void *buffer, unsigned int len);
void SPIWrite(unsigned char data);

/*
Define for serial speed
*/
#define XTFREQ          8000000L                 //On-board Crystal frequency
#define PLLMODE         2L                       //On-chip PLL setting
#define FCY             ((XTFREQ*PLLMODE))        //Instruction Cycle Frequency
#define BAUDRATE         57600   
#define BRGVAL          ( (FCY/BAUDRATE)/16L)-1L

/*
Define for SPI and SDCard
*/
#define  SEC_PRESCAL_1_1        0b0000000000011100  /* Secondary Prescale 1:1   */
#define  SEC_PRESCAL_2_1        0b0000000000011000  /* Secondary Prescale 2:1   */
#define  SEC_PRESCAL_3_1        0b0000000000010100  /* Secondary Prescale 3:1   */
#define  SEC_PRESCAL_4_1        0b0000000000010000  /* Secondary Prescale 4:1   */
#define  SEC_PRESCAL_5_1        0b0000000000001100  /* Secondary Prescale 5:1   */
#define  SEC_PRESCAL_6_1        0b0000000000001000  /* Secondary Prescale 6:1   */
#define  SEC_PRESCAL_7_1        0b0000000000000100  /* Secondary Prescale 7:1   */
#define  SEC_PRESCAL_8_1        0b0000000000000000  /* Secondary Prescale 8:1   */

#define  PRI_PRESCAL_1_1        0b0000000000000011  /* Primary Prescale 1:1     */
#define  PRI_PRESCAL_4_1        0b0000000000000010  /* Primary Prescale 4:1     */
#define  PRI_PRESCAL_16_1       0b0000000000000001  /* Primary Prescale 16:1    */
#define  PRI_PRESCAL_64_1       0b0000000000000000  /* Primary Prescale 64:1    */

#define SD_PWR         LATBbits.LATB11                // Pin 22
#define SD_PWR_DIR     TRISBbits.TRISB11            //
#define SD_CS         LATBbits.LATB12                // Pin  23
#define SD_CS_DIR     TRISBbits.TRISB12            //

#define SD_WR        PORTBbits.RB2            // Pin  6
#define SD_WR_DIR    TRISBbits.TRISB2            //
#define SD_CD        PORTBbits.RB3            // Pin  7
#define SD_CD_DIR    TRISBbits.TRISB3            //

#define SDI         PORTBbits.RB14            // Pin  25
#define SDI_DIR     TRISBbits.TRISB14
#define SCK         PORTBbits.RB15            // Pin  26
#define SCK_DIR     TRISBbits.TRISB15
#define SDO         PORTBbits.RB13            // Pin  24
#define SDO_DIR     TRISBbits.TRISB13

#define SD_PowerOn()     SD_PWR = 1
#define SD_PowerOff()     SD_PWR = 0
#define SD_Enable()     SD_CS = 0 /* set low to activate SD Card chip select */
#define SD_Disable()     SD_CS = 1 /* set high to deactivate SD Card chip select */


// general clock
unsigned int timer_ticks;

int main( void)
{
   unsigned int vTime=0;
  
   CLKDIVbits.RCDIV = 0;    // FRC Postscaler Select bits: 0=8MHz
   //
   InitModule();
   //
   InitBoard();
   InitSerial();
   InitTimer();            // clock di servizio   
   InitSPI();                // @250KHz
  
   vTime = timer_ticks;
   do
   {
       SPIWrite(0xAA);
   }while( ( timer_ticks-vTime) < 10000);
  
   // Speed up SPI freq.
   SPIFastClock();            // @500KHz
  
   vTime = timer_ticks;
   do
   {
       SPIWrite(0xAA);
   }while( ( timer_ticks-vTime) < 10000);

   // loop...
   while(1);
  
}


void SPIWrite(unsigned char data)
{
   // DO NOT WAIT FOR SPITBF TO BE CLEAR HERE
   // (for some reason, it doesn't work on this side of the write data).


   // Write the data!
   SPI2BUF = data;

   // Wait until send buffer is ready for more data.
   while(SPI2STATbits.SPITBF);
   SPI2STATbits.SPIROV = 0;
}

void InitSPI(void)
{
  
   SDI_DIR = 1; // input
   SCK_DIR = 0;
   SDO_DIR = 0;
   //
   SD_CD_DIR = 1;
   SD_WR_DIR = 1;

   // SPI2 Off   
   SPI2STAT = 0x0000;
  
   // Azzero i bit dei due prescaler...
   SPI2CON1 = 0x0000;
   SPI2CON1 |= SEC_PRESCAL_4_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // 250KHz
   SPI2CON1bits.MSTEN = 1;
   SPI2CON1bits.CKP = 0;
   SPI2CON1bits.CKE = 1;
   SPI2CON1bits.SMP = 0;

   SPI2CON2 = 0x0000;
   //
   SPI2STAT = 0x8000; // enable SPI port

}

void SPIFastClock( void)
{
   // SPI2CON1 = 0x007B;
  
//    SPI2STAT = 0x0000;    // disable SPI port
//    SPI2CON1 = 0x0000;
//    SPI2CON1 |= SEC_PRESCAL_4_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // 250KHz
//    SPI2CON1 |= SEC_PRESCAL_2_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // 500KHz
//    SPI2CON1 |= SEC_PRESCAL_6_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // 167KHz
//    SPI2CON1 |= SEC_PRESCAL_4_1; SPI2CON1 |= PRI_PRESCAL_64_1;            // 64KHz
//    SPI2CON1bits.MSTEN = 1;
//    SPI2CON1bits.CKP = 1;
//    SPI2CON1bits.CKE = 0;
//    SPI2CON1bits.SMP = 0;
//
//    SPI2CON2 = 0x0000;
//   
//    SPI2STAT = 0x8000; // enable SPI port

  SPI2CON1bits.SPRE2=1;         //2:1
  SPI2CON1bits.SPRE1=1;
  SPI2CON1bits.SPRE0=0;
  SPI2CON1bits.PPRE1=0;         //16:1                                         111111
  SPI2CON1bits.PPRE0=1;        //                                                54321098 76543210
  Nop();                               // Break point here SPI2CON is          00000001 00110001
                                         // No change to the SecPresc bits.                        ssspp
  Nop();
}

void __attribute__((__interrupt__)) _T1Interrupt(void)
{

   timer_ticks++;

   // Blink del LED1 ogni secondo.
   if (( timer_ticks % 500) == 0)
       _LATB5 = !_LATB5;
          
   /* reset timer 1 interrupt flag */
   IFS0bits.T1IF = 0;   
}

void InitTimer( void)
{
   /*
    Timer1 setup
   */
   TMR1 = 0;                // Clear timer 1
   PR1 = 0x003E;            // Interrupt every 1ms
   IFS0bits.T1IF = 0;        // Clear interrupt flag
   IEC0bits.T1IE = 1;        // Set interrupt enable bit
   T1CON = 0x8030;            // Fosc/2, 1:256 prescale, start TMR1
}

void InitSerial( void)
{
   /*
    UART setup
   */
   U1BRG  = BRGVAL;
   U1MODE = 0x8000;         // Reset UART to 8-n-1, alt pins, and enable
   U1STA  = 0x0440;         // Reset status register and enable TX & RX
   _U1RXIF=0;                    // Clear UART RX Interrupt Flag   
}


void InitBoard( void)
{
  
   AD1PCFG = 0xFFFF;            // Make analog pins digital
      
   LATB = 0x0000;
   _TRISB5 = 0;                // port 5 as output (Led)
   _TRISB6 = 1;                // port 6 as input (button)
   _TRISB2 = 1;                // port 2 as input (SDCard Write Enable)
   _TRISB3 = 1;                // port 3 as input (SDCard Card Detect)

   _CN24PUE = 1;                // port RB6 (CN24) pullup enabled (button)
  
}


void InitModule( void)
{
   // Programmo la UART1
   RPINR18bits.U1RXR = 9;    // Make Pin RP9 U1RX (pin 18)
   RPOR4bits.RP8R = 3;        // Make Pin RP8 U1TX (pin 17)

   // Programmo la SPI2
   RPINR22bits.SDI2R = 14;        // Make Pin RP14 SDI2 (pin 25)
   RPOR6bits.RP13R = 10;        // Make Pin RP13 SDO2 (pin 24)
   RPOR7bits.RP15R = 11;        // Make Pin RP15 SCK2 (pin 26)
}

#define    TXBF    0x0200u
/*
In order to redirect stdout to an alternate peripheral (or other outlet),
the user just needs to provide a write() function:
int write(int handle, void *buffer, unsigned int len);

The default function is 'weak' and therefore overridable by a user function.
The source for the default function can be found in the MPLAB C30 installation directory:
<\src\pic30\write.c>

*/
int write(int handle, void *buffer, unsigned int len)
{
   int i;
  
   /*
   handle 0 corresponds to stdout
   handle 1 corresponds to stdin
   handle 2 corresponds to stderr
   */
   switch (handle)
   {
       case 0:
       case 1:
       case 2:
       default:
           for (i = len; i; --i)
           {
               while (U1STA & TXBF)
                   ;
               U1TXREG = *(char*)buffer++;
           }
   }
   return(len);
}

void display_buffer(unsigned char * ptr, unsigned int size)
{
   unsigned int i;
   unsigned int j;
   unsigned char * local;
  
   local = ptr;
   for (i=0; i < size; i++)
   {
       if (!(i % 16)) {
           if (i) {
               for (j=0;j<16;j++)
               {
                   if (*local < 32)
                       printf(" .");
                       // putc('.',stdout);
                   else
                       // printf("%s",*local);
                       printf("%02c",*local);        // zero padding, 2 char size
                       // putc(*local, stdout);
                   local++;
               }
           }
           printf("\r\n%4X - ",i);
       }
       printf("%02X ",*ptr++);    // zero padding, 2 char size
   }
  
   for (j=0;j<16;j++)
       {
       if (*local < 32)
           printf(" .");
       else
           // printf("%s",*local);
           printf("%02c",*local);        // zero padding, 2 char size
       local++;
       }
   printf("\r\n");
}


The code is very simple. After the MCU initialization the program write for 10sec the byte 0xAA to the SPI.
Then the code changes the SPI speed and write again for 10sec the byte 0xAA to the SPI.

I test the SPI clock with an oscilloscope, and never changes! I see inside the windows "File Register" that the secondary prescaler bits never changes.
I can add the other SDCard specific code to this program, without the FAT16 code, to test it better. But I think I need to resolve the speed problem first.

TIA

Clemente
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/03 08:45:41
Hi
I can add the other SDCard specific code to this program, without the FAT16 code, to test it better. But I think I need to resolve the speed problem first.
OK

I used this code below on a 24FJ128GA010, check datasheet for your mcu registers. Try it first without the tick, using some pushbutton for switching speed and verify speed using oscilloscope.
Actually i can't verfiy the speed here now therefore i am not sure if the speed increases up to 32Mhz using the method below but the sdcard is working so the speed must 333.33Khz and then changed to the 32Mhz i guess.
Maby the speed will sticked at 333.33KHz here too i don't yet sounds interesting to verify itSmile

Regards


void OpenSPI1(void)
{  IFS0bits.SPI1IF = 0;
  IEC0bits.SPI1IE = 0;

  SPI1CON1bits.DISSCK=0;
  SPI1CON1bits.DISSDO=0;
  SPI1CON1bits.MODE16=0;
  SPI1CON1bits.SMP=0;
  SPI1CON1bits.CKE=1;
  SPI1CON1bits.SSEN=0;
  SPI1CON1bits.CKP=0;
  SPI1CON1bits.MSTEN=1;
  SPI1CON1bits.SPRE2=0; //6:1  Fcy=32MHz DOZE 1:1 32000/96=333.33KHz
  SPI1CON1bits.SPRE1=1;
  SPI1CON1bits.SPRE0=0;
  SPI1CON1bits.PPRE1=0; //16:1
  SPI1CON1bits.PPRE0=1;
  SPI1CON2bits.FRMEN=0;
  SPI1STATbits.SPISIDL=0;

  SPI1STATbits.SPIROV=0;
  SPI1STATbits.SPIEN=1;
}


void CloseSPI1(void)
{ //Disable the Interrupt bit in the  Interrupt Enable Control Register
IEC0bits.SPI1IE=0;       

//Disable the module. All pins controlled by PORT Functions  
SPI1STATbits.SPIEN=0;  

//Disable the Interrupt flag bit in the Interrupt Flag Control Register
IFS0bits.SPI1IF=0;

}       


unsigned int ReadSPI1(void)
{ unsigned int data;
   SPI1STATbits.SPIROV = 0;
   SPI1BUF=0x00;
   while(!SPI1STATbits.SPIRBF);

   if(SPI1CON1bits.MODE16) {
     data=SPI1BUF;
   }else{
     data=SPI1BUF&0x00ff;
   }
return(data);
}


void WriteSPI1(unsigned int data)
{ if(SPI1CON1bits.MODE16) {
   SPI1BUF=data;
}else{
   SPI1BUF=data&0x00ff;
}
while(SPI1STATbits.SPITBF);
data=SPI1BUF;
}

// Setup configuration bits
_CONFIG1(0xBF6F)
_CONFIG2(0x7BBE)

void main (void)
{  _COSC2=0;
  _COSC1=1;
  _COSC0=1;
  _NOSC2=0;
  _NOSC1=1;
  _NOSC0=1;
_CLKLOCK=0;
_SOSCEN=0;
_OSWEN=0;

_ROI=0;
//_DOZE
_DOZE2=0;
_DOZE1=0;
_DOZE0=0;
_DOZEN=1;
//_RCDIV
_RCDIV2=0;
_RCDIV1=0;
_RCDIV0=0;

//_TUN
_TUN5=0;
_TUN4=0;
_TUN3=0;
_TUN2=0;
_TUN1=0;
_TUN0=0;


  while(!_LOCK);
  CloseSPI1();
  CNPU1=0x0000;
  CNPU2=0x0000;
  AD1PCFG=0xffff;
  AD1CON1=0;
  TRISBbits.TRISB1=0;        //Output RB1 SDC_CS
  //Done by SPI1STAT.SPIEN
  TRISFbits.TRISF6=0;        //Output RF6/SCK1
  TRISFbits.TRISF7=1;        //Input  RF7/SDI1_E
  TRISFbits.TRISF8=0;        //Output RF8/SDO1_E
  LATBbits.LATB1=1;

OpenSPI1();
while(button) WriteSPI1(0xaa);

  SPI1CON1bits.SPRE2=1; //1:1  Fcy=32MHz DOZE 1:1 32000/1=32MHz
  SPI1CON1bits.SPRE1=1;
  SPI1CON1bits.SPRE0=1;
  SPI1CON1bits.PPRE1=1; //1:1
  SPI1CON1bits.PPRE0=1;
while(1) WriteSPI1(0xaa);  

}
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/03 14:44:14
ORIGINAL: Neiwiertz
 Try it first without the tick, using some pushbutton for switching speed and verify speed using oscilloscope.

Hello Neiwiertz, thanks for your time!
I modify the code for my MCU, adding the setup of the module, and changing the configuration bits. I use the FRC with prescaler and PLL. I change the SPI too, because I use the SPI2 insteand of SPI1. And I use the button to switch from one speed to the other, but without success. From the oscilloscope, the speed was the same. I use first to change from 250KHz to 500KHz, like my original code, then I use to change from 2MHz to 500KHz but again without success.
Where am I wrong again?

This is my modified code:

/*
*/
#include <p24fj64ga002.h>

void InitModule( void);
void OpenSPI2(void);
void CloseSPI2(void);
unsigned int ReadSPI2(void);
void WriteSPI2(unsigned int data);

void InitModule( void)
{
    // Programmo la UART1
    RPINR18bits.U1RXR = 9;    // Make Pin RP9 U1RX (pin 18)
    RPOR4bits.RP8R = 3;        // Make Pin RP8 U1TX (pin 17)

    // Programmo la SPI2
    RPINR22bits.SDI2R = 14;        // Make Pin RP14 SDI2 (pin 25)
    RPOR6bits.RP13R = 10;        // Make Pin RP13 SDO2 (pin 24)
    RPOR7bits.RP15R = 11;        // Make Pin RP15 SCK2 (pin 26)
}


void OpenSPI2(void)

 IFS2bits.SPI2IF = 0;
 IEC2bits.SPI2IE = 0;

 SPI2CON1bits.DISSCK=0;
 SPI2CON1bits.DISSDO=0;
 SPI2CON1bits.MODE16=0;
 SPI2CON1bits.SMP=0;
 SPI2CON1bits.CKE=1;
 SPI2CON1bits.SSEN=0;
 SPI2CON1bits.CKP=0;
 SPI2CON1bits.MSTEN=1;
 SPI2CON1bits.SPRE2=1; //4:1  Fcy=16MHz DOZE 1:1 16000/64=250KHz
 SPI2CON1bits.SPRE1=0;
 SPI2CON1bits.SPRE0=0;
 SPI2CON1bits.PPRE1=0; //16:1
 SPI2CON1bits.PPRE0=1;
 SPI2CON2bits.FRMEN=0;
 SPI2STATbits.SPISIDL=0;

 SPI2STATbits.SPIROV=0;
 SPI2STATbits.SPIEN=1;
}


void CloseSPI2(void)
{ //Disable the Interrupt bit in the  Interrupt Enable Control Register
 IEC2bits.SPI2IE=0;       
 
 //Disable the module. All pins controlled by PORT Functions  
 SPI2STATbits.SPIEN=0;  
 
 //Disable the Interrupt flag bit in the Interrupt Flag Control Register
 IFS2bits.SPI2IF=0;
 
}       


unsigned int ReadSPI2(void)
{ unsigned int data;
  SPI2STATbits.SPIROV = 0;
  SPI2BUF=0x00;
  while(!SPI2STATbits.SPIRBF);
 
  if(SPI2CON1bits.MODE16) {
    data=SPI2BUF;
  }else{
    data=SPI2BUF&0x00ff;
  }
 return(data);
}


void WriteSPI2(unsigned int data)
{ if(SPI2CON1bits.MODE16) {
  SPI2BUF=data;
 }else{
  SPI2BUF=data&0x00ff;
 }
 while(SPI2STATbits.SPITBF);
 data=SPI2BUF;
}

// Setup configuration bits
//_CONFIG1(0xBF6F)
//_CONFIG2(0x7BBE)

int main (void)
{
    _COSC2=0;
    _COSC1=0;
    _COSC0=1;
    _NOSC2=0;
    _NOSC1=0;
    _NOSC0=1;        // Fast RC Oscillator with postscaler and PLL
    _CLKLOCK=0;
    _SOSCEN=0;
    _OSWEN=0;
   
    _ROI=0;
    //_DOZE
    _DOZE2=0;
    _DOZE1=0;
    _DOZE0=0;        // CPU Peripheral Clock Ratio Select bits: 1:1
    _DOZEN=1;        // DOZE2:DOZE0 bits specify the CPU peripheral clock ratio
    //_RCDIV
    _RCDIV2=0;
    _RCDIV1=0;
    _RCDIV0=0;        // FRC @8MHz
   
    //_TUN
    _TUN5=0;
    _TUN4=0;
    _TUN3=0;
    _TUN2=0;
    _TUN1=0;
    _TUN0=0;        // Center frequency, oscillator is running at factory calibrated frequency
   
   
    while(!_LOCK);
   
    InitModule();    // UART and SPI2 configured. (UART module not used here)
   
    CloseSPI2();
    CNPU1=0x0000;
    CNPU2=0x0000;
    AD1PCFG=0xffff;
    AD1CON1=0;
   
    LATB = 0x0000;
    _TRISB5 = 0;                // port 5 as output (Led)
    _TRISB6 = 1;                // port 6 as input (button)
    _TRISB2 = 1;                // port 2 as input (SDCard Write Enable)
    _TRISB3 = 1;                // port 3 as input (SDCard Card Detect)
   
    _CN24PUE = 1;                // port RB6 (CN24) pullup enabled (button)

    _TRISB14 = 1;                // SDI
    _TRISB15 = 0;                // SCK
    _TRISB13 = 0;                // SDO
   
//    TRISBbits.TRISB1=0;        //Output RB1 SDC_CS
//    //Done by SPI2STAT.SPIEN
//    TRISFbits.TRISF6=0;        //Output RF6/SCK1
//    TRISFbits.TRISF7=1;        //Input  RF7/SDI1_E
//    TRISFbits.TRISF8=0;        //Output RF8/SDO1_E
//    LATBbits.LATB1=1;
   
    PORTBbits.RB5 = 1;            // Led ON
    //
    OpenSPI2();
   
    while(PORTBbits.RB6)         // loop until the button is pressed...
        WriteSPI2(0xaa);        // sending 0xAA to the SPI
   
    // next change the SPI speed...
    SPI2CON1bits.SPRE2=1;         //2:1  Fcy=16MHz DOZE 1:1 16000/32=500KHz
    SPI2CON1bits.SPRE1=1;
    SPI2CON1bits.SPRE0=0;
    SPI2CON1bits.PPRE1=0;         //16:1
    SPI2CON1bits.PPRE0=1;
   
    PORTBbits.RB5 = 0;            // Led OFF
   
    while(1)
        WriteSPI2(0xaa);  
   
}


TIA
Clemente
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/04 10:48:37
Hi Clemente
Where am I wrong again

Sorry i don't have a clue where it goes wrongSmile  We have to find the right road it isn't a generic car gear box grin
actually i don't know the exact "rules" for swichting spi bus speeds maybe it is somewhere explained in the datasheet

I think you are on the right track first try to enable and disable, We know that openspi function is working so we have to re-use some parts from that openspi function to achief re-switching spi speed

SPI2STATbits.SPIEN=0; //disable
   SPI2CON1bits.SPRE2=1;         //2:1  Fcy=16MHz DOZE 1:1 16000/32=500KHz
   SPI2CON1bits.SPRE1=1;
   SPI2CON1bits.SPRE0=0;
   SPI2CON1bits.PPRE1=0;         //16:1
   SPI2CON1bits.PPRE0=1;

SPI2STATbits.SPIEN=1; //enable

I hope there is an other way out I mean this comments:
All pins controlled by PORT Functions

//Disable the module. All pins controlled by PORT Functions  
SPI2STATbits.SPIEN=0;

Cheers
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/04 13:28:32
Hello Neiwiertz,
A short note inside the 39699b.pdf document: "Family Reference Manual Sect.23 Serial Peripherial Interface" (pag.23-4):
NOTE:SPIxCON1 and SPIxCON2 can not be written while the SPIx modules are enabled.
The SPIEN (SPIxSTAT<15>) bit must be clear before modifying either register.


At this point is better for me to understand why disabling and then enabling the SPI, the SDCard is not working again! As a new test I want to do this: before to disable the SPI, I want to program all the SPI pins as input, and using some pullup and pulldown, I leave the SDCard's pins in a consistent state. (terrible phrase, I know, like my english).

Are there other ideas?
TIA

Saluti.
Clemente


c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/04 16:25:12
Hello to all,
I modify my SPIFastClock procedure in this manner:


void SPIFastClock( void)
{
    unsigned char data;
   
    SDI_DIR = 1; // as input
    SCK_DIR = 1;
    SDO_DIR = 1;

    data = SPI2BUF;
    // SPI2 Off   
    SPI2STATbits.SPIEN=0;
    //
    Nop();
    Nop();
    SPI2CON1bits.MSTEN = 1;
    SPI2CON1bits.CKP = 0;
    SPI2CON1bits.CKE = 1;
    SPI2CON1bits.SMP = 0;
    SPI2CON2 = 0x0000;   
    // New speed
//    SPI2CON1 |= SEC_PRESCAL_4_1; SPI2CON1 |= PRI_PRESCAL_16_1;        // 250KHz
    SPI2CON1bits.SPRE2=1;         //2:1  Fcy=16MHz DOZE 1:1 16000/32=500KHz
    SPI2CON1bits.SPRE1=1;
    SPI2CON1bits.SPRE0=0;
    SPI2CON1bits.PPRE1=0;         //16:1
    SPI2CON1bits.PPRE0=1;
    // SPI2 ON
    SPI2STATbits.SPIEN=1;
}

I put the SPI pins as input before to switch off the SPI. And with two pullup to the SDO and SPI pins, and a pulldown to the SCK pins I leave the same signale as before the switch off.
The problem obviously remain.
The news is that if I program inside SPIFastClock the same speed as the init procedure, 250KHz, the SDCard is still not working! So it appear as the close and open SPI procedure make something really wrong!


BruceTElliott
Super Member
RE: SPI and SDCard problem 2007/06/04 23:22:20
if you deselect the sdcard (/CS = 1) the sdcard pins will tri-state, so you don't really need to use pull-ups or change the pic-pins to inputs.
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/05 10:10:34
ORIGINAL: BruceTElliott

if you deselect the sdcard (/CS = 1) the sdcard pins will tri-state, so you don't really need to use pull-ups or change the pic-pins to inputs.

Thank you BruceTElliott, you are right.

Ciao
Clemente.
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/05 10:50:42
This works for switching spi speed
   SPI1STATbits.SPIEN=0;
//   SPI1CON1bits.SPRE2=1; //1:1  Fcy=32MHz DOZE 1:1 32000/1=32MHz
//   SPI1CON1bits.SPRE1=1;
//   SPI1CON1bits.SPRE0=1;
//   SPI1CON1bits.PPRE1=1; //1:1
//   SPI1CON1bits.PPRE0=1;
   SPI1CON1bits.SPRE2=1;         //2:1  Fcy=32MHz DOZE 1:1 32000/32=1MHz
   SPI1CON1bits.SPRE1=1;
   SPI1CON1bits.SPRE0=0;
   SPI1CON1bits.PPRE1=0;         //16:1
   SPI1CON1bits.PPRE0=1;
   SPI1STATbits.SPIEN=1;


Regards
post edited by Neiwiertz - 2007/06/05 13:09:59
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/06 04:55:42
ORIGINAL: Neiwiertz
This works for switching spi speed
...

Hello Neiwiertz,
I use the same code to change the speed, and the oscilloscope confirm that change, but the SDCard does not want to work anymore. For example: the SD_ReadCSD procedure fail because the SDCard is returning 0x80 to the command 9, and not 0x00. Different problem with the SD_ReadBlock procedure, where for the command 17 the SDCard respond with 0x40 forever!
Strange, because @250KHz all works without problem!


Ciao
Clemente.
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/06 10:52:57
Strange, because @250KHz all works without problem!

Yeah i'd noticed the same behaviour last day, the sdcard handler runs into paradise of trouble when increasing the speed sad  i am working on it and hope to find a way out to use full speed like a dragstargrin.

Which sdcard size are you using to test the handler?

Cheers
asmallri
Super Member
RE: SPI and SDCard problem 2007/06/06 12:33:07
I have tested lots of cards with my drivers. Despite the driver sayiung that the SD card must first be initialized at a low bit rate before changing speeds I have found lots of cards can be initialized at 10Mbps.

Try initializing your card at high speed and see what happens. There are four common problems with symptoms where the card works at low speed but not high speed:

1. incorrect SPI bus mode
2. missing decoupling capacitors on the power rails immediately adjacent to the SD card socket
3. incorrect level conversion between 5volt pics and 3.3 volt cards
4. incorrectly sharing the SPI bus with other devices.
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/06 12:58:11
@Neiwiertz

Which sdcard size are you using to test the handler?

I'm using a TOSHIBA and a SanDisk SDCard with different size: 16MByte and 256MByte.

@asmallri

Try initializing your card at high speed and see what happens.

Hello asmallri, thanks for your response. I will try this metod very soon!

1. incorrect SPI bus mode

it's my primary doubt, for me the SDCard works @ lowrate with CKE=1,CKP=0 or CKE=0,CKP=1 with SMP=0 for both cases.

2. missing decoupling capacitors on the power rails immediately adjacent to the SD card socket

OK I need one.

3. incorrect level conversion between 5volt pics and 3.3 volt cards
4. incorrectly sharing the SPI bus with other devices.

it's not my case, I use a 3.3 voltage MCU and the SDCard is the only device.

thanks again at both!
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/06 13:34:48
Hello Clemente

@Neiwiertz
Which sdcard size are you using to test the handler?

I'm using a TOSHIBA and a SanDisk SDCard with different size: 16MByte and 256MByte.

Ok i'am using these cards:
sd kingston 128MB
sd kingston 256MB
sd apacer 512MB
sd apacer 1024MB
MMC apacer 1GB

Clemente the problem will be our changing speed method previously posted!
just use the same openspi function for changing speeds!
void OpenSPI1FAST(void)
{  IFS0bits.SPI1IF = 0;
   IEC0bits.SPI1IE = 0;

   SPI1CON1bits.DISSCK=0;
   SPI1CON1bits.DISSDO=0;
   SPI1CON1bits.MODE16=0;
   SPI1CON1bits.SMP=0;
   SPI1CON1bits.CKE=1;
   SPI1CON1bits.SSEN=0;
   SPI1CON1bits.CKP=0;
   SPI1CON1bits.MSTEN=1;

//   SPI1CON1bits.SPRE2=1;         //2:1  Fcy=32MHz DOZE 1:1 32000/32=1MHz
//   SPI1CON1bits.SPRE1=1;
//   SPI1CON1bits.SPRE0=0;
//   SPI1CON1bits.PPRE1=0;         //16:1
//   SPI1CON1bits.PPRE0=1;
   SPI1CON1bits.SPRE2=1; //1:1  Fcy=32MHz DOZE 1:1 32000/1=32MHz
   SPI1CON1bits.SPRE1=1;
   SPI1CON1bits.SPRE0=1;
   SPI1CON1bits.PPRE1=1; //1:1
   SPI1CON1bits.PPRE0=1;

   SPI1CON2bits.FRMEN=0;
   SPI1STATbits.SPISIDL=0;

   SPI1STATbits.SPIROV=0;
   SPI1STATbits.SPIEN=1;
}


Regards

c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/06 14:36:20
Hello Neiwiertz,
is not true for me. The MCU I use wants that I switch off the SPI before to change any configurations bits.
Anyway I used your code, but without success.

@asmallri
I changed the initialization speed to 2MHz but without success. And I added some decoupling capacitors to SDCard, very near the flat cable that connect to the SDcard holder. A capacitor was already present, very near the SDCard's Vdd and GND pins.
The stange behavior is if I change the SPI clock to a lower value, instend of a higher, the SDCard does not work too!

Asmallri, Neiwiertz, for your experience, how important are the "8 clock" before and after single commands and after the read and write block sequence? Is it possible for you that if I misconfiguring them, the result is this strange  behavior?

TIA
Clemente.
post edited by c.dicaprio - 2007/06/06 14:44:12
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/06 14:52:55
Hi Clemente

Yeah i'd noticed the same behaviour last day, the sdcard handler runs into paradise of trouble when increasing the speed i am working on it and hope to find a way out to use full speed like a dragstar.


Try this "dragstar car" below it drives like a rocket in the skygrin
at 32MHz SPI speed![8D].
I used this hardware check  SD PICtail on explorer16 using pim 24F 
I'd tested it using above cards @333.33KHz, @1MHz and @32MHz

Please use the code below with respect!

void OpenSPI1(void)
{  IFS0bits.SPI1IF = 0;
   IEC0bits.SPI1IE = 0;

   SPI1CON1bits.DISSCK=0;
   SPI1CON1bits.DISSDO=0;
   SPI1CON1bits.MODE16=0;
   SPI1CON1bits.SMP=0;
   SPI1CON1bits.CKE=1;
   SPI1CON1bits.SSEN=0;
   SPI1CON1bits.CKP=0;
   SPI1CON1bits.MSTEN=1;
   SPI1CON1bits.SPRE2=0; //6:1  Fcy=32MHz DOZE 1:1 32000/96=333.33KHz
   SPI1CON1bits.SPRE1=1;
   SPI1CON1bits.SPRE0=0;
   SPI1CON1bits.PPRE1=0; //16:1
   SPI1CON1bits.PPRE0=1;
   SPI1CON2bits.FRMEN=0;
   SPI1STATbits.SPISIDL=0;

   SPI1STATbits.SPIROV=0;
   SPI1STATbits.SPIEN=1;
}


void OpenSPI1FAST(void)
{  IFS0bits.SPI1IF = 0;
   IEC0bits.SPI1IE = 0;

   SPI1CON1bits.DISSCK=0;
   SPI1CON1bits.DISSDO=0;
   SPI1CON1bits.MODE16=0;
   SPI1CON1bits.SMP=0;
   SPI1CON1bits.CKE=1;
   SPI1CON1bits.SSEN=0;
   SPI1CON1bits.CKP=0;
   SPI1CON1bits.MSTEN=1;

//   SPI1CON1bits.SPRE2=1;         //2:1  Fcy=32MHz DOZE 1:1 32000/32=1MHz
//   SPI1CON1bits.SPRE1=1;
//   SPI1CON1bits.SPRE0=0;
//   SPI1CON1bits.PPRE1=0;         //16:1
//   SPI1CON1bits.PPRE0=1;
   SPI1CON1bits.SPRE2=1; //1:1  Fcy=32MHz DOZE 1:1 32000/1=32MHz
   SPI1CON1bits.SPRE1=1;
   SPI1CON1bits.SPRE0=1;
   SPI1CON1bits.PPRE1=1; //1:1
   SPI1CON1bits.PPRE0=1;

   SPI1CON2bits.FRMEN=0;
   SPI1STATbits.SPISIDL=0;

   SPI1STATbits.SPIROV=0;
   SPI1STATbits.SPIEN=1;
}


void CloseSPI1(void)
{ //Disable the Interrupt bit in the  Interrupt Enable Control Register
  IEC0bits.SPI1IE=0;

  //Disable the module. All pins controlled by PORT Functions
  SPI1STATbits.SPIEN=0;

  //Disable the Interrupt flag bit in the Interrupt Flag Control Register
  IFS0bits.SPI1IF=0;

}


unsigned int ReadSPI1(void)
{ unsigned int data;
    SPI1STATbits.SPIROV = 0;
    SPI1BUF=0x00;
    while(!SPI1STATbits.SPIRBF);

    if(SPI1CON1bits.MODE16) {
      data=SPI1BUF;
    }else{
      data=SPI1BUF&0x00ff;
    }
  return(data);
}


void WriteSPI1(unsigned int data)
{ if(SPI1CON1bits.MODE16) {
    SPI1BUF=data;
  }else{
    SPI1BUF=data&0x00ff;
  }
  while(SPI1STATbits.SPITBF);
  data=SPI1BUF;
}


BYTE SendSDCCmd(BYTE cmd, DWORD address, BYTE crc, BYTE more)
{ WORD  timeout;
  BYTE  index;
  BYTE  response;

    LATBbits.LATB1=0;
    WriteSPI1(0xFF);
    WriteSPI1(0xFF);
    WriteSPI1(0xFF);

    WriteSPI1(cmd);
    WriteSPI1(((address&0xFF000000)>>24));
    WriteSPI1(((address&0x00FF0000)>>16));
    WriteSPI1(((address&0x0000FF00)>>8));
    WriteSPI1(((address&0x000000FF)>>0));
    WriteSPI1(crc);

    timeout=8;
    do {
      response=ReadSPI1();
      timeout--;
    }while((response&0x80)&&(timeout!=0));

    WriteSPI1(0xFF);

    if(!more) {
      LATBbits.LATB1=1;
      WriteSPI1(0xFF);
      WriteSPI1(0xFF);
      WriteSPI1(0xFF);
    }

  return(response);
}


BYTE MediaInitialize(void)
{ WORD  timeout;
  BYTE  response;
  BYTE  status=0;

    OpenSPI1();

    LATBbits.LATB1=1;

    for(timeout=0;timeout<=9;timeout++) { WriteSPI1(0xFF); }

    timeout=0xFFFF;
    do {
      response=SendSDCCmd(0x40,0x0,0x95,0);
      timeout--;
    }while((response!=0x01)&&(timeout!=0));

    timeout=0xFFFF;
    do {
      response=SendSDCCmd(0x41,0x0,0xF9,0);
      timeout--;
    }while((response!=0x00)&&(timeout!=0));


    OpenSPI1FAST();


    timeout=0xFFFF;
    do {
      response=SendSDCCmd(0x50,0x00000200,0xFF,0);
      timeout--;
    }while((response!=0x00)&&(timeout!=0));

  return(!status);
}


BYTE SECTORread(DWORD sector_addr, BYTE* buffer)
{ DWORD  index;
  BYTE   data_token;

    SendSDCCmd(0x51,(sector_addr<<9),0xFF,1);

    index=0xFFFF;
    do {
      data_token = ReadSPI1();
      index--;
    }while((data_token!=DATA_START_TOKEN) && (index != 0));

    for(index = 0; index < 512; index++) {
      *buffer=ReadSPI1();
      buffer++;
    }
    WriteSPI1(0xFF);
    WriteSPI1(0xFF);

    WriteSPI1(0xFF);

    LATBbits.LATB1=1;
    WriteSPI1(0xFF);
    WriteSPI1(0xFF);
    WriteSPI1(0xFF);

  return;
}


#include "p24FJ128GA010.h"

_CONFIG1(0xBF6F)
_CONFIG2(0x7BBE)

void main(void)
{  _COSC2=0;
   _COSC1=1;
   _COSC0=1;
   _NOSC2=0;
   _NOSC1=1;
   _NOSC0=1;
  _CLKLOCK=0;
  _SOSCEN=0;
  _OSWEN=0;

  _ROI=0;
  //_DOZE
  _DOZE2=0;
  _DOZE1=0;
  _DOZE0=0;
  _DOZEN=1;
  //_RCDIV
  _RCDIV2=0;
  _RCDIV1=0;
  _RCDIV0=0;

  //_TUN
  _TUN5=0;
  _TUN4=0;
  _TUN3=0;
  _TUN2=0;
  _TUN1=0;
  _TUN0=0;

   while(!_LOCK);

   CNPU1=0x0000;
   CNPU2=0x0000;
   AD1PCFG=0xffff;
   AD1CON1=0x0000;

   TRISBbits.TRISB1=0;    //Output RB1 SDC_CS
   //Done by SPI1STAT.SPIEN
   //TRISFbits.TRISF6=0;    //Output RF6/SCK1
   //TRISFbits.TRISF7=1;    //Input  RF7/SDI1_E
   //TRISFbits.TRISF8=0;    //Output RF8/SDO1_E

   LATBbits.LATB1=1;

   MediaInitialize();

   //SECTORread(0x00000000, &buffer[0]);

   CloseSPI1();

   while(1);
}


Regards
asmallri
Super Member
RE: SPI and SDCard problem 2007/06/06 18:04:33
ORIGINAL: c.dicaprio

Hello Neiwiertz,
is not true for me. The MCU I use wants that I switch off the SPI before to change any configurations bits.
Anyway I used your code, but without success.


Make sure that the I/O is configured such than when the SPI is disabled the SPI lines are driven to the idle conditions for the SD card (clock driven low).

@asmallri
I changed the initialization speed to 2MHz but without success. And I added some decoupling capacitors to SDCard, very near the flat cable that connect to the SDcard holder. A capacitor was already present, very near the SDCard's Vdd and GND pins.
The stange behavior is if I change the SPI clock to a lower value, instend of a higher, the SDCard does not work too!


This behaviour is typical of an incorrect SPI bus mode.


Asmallri, Neiwiertz, for your experience, how important are the "8 clock" before and after single commands and after the read and write block sequence? Is it possible for you that if I misconfiguring them, the result is this strange  behavior?


The 8 clock pulses are required to force the SD cards internal controller to execute the last command.

I have successfully driven the Toshiba and SANDISK cards (and lots of others) at 10Mbps.

If you get desperate you might want to consider buying my driver software - it was developed for the PIC18F family and will require the initialization code to be modified for the 24F and dsPICs. I plan to port this and the file system code to the PIC24 and dsPIC families over the next couple of weeks.

c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/07 06:34:37
Hello asmallri, thanks for the replay.
ORIGINAL: asmallri
Make sure that the I/O is configured such than when the SPI is disabled the SPI lines are driven to the idle conditions for the SD card (clock driven low).

OK, I put a pulldown to the SCK pin and a pullup to the SDO and SDI pins. Is it correct for you?


I changed the initialization speed to 2MHz but without success...

This behaviour is typical of an incorrect SPI bus mode.

OK, but how can I discover the mistake? I'm using this SPI configuration: CKE=1,CKP=0, but works with CKE=0,CKP=1 too, both with SMP=0. I know this are two well know "SPI mode".

If you get desperate you might want to consider buying my driver software - it was developed for the PIC18F family and will require the initialization code to be modified for the 24F and dsPICs. I plan to port this and the file system code to the PIC24 and dsPIC families over the next couple of weeks.

Thanks Asmallri, I know your driver is a very complite software, but for now I want to discover why my software stop to works at different clock speed.

Thanks again for your time.

Clemente.

Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/07 10:15:30
Hello Clemente
quote:
quote:
I changed the initialization speed to 2MHz but without success...
This behaviour is typical of an incorrect SPI bus mode.

Read the spec (chap 5) initialization speed to 2MHz isn't allowed and must stay below 400KHZ because the command 0x40 and 0x41 are not supported
Commands like set blocklen and readblock are supported at max speedwink
see page 3-6 and 4-27 http://www.digitalspirit.org/file/?aff=,/docs/sd/ProductManualSDCardv2.2final.pdf

but for now I want to discover why my software stop to works at different clock speed
Did you try new openspi1FAST to switch the speed? When still facing trouble throw the 16MB card a way for a while and use your 256MB sdcard. In the send command function the 8 clocks write is called Nec (5-19) see page 5-17 diagram datain for the card means dataout for mcuwink.  Before writespi(cmd) enough 3 times writespi(0xff) Ncs are written to the card.

For schematic see page 4 my advice don't use a pulldown on clk line
from the sd/mmc pictail  board only pin 8, 9, 10, 11 and 7 (SDI) use pullup 10K other lines don't have any pullup or pulldown resistors. Did you notice pin number 9 is actually the first pin of your socket

Good luck
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/07 10:23:32
Very usefull info about speeds

MIPS/MHZ ratio for microchip's 16-bits micros
http://forum.microchip.com/tm.aspx?m=259691&mpage=1&key=??

c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/07 12:49:02
Thanks Neiwiertz,
a lot of information! I'm going to verify all.

Thanks again.

Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/09 04:11:35
Hello Clemente
I'm going to verify all

I was wondering if it is working or are there still some problems?

Just notice that PERIPHERAL PIN SELECTION is possible because i was looking at your schematic :
RP13 - RB13 -SDO
RP14 - RB14 -SDI
RP15 - RB15 -SCK

Did you use something like this below? page 101, 102 datasheet

Something like:
RP13 - SDO1 = 7
RPOR6bits.RP13R4 = 0;
RPOR6bits.RP13R3 = 0;
RPOR6bits.RP13R2 = 1;
RPOR6bits.RP13R1 = 1;
RPOR6bits.RP13R0 = 1;

RP14 - SDI1  RPn Pin bits = 14 (RP14)
RPINR20bits.SDI1R4 = 0;
RPINR20bits.SDI1R3 = 1;
RPINR20bits.SDI1R2 = 1;
RPINR20bits.SDI1R1 = 1;
RPINR20bits.SDI1R0 = 0;

RP15 - SCK = 8
RPOR7bits.RP15R4 = 0;
RPOR7bits.RP15R3 = 1;
RPOR7bits.RP15R2 = 0;
RPOR7bits.RP15R1 = 0;
RPOR7bits.RP15R0 = 0;

HOLDER PIC
1   -> CS
2   -> SDO
3   -> GND
4   -> 3.3V
5   -> SCK
6   -> GND
7   -> SDI + 10K 3.3V
8   -> 10K 3.3V
9   -> 10K 3.3V
10  -> CD + 10K 3.3V
11  -> WP + 10K 3.3V

holder layout 9 1 2 3 4 6 7 8 10 11
post edited by Neiwiertz - 2007/06/09 05:12:47
c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/09 14:59:56
ORIGINAL: Neiwiertz

Hello Clemente
I was wondering if it is working or are there still some problems?

Hello Neiwiertz, there are still problems!

Just notice that PERIPHERAL PIN SELECTION is possible because i was looking at your schematic :
RP13 - RB13 -SDO
RP14 - RB14 -SDI
RP15 - RB15 -SCK

Yes I use this procedure to enable the SPI module before I use it.

/*
*/
#include <p24fj64ga002.h>

void InitModule( void);

void InitModule( void)
{
    // Programmo la UART1
    RPINR18bits.U1RXR = 9;    // Make Pin RP9 U1RX (pin 18)
    RPOR4bits.RP8R = 3;        // Make Pin RP8 U1TX (pin 17)

    // Programmo la SPI2
    RPINR22bits.SDI2R = 14;        // Make Pin RP14 SDI2 (pin 25)
    RPOR6bits.RP13R = 10;        // Make Pin RP13 SDO2 (pin 24)
    RPOR7bits.RP15R = 11;        // Make Pin RP15 SCK2 (pin 26)
}

I'm reading some Motorola's documents to learn about SPI and to understand how to setup SPI pins; and I'm changing my code to better discover what the SDCard is responding when I run at different speed.

I will back with news. Good I hope!


Bye
Clemente.
Neiwiertz
Super Member
RE: SPI and SDCard problem 2007/06/10 03:37:26
RPOR7bits.RP15R = 11; // Make Pin RP15 SCK2 (pin 26)

I think it should be something like this
RP15 - SCK2 =  11
RPOR7bits.RP15R4 = 0;
RPOR7bits.RP15R3 = 1;
RPOR7bits.RP15R2 = 0;
RPOR7bits.RP15R1 = 1
RPOR7bits.RP15R0 = 1;

and more documentation, try my posted code for sdcard init and sector read, i tested these at high speed therefore if it is still not working i think your problem will be hardware related. when asume that spi read and write is functioning correctly

SanDisk SD Card Product Manual Version 2.2 Document No. 80-13-00169 November 2004
http://www.digitalspirit.org/file/?aff=,/docs/sd/ProductManualSDCardv2.2final.pdf

SD Specifications Part 1 Physical Layer Simplified Specification 2006
http://www.sdcard.org/sd_memorycard/Simplified%20Physical%20Layer%20Specification.PDF

SD Specifications Part E1 SDIO Simplified Specification 2007
http://www.sdcard.org/sdio/Simplified%20SDIO%20Card%20Specification.pdf


c.dicaprio
Starting Member
RE: SPI and SDCard problem 2007/06/10 07:26:47
ORIGINAL: Neiwiertz

RPOR7bits.RP15R = 11; // Make Pin RP15 SCK2 (pin 26)

I think it should be something like this
RP15 - SCK2 =  11
RPOR7bits.RP15R4 = 0;
RPOR7bits.RP15R3 = 1;
RPOR7bits.RP15R2 = 0;
RPOR7bits.RP15R1 = 1
RPOR7bits.RP15R0 = 1;

Yes!

try my posted code for sdcard init and sector read,

I used your code but without success.

i think your problem will be hardware related

My be, but why it appear only when I change the speed? I change from 250KHz to 500KHz, not to so high speed like MHz.

SanDisk SD Card Product Manual Version 2.2 Document No. 80-13-00169 November 2004
http://www.digitalspirit.org/file/?aff=,/docs/sd/ProductManualSDCardv2.2final.pdf
SD Specifications Part 1 Physical Layer Simplified Specification 2006
http://www.sdcard.org/sd_memorycard/Simplified%20Physical%20Layer%20Specification.PDF
SD Specifications Part E1 SDIO Simplified Specification 2007
http://www.sdcard.org/sdio/Simplified%20SDIO%20Card%20Specification.pdf

Thanks a lot for the documentation.

Trying more on my board, reading the SDCard @500KHz, I realize that the SDCard is responding with 0x80 at every command. No more with 0x00.
Page: 123 > Showing page 1 of 3