A complete guide for beginners to read and write SD card FAT using C8051F020 SPI

Publisher:sky0001Latest update time:2016-07-19 Source: eefocusKeywords:C8051F020 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
I started to learn how to read and write SD cards with a microcontroller just after the summer vacation a month ago. I finished FAT16 in early August and can now write TXT files and read them on Windows. Since the information on the Internet is scattered, I took a lot of detours at the beginning. Now I write a summary to list the problems I encountered in detail, hoping to help novices like me avoid detours. Some of the problems mentioned in the article are just common sense for experts, so please bear with me.

      Step 1: Build the circuit

      I bought a small honeycomb board and an SD slot, and soldered them according to the standard circuit. Since the SPI mode is used, you must be careful when choosing the circuit diagram. Don't make a mistake in the pin order on the SD card, 912345678. The last two are very close together, so don't connect them when soldering. The relevant pins must be connected to a 47K pull-up resistor as required. Although the circuit is simple, you must ensure that it is correct. Another point is that there are different types of SD card holders. A senior bought a spring-type one. After soldering, the initialization was successful at the beginning, but it suddenly stopped working after a few days. After checking the pins, there was no problem. Finally, it was found that it was a problem with the card holder. Such hardware problems are difficult to find and waste time, so it is better to buy a simple card holder.

      Step 2: Set up the hardware SPI

       I use sililab's C8051F020, which comes with hardware SPI. If it doesn't come with hardware SPI, you can use software to simulate it. There are many ready-made programs on the Internet for software simulation of SPI. In this step, I first wrote a program according to the 020 manual. Of course, it is set to master mode. At this time, CONFIG (this software can operate most registers of C8051F in a windowed manner and automatically generate code) will allocate 4 pins, CLK clock bit, MISO and MOSI two data transmission bits, and an NSS bit. This pin is not used. Don't use it as a CS chip select bit. Just select a normal IO for the CS bit. All pins output from the microcontroller are set to push-pull output. After the setting is completed, it is best to get an oscilloscope to see if the output waveform is the same as you imagined, so that you can ensure that your SPI is working properly. This step is also critical. SPI is the basis of underlying communication.

       Step 3: Initialize the SD card

        This step officially enters the MCU debugging SD part. After understanding the timing of the SD card (I will upload this part of the information later), there are many different opinions on the Internet, and some people say that you need to read the 178-page English PDF. I am dizzy. I guess I am an expert after reading this. There are many opinions about the initialization command. I sent CMD0 and CMD1 to successfully initialize.

         Explain the meaning of this command format: This is a one-byte command format of 01xx xxxx. The last six digits are the binary value of the number following CMD, such as CMD1=0100 0001=0x41. It is written as CMD | 0x40 in the program. CMD represents the number following it.

         It should be noted that the SPI rate cannot exceed 400K during initialization. I set it to 100K and there was no problem with initialization. Also, at least 74 clock cycles must be sent to the SD card before sending CMD0. Only CMD0 needs to be special.

The following is the program segment for sending CMD0:

 retry=0;
  CSH;

 do{
  for(i=0;i<10;i++) SPI_WriteByte(0xFF); // Send at least 74 clock cycles Note that the chip select line is high at this time
  r1=mmcSendCommand(MMC_GO_IDLE_STATE, 0); // Send CMD0, note that the chip select line is low at this time
  retry++;
  if(retry>0xfe) return -1; // The number of attempts to send can be appropriately more
 } while(r1 != MMC_R1_IDLE_STATE); // The correct response is 1

      Try to send at least 200 times. Some people suggest 2000. It doesn't matter. If it is unstable, such as sometimes it can be received and sometimes it can't, you can increase the number of sending times appropriately.

      This is the CMD1 program segment sent immediately afterwards:

 retry=0;
 do{   
  r1=mmcSendCommand(MMC_SEND_OP_COND, 0); //Send CMD1
  retry++;
  if(retry>100) return -1;
 } while(r1!=0); //Correct response is 0

     Initialization can be completed with these two, and some programs will also add 

mmcSendCommand(MMC_CRC_ON_OFF, 0); // Turn off CRC check

mmcSendCommand(MMC_SET_BLOCKLEN, 512); //Set the block length to 512 bytes

      This is irrelevant. There is no CRC check by default in SPI mode, and the number of bytes per block is 512. Don't change the block size. If you set it to another size, there will be trouble when adding FAT later.

      The following explains the uint8_t mmcCommand(uint8_t cmd, uint32_t arg) function in the above program

      uint8_t mmcCommand(uint8_t cmd, uint32_t arg)

{
 uint8_t r1,retry=0;
 SPI_WriteByte(cmd|0x40); // send command
 SPI_WriteByte(arg>>24);
 SPI_WriteByte(arg>>16);
 SPI_WriteByte(arg>>8);
 SPI_WriteByte(arg);
 SPI_WriteByte( 0x95); //Explanation mark (1)
 SPI_WriteByte(0xFF);//Explanation mark (2)


 while((r1=SPI_WriteByte(0xFF))==0xFF)if(retry++>8)break;
 return r1;
}

The arg parameter is a command attribute, usually 0.

Explanation Marking (1)

The CRC bit 0x95 is only meaningful for CMD0. This bit can be any value when sending other commands, so it does not need to be modified.

Explanation Marking (2)

This is easy to ignore. If you don't ignore the first byte, you may not receive the correct response. In many programs, this is called dummy values. Pay special attention to the timing diagram. In the program that writes the command later, two bytes are sent. Don't confuse this.

Write command program segment:

uint8_t mmcWrite(uint32_t sector, uint8_t* buffer){
 uint8_t r1;
 uint16_t i;

 CSL; // assert chip select 
 r1 = mmcCommand(MMC_WRITE_BLOCK,sector<<9); // issue command
 if(r1 != 0)return r1; 
 SPI_WriteByte(0xFF); // send dummy 
 SPI_WriteByte(MMC_STARTBLOCK_WRITE); // send da ta start token
 
 for(i=0; i<512; i++){
  SPI_WriteByte(*buffer++); // write da ta
 }
 
 SPI_WriteByte(0xFF); // write 16-bit CRC (dummy values) See clearly! Two bytes!
 SPI_WriteByte(0xFF);
 
 r1 = SPI_WriteByte(0xFF); // read da ta response token
 if((r1&MMC_DR_MASK)!=MMC_DR_ACCEPT)return r1; //Explain token (1)
 while(!SPI_WriteByte(0xFF)); // wait until card not busy
 CSH; // release chip select
 return 0;
}

Explanation Marking (1)

This is so important!!! I wasted a week on this!!!

Many programs including most of the information on the Internet say that the response is 0x05, but I never receive this response. What I receive is 0xE5. I thought there was something wrong with the program, but it was not. I checked the information and found the meaning of the 8 bits of this response token. I found that the upper three bits are reserved bits, and the lower five bits of 0xE5 and 0x05 are the same, which means the response is correct. The upper three bits may have different values ​​due to different manufacturers.

This program is relatively complete. In response to r1 and the previous MMC_DR_MASK (the macro definition value is 0x0001 1111), the upper three bits are ANDed to 0. Some programs on the Internet do not have this process.

 

If you want to verify whether the card can be read and written normally, you can assign the value to the array and write it to a sector of the SD card (the sector here refers to the physical sector, which will be discussed in the FAT file). Then read it out with the array and see if it is the same in the emulator. This process may not use the winhex software, because the sector you write to may be the boot area, which will cause you to be prompted to format the card when you insert it into the computer.

Below is the waveform of CMD0

Click to enlarge

 

I originally thought that there was something wrong with the waveform, because the chip select line in the timing diagram was always low during the data transmission process. I asked about it online for a while, but unfortunately no one paid attention to me. In fact, it was correct. The level jump in the middle was due to the chip select being pulled low and high at the beginning and end of the SPI sending function. Once the chip select line is pulled high, the data line will become high as well, so the jump occurred. I tried to remove the chip select at the beginning and end of the SPI sending function, and found that this also worked.

 

Step 4: Add FAT

If the above tests are all OK, then there is no problem with the underlying communication. So far, we have been operating the SD as a large FLASH, but if you want to read the program written by the microcontroller on the computer, you must write it in accordance with certain rules, and this rule is FAT. I use a 2G Kingston SD card, which can use FAT16, and FAT16 supports up to 2G.

For more information about this section, please refer to http://www.sjhf.net/document/fat/ #index

The explanation inside is very detailed and will help you understand the file system

The idea that needs to be grasped is: first use a computer to format the SD card into FAT16 (i.e. FAT), and then the reading and writing rules are: find the MBR (master boot area) and read the relevant bytes to get the address of the logical boot area, read the BPB data in the logical sector, and then perform corresponding operations on the FAT table, root directory and data area.

You can use winhex to view the physical and logical sectors of the SD card for comparison.

 

Here I will talk about some problems I encountered.

1>>If it is VISTA operating system, you need to enter as an administrator, otherwise you will not be able to see the physical sectors, that is, stop the mouse on the winhex icon, right-click and select Run as administrator (don't laugh, I didn't know how to do this at the beginning, haha)

2>>Some SD cards do not have a master boot area, or MBR. This is better, and the logical sector is the same as the physical sector. So how do you determine whether there is an MBR? The simplest way is to use winhex to look at the physical and logical sectors. If the data is the same, there is no MBR. Another more rigorous method is to pay attention to the explanation of the logical boot area in the PDF. The logical boot area basically starts with E9 and EB. This alone can be easily determined using a function. So before writing a file, find out whether your SD card has an MBR. For more information, please refer to http://hi.baidu.com/bg4uvr/blog/item/b59f2fde196efd5fcdbf1aee.html

Is there any MBR that can be converted? For details, please see: http://hi.baidu.com/bg4uvr/blog/item/9489a6295f7bcff998250a48.html

3>>Here are some questions about compilation. After adding the FAT part of the program, there will be more program files in the project. Here we should pay attention to the problem of repeated inclusion. There are many such problems on the Internet, so I will not repeat them here. Sometimes the error is not in the line indicated by the pointer.

For example, sometimes the line you are referring to contains only a statement like int a;. In this case, you should look up to see if the semicolon at the end was omitted when defining the function, causing the compiler to treat a as its parameter. This error is sometimes very subtle, such as int a; contains only #include "bh". In this case, you should look in b to see if the semicolon was forgotten after the function defined at the end of the file.

If the compiler reports "segment too large", you need to set the Variable in the Memory Model in the compiler options to XDATA. This is for the sililab IDE development environment, or you can put it in the xdata array. Project -> Tool Chain Intergration -> Compiler -> Custmize -> Memory Model -> Variable -> Large: XDATA

The official download of this IDE will limit the code size because the compiler used in it is a limited version. At this time, if you install the genuine KEIL, you can use the KEIL compiler without code restrictions. Specific steps: Project——>Tool Chain Intergration, modify the paths in Compiler and Linker to the corresponding paths of KEIL.

Also, some programs do not support nested folders.

 

          Now I will talk about the most important problem, which is also the last problem I encountered, the byte order problem. Please refer to http://blog.csdn.net/sunshine1314/archive/2008/04/20/2309655.aspx

Now that you know the byte order, you don't need to worry about the bit order. If you are using an AVR microcontroller, congratulations, the word order is the same as that of the SD card and the computer, so you don't need to convert the word order. You can use most programs on the Internet. The C8051F020 I use needs to do a conversion every time I exchange data larger than one byte with the card. Since only data such as 8 16 32 is used in the program, I only add two-byte conversion functions and four-byte conversion functions. The function body is as follows:

uint16_t two_byte_exchange(uint16_t h)
{
 if(!Big_Small_ending_Switch) //If byte conversion is not enabled, return the original value
 return h;
 
 return (h >> 8) + (h << 8); 
 
}
uint32_t four_byte_exchange(uint32_t h)
{   
   
 if(!Big_Small_ending_Switch) //If byte conversion is not enabled, return the original value
 return h;
      
    return (h >> 24) + ((h >> 16) << 8)+ ((h >> 8) << 16)+ (h << 24);   
    
    
}

 

The above are most of the problems I encountered. I hope it will be helpful to everyone. Due to my limited level, I would like to ask seniors to give me advice if there are any shortcomings!

Keywords:C8051F020 Reference address:A complete guide for beginners to read and write SD card FAT using C8051F020 SPI

Previous article:If you use the sprintf() function in 51, you must be more careful!
Next article:Design of intelligent fast charger for electric vehicle battery based on single chip microcomputer

Recommended ReadingLatest update time:2024-11-17 00:43

lpc1788 transplant u-boot-2010.03 spi flash transplant
Development environment: MCU: NXP LPC1788 u-boot: u-boot-2010.03 SPI Flash: AT45DB321D Since ATMEL's SPI flash has been implemented in u-boot, we don't need to write the driver for AT45DB321D. Now consider the SPI bus (the SPI driver in u-boot is in the driver/spi directory). In the driver/spi directory, you can see
[Microcontroller]
Remote upgrade design of LPC17xx via SPI
1. Introduction to the design This solution is based on NXP's LPC1768 microprocessor as the platform, uses KEIL MDK4.70A as the development tool, and realizes automatic program update through SPI. The program of this solution consists of three parts: bootloader, low-zone user program, and high-zone user program. B
[Microcontroller]
Remote upgrade design of LPC17xx via SPI
Design based on C8051F020 seawater desalination pretreatment system
During the actual use of the seawater desalination device, it was found that the actual working parameters of the device are generally different from the designed working parameters, making the device unable to exert the process characteristics of the original designed system and performing poorly; this situation is b
[Microcontroller]
Design based on C8051F020 seawater desalination pretreatment system
STM8 SPI slave mode
STM8 SPI slave mode In slave configuration, the SCK pin is used to receive the serial clock from the master device. The setting of BR in the SPI_CR1 register does not affect the data transfer rate. Configuration Steps 1. Select the CPOL and CPHA bits to define the phase relationship between data transmission and the
[Microcontroller]
STM8 SPI slave mode
Distributed detection method of vibration signal based on C8051F020 and MXA2500GL sensor
         Introduction           Due to the distance limit of the connecting cable of the acceleration sensor and the charge amplifier, it is difficult to implement a centralized data acquisition and processing system in a space with a long distance, and its reliability and anti-interference problems are difficult to s
[Microcontroller]
Distributed detection method of vibration signal based on C8051F020 and MXA2500GL sensor
Max7219 controls 8-segment digital tube SPI interface
  #include iom16v.h #define uint unsigned int  #define uchar unsigned char #define CS_H PORTB|=(1 4) #define CS_L PORTB&=~(1 4) void SPI_MasterInit(void) { /* Set MOSI and SCK to output, others to input */ DDRB = (1 4)|(1 5)|(1 7); /* Enable SPI master mode, set clock rate to fck/16 */ SPCR
[Microcontroller]
Max7219 controls 8-segment digital tube SPI interface
How to use the SPI communication interface inside the PIC microcontroller
#include #define uchar unsigned char #define uint  unsigned int #define cs RC2 #define dout RC4 #define nop() asm("nop") __CONFIG(0x3B31); const uchar table ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,                         0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; uchar da ta_temp; void delay(uint x); void
[Microcontroller]
SD card underlying driver of STC52 microcontroller - SPI
Recently I've been working on the FAT32 file system on SD cards and microcontrollers. This is my own SD card driver that I wrote after referring to other people's source code. If there are any incomplete parts, I hope you can give me your advice.       Definition statement: #ifndef _SD_H_ #define _SD_H_
[Microcontroller]
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号