MSP430F5438A MCU FatFs transplantation notes based on SPI

Publisher:皮球Latest update time:2018-09-19 Source: eefocusKeywords:MSP430F5438A Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

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


Keywords:MSP430F5438A Reference address:MSP430F5438A MCU FatFs transplantation notes based on SPI

Previous article:MSP430 SD card SPI read and write operations (4) —— FatFs file system implementation
Next article:MCU polling mode multi-task parallel processing

Latest Microcontroller Articles
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号