No matter what program you transplant, the most important thing is,
Don't be self-righteous
You must check the information first, spend a week looking for information, and wait until you can't find it. Otherwise, you will not be able to make up your mind to start over after you have written half of the program.
1. Key points of FatFs transplantation:
I believe that everyone who can read this blog knows what FatFs is. It should be version 0.11 at the moment, so I won’t say too much. It is an open source file system. To put it simply, its function is to allow you to program the contents written to the SD card so that the contents can be read by a PC (if there is something wrong, please correct me if I know anything about it)
Its advantage is that you only need to write a few low-level hardware driver functions. The upper-level functions have already been written, and you can call them directly with clear formats.
The so-called "hardware driver" function tells the microcontroller which IO port needs to change in order to complete an action (such as initialization), which IO port should be high, which IO port should be low, which communication port to choose, and what to send. These basic actions combined together can complete the initialization.
There are five driver functions required by FatFs, which are shown in the diskio.h file:
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
Function return value:
DSTATUS
It is an enumeration type variable, containing 5 elements, which are success, read/write error, write protection, not ready, and parameter error:
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
Actually, when writing a program, it is helpful to divide the return value into smaller parts to quickly locate the problem. However, when I ported it, I only used success, read/write error, and parameter error to save trouble. The reason is that I did not write a special function to judge the write protection, and the probability of not being prepared is very low.
The input parameters of each function are explained one by one.
Then first initialize the program
DSTATUS disk_initialize (BYTE pdrv);
Specifically: the steps to implement the function through TI's single-chip microcomputer MSP430F5438A
The conscientious documents and websites that need to be referred to here are:
1. FatFs official website: http://www.elm-chan.org/fsw/ff/00index_e.html
The explanation is very simple. The advantage is that it is easy to understand. The disadvantage is that it is almost impossible to implement it with the little explanation he said.
2. A website by a foreigner named Tilen Majerle, based on FatFs developed by STM32 series microcontrollers: http://stm32f4-discovery.com/2014/07/library-21-read-sd-card-fatfs-stm32f4xx-devices/
Note that this guy has divided the full set of implementation files into several download links. The classification effect is very good. People who see it at the beginning will be dizzy. After downloading this file, the functions in the code are in another download link... But it is really complete. Although it may be different from the platform you need to implement, it is very helpful for understanding the implementation process and timing.
3. A technical report written by someone at the University of Michigan, a program written for MSP430F149, but only single read and write is implemented, and high-end functions such as DMA (direct memory access) are used (I will upload it to the data to be completed)
4. The official protocol specification of SD card. This is very important. Its name is part1_410. It seems to be only a part of the whole, but it is very detailed and clear. As long as you are patient and careful, you can find many things directly. If you are concerned about the SPI mode, Chapter 7 is the key point!
2. disk_initialize function implementation
The function body of this function in diskio.c is as follows:
/*------------------------------------------------ -----------------------*/
/* Initialize a Drive */
/*------------------------------------------------ -----------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
switch (pdrv) {
case ATA:
result = ATA_disk_initialize();
// translate the reslut code here
return stat;
case MMC:
result = MMC_disk_initialize();
// translate the reslut code here
return stat;
Case USB:
result = USB_disk_initialize();
// translate the reslut code here
return stat;
}
return STA_NOINIT;
}
It can be seen that FatFs is very "considerate" and provides initialization programs for three interface storages: ATA, MMC, and USB. But if you really think it is considerate, you are wrong...
First, let's talk about the input parameter pdrv, which can be understood as the memory number you want to operate. We usually operate a single-chip microcomputer with only one memory (the SD card in my project), so in the definition of ffconf.h:
#define _VOLUMES 1
In this way, all input parameters pdrv are 0, and the definition of ATA MMC USB is as follows:
/* Definitions of physical drive number for each drive */
#define ATA 0 /* Example: Map ATA harddisk to physical drive 0 */
#define MMC 1 /* Example: Map MMC/SD card to physical drive 1 */
#define USB 2 /* Example: Map USB MSD to physical drive 2 */
Damn, I was so naive at first that I thought mine was an SD card, but my mind only realized
MMC_disk_initialize();
Who knew that it is impossible to execute this under the condition of single memory!
So, if you only have one disk, you must implement the ATA one, no matter what its name is. Here I made a compromise when I finally implemented it.
MMC_disk_initialize();
I copied it to ATA, which was a bit lazy.
MMC_disk_initialize();
How to implement this function?
The following idea is to go deep into the bottom layer step by step, so you may not be able to see the implementation process of this function at a glance, don't worry
We mainly figure out all the operating mechanisms step by step through the implementation process of this function
I used the several conscience files I mentioned above.
In fact, many people have mentioned the process and it is very clear. Here is a classic flowchart from part1_410.pdf (171/202) (hereinafter I will refer to this document as the 410 document)
As you can see, the first step is to send the command CMD0. The instructions for each command are also described in the 410 document (179/202). Note that SPI users should read the table in Chapter 7.
A command consists of the following parts:
A command is 6 bytes in total
The first byte is the command header
The highest bit is the start bit, 0, the second bit is the transmission bit, 1, and the next 6 bits are the command index. The CMD in the flowchart above can be converted here. For example, if we send CMD0 first, then the first byte is
0x40 ( 0100 0000b )
It should be noted that the SPI communication supported by the SD card is 3pin 8bit MSB First, that is, the high bit is sent first, 8 bits at a time, so the first bit sent by CMD0 is 0x40
The second to fifth bytes, totaling 4 bytes, are command parameters.
The meaning of the corresponding command can be found in 410. The argument of CMD0 is marked with stuff bits, and it is OK to write 0
The sixth byte is a 7-bit CRC check bit and the last end bit which is always 1.
I didn't pay attention to the calculation process of the CRC check bit, because in SPI mode, except for CMD0 and CMD8 mentioned later, the SD card will not care about the correctness of other check bits.
Here for CMD0, add your argument all 0, then the last byte is fixed to
0x95, fixed and don't worry about it
Now that we have explained the composition of commands, how do we send a command? Let's take MSP430F5438A as an example.
This microcontroller has several SPI interfaces. I use the 3-pin SPI composed of P3.1, P3.2, and P3.3. The specific configuration method should be easy to find. It will also be in TI's user's guide.
Mainly talking about the communication mechanism of SPI, it is actually similar to and different from the common RS232.
The three pins of SPI are input, output, and clock. In addition, the SD card also has a chip select port CS that needs to be connected to a GPIO. Only when this chip select port is at a low level, the SD card will respond (of course, there are also situations in each stage where it is necessary to work when CS is at a high level)
During communication, the Master (MCU) provides the clock signal and the Slave (SD card) receives the clock signal. Both parties sample the voltage on the input or output line according to the edge of the clock, which changes according to the data being sent, thereby realizing data transmission.
Similar to the serial port, if your microcontroller needs to send data to the SD card, just write the data to be sent to the send buffer at the appropriate time (I will talk about the appropriate time later).
Different from the serial port, if your microcontroller needs to receive data sent by the SD card, to receive 1 byte of data, the microcontroller needs to write a 0xFF data to "push" the data to be received. Knowing this, the rest is easy.
For one SPI communication port, the 5438A is equipped with:
A transmit interrupt flag: UCTXIFG
A receive interrupt flag: UCRXIFG
One transmit buffer: UCxTXBUF
One receive buffer: UCxRXBUF
Although the interrupt flag can be cleared manually, I personally do not recommend it. Because TI has an automatic mechanism, we can just query it.
send data:
Keep checking and confirming the send interrupt flag UCTXIFG until the send interrupt flag is 1, indicating that the send buffer can write data. At this time, write the 1-byte data to be sent into the send buffer. After writing, the send interrupt flag automatically returns to 0, and returns to 1 after the sending is completed.
Receive data:
Continuously query the receive interrupt flag UCRXIFG. If it is 1, it means that the data in the receive buffer is valid and 1 byte can be read. After reading, the receive interrupt flag is automatically reset to zero until the complete data is received again.
With this process, sending and receiving a single byte is no longer a problem. Can we send the command CMD0 smoothly? No, there is also a timing problem.
Here is another conscientious document, Zhennan's SD manual
Long time no see Chinese ah haha, the time sequence is like this
First, when CS is high, input 8 wake-up clocks (maybe the two words "cycle" are omitted, it should be 8 clock cycles) (I understand it is for insurance, right?) The method of inputting the wake-up clock cycle is to write a 0xFF to the write buffer every 8 wake-up clock cycles. Because SI is high, write FF, and the clock runs when writing.
Then pull the CS level low
Then read nx8 clocks, also read bytes, the method is to write 0xFF and then check the input register, and then read the number. Note that if the SD card is ready, the number read should be 0xFF
After confirming that it is ready, write a 6-byte command, and then keep CS at a low level until the read return value is not 0xFF, indicating that the command has been processed. The SD card starts to send reply data. Depending on the recovery type of the command, different byte numbers of replies are read. After the reading is completed, the CS signal is set to a high level, and the command sending process is completed!
The reply types are divided into R1, R1b, R2, R3, R7, etc., which can also be found in 410
The reply of CMD command is R1, which is 1 byte in length and contains the status of SD card. The normal reply during initialization is Idle: 0x01, indicating that SD card is idle!
The complete code for sending CMD is as follows:
//Send CMD command
char SD_Send_Command(unsigned char cmd,
unsigned char response_type,
unsigned char *response,
unsigned char *argument)
{
int i;
char response_length;
unsigned char tmp;
// According to Zhennan's suggestion, add a wake-up process:
SPI_CS_HIGH();
SPI_SendByte(0xFF);
//---------------------------------------------
while(0xFF != SPI_RcveByte());
// Set CS low before sending command
SPI_CS_LOW();
//Send CMD header
tmp = 0x40 + cmd;
SPI_SendByte(tmp);
// Send Argument
for (i=3; i>=0; i--) //Note! Here it is MSB First, but I don't quite understand how the arguments are arranged in this way, see Application Note P15
{
SPI_SendByte(argument[i]);
}
// Send CRC
SPI_SendByte(0x95); //To put it bluntly, only CMD0 is needed, and the others are not needed, so here we simply write all CRC as CMD0
// Determine the response type
response_length = 0;
switch (response_type)
{
case R1:
case R1B:
response_length = 1;
break;
case R2:
response_length = 2;
break;
case R3:
response_length = 5;
break;
default:
break;
}
// Waiting for reply - the first bit of a valid reply is 0, so a loop with an exit mechanism should be set up to wait for the reply byte starting with 0
i=0;
do
{
tmp = SPI_RcveByte();
i++;
}
while( ((tmp&0x80)!=0) && (i // If it fails, just return 0 to exit if ( i >= SD_MAX_CMD_RETRY ) { //DEBUG4 /* if(cmd == 13) { sd_RS232TX_PROC("ACMD13 FAIL!"); sd_RS232TX_PROC(sd_NewRow); } */ SPI_CS_HIGH(); return 0; } // If successful i = response_length - 1; response[i] = tmp; i--; while (i>=0) { tmp = SPI_RcveByte(); response[i] = tmp; i--; } // The following content involves: If the return value is R1B, that is, BusyType, then there are some additional tasks to do: // The SD card will output a series of "0", so any non-zero reply is a sign that the BUSY state has ended i=0; if (response_type == R1B) { do { i++; tmp = SPI_RcveByte(); } while (tmp != 0xFF); SPI_SendByte(0xFF);// I don't know what the last sentence means, so let's do this first } // If you can get here, it means that the command execution has been successfully completed and the corresponding results have been obtained. Return to exit SPI_CS_HIGH(); return 1; } The above program is based on the old man from the University of Michigan. A few notes: argument and response are global static char type arrays defined in the C file where the function is located. The number of elements is 4 and 5 respectively, because the R3 and R7 types will return a 5-byte response. When sending CRC, the situation of CMD8 is not considered, so it is okay to write a separate function for CMD8 or add a judgment here (what CMD8 does will be discussed later) The definitions of R1, R1b, etc. are actually integers that are easy to distinguish. They are defined in order starting from 0. Regarding the input variable cmd, you can define CMD0 as 0 in the h file, and the same goes for the others, such as CMD24 as 24, and so on. Even ACMD can be defined according to the row number, but the prefix command CMD55 must be sent before the ACMD command. In addition, there are some weird parts in the function. My function is a little different from that of the guy in Michigan. Mine is actually debugged and passed. I don't know if it has anything to do with the development board I use. Friends who are interested can take a look at his original program again. The above is the complete function of sending commands. In the future, you can directly say "send CMDxxx" to send each command. I will not elaborate on the process (how to send CMD8 and ACMD will be described in detail later) Come here first today
Previous article:MSP430 SD card SPI read and write operations (4) —— FatFs file system implementation
Next article:MCU polling mode multi-task parallel processing
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- CGD and Qorvo to jointly revolutionize motor control solutions
- CGD and Qorvo to jointly revolutionize motor control solutions
- Keysight Technologies FieldFox handheld analyzer with VDI spread spectrum module to achieve millimeter wave analysis function
- Infineon's PASCO2V15 XENSIV PAS CO2 5V Sensor Now Available at Mouser for Accurate CO2 Level Measurement
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- A new chapter in Great Wall Motors R&D: solid-state battery technology leads the future
- Naxin Micro provides full-scenario GaN driver IC solutions
- Interpreting Huawei’s new solid-state battery patent, will it challenge CATL in 2030?
- Are pure electric/plug-in hybrid vehicles going crazy? A Chinese company has launched the world's first -40℃ dischargeable hybrid battery that is not afraid of cold
- 【McQueen Trial】McQueen's new ultrasonic drive
- Dial design based on lvgl
- Soldering example of SMA coaxial connector to PCB board
- 100% duty design of buck chip
- Limited time download gift: "What you need to know about USB3.1"
- Bluetooth host and slave address mutual binding communication test
- [Evaluation and experience of Zhongke Yihaiwei EQ6HL45 development platform] + ip_pll routine and eLinx software debugging
- Let’s discuss the development trend and direction of RF GaN
- Today's live broadcast prize addition: Introduction to Keysight's new optical communication test solution
- Chat with Vicor engineers about how to improve throughput and uptime of automated test equipment?