CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Help! SD card in 4-bit mode
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
metalm



Joined: 22 Mar 2007
Posts: 23
Location: Buenos Aires, Argentina

View user's profile Send private message

Help! SD card in 4-bit mode
PostPosted: Wed Aug 08, 2007 2:08 pm     Reply with quote

Hello! I am bothering again....

I have tested a code from microchipC.com for using the SD card in spi mode, but the speed is not enough for me. I only can take a byte per 4.8 uS when I need a byte per uS (1 MB/s), so I am interested in use the SD 4 bit parallel mode to communicate with this memory. I have a kingston elite pro 55x memory so the speed problem don't is from the card.

Is there any information about this mode? because i have search A LOT and can't found anything :(

I have the specification v1.9 (the one that isn't simplificate) but i'm going crazy with this.. it's so abstract and don't seems to have all the information (For low level programming)

Can anyone help me with this one?
THANKS!! y perdón por mi inglés Razz Razz
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Aug 08, 2007 5:18 pm     Reply with quote

How about raising the clock speed of your PIC? At 40MHz you can clock the SPI bus with 10MHz = 1.25Mbyte /second.

SD-cards are difficult to get information on because companies who want access to the specs have to sign a strict non-disclosure agreement with SDCA and pay steep licensing fees. SD-licencies are not allowed to share any SD technology, even if they've developed it themselves, with anyone who is not also a member company. MMC cards are much more relaxed in this respect.

Basically an SD card starts up exactly the same as an MMC card because of backwards compatiblity reasons. After the CMD0 command is sent the card is in 'idle state', you still don't know if the card is an MMC or SD type.
Then you sent the ACMD41. Do you get the 'no valid command' than it must be an MMC card you are talking to, otherwise continue the SD initialization which switches the card from SPI mode to the 4-bit bus.
Check figure 4-7 of your v1.9 specification for an overview.
MMC initialization code can be found in the CCS driver, mmc_spi.c
Not checked, but the Linux kernel contains a complete SD card driver.

Extra info regarding MMC cards:
The 4-bit bus of older MMC cards (before v4.0) is not recommended for new designs. The new MMC Plus cards do support a 4-bit and even an 8-bit bus.
metalm



Joined: 22 Mar 2007
Posts: 23
Location: Buenos Aires, Argentina

View user's profile Send private message

PostPosted: Thu Aug 09, 2007 6:38 am     Reply with quote

Thanks! I am already using the pic at 40 mhz (this is an 18F65J10 @ 3.3V) but when I see the LST file of the ccs compiller, I can view that the loss of time is when this waiting the flag of the SPI to be done with the transmission/reception.

In SD mode with 4 lines, you can get the data 4 times faster, and the command/response line is a sepparate pin, so I put the 4 data lines in PORTB<0:3>, the command/response line to the SDI and SDO (connected togheter and commanded by the TRIS) and the clock to the SCK from hardware SPI. Now I see that this requires START BIT, so i must do something to emulate a start bit or making the spi in soft. . .

Another problem, is that it seems that the bits comes in inverse order, could it be? Because in page 54 of the PDF it shows that the MSB is sent first...


for those that wants the old (But "full") specification 1.9 of SANDISK, can use this link wich still available:
http://www.cs.ucr.edu/~amitra/sdcard/ProdManualSDCardv1.9.pdf
(taken from wikipedia IN ENGLISH only).


THANKS!!!!!!!!!!!
Pret



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

PostPosted: Thu Aug 09, 2007 7:11 am     Reply with quote

The bit order can be reversed directly from PCB HW Smile
metalm



Joined: 22 Mar 2007
Posts: 23
Location: Buenos Aires, Argentina

View user's profile Send private message

PostPosted: Thu Aug 09, 2007 9:54 am     Reply with quote

Thanks but I think that the byte order is something impossible to change :(

it sends first the most significant BYTE of the 512 block, isn't it? hopefully that no!
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Aug 09, 2007 10:34 am     Reply with quote

metalm wrote:
it sends first the most significant BYTE of the 512 block, isn't it? hopefully that no!
From how I read the documentation you are right, the most significant byte is transmitted first. This makes sense as it equals reading the card status (CSD register) where you also get the most significant bit (nr 127) first

The sequence is the same for reading and writing, so if your application is the only device accessing the card you can write in reverse order as well and no conversion is needed.
metalm



Joined: 22 Mar 2007
Posts: 23
Location: Buenos Aires, Argentina

View user's profile Send private message

PostPosted: Thu Aug 09, 2007 11:40 am     Reply with quote

OK! I must do that way because if i use a buffer of 512 bytes this will be so slow again Sad Sad Sad Sad

Another think i don't understand is the block addressing, my source (from microchipC.com) is as follows:

[code]
int mmc_read_block(unsigned long block_number) {
unsigned long i;
unsigned long varh,varl;

varl=((block_number&0x003F)<<9);
varh=((block_number&0xFFC0)>>7);

OUTPUT_LOW(SS); // set SS = 0 (on)

SPI_WRITE(0x51); // send mmc read single block command
SPI_WRITE(make8(varh, 1)); // arguments are address
SPI_WRITE(make8(varh, 0));
SPI_WRITE(make8(varl, 1));
SPI_WRITE(0x00);
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF

..........[/code]

Why this applies that mask before sending the block number to the argument of the CMD? Confused Confused
The block number variable is an unsigned long (16 bits in this compiller). If I assume a value to a block, this function ONLY can address 32 MB of data! I need to address up to 1 GB (no more than this). Luckily in this specification exist up to 1GB cards, but i don't understand so good the way to address far as 1 gb... Sad Sad
sorry for the annoyance but this card isn't designed for humans! hahaha
thanks so much for the help
metalm



Joined: 22 Mar 2007
Posts: 23
Location: Buenos Aires, Argentina

View user's profile Send private message

PostPosted: Thu Aug 09, 2007 12:09 pm     Reply with quote

YEESSS I have found the 2.2 specification! Hope that this is more useful...

http://www.digitalspirit.org/file/?aff=,/docs/sd/ProductManualSDCardv2.2final.pdf

download it fast because i don't think this could be available for much time!!

yesterday i just print all the 1.9 Mad Mad Mad
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Aug 10, 2007 2:25 am     Reply with quote

Code:
 unsigned long varh,varl;

varl=((block_number&0x003F)<<9);
varh=((block_number&0xFFC0)>>7);
In MMC cards the block size is always 512 bytes. Here the block number is converted to the block start address.

2 notes on this code:
1) There is a bug in the bit mask, should have been 0x007F and 0xFF80.
2) Difficult to understand, error prone (see note 1) and inefficient.

Code:
int mmc_read_block(unsigned long block_number) {
  int32 address;

  address = (int32)block_number * 512;

  OUTPUT_LOW(SS); // set SS = 0 (on)

  SPI_WRITE( 0x51 ); // send mmc read single block command
  SPI_WRITE( make8(address, 3) ); // arguments are address
  SPI_WRITE( make8(address, 2) );
  SPI_WRITE( make8(address, 1) );
  SPI_WRITE( make8(address, 0) );
  SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF

......

With the v4.038 compiler the address calculation of the original code is translated into 29 assembly instructions. The improved version is much easier to understand and takes only 9 assembly instructions for the address calculation. Another interesting proof of the K.I.S.S. concept being better in several ways. Cool
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Aug 10, 2007 2:43 am     Reply with quote

Quote:
The block number variable is an unsigned long (16 bits in this compiller). If I assume a value to a block, this function ONLY can address 32 MB of data! I need to address up to 1 GB (no more than this). Luckily in this specification exist up to 1GB cards, but i don't understand so good the way to address far as 1 gb...
The 32Mb limit is a limitation of this function only. The MMC and SD cards are addressed bytewise with a 32 bit address, a limit of 4Gb.
To work around the 32Mb limit change the card access functions to accept a 32bit address instead of a block number.

Quote:
OK! I must do that way because if i use a buffer of 512 bytes this will be so slow again
Writing to the card is always in 512byte blocks, but for reading you can set smaller block sizes, even to a single byte if you want to.
metalm



Joined: 22 Mar 2007
Posts: 23
Location: Buenos Aires, Argentina

View user's profile Send private message

PostPosted: Fri Aug 10, 2007 6:33 am     Reply with quote

THAKNYOU THAKNYOU THAKNYOU THAKNYOU!!

i will use that way, the code i have posted is from microchipC.com, may not be the best but helps me to understand some things hehe Razz

I will send the commands to the "COMMAND/RESPONSE" line with hardware SPI and receive the response with software (with inline assembler) because I use the CMD18 instead the CMD17 for reading multiple blocks, and in the block graph the response cames superposed with the data! what a POO!! Shocked

If I can make it work, I promise that i will post the code here. I'm not the best programmer (may be the worst) but it could be useful for somebody Very Happy Very Happy Very Happy Very Happy
metalm



Joined: 22 Mar 2007
Posts: 23
Location: Buenos Aires, Argentina

View user's profile Send private message

PostPosted: Wed Aug 15, 2007 8:44 am     Reply with quote

I am having problems with the initialization :( I don't know how to set the arguments of the ACMD41!!! the code is:

[code]
#include <18F65J10.h>
#fuses H4_SW,NODEBUG,NOXINST,STVREN,NOWDT,NOPROTECT,NOFCMEN,NOIESO

#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)
#use fast_io(F)
#use fast_io(G)

#use delay(clock = 40000000)

#bit PLLEN = 0xF9B.6
#bit RBPU = 0xFF1.7
#bit TRISC5 = 0xF94.5
#byte SSP1STAT = 0xFC7
#byte SSP1CON1 = 0xFC6
#byte SSP1BUF = 0xFC9
#bit BF = 0xFC7.0 // 1 = buffer full (read-only)
#bit SSP1IF = 0xF9E.3 // flag de interrupcion Tx/Rx de SPI, R/W
#bit SSPEN = 0xFC6.5 // habilita SPI1
#bit WCOL = 0xFC6.7 // colision de escritura SPI

#define D0 PIN_B0
#define D1 PIN_B1
#define D2 PIN_B2
#define D3 PIN_B3
#define CLK PIN_C3
#define SPI PIN_C5

unsigned char data[5];

unsigned char _crc7(void) {
unsigned int i, a;
unsigned char crc,aux;
crc = 0;
for(a=0; a<5; a++) {
aux = data[a];
for(i=0; i<8; i++) {
crc <<= 1;
if((aux & 0x80)^(crc & 0x80))
crc ^=0x09;
aux <<= 1;
}
}
crc=(crc<<1)|1; // agrega stop bit
return(crc);
}

void _sd_cmd(void) {
SSP1IF = 0;
SSP1BUF = data[0]; // envia comando a la tarjeta
while(~SSP1IF);
SSP1IF = 0;
SSP1BUF = data[1];
while(~SSP1IF);
SSP1IF = 0;
SSP1BUF = data[2];
while(~SSP1IF);
SSP1IF = 0;
SSP1BUF = data[3];
while(~SSP1IF);
SSP1IF = 0;
SSP1BUF = data[4];
while(~SSP1IF);
SSP1IF = 0;
SSP1BUF = _crc7(); // calcula CRC7 y lo envia
while(~SSP1IF);
SSP1IF = 0;
}

void _sd_init(void) {
unsigned int8 i;
unsigned char rxbuff[17];
SSPEN = 1;
TRISC5 = 0;
SSP1IF = 0;
for(i = 0; i < 10; i++) { // envia 80 ciclos de clock para inicializar
SSP1BUF = 0xFF;
while(~SSP1IF);
SSP1IF = 0;
}
data[0]=0x40, data[1]=0x00, data[2]=0x00, data[3]=0x00, data[4]=0x00;
_sd_cmd(); // envia CMD0
SSP1IF = 0;
SSP1BUF = 0xFF; // 8 clocks adicionales despues de stop bit
while(~SSP1IF);
data[0]=0x77, data[1]=0x00, data[2]=0x00, data[3]=0x00, data[4]=0x00;
_sd_cmd(); // envia CMD55
SSP1IF = 0;
SSP1BUF = 0xFF; // 8 clocks adicionales despues de stop bit
while(~SSP1IF);
data[0]=0x69, data[1]=0x00, data[2]=0xFF, data[3]=0x80, data[4]=0x00;
_sd_cmd(); // envia ACMD41
TRISC5 = 1;
delay_ms(50);
SSP1IF = 0;
for(i = 0; i < 17; i++) {
rxbuff[i] = SPI_READ();
}
SSPEN = 0;
delay_ms(1000);
}

void main(void) {
PLLEN = 1;
set_tris_A(0xFF);
set_tris_B(0xFF); // PORTB<0:3> = D0:D3
set_tris_C(0xF7); // C5 = COMMAND/RESPONSE; C3 = CLOCK
set_tris_D(0xFF);
set_tris_E(0xFF);
set_tris_F(0xFF);
set_tris_G(0x1F);
RBPU = 0; // PULL-UPS en PORTB habilitados
SSP1STAT = 0x40; // CKE = 1
// SSP1CON1 = 0x00; // Master, FOSC/4, CKP = 0
SSP1CON1 = 0x02; // Master, FOSC/64, CKP = 0
SETUP_ADC(ADC_OFF);
SETUP_ADC_PORTS(NO_ANALOGS);
for(;;) {
if(WCOL)
WCOL = 0;
_sd_init(); // inicializa memoria SD
}
}
[/code]


I must say the voltage ranges to the card thru the ACMD41 argument?? I am not receiving any response...
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Aug 15, 2007 2:59 pm     Reply with quote

You started out with a nice example program using the inbuilt CCS functions, why did you revert to the very low level of writing directly to the registers? To me it doesn't make for easier reading. Also, instead of creating a function similar to spi_write() you now have the same sequence of three commands about 20 times in your code. Again, difficult to read and error prone.

Am I right when I guess you have the chip select line connected to PIN_C5? If yes, than I think you should be writing to the PORTC5 register instead of TRISC5.
I didn't check if it is compulsory, but otherwise it is a nice addition, do release the chip select line in between commands. This makes it possible for the SD card to synchronize to the start of commands in case it is out of sync,

After sending the reset command (0x40) you have to wait for the SD card response. And check this response to tell you the card did reset properly !
Only then can you send CMD_55, and again wait for result and check.
Same for ACMD41.
metalm



Joined: 22 Mar 2007
Posts: 23
Location: Buenos Aires, Argentina

View user's profile Send private message

PostPosted: Wed Aug 15, 2007 3:21 pm     Reply with quote

[quote="ckielstra"]You started out with a nice example program using the inbuilt CCS functions, why did you revert to the very low level of writing directly to the registers? To me it doesn't make for easier reading. Also, instead of creating a function similar to spi_write() you now have the same sequence of three commands about 20 times in your code. Again, difficult to read and error prone.

Am I right when I guess you have the chip select line connected to PIN_C5? If yes, than I think you should be writing to the PORTC5 register instead of TRISC5.
I didn't check if it is compulsory, but otherwise it is a nice addition, do release the chip select line in between commands. This makes it possible for the SD card to synchronize to the start of commands in case it is out of sync,

After sending the reset command (0x40) you have to wait for the SD card response. And check this response to tell you the card did reset properly !
Only then can you send CMD_55, and again wait for result and check.
Same for ACMD41.[/quote]

you are right that it isn't the best way to do the program, but I don't like some of the built-in functions because they aren't good in all cases. In my spi read function, i had to use the direct registers because the built-in functions verifies the BF status flag wich isn't useful for me because i have the both pins of SPI hardware port togheter in the command/response line (i must use SSPIF). Thats why i am switching TRISC5 to send and receive trhu the same pin. Remember that I need the SD mode and in this mode there is no chip select pin Sad Sad , in the manual, the CMD0 of the SD mode appears as a BC command (broadcast comand) wich are the ones that does not send response.
I am going crazy with this protocol!!! I cannot get any response
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Aug 15, 2007 4:43 pm     Reply with quote

Ok, I see where I went wrong: in the SD-datasheet figure 4-7 I overlooked the 'Power on' arrow and assumed the flow chart to start at the upper left.

I never used the SD-bus mode so can't really help you with that. Did you follow my suggestion to look up the SD-card driver software in Linux? Maybe they are using SPI as well, but you might be lucky.

From the datasheet figure 3-5 you can see that at power-up you have to send at least 74 clock pulses _and_ wait for 1ms (whichever of these two takes the longest).

Check chapter 4.8.2 Command Format, every command is 8 bytes long, not 1 byte like you have now. This includes the commands 0 and 55.

Maybe CMD0 has no response, but ACMD41 does! You will have to check for the busy flag to clear.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group