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 Oct 26 2016, 08:23 AM
is it possible to completly get the robot running from java code
Sun Oct 23 2016, 05:50 PM
mamata thakur
plz send full mini project report for ic 741&ic 555 tester
Wed Oct 19 2016, 03:30 PM
can you provide an explanation for the inverter 8051 code and how it works
Sat Oct 15 2016, 12:15 AM
@snaya. Create a thread in the 8051 forum for your questions
Fri Oct 14 2016, 10:00 AM
i m going to make a project with 8051and the name is scrolling led message display .now i wanna ask so many of questions.may be u can help me .so help me out
Fri Sep 30 2016, 10:40 AM
plz I want code for adc interfacing with8051
Sun Sep 25 2016, 04:41 AM
hi sir, could you help me regarding simple multiplication calculator?it should be include with buzzer. i use dragonplus. please
Sat Sep 24 2016, 05:49 PM
@Rus Ans .. what project ?
Sat Sep 24 2016, 05:48 PM
@engr1931 depends on type of scanner
Sat Sep 24 2016, 03:07 PM
Is it possible to send data from 2 barcode scanner to pc using serial port using 8051?



Thu Oct 27 2016, 01:54 PM
[email protected]
Fri Oct 21 2016, 10:35 PM
Sat Oct 15 2016, 09:40 AM
Wed Oct 05 2016, 08:16 AM
Mon Oct 03 2016, 07:37 PM
Thu Sep 29 2016, 06:31 AM
Thu Sep 08 2016, 06:28 PM
Sat Aug 20 2016, 01:44 PM


Guests: 31, Members: 0 ...

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

Members: 37787
Newest member: ozancakiroglu
Forum Activity
Pratik_Suthar Avatar
Posted By Pratik_Suthar
Thu Oct 13 2016, 12:39 PM
@martin the HEX file provided in the project is no...
ajay_bhargav Avatar
Posted By ajay_bhargav
Thu Oct 06 2016, 06:15 AM
Hi Phil, Do you want to add this to existing proje...
ajay_bhargav Avatar
Posted By ajay_bhargav
Thu Oct 06 2016, 06:13 AM
CE should be high when you go for reading mode/wai...
ajay_bhargav Avatar
Posted By ajay_bhargav
Thu Oct 06 2016, 06:03 AM
You can also use ESP8266 with its SDK to write app...
ExperimenterUK Avatar
Posted By ExperimenterUK
Mon Oct 03 2016, 11:15 PM
This is an old thread and the links no longer work...
martinsnc115877 Avatar
Posted By martinsnc115877
Wed Sep 14 2016, 12:51 PM
sir, i did your led scrolling mass display, and it...
ExperimenterUK Avatar
Posted By ExperimenterUK
Fri Sep 09 2016, 11:45 PM
The Hex file for this project is a bit too big for...
rajavarmanslr Avatar
Posted By rajavarmanslr
Thu Aug 18 2016, 01:40 PM
I have two 8051 that interfaces with nRF24l01. One...
rajavarmanslr Avatar
Posted By rajavarmanslr
Thu Aug 18 2016, 12:31 PM
I have two 8051 that interfaces with nRF24l01. One...