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

Writing to an SD card and reading it on a computer
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
Giawa
Guest







Writing to an SD card and reading it on a computer
PostPosted: Wed Mar 28, 2007 4:56 am     Reply with quote

So I'm working on a school project where I would like to easily take the data from the microcontroller and put it on the computer. The easiest way would be to pull out an SD card from the project and put it in a reader. My question is this. When using the FAT file system and the SPI code available in CCS, will it be possible to read the data from the computer? I have just gotten my MMC to initialize but I don't want to keep working on this if it is in vain. Would it be easier to just use the USB on the PIC18F4550 and forget about MMC/SD capabilities? Is there anyway without using a FAT32 system to store data as text on the SD card?
asmallri



Joined: 12 Aug 2004
Posts: 1635
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

Re: Writing to an SD card and reading it on a computer
PostPosted: Wed Mar 28, 2007 7:53 am     Reply with quote

Giawa wrote:
So I'm working on a school project where I would like to easily take the data from the microcontroller and put it on the computer. The easiest way would be to pull out an SD card from the project and put it in a reader. My question is this. When using the FAT file system and the SPI code available in CCS, will it be possible to read the data from the computer?


I do not use the CCS code (I have my own) however the answers are generic. If you have written to the media using the FAT file system then you can remove and read it on a PC HOWEVER don't forget to ensure you have closed any open files before you remove the card as the file system data structures may be stale.

Quote:

Would it be easier to just use the USB on the PIC18F4550 and forget about MMC/SD capabilities?


Only you know your intended application objective so it is difficult to answer. If you are refering to AN1003 (?) then this is not a FAT implementation. The PC can only read the media via the PIC.

Quote:
Is there anyway without using a FAT32 system to store data as text on the SD card?


Yes but it is easier if you use FAT16 (which is also much more efficient for the PIC). There are two ways, one required you to write custom code on the PC to read the data structures you write to the media. The other is to "cheat". Format the media and create a single dummy file of greater that the maximum file size you want to support. Write your SD code to find the file (its easy with FAT 16) because it is in the root directory and the root is in an easily identifiable location. Once you locate the start of the file you can access each sector easily because they are contiguous.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
Giawa
Guest







PostPosted: Wed Mar 28, 2007 11:34 am     Reply with quote

Alright, here's my code.... It is mostly code that I found on the internet (the sample MMC/SD code from Microchip).

Code:
#include "C:\Documents and Settings\HP_Administrator\Desktop\attempt3\wewt.h"
#define delay     5    // in seconds
#define HBM       0     // Heartbeat Mode
#define SD_CARD   1     // No SD card present yet (set to 1 to compile for SD card)
#use I2C(Master,sda=PIN_B4,scl=PIN_B5,FAST)  // SCL is purple, SDA is gray

void my_timer(unsigned long seconds);
void eeprom_write(unsigned char addrh,unsigned char addrl,unsigned char data);
unsigned char eeprom_read(unsigned char addrh,unsigned char addrl);
int init_sd();
int sd_response(unsigned char response);
int sd_write_block(unsigned long block_number);
unsigned int HIGH(unsigned long var);
unsigned int LOW(unsigned long var);
int get_sd_status();
unsigned char take_measure(int sensor);
void my_blink(unsigned int num);

void main()
{
   unsigned long data_pos, data_block=1, clk=0;
   unsigned char temp;
   //setup_adc(ADC_CLOCK_INTERNAL);
   //setup_adc_ports(AN0_TO_AN2);
   output_high(PIN_C1);     // Use as a power indicator?
   while (HBM) {
      output_toggle(PIN_C2);
      output_toggle(PIN_C1);
      delay_ms(500);
   }
   if (SD_CARD) {
      if (!init_sd()) output_low(PIN_C1);
   }
   for (data_pos=0; data_pos<512; data_pos++) {
      eeprom_write(HIGH(data_pos),LOW(data_pos),take_measure(1));
   }
   output_toggle(PIN_C1);
   if (SD_CARD) my_blink(sd_write_block(data_block));
   /*while (TRUE) {
      for (data_pos=0; data_pos<512; data_pos++) {
         clk++;
         eeprom_write(HIGH(data_pos),LOW(data_pos),HIGH(clk));
         data_pos++;
         eeprom_write(HIGH(data_pos),LOW(data_pos),LOW(clk));
         data_pos++;
         eeprom_write(HIGH(data_pos),LOW(data_pos),take_measure(0));
         data_pos++;
         temp=take_measure(1);
         eeprom_write(HIGH(data_pos),LOW(data_pos),temp);
         if (eeprom_read(HIGH(data_pos),LOW(data_pos))==temp) my_blink(2);
         take_measure(2);
         my_timer(delay);
      }
      if (SD_CARD) sd_write_block(data_block);
      data_block++;
   }*/
}

unsigned char take_measure(int sensor)
{
   unsigned int adc_value;
   set_adc_channel(sensor);
   return (char)read_adc();
}

void my_blink(unsigned int num) {
   unsigned int i;
   for (i=0; i<num; i++) {
      output_high(PIN_C2);
      delay_ms(250);
      output_low(PIN_C2);
      delay_ms(250);
   }
}

void my_timer(unsigned long seconds) {
   unsigned long c_seconds;
   for (c_seconds=0; c_seconds<seconds; c_seconds++) {
      delay_ms(1000);
   }
}

void eeprom_write(unsigned char addrh,unsigned char addrl,unsigned char data)
{
   i2c_start();
   i2c_write(0xA0);                // send chip addr and set data to write mode
   i2c_write(addrh);               // high addr bits
   i2c_write(addrl);               // low addr bits
   i2c_write(data);                // write data
   i2c_stop();
   delay_ms(5);
}

unsigned char eeprom_read(unsigned char addrh,unsigned char addrl)
{
   unsigned char temp;
   i2c_start();
   i2c_write(0xA0);                // send address data in write mode
   i2c_write(addrh);               // high addr bits
   i2c_write(addrl);               // low addr bits
   i2c_start();
   i2c_write(0xA1);                // change to read mode
   temp = i2c_read(0);             // reads are not acknowledged (0)
   i2c_stop();                     // if no stop() can get continuous read
   return temp;
}

int init_sd()
{
   int i;
   SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SAMPLE_AT_END); //SPI_SS_DISABLED);
   *0x94 |= 0x40;                          // set CKE = 1 - clock idle low
   *0x14 &= 0xEF;                          // set CKP = 0 - data valid on rising edge
   output_high(PIN_D3);                    // set SS = 1 (off)
   for(i=0;i<10;i++)                       // initialise the MMC card into SPI mode by sending clks on
   {
      SPI_WRITE(0xFF);
   }
   output_low(PIN_D3);                     // set SS = 0 (on) tells card to go to spi mode when it receives reset

   SPI_WRITE(0x40);                        // send reset command
   SPI_WRITE(0x00);                        // all the arguments are 0x00 for the reset command
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x95);                        // precalculated checksum as we are still in MMC mode

   if(sd_response(0x01)==1) return 1;     // if = 1 then there was a timeout waiting for 0x01 from the mmc
   // Got response from MMC
   i = 0;
   while((i <255>= 254) return 2;                   // if >= 254 then there was a timeout waiting for 0x00 from the mmc
   // Got out of idle response
   output_high(PIN_D3);                    // set SS = 1 (off)
   SPI_WRITE(0xFF);                        // extra clocks to allow mmc to finish off what it is doing
   output_low(PIN_D3);                     // set SS = 0 (on)

   SPI_WRITE(0x50);                // send mmc command one to bring out of idle state
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x02);                // high block length bits - 512 bytes
   SPI_WRITE(0x00);                // low block length bits
   SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
   if((sd_response(0x00))==1) return 3;
   output_high(PIN_D3);            // set SS = 1 (off)
   // Got set block length from MMC
   return 0;
}

int sd_write_block(unsigned long block_number)
{
   unsigned long i;
   unsigned long varh,varl;
   varl=((block_number&0x003F)<<9>>7);
   output_low(PIN_D3);                     // set SS = 0 (on)
   SPI_WRITE(0x58);                // send mmc write block
   SPI_WRITE(HIGH(varh));
   SPI_WRITE(LOW(varh));
   SPI_WRITE(HIGH(varl));
   SPI_WRITE(0x00);                // always zero as mulitples of 512
   SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
   if((sd_response(0x00))==1) return 1;
   // Got response from SD
   SPI_WRITE(0xFE);                        // send data token
   for(i=0;i<512> 0);
   if(count==0) return 1;                  // loop was exited due to timeout
   else return 0;                          // loop was exited before timeout
}

int get_sd_status()
{
   output_low(PIN_D3);             // set SS = 0 (on)
   SPI_WRITE(0x58);                // send mmc command one to bring out of idle state
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);                //
   SPI_WRITE(0x00);                // always zero as mulitples of 512
   SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
   output_high(PIN_D3);            // set SS = 1 (off)
   return 0;
}

/*unsigned int HIGH(unsigned long var)
{
   return (var>>8)&0xFF;
}

unsigned int LOW(unsigned long var)
{
   return (var&0xFF);
}*/


Now, my code initializes the PIC so far, which is all it is really set up to do at the moment, but it doesn't write to the PIC. I believe this is because of the block number I am choosing to write to. If I do want to read the file it writes on the computer, how would I go about creating this dummy file and finding the start of it using the PIC in FAT16? Thanks for the help[/code]
Giawa
Guest







PostPosted: Wed Mar 28, 2007 8:06 pm     Reply with quote

Alright... here are my questions...

CCS compiler did not have a HIGH and LOW function that take the high and low bytes of a 16-bit number. So I wrote ones that I think work... Are these right?

Code:
unsigned int HIGH(unsigned long var)
{
   return (var>>8)&0xFF;
}

unsigned int LOW(unsigned long var)
{
   return (var&0xFF);
}


What will it looks like when I write a 512 byte sector the a FAT formatted SD card on my computer? Will there be a random text file with no name?

Finally, what data block do I start writing at?
libor



Joined: 14 Dec 2004
Posts: 288
Location: Hungary

View user's profile Send private message

PostPosted: Thu Mar 29, 2007 1:59 am     Reply with quote

Right.

Btw the complier has a make8() function. (this'll be quicker, than rotating bits 8 times)
make8(var,0) returns the low byte, and make8(var,1) the high byte of a long variable.

The other way No1: you can declare a union of a long and two int variables (overlapping each other) and access them directly.
The other way No2: using #locate you can declare a long and two int variables at the same memory position (without unions) and access them directly.
Giawa
Guest







PostPosted: Thu Mar 29, 2007 2:55 am     Reply with quote

Cool, I'll use the make8() function then, just because sometimes I do not trust my own code (especially with CCS because I am very new to it).

Any ideas on how to read the information from the SD card, and what block I need to start with? If I can't get this SD Card working I might just have to output the data serially, which would be too bad. The SD card idea seemed pretty awesome.

Thanks for the help so far :D
Giawa
Guest







PostPosted: Thu Mar 29, 2007 5:19 am     Reply with quote

Alright, for those of you who are following... I've been doing a lot of research about the SD cards and am starting to get somewhere... Here is my code!

Code:
#include "C:\Documents and Settings\HP_Administrator\Desktop\attempt3\wewt.h"
#define delay     5    // in seconds
#define HBM       0     // Heartbeat Mode
#define SD_CARD   1     // No SD card present yet (set to 1 to compile for SD card)
#use I2C(Master,sda=PIN_B4,scl=PIN_B5,FAST)  // SCL is purple, SDA is gray

void my_timer(unsigned long seconds);
void eeprom_write(unsigned char addrh,unsigned char addrl,unsigned char data);
unsigned char eeprom_read(unsigned char addrh,unsigned char addrl);
int init_sd();
int sd_response(unsigned char response);
int sd_write_block(unsigned int32 block_number);
unsigned int HIGH(unsigned long var);
unsigned int LOW(unsigned long var);
int get_sd_status();
unsigned char take_measure(int sensor);
void my_blink(unsigned int num);

void main()
{
   unsigned long data_pos, clk=0;
   unsigned int32 data_block=1;
   unsigned char temp=0;
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(AN0_TO_AN2);
   output_high(PIN_C1);     // Use as a power indicator?
   while (HBM) {
      output_toggle(PIN_C2);
      output_toggle(PIN_C1);
      delay_ms(500);
   }
   if (SD_CARD) {
      if (!init_sd()) output_low(PIN_C1);
   }
   for (data_pos=0; data_pos<512; data_pos++) {
      eeprom_write(HIGH(data_pos),LOW(data_pos),take_measure(1));
   }
   output_toggle(PIN_C1);
   if (SD_CARD) my_blink(sd_write_block(data_block));
}

unsigned char take_measure(int sensor)
{
   unsigned int adc_value;
   set_adc_channel(sensor);
   return (char)read_adc();
}

void my_blink(unsigned int num) {
   unsigned int i;
   for (i=0; i<num; i++) {
      output_high(PIN_C2);
      delay_ms(250);
      output_low(PIN_C2);
      delay_ms(250);
   }
}

void my_timer(unsigned long seconds) {
   unsigned long c_seconds;
   for (c_seconds=0; c_seconds<seconds; c_seconds++) {
      delay_ms(1000);
   }
}

void eeprom_write(unsigned char addrh,unsigned char addrl,unsigned char data)
{
   i2c_start();
   i2c_write(0xA0);                // send chip addr and set data to write mode
   i2c_write(addrh);               // high addr bits
   i2c_write(addrl);               // low addr bits
   i2c_write(data);                // write data
   i2c_stop();
   delay_ms(5);
}

unsigned char eeprom_read(unsigned char addrh,unsigned char addrl)
{
   unsigned char temp;
   i2c_start();
   i2c_write(0xA0);                // send address data in write mode
   i2c_write(addrh);               // high addr bits
   i2c_write(addrl);               // low addr bits
   i2c_start();
   i2c_write(0xA1);                // change to read mode
   temp = i2c_read(0);             // reads are not acknowledged (0)
   i2c_stop();                     // if no stop() can get continuous read
   return temp;
}

int init_sd()
{
   int i;
   SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SAMPLE_AT_END); //SPI_SS_DISABLED);
   *0x94 |= 0x40;                          // set CKE = 1 - clock idle low
   *0x14 &= 0xEF;                          // set CKP = 0 - data valid on rising edge
   output_high(PIN_D3);                    // set SS = 1 (off)
   for(i=0;i<10;i++)                       // initialise the MMC card into SPI mode by sending clks on
   {
      SPI_WRITE(0xFF);
   }
   output_low(PIN_D3);                     // set SS = 0 (on) tells card to go to spi mode when it receives reset

   SPI_WRITE(0x40);                        // send reset command
   SPI_WRITE(0x00);                        // all the arguments are 0x00 for the reset command
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x95);                        // precalculated checksum as we are still in MMC mode

   if(sd_response(0x01)==1) return 1;     // if = 1 then there was a timeout waiting for 0x01 from the mmc
   // Got response from MMC
   i = 0;
   while((i < 255) && (sd_response(0x00)==1))     // must keep sending command if response
   {
      SPI_WRITE(0x41);                // send mmc command one to bring out of idle state
      SPI_WRITE(0x00);                // all the arguments are 0x00 for command one
      SPI_WRITE(0x00);
      SPI_WRITE(0x00);
      SPI_WRITE(0x00);
      SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
      i++;
   }
   if(i >= 254) return 2;                   // if >= 254 then there was a timeout waiting for 0x00 from the mmc
   // Got out of idle response
   output_high(PIN_D3);                    // set SS = 1 (off)
   SPI_WRITE(0xFF);                        // extra clocks to allow mmc to finish off what it is doing
   output_low(PIN_D3);                     // set SS = 0 (on)

   SPI_WRITE(0x50);                // send mmc command one to bring out of idle state
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x02);                // high block length bits - 512 bytes
   SPI_WRITE(0x00);                // low block length bits
   SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
   if((sd_response(0x00))==1) return 3;
   output_high(PIN_D3);            // set SS = 1 (off)
   // Got set block length from MMC
   return 0;
}

int sd_write_block(unsigned int32 block_number)
{
   unsigned long i;
   unsigned long count = 0xFFFF;
   unsigned int varh,varm,varl;
   char temp;
   varh=make8(block_number,2);
   varm=make8(block_number,1);
   varl=make8(block_number,0);
   output_low(PIN_D3);                     // set SS = 0 (on)
   SPI_WRITE(0x58);                // send mmc write block
   SPI_WRITE(varh);
   SPI_WRITE(varm);
   SPI_WRITE(varl);
   SPI_WRITE(0x00);                // always zero as mulitples of 512
   SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
   if((sd_response(0x00))==1) return 1;
   // Got response from SD
   //for(i=0;i<8;i++) SPI_WRITE(0x00);
   SPI_WRITE(0xFE);                        // send data token
   for(i=0;i<512;i++)
   {
      SPI_WRITE(0x42);//eeprom_read(HIGH(i),LOW(i)));     // send data
   }
   SPI_WRITE(0xFF);                        // dummy CRC
   SPI_WRITE(0xFF);
   if ((temp=(SPI_READ(0xFF)&0x0F))!=0x05) return temp;
   // Got data response
   output_high(PIN_D3);                    // set SS = 1 (off)
   //for(i=0;i<8;i++) SPI_WRITE(0x00);
   return 0;
}

int sd_response(unsigned char response)
{
   unsigned long count = 0xFFFF;           // 16bit repeat, it may be possible to shrink this to 8 bit but there is not much point
   while(SPI_READ(0xFF) != response && --count > 0);
   if(count==0) return 1;                  // loop was exited due to timeout
   else return 0;                          // loop was exited before timeout
}

int get_sd_status()
{
   output_low(PIN_D3);             // set SS = 0 (on)
   SPI_WRITE(0x58);                // send mmc command one to bring out of idle state
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);                //
   SPI_WRITE(0x00);                // always zero as mulitples of 512
   SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
   output_high(PIN_D3);            // set SS = 1 (off)
   return 0;
}

unsigned int HIGH(unsigned long var)
{
   return make8(var,1);
}

unsigned int LOW(unsigned long var)
{
   return make8(var,0);
}



So here is what is going on...

I have no serial output, nor USB output, so the only feedback I get from this setup are two LEDs on pin C1 and C2.

So the LED on PIN_C1 turns on, which means the unit has power. Then it shortly shuts off, letting me know that the SD card has been initialized. Then it turns back on again letting me know that the EEPROM was successfully written to (512 bytes of data).

Then if there is a problem with writing which block to write to the SD card (the block number and write command) then LED on PIN_C2 will blink once. This used to be where my code got held up, but now the LED is not blinking once. Instead it is blinking 15 times, which is just 0x0F, a temp char value which is passed back out of sd_write_block() in my attempt to be able to read what codes the SD card is sending back.

Unfortunately, this value of 15 does not match up with any of the data response codes... So, can anyone see where I am going on?

I read that there should be 8 clock cycles between the writing the data block address and CRC, and then the data. I added 8 clock cycles by coding:
Code:
for(i=0;i<8;i++) SPI_WRITE(0x00);

This didn't change anything....

Are there any other hints? Right now I am just trying to right 0x42 512 times to the SD card at block_number 1.

Thanks!
Giawa
Guest







PostPosted: Thu Mar 29, 2007 5:38 am     Reply with quote

On a side note I realized that sending one byte sends 8 clock signals, so I didn't need the loop from 1 to 8... anyways, that didn't help at all either.

Code:
SPI_WRITE(0x00);   // send 8 block signals
ckielstra



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

View user's profile Send private message

PostPosted: Thu Mar 29, 2007 8:28 am     Reply with quote

You are free to write your own SD card routines but why not use the CCS supplied and tested MMC example routines?

For a file system implementation you can use one of the (commercial) available libraries. Search this forum for links. Implementations of FAT16 and FAT32 drivers are also available in the Code Library of this forum.
Or use one of the two quick methodes as suggested by asmallri.

For an overview of FAT16: http://en.wikipedia.org/wiki/FAT16

For low level checking of the memory cards I use the Hex disk editor tool called Hexplorer: http://hexplorer.sourceforge.net/
For example if you want to study the boot sector of a formatted flash card, you do the following:
- Under the menu 'Disk' select the drive letter of your flash card reader.
- Start with sector 0 (the boot sector).
- Place the cursor at the very first byte.
- From the menu 'Structures' select 'Fat32 boot sector', now a new window opens showing an easy to read overview of all field values.
Giawa
Guest







PostPosted: Thu Mar 29, 2007 10:44 am     Reply with quote

I unfortunately cannot afford a pre-written FAT implementation, and I am using SD card and MMC code that I found on the internet because I didn't understand exactly what was going on in the CCS version.

Now, I have some new news!!! By using that hex viewing program I am able to see that the SD card is indeed being written to. I just don't know how it is being written to... haha... To clarify, I do not know how to write where I want to on the SD card.
Code:

int sd_write_block(unsigned int32 block_number)
{
   unsigned long i;
   unsigned long count = 0xFFFF;
   unsigned int varh,varm,varl;
   char temp;
   varh=make8(block_number,2);
   varm=make8(block_number,1);
   varl=make8(block_number,0);
   output_low(PIN_D3);                     // set SS = 0 (on)
   SPI_WRITE(0x58);                // send mmc write block
   SPI_WRITE(varh);
   SPI_WRITE(varm);
   SPI_WRITE(varl);
   SPI_WRITE(0x00);                // always zero as mulitples of 512
   SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
   if((sd_response(0x00))==1) return 1;
   // Got response from SD
   //for(i=0;i<8;i++) SPI_WRITE(0x00);
   SPI_WRITE(0xFE);                        // send data token
   for(i=0;i<512;i++)
   {
      SPI_WRITE(0x42);//eeprom_read(HIGH(i),LOW(i)));     // send data
   }
   SPI_WRITE(0xFF);                        // dummy CRC
   SPI_WRITE(0xFF);
   if ((temp=(SPI_READ(0xFF)&0x0F))!=0x05) return temp;
   // Got data response
   output_high(PIN_D3);                    // set SS = 1 (off)
   //for(i=0;i<8;i++) SPI_WRITE(0x00);
   return 0;
}


So, now that I have been looking at this. I think the 32 bit data field, currently being filled:

Code:
   SPI_WRITE(varh);
   SPI_WRITE(varm);
   SPI_WRITE(varl);
   SPI_WRITE(0x00);                // always zero as mulitples of 512


is not quite right.... Does this mean that block_number should always be a multiple of 512, and then I should be taking the highest 8 bits for varh, the second highest 8 bits for varm and the second lowest 8 bits for varl? Then just add 512 to block_number everytime I want to move to the next block? This is what is confusing me now. I haven't been able to figure out a pattern...[/code]
Giawa
Guest







PostPosted: Fri Mar 30, 2007 12:21 am     Reply with quote

Can anyone shed some light on how the address scheme for SD cards works? I'm confused....
ckielstra



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

View user's profile Send private message

PostPosted: Fri Mar 30, 2007 12:24 pm     Reply with quote

Giawa wrote:
Can anyone shed some light on how the address scheme for SD cards works? I'm confused....
Get yourself some documentation on SD cards. The full SD specifications are only available to paying members of the SD Association but Sandisk used to provide a datasheet on their SD cards which was very detailed. A link to this datasheet and other usefull information can be found on Wikipedia.

Quote:
Does this mean that block_number should always be a multiple of 512, and then I should be taking the highest 8 bits for varh, the second highest 8 bits for varm and the second lowest 8 bits for varl? Then just add 512 to block_number everytime I want to move to the next block? This is what is confusing me now. I haven't been able to figure out a pattern...
Check the above mentioned datasheet, chapter 1.5.9.6: MMC / SD cards have to be written with a sector at a time, where the sector size is 512 bytes or a multiple of that (card dependent). When writing the data is not allowed to cross a sector boundary.
For all cards I know the sector size is 512 bytes, only the cards larger than 2Gb might require an increased sector size.
Reading the data is allowed in smaller blocks, even as small as 1 byte, but may still not cross a sector boundary.

What address are you trying to write to and where do you see it is written to?


Just for your information: When used in SPI-bus mode the SD cards are very similar to MMC cards. I prefer MMC cards over SD as the MMC licensing rules are much more relaxed (read cheaper) and allow for open source implementations. Another small dis-advantage of SD cards is that they waste 1% of memory on a protected memory area used by a copyright protection mechanism.
Giawa
Guest







PostPosted: Sat Mar 31, 2007 12:14 am     Reply with quote

Okay, progress has been made!!!

It seems like the SD card initializes about 95% of the time... And then it now writes to the correct block... But only about 1% of the time.

Any ideas on what could cause it to work sometimes, but not very often?
ckielstra



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

View user's profile Send private message

PostPosted: Sat Mar 31, 2007 11:03 am     Reply with quote

Code:
   SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SAMPLE_AT_END); //SPI_SS_DISABLED);
   *0x94 |= 0x40;                          // set CKE = 1 - clock idle low
   *0x14 &= 0xEF;                          // set CKP = 0 - data valid on rising edge
Here you are mixing CCS code and direct register access. Why?
The SPI_SAMPLE_AT_END is suspicious, it is not in my working initialization:
Code:
#define SPI_MODE_0_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1  (SPI_L_TO_H)
#define SPI_MODE_1_0  (SPI_H_TO_L)
#define SPI_MODE_1_1  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

// MMC can de used in either SPI mode 0 or 3.
  setup_spi(SPI_MASTER | SPI_MODE_1_1 | SPI_CLK_DIV_4);



Make sure to send at least 8 dummy clocks (i.e. 1 byte) between SD commands. You have disabled these lines in the posted code. Send the clock pulses with the data line high
Code:
  spi_read(0xFF);
You were sending 0x00 which is not according to the specifications.
Giawa
Guest







PostPosted: Sat Mar 31, 2007 12:30 pm     Reply with quote

Heya, in my new code I have removed direct register access..... Here's the new code

Code:
#include "C:\Documents and Settings\HP_Administrator\Desktop\attempt3\wewt.h"
#include "C:\Documents and Settings\HP_Administrator\Desktop\attempt3\mmc_spi.c"
#define delay     5    // in seconds
#define HBM       0     // Heartbeat Mode
#define SD_CARD   1     // No SD card present yet (set to 1 to compile for SD card)
#use I2C(Master,sda=PIN_B4,scl=PIN_B5,FAST)  // SCL is purple, SDA is gray

void my_timer(unsigned long seconds);
void eeprom_write(unsigned char addrh,unsigned char addrl,unsigned char data);
unsigned char eeprom_read(unsigned char addrh,unsigned char addrl);
int init_sd();
int sd_response(unsigned char response);
int sd_write_block(unsigned int32 block_number);
unsigned int HIGH(unsigned long var);
unsigned int LOW(unsigned long var);
int get_sd_status();
unsigned char take_measure(int sensor);
void my_blink(unsigned int num);

void main()
{
   unsigned long data_pos, clk=0;
   unsigned int32 data_block=1;
   unsigned int temp=0;
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(AN0_TO_AN2);
   output_high(PIN_C1);     // Use as a power indicator?
   while (HBM) {
      output_toggle(PIN_C2);
      output_toggle(PIN_C1);
      delay_ms(500);
   }
   if (SD_CARD) {
      delay_ms(10);
      if (!init_sd()) output_low(PIN_C1);
   }
   for (data_pos=0; data_pos<512; data_pos++) {
      eeprom_write(HIGH(data_pos),LOW(data_pos),take_measure(1));
   }
   output_toggle(PIN_C1);
   my_blink(sd_write_block(data_block));
   get_sd_status();
   output_toggle(PIN_C1);
}

unsigned char take_measure(int sensor)
{
   unsigned int adc_value;
   set_adc_channel(sensor);
   return (char)read_adc();
}

void my_blink(unsigned int num) {
   unsigned int i;
   for (i=0; i<num; i++) {
      output_high(PIN_C2);
      delay_ms(250);
      output_low(PIN_C2);
      delay_ms(250);
   }
}

void my_timer(unsigned long seconds) {
   unsigned long c_seconds;
   for (c_seconds=0; c_seconds<seconds; c_seconds++) {
      delay_ms(1000);
   }
}

void eeprom_write(unsigned char addrh,unsigned char addrl,unsigned char data)
{
   i2c_start();
   i2c_write(0xA0);                // send chip addr and set data to write mode
   i2c_write(addrh);               // high addr bits
   i2c_write(addrl);               // low addr bits
   i2c_write(data);                // write data
   i2c_stop();
   delay_ms(5);
}

unsigned char eeprom_read(unsigned char addrh,unsigned char addrl)
{
   unsigned char temp;
   i2c_start();
   i2c_write(0xA0);                // send address data in write mode
   i2c_write(addrh);               // high addr bits
   i2c_write(addrl);               // low addr bits
   i2c_start();
   i2c_write(0xA1);                // change to read mode
   temp = i2c_read(0);             // reads are not acknowledged (0)
   i2c_stop();                     // if no stop() can get continuous read
   return temp;
}

int init_sd()
{
   int i;
   SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SAMPLE_AT_END); //SPI_SS_DISABLED);
   //*0x94 |= 0x40;                          // set CKE = 1 - clock idle low
   //*0x14 &= 0xEF;                          // set CKP = 0 - data valid on rising edge
   output_high(PIN_D3);                    // set SS = 1 (off)
   for(i=0;i<10;i++)                       // initialise the MMC card into SPI mode by sending clks on
   {
      SPI_WRITE(0xFF);
   }
   output_low(PIN_D3);                     // set SS = 0 (on) tells card to go to spi mode when it receives reset

   SPI_WRITE(0x40);                        // send reset command
   SPI_WRITE(0x00);                        // all the arguments are 0x00 for the reset command
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x95);                        // precalculated checksum as we are still in MMC mode

   if(sd_response(0x01)==1) return 1;     // if = 1 then there was a timeout waiting for 0x01 from the mmc
   // Got response from MMC
   output_high(PIN_D3);
   SPI_READ(0xFF);
   output_low(PIN_D3);
   i = 0;
   while((i < 255) && (sd_response(0x00)!=0))     // must keep sending command if response
   {
      SPI_WRITE(0x41);                // send mmc command one to bring out of idle state
      SPI_WRITE(0x00);                // all the arguments are 0x00 for command one
      SPI_WRITE(0x00);
      SPI_WRITE(0x00);
      SPI_WRITE(0x00);
      SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
      i++;
   }
   if(i >= 254) return 2;                   // if >= 254 then there was a timeout waiting for 0x00 from the mmc
   // Got out of idle response
   output_high(PIN_D3);                    // set SS = 1 (off)
   SPI_WRITE(0xFF);                        // extra clocks to allow mmc to finish off what it is doing
   output_low(PIN_D3);                     // set SS = 0 (on)

   SPI_WRITE(0x50);                // send mmc command one to bring out of idle state
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x02);                // high block length bits - 512 bytes
   SPI_WRITE(0x00);                // low block length bits
   SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
   if((sd_response(0x00))==1) return 3;
   output_high(PIN_D3);            // set SS = 1 (off)
   // Got set block length from MMC
   return 0;
}

int mmc_wait_for_write_finish(void)
{
   unsigned long count = 0xFFFF;
   unsigned int result=0;
   while ((result==0 | result==0xFF) && count)
   {
      result=SPI_READ(0xFF);
      count--;
   }
   if (count==0) return 1;
   else return 0;
}

/* int sd_write_block - takes a 32bit integer block_number
will write a 512 byte segment to the assignmed block address*/
int sd_write_block(unsigned int32 block_number)
{
   unsigned long i;              // counter
   unsigned int32 data_block;    // data block to write to
   unsigned long count = 0xFFFF; // another counter
   BYTE Status;                  // status byte
   output_low(PIN_D3);           // set CS low
   data_block=block_number*512;  // shift block_number 9 bits so that block 1 will be 512 bytes
   SPI_WRITE(0x58);
   SPI_WRITE(make8(data_block,3));
   SPI_WRITE(make8(data_block,2));
   SPI_WRITE(make8(data_block,1));
   SPI_WRITE(0x00);
   SPI_WRITE(0xFF);
   if((sd_response(0x00))==1) {
      output_high(PIN_D3);
      return 1;
   }
   
   SPI_WRITE(0xFE);
   for(i=0;i<512;i++)
   {
      SPI_WRITE(0x07);
      SPI_READ();
   }
   SPI_WRITE(0xFF);
   SPI_WRITE(0xFF);
   Status=SPI_READ(0);
   if ((Status&0x0F)!=0x05) {
      output_high(PIN_D3);
      return Status&0x0F;
   }
   if (mmc_wait_for_write_finish()==1)
   {
      output_high(PIN_D3);
      return 3;
   }
   output_high(PIN_D3);
   return 0;
}

int sd_response(unsigned char response)
{
   unsigned long count = 0xFFFF;           // 16bit repeat, it may be possible to shrink this to 8 bit but there is not much point
   while(SPI_READ(0xFF) != response && --count > 0);
   if(count==0) return 1;                  // loop was exited due to timeout
   else return 0;                          // loop was exited before timeout
}

int get_sd_status()
{
   output_low(PIN_D3);             // set SS = 0 (on)
   SPI_WRITE(0x58);                // send mmc command one to bring out of idle state
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);
   SPI_WRITE(0x00);                //
   SPI_WRITE(0x00);                // always zero as mulitples of 512
   SPI_WRITE(0xFF);                // checksum is no longer required but we always send 0xFF
   output_high(PIN_D3);            // set SS = 1 (off)
   return 0;
}

unsigned int HIGH(unsigned long var)
{
   return make8(var,1);
}

unsigned int LOW(unsigned long var)
{
   return make8(var,0);
}
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