|
|
View previous topic :: View next topic |
Author |
Message |
Giawa Guest
|
Writing to an SD card and reading it on a computer |
Posted: Wed Mar 28, 2007 4:56 am |
|
|
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: 1634 Location: Perth, Australia
|
Re: Writing to an SD card and reading it on a computer |
Posted: Wed Mar 28, 2007 7:53 am |
|
|
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
|
|
Posted: Wed Mar 28, 2007 11:34 am |
|
|
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
|
|
Posted: Wed Mar 28, 2007 8:06 pm |
|
|
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
|
|
Posted: Thu Mar 29, 2007 1:59 am |
|
|
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
|
|
Posted: Thu Mar 29, 2007 2:55 am |
|
|
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
|
|
Posted: Thu Mar 29, 2007 5:19 am |
|
|
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
|
|
Posted: Thu Mar 29, 2007 5:38 am |
|
|
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
|
|
Posted: Thu Mar 29, 2007 8:28 am |
|
|
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
|
|
Posted: Thu Mar 29, 2007 10:44 am |
|
|
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
|
|
Posted: Fri Mar 30, 2007 12:21 am |
|
|
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
|
|
Posted: Fri Mar 30, 2007 12:24 pm |
|
|
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
|
|
Posted: Sat Mar 31, 2007 12:14 am |
|
|
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
|
|
Posted: Sat Mar 31, 2007 11:03 am |
|
|
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 highYou were sending 0x00 which is not according to the specifications. |
|
|
Giawa Guest
|
|
Posted: Sat Mar 31, 2007 12:30 pm |
|
|
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);
} |
|
|
|
|
|
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
|