Discussion in "8051 Discussion Forum" started by    Help    Dec 8, 2008.
Sat Jan 31 2009, 12:58 AM
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_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 >

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, 05:10 AM
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"

Mon Feb 02 2009, 08:15 AM
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, 08:20 AM ]
Mon Feb 02 2009, 11:03 AM
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:


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;
      case TEMP_CHIP :
         P3 = (P3 & 0xFC) | 0x02;
      default :
         P3 = (P3 & 0xFC);

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:


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 "Format R1"

My function is as follows:
   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 */

I believe you can get the idea from this example, and write your own code for the R2 response. If you read section 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;
		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:


Tue Feb 03 2009, 07:46 AM
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_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, 08:08 AM
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,
Length = 5
CRC = 0x4A

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,.
Tue Feb 03 2009, 07:10 PM

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


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...
Tue Feb 03 2009, 07:43 PM

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.

Tue Feb 03 2009, 08:46 PM

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

Length = 5
CRC = 0x95

Length = 5
CRC = 0xD1

Here's a link to everything you ever wanted to know about CRC calculations:

I got help from here:


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, 11:32 AM
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;
                     // SPI coding start
                     // ....
                     // ..   

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


	TL0 = TL;
	TH0 = TH;

	ET0 = 1;
	TR0 = 1;

Please advice...

Thank you,.

[ Edited Wed Feb 04 2009, 02:33 PM ]

Get Social


Powered by e107 Forum System


Wed Mar 22 2017, 09:13 PM
ajay kumar
help me nokia lcd light
Wed Feb 22 2017, 06:14 AM
Indeed, on the LCD tutorial, many missing Tables and figures !!
Wed Feb 22 2017, 06:06 AM
I don't see any Table 3. I'm using Chrome.
Fri Feb 03 2017, 05:56 AM
irfan shaikh
hi, i want interface WS2811 pixel led using NUVOTON N79E352, but i dont know how to code it. can anyone help me or provide me sample coding for interfacing WS2811 PIXEL LED. THNX
Thu Jan 19 2017, 08:42 PM
Hi...i have made a circuit for interfacing PT100 with LM358 whose temperature is shown on the LCD...But the temperature is not getting incresed slowly ..a small change directly increses the temp...can any one help me
Thu Jan 19 2017, 04:27 PM
send me alarm clock simulation using proteus software
Mon Jan 16 2017, 03:15 PM
How can we read notepad file using random acess file
Fri Jan 06 2017, 06:18 AM
muhammad Umar
i need cd4047 library file for protious please help me i s
Wed Jan 04 2017, 09:01 PM
@Emin what is your site user name ?
Tue Jan 03 2017, 11:16 PM
Emin: I'm already a member since 2012 and entered repeatedly during period. But now it is impossible and obtaining a new registration is also failed. The same error message specifying that two e-mails i entered are different!. In fact thaey are the same. Now, what will be happen, what is your solution? Thanks..



Tue Mar 21 2017, 02:29 PM
Mon Mar 20 2017, 11:21 AM
Tue Mar 14 2017, 07:08 AM
Wed Feb 22 2017, 02:40 AM
Thu Feb 16 2017, 02:40 PM
Thu Feb 09 2017, 09:59 AM
Sat Jan 28 2017, 08:58 AM
Tue Jan 17 2017, 06:25 PM


Guests: 74, Members: 0 ...

most ever online: 182184
(Members: , Guests: 182184) on 06 Aug 2010: 05:37 AM

Members: 37804
Newest member: SAUnwin
Forum Activity
Deepakvaishu Avatar
Posted By Deepakvaishu
Fri Mar 24 2017, 05:22 AM
Hi,I got that we should use timer......But I am a ...
ExperimenterUK Avatar
Posted By ExperimenterUK
Thu Mar 23 2017, 09:14 PM
You have largely answered your own question.Use on...
ExperimenterUK Avatar
Posted By ExperimenterUK
Thu Mar 23 2017, 07:03 AM
I have looked at your code.I think you are confuse...
Deepakvaishu Avatar
Posted By Deepakvaishu
Thu Mar 23 2017, 05:34 AM
hello,I can type the letters now when the particul...
SAUnwin Avatar
Posted By SAUnwin
Tue Mar 21 2017, 02:55 PM
HI,There are two ways I'd tackle thiss.Key down on...
Deepakvaishu Avatar
Posted By Deepakvaishu
Mon Mar 20 2017, 08:24 AM
hello,I am using a keypad to type the text message...
Helia Avatar
Posted By Helia
Thu Mar 16 2017, 09:15 AM
hi.. the following code is not working on hardware...
ajay_bhargav Avatar
Posted By ajay_bhargav
Tue Mar 14 2017, 08:39 AM
ajay_bhargav Avatar
Posted By ajay_bhargav
Tue Mar 14 2017, 08:36 AM
Try to check the character set currently set in yo...
Deepakvaishu Avatar
Posted By Deepakvaishu
Thu Mar 09 2017, 05:14 AM
sim 300 gsm modem is not able to send the message ...