The SD card has been watched for two days. It is mainly because the tested card capacity is incorrect, so I have been searching for the reason and finally found out that the total ratio is just a problem with the unit, maybe it's because I haven't touched SD before, so I don't know much about some of the registers. Everything is a new start. Compare this Register Manual, understand the program, and modify the program. Step by step!
First of all, it is necessary to know about the SD card protocol. I spent a morning in class to understand the SD card protocol, which is based on this document, this document is suitable for getting started with the SD protocol (I personally think ). Http://download.csdn.net/detail/king_bingge/5218183
After getting started with SD, you can start learning SD cards!
1. If you want to use an SD card, you must first initialize the SD card. How can you initialize it? (Command parameters are not mentioned at the moment)
1. Many Commands are involved here. The Protocol stipulates that after the SD card is powered on, at least 74 clock pulses must be provided before the related SD initialization work can be performed, he can still initialize it.
for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XF);
However, it may be better to perform initialization more successfully. Therefore, we have to give it 74 clocks. It doesn't matter!
2. The protocol says that when we reset or power on, the SD control register of the SD card is in idle mode in the card recognition mode. We didn't need to send the reset command, but we don't know the voltage range supported by our SD. Therefore, we 'd better give a reset command first, followed by a command to obtain the operating voltage. This is also relatively safe. If there is any doubt about the operating voltage of multiple SD cards, you have to go to the chip manual. With this knowledge, the following code is not a problem.
Retry = 20; do {R1 = sd_sendcmd (defaults 0, x 95); // enter idle status} while (R1! = 0x01) & retry --); sd_type = 0; // default card-free if (r1 = 0x01) {If (sd_sendcmd (defaults 8, 0x1aa, 0x87) = 1) // SD V2.0 {for (I = 0; I <4; I ++) BUF [I] = sd_spi_readwritebyte (0xff ); // get trailing return value of R7 respif (BUF [2] = 0x01 & Buf [3] = 0xaa) // whether the card supports 2.7 ~ 3.6 V
3. The protocol also mentions that the acmd41 command aims to give the SD card controller a mechanism to identify whether the SD card can work within the scope of the given VDD. If the SD card cannot work within the specified VDD range, then it enters the inactive state, so we need to send this command next, but before sending this command, we need to know that this is an application-oriented command, so we need to add the limit 55 command, so we have the following code.
If (BUF [2] = 0x01 & Buf [3] = 0xaa) // is the card 2.7 ~ 3.6 V {retry = 0 xfffe; do {sd_sendcmd (Limit 55, x 01); // send limit 55r1 = sd_sendcmd (Limit 41, 0x40000000,0x01 ); // send limit 41} while (R1 & retry --); If (retry & sd_sendcmd (Limit 58, x 01) = 0) // identify the start of the sd2.0 card version // obtain the power supply status {for (I = 0; I <4; I ++) BUF [I] = sd_spi_readwritebyte (0xff ); // obtain the OCR value if (BUF [0] & 0x40) sd_type = sd_type_v2hc; // check ccselse sd_type = sd_type_v2 ;}
In this way, the card type is obtained. At this point, the card Initialization is basically complete. Of course, based on the protocol, we can also modify the relative address here. If necessary, you can do this!
2. After the SD card is initialized, you can do this if you want to view the SD capacity!
Previously, I was depressed for a long time because of the capacity problem. I understood it! Note that the function name here is the number of read sectors, and the actually returned value is the capacity of our card. Pay attention to it here.
1. First, check the code
U32 SD_GetSectorCount (void) {u8 csd [16]; u32 Capacity_KB, Capacity_MB; u8 n; b2csize; // obtain CSD information. If an error occurs during this period, returns 0 if (SD_GetCSD (csd )! = 0) return 0; n = (csd [5] & 15) + (csd [10] & 128)> 7) + (csd [9] & 3) <1) + 2; csize = (csd [8]> 6) + () csd [7] <2) +) (csd [6] & 3) <10) + 1; Capacity_KB = (u32) csize <(n-10); // obtain the number of sectors, the unit here is KBCapacity_MB = Capacity_KB/1024; return Capacity_MB ;}
For this computing problem, you must read the SD card manual, that is, the 128-bit CSD register. Here I posted my analysis process. I have to say it's messy. Maybe I can only understand it myself, so I am too lazy to sort it out for reference only!
The value in the my sd_cardcsd register is as follows: 00 7f FF 32 bit (127-96) csd0-csd35f 59 83 CB bit (95--64) csd4-csd7 0101 1111 0101 1001 1000 0011 1100 dB df ff bit (63--32) csd8-csd11 101176 0111 0110 1101 1011 1101 1111 40 00 97 bit (31---0) CSD12-csd15csize {1111} csize_muti {47,49} Read {80, 83} csize = 0010 1101 111 = 3885csize_muti = 1001 = 7 read = 9 formula: blocknr = (csize + 1) * mult = (csize_muti <8) * (2 ^ (csize_muti + 2) block_len = (read <12) * (2 ^ (read )) capacity = blocknr * block_len = 13*4*3516*98304 calculate my capacity based on the following code: N = (CSD [5] & 15) + (CSD [10] & 128)> 7) + (CSD [9] & 3) <1) + 2; csize = (CSD [8]> 6) + () CSD [7] <2) + () (CSD [6] & 3) <10) + 1; capacity_kb = (u32) csize <(n-10); // obtain the number of slices, here the unit is KB // 00 7f FF 32 5f 59 83 CB 76 dB df ff 96 40 00 97capacity_mb = capacity_kb/1024; 1. (CSD [8]> 6) the result is that bit62 and bit63 values are removed by two digits. 2. () CSD [7] <2) what we get is bit64 -- the value of bit69 is removed from 6 bits. 3. () (CSD [6] & 3) <10) the value of bit70 -- bit73 is obtained.
In fact, my problem still exists in the unit!
In this way, we can see the displayed capacity value. Mine is 1 GB. The output is 971 M, which is consistent with that in windows. In fact, we can read the relevant information by reading the Boot Sector of the SD card without using those registers. Now our formula is (this is just written by myself. If you want to understand it, you have to read the content of the slice. I just wrote it against the MBR)
X = (buf_read [34]) * 64*1024 + (buf_read [33]) * 256 + (buf_read [32]) * 512/1024/1024; // print the printf Size ("\ n SD Sector Size: % d Mb \ n", x );
Although not elegant, it can be used.
2. Next let's take a look at how to use SPI to read a sector. Let's first look at the code.
U8 SD_ReadDisk (u8 * buf, u32 sector, u8 cnt) {u8 r1; if (SD_Type! = SD_TYPE_V2HC) sector <= 9; // convert to the byte address if (cnt = 1) {r1 = SD_SendCmd (Listen 17, sector, 0X01 ); // READ command if (r1 = 0) // Command sent successfully {r1 = SD_RecvData (buf, 512 ); // receive 512 bytes} else {r1 = SD_SendCmd (Listen 18, sector, 0X01); // continuous read command do {r1 = SD_RecvData (buf, 512 ); // receives 512 bytes of buf + = 512;} while (-- cnt & r1 = 0); SD_SendCmd (Limit 12, X 01 ); // send Stop command} SD_DisSelect (); // cancel the option return r1 ;//}
These lines of code can be used to read and write a single sector or multiple sectors. You can see this function after tracking.
// Spix reads and writes one byte // txdata: bytes to be written // return value: Read byte u8 spix_readwritebyte (u8 txdata) {u8 retry = 0; while (spi_i2s_getflagstatus (spi1, spi_i2s_flag_txe) = reset) // check whether the specified SPI flag is set or not: Send cache empty flag {retry ++; If (retry> 200) return 0 ;} spi_i2s_senddata (spi1, txdata); // send a data retry = 0 through the peripheral Spix; while (spi_i2s_getflagstatus (spi1, spi_i2s_flag_rxne) = reset ); // check whether the specified SPI flag is set: accept the non-empty flag of the cache {retry ++; If (retry> 200) return 0;} return spi_i2s_receivedata (spi1 ); // return the data recently received through Spix}
This function enables both sending and reading data. Now let's summarize it!
Read a sector
1. First run the command R1 = sd_sendcmd (Sector 17, sector, 0x01); // read a single sector command
2. the received data is stored in a temporary array.
U8 sd_recvdata (u8 * Buf, 2010len) {If (sd_getresponse (0xfe) return 1; // wait for the start token 0xfe while (Len --) for the SD card to send back data --) // start receiving data {* Buf = spix_readwritebyte (0xff); Buf ++;} // The following two pseudo CRC (dummy CRC) sd_spi_readwritebyte (0xff ); sd_spi_readwritebyte (0xff); Return 0; // read Successful}
The corresponding write sector is similar.
1. First write the command r1 = SD_SendCmd (sector 24, sector, 0X01) for a single sector; // write the command
2. Write the content in the Buffer to the corresponding slice.
U8 SD_SendBlock (u8 * buf, u8 cmd) {servict; if (SD_WaitReady () return 1; // wait for the preparation to expire SD_SPI_ReadWriteByte (cmd); if (cmd! = 0XFD) // not the end command {for (t = 0; t <512; t ++) SPIx_ReadWriteByte (buf [t]); // speed up, reduce function parameter passing time SD_SPI_ReadWriteByte (0xFF); // ignore crc SD_SPI_ReadWriteByte (0xFF); t = SD_SPI_ReadWriteByte (0xFF); // receive response if (t & 0x1F )! = 0x05) return 2; // response error} return 0; // write successful}
Here, the read/write sector is complete, and the next step is to use the file system for operations.