Discussion in "8051 Discussion Forum" started by    Help    Dec 8, 2008.
Sat Jan 31 2009, 06:28 am
#71
I'll try:

Firstly, Chan has written two different versions of his FAT file system: FF.C and TFF.C - I chose to port the TFF.C version.

The only files you need to concern yourself with are the DISKIO.C file and the TFF.H file, which has conditional compiler options in it...

Before you begin the port, I recommend you have working the basic SPI functions you need to communicate with the card. This is very important, so you don't waste time trying to debug something within Chan's stuff, when really it's your routine that doesn't work...

My basic routines are as follows:

   enum SPI_FREQUENCIES { kHz400, MHz1, MHz5, MHz10 };

   extern void SPI_EnableCS      ( );
   extern void SPI_DisableCS     ( );
   extern void SPI_Init          ( enum SPI_FREQUENCIES ThisFrequency );
   extern BYTE SPI_Byte          ( BYTE ThisByte );
   extern void SPI_SetChannel    ( BYTE ThisChannel );

   extern BYTE SD_Init           ( );
   extern BYTE SD_Command        ( BYTE ThisCommand, ULONG ThisArgument );
   extern BYTE SD_CRC_7          ( BYTE *List, BYTE Length );
   extern BYTE SD_GetR1          ( );
   extern WORD SD_GetR2          ( );
   extern BYTE SD_ReadSector     ( ULONG SectorNumber, BYTE *Buffer );
   extern BYTE SD_WriteSector    ( ULONG SectorNumber, BYTE *Buffer );
   extern BYTE SD_WaitForReady   ( );


When you feel each of the above routines works perfectly, begin the port by rewriting the 5 simple functions in DISKIO.C, namely:
DSTATUS disk_initialize( BYTE drv )
DSTATUS disk_status( BYTE drv	)
DRESULT disk_read ( BYTE drv, BYTE *buff, DWORD sector, BYTE count )
DRESULT disk_write( BYTE drv, const BYTE *buff, DWORD sector, BYTE count )
DRESULT disk_ioctl ( BYTE drv, BYTE ctrl, void *buff )


Here is an example of how I wrote the disk_read(...) function above:
/*-----------------------------------------------------------------------*/
/* Read Sector...                                                        */
/*-----------------------------------------------------------------------*/
DRESULT disk_read ( BYTE drv, BYTE *buff, DWORD sector, BYTE count )
   {
   /* Supports only single drive and must have a size of 1 sector */
   if( drv || !count || (count>
1) ) 
      return( RES_PARERR );

   /* if we haven't initialized the card yet... */
   if( Stat & STA_NOINIT ) 
      return RES_NOTRDY;
   
   /* Single block read */
   if( SD_ReadSector( sector, buff ) )
      return( RES_ERROR );
   
   return( RES_OK );
   }


The same must be done for each of the 5 functions listed...
Also, the compiler options within TFF.C must be set correctly. Here is how I have mine set:
#define _MCU_ENDIAN	2
#define _FS_READONLY	0
#define _FS_MINIMIZE	0
#define	_USE_STRFUNC	1
#define	_USE_FORWARD	1
#define _FAT32	        0
#define _USE_FSINFO	1
#define	_USE_SJIS	1
#define	_USE_NTFLAG	1


Once you have written each of the 5 functions listed, and everything compiles, you will need one final function:
DWORD get_fattime()
   {
   RTC_CURRENT rtc;
   
   
   RTC_read( &rtc );
   
   return	  ((DWORD)((WORD)(rtc.Year) + 2000 - 1980) << 25)
                  | ((DWORD)rtc.Month << 21)
                  | ((DWORD)rtc.Date << 16)
                  | ((DWORD)rtc.Hours << 11)
                  | ((DWORD)rtc.Minutes << 5)
                  | ((DWORD)rtc.Seconds >
>
 1);
   }


This particular function reads the time from my on-board real-time clock and formats the data for Chan's routines...

Hope this helps - my system is working perfectly...

Mon Feb 02 2009, 10:40 am
#72
I have been private-messaged by the Original Poster to start from the beginning... :-s

I'm not sure exactly what specific points you need help with. Perhaps you can explain your question in detail here.

i just re-read the entire thread on this subject, and Ajay has been very specific, including example code for the low-level drivers that interface with the SPI bus. I too have been very specific, with code examples and suggestions.

If you have a specific question, I would be happy to try and answer...

By the way, do you have a name, or is your real name "Help"

-dave
Mon Feb 02 2009, 01:45 pm
#73
Dear Dave,

I'm using AT89C52 uC. This uC don't have build in SPI function but Ajay have taught me how to write the SPI routine for MMC.
1) If for my case the uC have not SPI function. Do i still need SPI frequencies initial?
2) SPI_SetChannel() function, may i know how it work? Please can you guide me how to write the function routine.
3) SD_CRC_7(), SD_GetR1(), SD_GetR2(), and SD_WaitForReady() function, please can you share with us how you to write coding?

Dear Dave,..Sure i have a name. You can call me Tang Nice to meet you.

Thank you,.


[ Edited Mon Feb 02 2009, 01:50 pm ]
Mon Feb 02 2009, 04:33 pm
#74
Hello Tang,

To answer your questions:

1. Do i still need SPI frequencies initial? Yes. When communicating with the SD card over the SPI interface, the initial SPI clock frequency cannot exceed 400Khz, and must be faster than 100Khz. This can be found in the SanDisk Secure Digital Card Product Manual Version 1.9, section 4.5. under "Clock Control"

2. SPI_SetChannel() function SPI_SetChannel() is a function I wrote to select between several SPI devices that are all connected to the MOSI and MISO lines from my microcontroller. Recall that each SPI device has 4 basic connections: SPICLK, MISO, MOSI, and CS. These connections are the SPI clock signal, the input line to the microcontroller, the output line from the microcontroller, and a chip select (respectively). A very good description of this bus can be found at:

http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus

If you only have the SD card, you can connect the CS signal to any available output pin on your microcontroller (provided the voltage is 3.3v) and not use this function. If you have more than one device connected to this bus, then you must provide a way of selecting only one device at a time. For instance, say P3.0 is connected to the SD memory card CS pin, and P3.1 is connected to some other device (like a temperature sensor). Your routine might look like this:
enum DeviceChannel = { SD_CARD, TEMP_CHIP };

void SPI_SetChannel( enum DeviceChannel ThisChannel )
   {
   switch( ThisChannel )
      {
      case SD_CARD :
         P3 = (P3 & 0xFC) | 0x01;
         break;
      case TEMP_CHIP :
         P3 = (P3 & 0xFC) | 0x02;
         break;
      default :
         P3 = (P3 & 0xFC);
         break;
      }
   }


Please understand that your routine will be specifically designed for YOUR hardware configuration...
3. SD_CRC_7(), SD_GetR1(), SD_GetR2(), and SD_WaitForReady() function The SD_CRC_7() function is optional, actually. I wrote it so that I could calculate a 7-bit CRC value for a string of bytes. If you do not understand CRC, you can read about it here:

http://en.wikipedia.org/wiki/Cyclic_redundancy_check

Since you don't really need the CRC values for commands when communicating with the SD card, you can just ignore this function.

The SD_GetR1() function is for retrieving the response byte from the card when it is in the R1 format, as described in the SanDisk Secure Digital Card Product Manual Version 1.9, section 5.2.3.1. "Format R1"

My function is as follows:
BYTE SD_GetR1()
   {
   BYTE i, j;

   for( i=0; i<8; i++ )
      {              /* response will be after 1-8 0xffs.. */
      j = SPI_Byte( 0xff );
      if(j != 0xff)  /* if it isn't 0xff, it is a response */
         return(j);
     }
   return(j);
   }


I believe you can get the idea from this example, and write your own code for the R2 response. If you read section 5.2.3.3. from the product manual, it fully describes the format...

And finally, the SD_WaitForReady() function was just something to maintain compatibility with Chan's stuff. It is a simple routine that sends nothing but clock pulses to the SD card, and insures the card isn't in the middle of something.

My rendition of it looks like this:
BYTE SD_WaitForReady()
   {
   BYTE i;
   WORD j;

   SPI_Byte( 0xFF );
   
	j = 500;
   do
      {
		i = SPI_Byte( 0xFF );
      Delay( 1 );
      } while ((i != 0xFF) && j);
   
   return( i );
   }


Undoubtedly, you are wondering what the SPI_Byte() function does, as well as the Delay() function...
The SPI_Byte function sends a byte to the currently selected SPI device, and returns any response from that device. The Delay function waits for the number of milliseconds. In this example, the delay is 1 millisecond.

I hope this helps you...

By the way, if you don't already have a copy of the product manual, you can find it here:

http://www.cs.ucr.edu/~amitra/sdcard/ProdManualSDCardv1.9.pdf

-dave
Tue Feb 03 2009, 01:16 pm
#75
Dave, me and Help working on a controller with no SPI, i mean its just gonna be slow nothing else that that. everything else is going to remain same.

Well i cannot believe i made this mistake in downloading files

i just downloaded the new files.
so as i checked we only have to bother about diskio.c right? and define our own functions with name
MMC_disk_initialize();
MMC_disk_status();
MMC_disk_read(buff, sector, count);
MMC_disk_write(buff, sector, count);
MMC_disk_ioctl(ctrl, buff);

how much amount of minimum RAM needed for this?
Tue Feb 03 2009, 01:38 pm
#76
Dear Daves,



1. Please can you guide me how to write the SPI clock in 100kHz-400kHz? Is it correct the Clock Timing diagram? If correct, how can we write an efficiency code on this part? I'm worry if i put a while-loop/for-loop for delay 400kHz/100kHz then it will take the processor load usage, somemore SD have 512 byte's to send/receive, am i rite?

2. SPI_SetChannel() function i think i know how to do already. Thank for your advice.

3. I have ready CRC7 function. Please can you compare your result with mine? I would like to confirm the CRC7 function do correct not. Let say,
Ex1:
List[0]=0x40
List[1]=0x00
List[2]=0x00
List[3]=0x00
List[4]=0x00
Length = 5
CRC = 0x4A

Ex2:
List[0]=0x40
List[1]=0x00
List[2]=0x00
List[3]=0x00
List[4]=0x31
Length = 5
CRC = 0x68

The SD_GetR2(), and SD_WaitForReady() function i think should not be the problem, i can understand it. I think this two function have to complete all the basic routines then only can test. Hopefully after the basic routines finished tested is ok.

Thank you,.
Wed Feb 04 2009, 12:40 am
#77
Tang,

Actually, when they say 100-400kHz, they're talking about frequency, which is defined here:

http://en.wikipedia.org/wiki/Frequency

so actually, your picture should look like this:




That means that from rising edge to rising edge, the time should be 2.5 - 10 usecs, which means you will need an interrupt for the rising edge, and then an interrupt for the falling edge. In other words, your interrupt must happen every 1.25 usecs, but not slower than every 5 usecs. Also, when the interrupt occurs, you must shift 1 bit of information out over your designated MOSI pin, and shift 1 bit of information in from your designated MISO pin, every OTHER interrupt...
Wed Feb 04 2009, 01:13 am
#78
Ajay,

You are correct. :-) These, along with the compiler options located in either FF.H or TFF.H are the only things that need to be modified...

Regarding the memory, you need a buffer of 512 bytes for the read/write buffer and probably another 512 bytes for static variables, stack variables, and local buffers...

I am using XDATA for my variables, since I have NOVRAM attached to my microcontroller. My memory chip is an ST M48T37Y-70MH1E, which is an expensive part, but works nicely in my system. It also has an embedded real-time clock in it, which satisfies the need for date/time stamping on files I create on my SD card.

-dave
Wed Feb 04 2009, 02:16 am
#79
Tang,

Regarding the CRC calculations, I get a different answer than you do:

Ex1:
List[0]=0x40
List[1]=0x00
List[2]=0x00
List[3]=0x00
List[4]=0x00
Length = 5
CRC = 0x95

Ex2:
List[0]=0x40
List[1]=0x00
List[2]=0x00
List[3]=0x00
List[4]=0x31
Length = 5
CRC = 0xD1

Here's a link to everything you ever wanted to know about CRC calculations:
http://www.geocities.com/SiliconValley/Pines/8659/crc.htm

I got help from here:

http://www.edaboard.com/ftopic102279.html

Here is how I calculate the proper 7-bit CRC:
// _____________________________________________________________________________________________
//                                                                                              
// Function: SD_CRC_7()                                                                         
//                                                                                              
// Description:                                                                                 
// ------------                                                                                 
// calulates the 7-bit CRC for a list of bytes...                                               
//                                                                                              
// Design Notes:                                                                                
// -------------                                                                                
// In the case of CRC-7, the remainder can be calculated using a 7-bit shift register in        
// software. This shift register is initialized to all zeros at the start of the calculation. As
// each bit (MSB first) of the protected data is shifted into the LSB of the shift register,    
// the MSB of the shift register is shifted out and examined. If the bit just shifted out is    
// one, the contents of the shift register are modified by XORing with the CRC-7 polynomial     
// value 0x09. If the bit shifted out of the shift register is zero, no XOR is performed. Once  
// the last bit of protected data is shifted in and the conditional XOR completed, six more     
// zeros must be shifted through in a similar manner. This process is referred to as            
// augmentation, and completes the polynomial division. At this point, the CRC-7 value can be   
// read directly from the shift register.                                                       
// _____________________________________________________________________________________________
//                                                                                              
BYTE SD_CRC_7( BYTE *List, BYTE Length )
   {
   idata BYTE crc = 0x00;
   idata BYTE i, j, mask;

   for( i=0; i<Length; i++ )
      {
      mask = List[ i ];
      for( j=0; j<8; j++)
         {
         crc <<= 1;
         if(( mask & 0x80 ) ^ ( crc & 0x80 ) )
            crc ^= 0x09;
         mask <<= 1; 
         }
      }
   crc = (crc << 1) | 1;
   return( crc );
   }
Wed Feb 04 2009, 05:02 pm
#80
Dear Daves,

Thank for your usefull information and thank for your CRC7 coding. Previously my code is
crc = crc << 1 | 1;
now i change it to
crc = (crc << 1) | 1;
then work fine already..Thank again.

Please guide me how to write the 1.25uSec interrupt? The frequency is too high. I'm using this fomula
F = 11059200
t = 2us
S = 65535 - (F*t)/12
S = 65533.1568
S = 0xFFFD
So, i define TL0=0xFD and TH0=0xFF.
Is it correct?

I have write a simple Timer0 interrupt code, not sure correct not? Please can you check for me?
void init_timer0(void)
{
	TMOD &= 0xF0;
	TMOD |= 1;

	TL0 = TL;
	TH0 = TH;

	ET0 = 1;
	EA  = 1;
	TR0 = 1;
}

void ticks(void)
{
	char i;
	i++;
                     // SPI coding start
                     // ....
                     // ..   
}

void clk_tick() interrupt 1
{
	TR0 = 0;
	ET0 = 0;

	ticks(); 

	TL0 = TL;
	TH0 = TH;

	ET0 = 1;
	TR0 = 1;
}


Please advice...

Thank you,.


[ Edited Wed Feb 04 2009, 08:03 pm ]

Get Social

Information

Powered by e107 Forum System

Downloads

Comments

carpinteyrowrl
Fri Apr 19 2024, 02:51 pm
DonaldJAX
Fri Apr 19 2024, 01:08 pm
Lewisuhakeply
Thu Apr 18 2024, 06:00 pm
Darrellciz
Thu Apr 18 2024, 11:07 am
Charlessber
Thu Apr 18 2024, 09:29 am
BartonSem
Thu Apr 18 2024, 04:56 am
DonaldKnown
Thu Apr 18 2024, 12:24 am
utaletxcyw
Wed Apr 17 2024, 10:21 am