We work with an SD card without a file system. Connecting an SD card to a microcontroller

There are many different types of storage media based on so-called flash memory. We use regular flash drives to transfer files to each other, micro-SD cards to increase free space in smartphones, even instead of the good old hard drive in modern laptops we use SSD media - the same flash memory. Flash memory has no moving parts, unlike vintage floppy disks and newer hard drives. The read and write speed of such memory is higher than that of all previous media, and power consumption is, on the contrary, lower. In other words, if we want to store some data in our electronic devices and robots, then it would be rational to use flash memory. Why might you need a memory card? For example, in order to record data from various sensors of our device onto it. In addition to the sensor readings themselves, it is also rational to record the time these readings were taken - this is called logging. Thus, by connecting temperature, humidity and pressure sensors to Arduino, as well as a real-time clock and a memory card, we can make a real weather station! Let's look at exactly how the memory card is connected to Arduino and how it is written and read.

1. Connecting the micro-SD card module to Arduino

In this tutorial we will read and write data to a micro-SD card. In terms of connection to Arduino, the micro-SD module is no different from the module for regular SD cards. The module is connected to Arduino via the SPI bus, which means you need to connect the contacts already familiar from other lessons in the standard order:
Micro-SD card module GND VCC C.S. MOSI MISO SCK
Arduino Uno GND +5V 4 11 12 13
Schematic diagram
Layout appearance

2. Program for reading micro-SD cards

To check the operation of the device, we write a simple program, which will only read service information from the card: card type, file system type, size of the first partition and a list of files on it. #include #include Sd2Card card; SdVolume volume; SdFile root; const int chipSelect = 4; void setup() ( Serial.begin(9600); Serial.print("\nInitializing SD card..."); if (!card.init(SPI_HALF_SPEED, chipSelect)) ( // incorrect connection or card is faulty Serial.println ("initialization failed"); return; ) else ( // everything is ok! Serial.println("Wiring is correct and a card is present."); ) // read the card type and output it to the COM port Serial.print ("\nCard type: "); switch (card.type()) ( case SD_CARD_TYPE_SD1: Serial.println("SD1"); break; case SD_CARD_TYPE_SD2: Serial.println("SD2"); break; case SD_CARD_TYPE_SDHC: Serial .println("SDHC"); break; default: Serial.println("Unknown"); // initializing the file system if (!volume.init(card)) ( // invalid file system Serial.println("Could not find FAT16/FAT32 partition."); return; ) // read the type and calculate the size of the first partition uint32_t volumesize; Serial.print("\nVolume type is FAT"); Serial.println(volume.fatType(), DEC); Serial.println(); volumesize = volume.blocksPerCluster(); // blocks per cluster volumesize *= volume.clusterCount(); // clusters volumesize *= 512; // 512 bytes in a block, total bytes.. Serial.print("Volume size (bytes): "); Serial.println(volumesize); Serial.print("Volume size (Kbytes): "); volumesize /= 1024; Serial.println(volumesize); Serial.print("Volume size (Mbytes): "); volumesize /= 1024; Serial.println(volumesize); Serial.println("\nFiles found on the card (name, date and size in bytes): "); root.openRoot(volume); // display a list of files root.ls(LS_R | LS_DATE | LS_SIZE); ) void loop(void) ( ) Load the program into Arduino and open the COM port monitor:
If such information appears, then everything is in order with the card and module. You can begin further work.

3. Program for recording data on a micro-SD card

Now let’s try to create a new file on the map and write a simple phrase “Hello from robotclass” there. #include #include const int chipSelect = 4; void setup() ( Serial.begin(9600); if (!SD.begin(chipSelect)) ( Serial.println("Card failed, or not present"); return; ) // the string that we will write to the file String dataString = "Hello from RobotClass"; // open the file into which the string will be written File dataFile = SD.open("test.txt", FILE_WRITE); if (dataFile) ( // write the string to the file dataFile.println(dataString) ); dataFile.close(); Serial.println("Success!"); else ( // print an error if the file could not be opened Serial.println("error opening file"); ) ) void loop() ( ) Loading program. Then turn off the Arduino, remove the micro-SD card from the module and check its contents on the computer. The file test.txt with our phrase “Hello from RobotClass” should appear in the root of the map. Note! The file name specified in the open function must not contain more than 8 letters (not including the extension).

4. Program for reading data from a micro-SD card

Finally, we will read the test.txt file and output the text from it to the COM port. #include #include const int chipSelect = 4; void setup() ( Serial.begin(9600); if(!SD.begin(chipSelect))( Serial.println("initialization failed!"); return; ) // open the file for reading File myFile = SD.open( "test.txt"); if (myFile) ( // read all bytes from the file and output them to the COM port while (myFile.available()) ( Serial.write(myFile.read()); ) // close file myFile.close(); ) else ( // display an error if the file could not be opened Serial.println("error opening test.txt"); ) ) void loop() ( ) Load the program and open the COM port monitor. All text from the test.txt file should appear on the screen

Conclusion

In the next tutorial we will try to add a real time clock and a temperature sensor to the circuit. By leaving such a device for the whole day, we can eventually build a daily temperature graph.

SD and microSD cards can significantly expand the capabilities of Arduino projects that work with large amounts of data: data loggers, weather stations, smart home systems. Arduino boards are equipped with a relatively small internal memory, only up to 4 kilobytes, including both flash memory and EEPROM. This memory will not be enough to record large amounts of data, especially if the board is constantly turned off or turned off. Connecting an Arduino SD card as an external drive allows you to greatly increase the storage space for any information. Removable SD drives are cheap, easy to connect, and easy to use. The article will discuss how to properly connect an SD card to Arduino.

Working with SD memory in Arduino is not particularly difficult. The easiest way is to connect a ready-made module and use the standard library. We will start with this option.

Using a ready-made module has various advantages. This is a fairly simple and convenient tool for working with large amounts of data. It does not require special connection skills; all connectors are labeled directly on the board. You have to pay for convenience, but the cost of the module is relatively low; it can easily be found at affordable prices in Russian and foreign online stores.

The universal module is an ordinary board on which a card slot, resistors and a voltage regulator are placed. It has the following technical characteristics:

  • Operating voltage range 4.5-5 V;
  • Supports SD card up to 2 GB;
  • Current 80 mA;
  • File system FAT 16.

The SD card module implements functions such as storing, reading and writing information to the card, which is required for the normal functioning of a microcontroller-based device.


Naturally, inexpensive memory card modules also have disadvantages. For example, the cheapest and most common models only support cards up to 4GB, and almost all modules allow you to store files up to two gigabytes on an SD card - this is a limitation of the FAT file system used in most models.

Another disadvantage of memory cards is the relatively long recording time, but there are ways to work with it that can increase its speed. For this, a caching mechanism is used, when data is first accumulated in RAM and then dumped at a time onto the memory card.

Arduino boards for working with SD

There are several different boards for working with SD cards:

  • Arduino Ethernet - this board is equipped with a special module for data output. The CS output uses pin 4. For proper operation, the SD.begin(4) command must be used.
  • Adafruit Micro-SD is a development board that is used when working with Micro-SD cards.
  • Sparkfun SD – mounted on top of the Arduino, uses pin 8 for the CS output. The new version of the board has a 3.3 V connection and a built-in six-bit inverter.

Connecting SD and microSD to Arduino

There are two types of cards – microSD and SD. They are identical in connection, structure and program; they differ only in size. It is recommended to format the SD card before use. Usually new cards are already formatted and ready to go, but if you are using an old card, it is better to format it in the Arduino file system. To carry out the procedure, an SD library must be installed on the computer, preferably FAT16. To format on Windows, you need to click on the card icon and click “Format”.

To connect the card, 6 contacts are used, interaction is carried out via the SPI interface. It looks like a six-pin connector on the front surface of the board. To connect a card, you need the controller itself, the card module and 6 wires. In addition to SPI, there is an SDIO mode, but it is difficult to implement and is poorly compatible with Arduino. SPI is easily configured to work with all microcontrollers, so it is recommended to use it.

The digital pins are connected as follows: for an Arduino Nano or Uno board, the MOSI pin is connected to D11, MISO to D12, SCK to D13, CS to 4, VCC to +5 V, GND to GND. The board has connectors for connecting to 3.3 and 5 volts. The power supply of the card itself is 3.3 volts, so it is easier to use a microcontroller with the same power supply, otherwise you need a voltage level converter. The most common Arduino boards have such an output.

When connecting an SD card, you need to take into account the correspondence of SPI contacts for different types of Arduino boards:

Arduino library for working with SD and microSD

For the convenience of working with external data storage devices, ready-made libraries are available in the Arduino IDE. In most cases, you won’t need to download or install anything additional.

To include a library in a sketch, you need to use the include statement:

#include #include

The SPI library is needed for the correct operation of devices connected via SPI.

Library functions are needed to read and write data to the card. The library can support SD and SDHC cards.

Names are written in 8.3 format, that is, 8 characters for the name, 3 for the extension. The path to the file is written using slashes “/”.

Built-in SD library examples

The Arduino IDE has built-in ready-made examples for quickly learning the functions of the library:

  • Card Info is the extraction of information stored in the SD card. With its help, you can find out what file system the card is formatted into, the availability of free space, and what data is recorded.
  • Yun Datalogger – allows you to record log data from three sensors to a card.
  • Datalogger – registers and stores data received from the sensor onto the card.
  • Dump File – reads data from the card and transfers it to the serial port.
  • Files – creates and deletes data. There is a file.write() function that puts the written data into a buffer. Information is moved to the card when the flush() or close() functions are called, so it is important to close it after each file opening, otherwise the data will be lost.
  • Read Write – writes and reads files from the card.

SD Library Functions

The Arduino SD library contains various functions with which you can manipulate data. SD class features:

  • begin() – the function initializes the library, assigns a pin for the signal.
  • exists() – is designed to check whether the necessary information is available on the map.
  • mkdir() – allows you to create the desired folder on the memory card.
  • rmdir() – using this function you can delete a folder. It is important that the folder to be deleted is empty.
  • open() – allows you to open a file that is needed for writing or reading. If the required file is not on the card, it will be created.
  • remove() – removes any file.

All these functions should receive one of the following values ​​in response - true if the operation was successful and false if it failed.

Create, edit and delete files.

To work with files in Arduino, there is a File class. It includes functions that are designed to write and read information from the card:

  • available() – checks whether the file contains bytes that are available for reading. The answer is the amount of space that is available for reading.
  • close() – closes the file, before doing this it checks whether the data is saved to the card.
  • flush() – the function allows you to make sure that data is written to the card.
  • name() – returns a pointer to the name.
  • peek() – reads bytes of data, but does not move the pointer to the next character.
  • position() – finds the current position of the pointer in the file.
  • print() – outputs data to a separate file.
  • println() - Prints data into the file up to the point where the carriage return character and the empty line appear.
  • seek() – changes the position of the current position in the file.
  • size() – displays information about the size of the data.
  • read() – reads information.
  • write() – writes to a file.
  • isDirectory() - this method checks whether the file is a directory, that is, a directory or a folder.
  • openNextFile() – displays the name of the next file.
  • rewindDirectory() – returns to the first file in the directory.

For correct operation The board needs to be ensured that the SS output is configured.

Sketch of an example of working with the Arduino SD library

Below is a sketch demonstrating an example of working with a memory card module.

/* Data logger using SD cards An example of saving data from analog ports on an SD card. The data will be saved in a file as a set of lines with a field separator in the form of the symbol "," Connection diagram: * Analog sensors are connected to analog pins * The SD card module is connected to SPI according to the standard scheme: ** MOSI - pin 11 ** MISO - pin 12 ** CLK - pin 13 ** CS - pin 4 */ #include #include const int PIN_CHIP_SELECT = 4; void setup() ( Serial.begin(9600); Serial.print("Initializing SD card..."); // This pin must be defined as OUTPUT pinMode(10, OUTPUT); // Trying to initialize the module if ( !SD.begin(PIN_CHIP_SELECT)) ( Serial.println("Card failed, or not present"); // If something went wrong, exit: return; ) Serial.println("card initialized."); ) void loop() ( // String with data that we will place in the file: String logStringData = ""; // Read data from ports and write to line for (int i = 0; i< 5; i++) { int sensor = analogRead(i); logStringData += String(sensor); if (i < 4) { logStringData += ","; } } // Открываем файл, но помним, что одновременно можно работать только с одним файлом. // Если файла с таким именем не будет, ардуино создаст его. File dataFile = SD.open("datalog.csv", FILE_WRITE); // Если все хорошо, то записываем строку: if (dataFile) { dataFile.println(logStringData); dataFile.close(); // Публикуем в мониторе порта для отладки Serial.println(logStringData); } else { // Сообщаем об ошибке, если все плохо Serial.println("error opening datalog.csv"); } }

Creating a file and choosing a name for the arduino SD card

Creating a file is one of the most common tasks that arise when working with SD cards in Arduino. As we saw in the previous sketch, to create a file you just need to open it. If we want to check if such a file exists, we can use the exists() function:

  • SD.exists(“datalog.csv”);

The function returns TRUE if the file exists.

A popular practice when creating data logger projects is to split large files into smaller ones that are easier to update and open on a computer. For example, instead of one very large datalog.csv file on the SD card, you can have several small ones, adding a number to the end in order: datalog01.csv, datalog02.csv, etc.
Here's an example sketch that will help you do the job:

Char filename = "datalog00.CSV"; // Initial name for (uint8_t i = 0; i< 100; i++) { filename = i / 10 + "0"; filename = i % 10 + "0"; if (! SD.exists(filename)) { // Проверяем наличие logfile = SD.open(filename, FILE_WRITE); break; // Дальше продолжать смысла нет } }

Conclusion

As we have seen, connecting an SD memory card to Arduino and using it in a project is not very difficult. For this, there are ready-made libraries in the Arduino IDE and a wide variety of module options. You can buy a memory card at any electronics store; they are inexpensive, but they can significantly expand the potential of the Arduino board. Using memory cards, large amounts of data can be collected and stored for later analysis. With the help of our article, we can give memory to our research projects, create voice notification systems for a smart home, create a simple wav player and much more.

Downloaded the source.
Errors popped up:
stm32 nok1100 disp.axf: Error: L6218E: Undefined symbol USART_Cmd (referred from main.o).
stm32 nok1100 disp.axf: Error: L6218E: Undefined symbol USART_GetFlagStatus (referred from main.o).
stm32 nok1100 disp.axf: Error: L6218E: Undefined symbol USART_Init (referred from main.o).
stm32 nok1100 disp.axf: Error: L6218E: Undefined symbol USART_ReceiveData (referred from main.o).
stm32 nok1100 disp.axf: Error: L6218E: Undefined symbol USART_SendData (referred from main.o).

I added a library for working with USART to the project - it compiled (it would be nice to mention this in the article, huh?), but the card does not initialize. I tried swapping the MISO and MOSI pins - the result was zero...

In the project I use the Standard Peripheral Library + there is a noticeable mention in the text and code of UART, I thought this naturally entailed the use of the USART library. Listed the libraries used from SPL. A little later I’m thinking of posting the entire project.
Is there any dialogue via UART? What kind of card? Is she alive? Have you tried other cards?

The situation is that a person who has never encountered STM32 BEFORE finds your articles on the Internet and begins to read them. Installs the necessary software and reads your articles, one after another, compiling examples along the way and checking the functionality on the STM32VL Discovery board (as you said in the first article). In the first example, everything is chewed and sorted into detail - which library files should be put where, how to design the project structure, which options in the project properties to enable/disable. Everything is clear, everything is fine. Article for beginners. In the article about connecting SD cards - the complete opposite, as in that song - “guess it yourself...”. Moreover, the connection diagram of the card shows the pins of the processor, although in theory the pins of the connectors of the STM32VL Discovery board should be indicated (since the story began on its basis). I think that there should be some continuity in the articles, since we started to rely on the STM32VL Discovery from the first article - continue the rest of the story based on it. This will make it much easier for those reading your articles.

According to the UART, the data is sent to the terminal, but I haven’t tried the reverse.

In the process of writing the answer, I took another card - it did not initiate. I swapped the MISO and MOSI pins on the discovery connector and it worked. So there is an error in the diagram. By the way, here http://mycontroller.ru/stm32-sd-card-podklyuchenie/ the connection diagram is correct. Connecting the card to the STM32VL Discovery board is as follows: pin 1 card - PA4, pin 2 card - PA7, pin 5 card - PA5, pin 7 card - PA6. One old card (16 MB) and a new one (2 GB) worked. The old 8 MB card (a rarity, however 😉) from a JVC camcorder did not want to be initialized.

Request: if it’s not too much trouble, describe in more detail the additions/changes in the project, etc. Experienced comrades don’t need to read this, but for inexperienced people it will be clear and no stupid questions will arise. 🙂

PS. Data blocks are written/read to/from the card. Thanks for the article!

There is a special training series and it is numbered, so I try to chew it as much as possible in it. Ordinary articles can be review/superficial, i.e. the most important thing, because There is a lot of material and it’s impossible to mention everything, but they can also be expanded. For example: this article appeared before I talked about UART and SPI, so why not put the material off for later? and when will this happen next and will it happen at all?

Thanks for the note about the mixed up conclusions, I’ll double-check when I return to work from sick leave (I still have the SD cards there).

The answer to your request is that I will try.

The error in the diagram has been confirmed, I will update the information in the evening. Thanks for noticing.

Thank you, everything works fine on the F103RB, the Kingston SDHC on 4GB was consumed without any complaints. True, I didn’t immediately notice that I had PA4 on the board - this is a slave-select not for the card, debugging took a little longer))

You wrote that: SD_init() – initialization of SPI and memory card
if unsuccessful, returns 0.
Isn't it the other way around, in case of successful initialization, zero is returned, otherwise - one?

I made a mistake, we'll correct it. Thanks for noticing.

Have you tried an SDHC card? It is initialized, but it’s impossible not to read or write, plus it’s not clear how to address it, I couldn’t really find anything on the Internet

I tried SDHC Qumo 8GB - reading was successful, I don’t remember if I checked writing. I haven't tried other cards.

It’s strange, I can’t write or read Kingston SDHC 2GB

It may also depend on the card, i.e. lucky or unlucky.

Please tell me, is it possible to somehow read data recorded on an SD card (without a file system) from a computer. I mean using any programs to recover data from flash drives, etc.? The fact is that problems constantly arise with FatFS (with low-level functions, most likely). Either repair them or look for programs.

I haven’t looked for such software - there’s nothing in sight.

There, in the instructions for the library there is a description and notes on its critical areas, for example, during which operations it is better to disable interrupts and which termination will lead to data corruption.

It would be much more interesting to find/create a universal driver for card readers that are now available in any book for using CD/MMC slots as a universal SPI interface/programmer, naturally with COM port emulation because almost all programmer software works via COM/LPT and almost all hardware Now they have BIOS/bootloaders via SPI or communicate through it, then people would erect a monument to you (at least a virtual one).
I’m surprised why no one has written such a driver yet, I don’t think it’s impossible or extremely difficult - “we bypass the hardware with software and the software with hardware”, but no matter how much I searched on the Internet, I couldn’t find such a driver, and writing it myself is difficult.

Nice article! Is it possible to see the entire project with the described card initialization?

Isn't it attached to the article?

Hmm... I thought I posted all the main project files, I'll try to add them in the evening.
As for the site - yes, it’s sad, it was a good resource, but it’s been dead for a year now and I can’t find a full copy of the materials from that resource anywhere.
That site, about the FatFS library, was actually translating a similar resource, you can download the library from there - FatFs - Generic FAT File System Module, plus there is also its update dated November 14 of this year.

All the main project files are laid out, all that remains is to install the standard peripheral library.

Good evening!
I am interested in the issue of creating and writing data to a text file on a flash drive with a frequency of 100 kHz.

There is a DCR-DVD203E camera that writes to a mini SD disk... the task is to remove the SD and install a unit that records on a 32-64 GB flash card.. IT IS AVAILABLE BUT HOW TO DO IT???? QUESTION - COULD YOU DO IT AND PRICE QUESTION

I can't help you with either question.

“If you find that the feedback is not working, please report it via comments.”
I'm letting you know 😉

The site works properly, I see everything that comes in. This overwhelmed me with work on all fronts. And that’s why I haven’t responded to the site for a couple of weeks now. Soon I will finish some things and over time I will have a little more free time for the weeks, I will answer everything that has accumulated.
1. Ideally it is better to use simple cards memory, not HD. But I don’t have statistics on the cards.
2. Double-check the pinout of the memory card using other resources on the Internet, someone once noticed an error with me, I don’t remember if he confirmed it and corrected it or not.

I see, sorry for the impatience :)
Thank you for your answer, if I find an error, I’ll write what was wrong.

Hmm, the problem is in an interesting place. On one forum I found an article by a person who had a similar problem. JTAG also hangs on the legs involved in SPI1. So it turned out that it turns on automatically after Reset, despite the fact that I don’t turn it on anywhere as an alternative function. The article suggested a solution to this problem (), but I simply used a different SPI. After which it became possible to send 74 sync pulses.
P.S. True, it still didn’t work 🙂 After sending a request for a soft reset (with an empty argument), the command does not receive a response 🙁 We will look for more errors.

And it's me again. And again the error arose due to incorrect operation of the leg. For the SlaveSelect leg, I chose the one that is indicated in the DS as NSS for SPI2. I configured it to be controlled by software. The leg was reset/installed using the SPI_NSSInternalSoftwareConfig() function (as written in the SPL library). So the leg did not change its meaning! Moreover, when I stopped using this function and began to directly change the bit through the BSRR port register, the pin was still constantly set! I don't know the reasons. It is possible that the whole issue is in the NSS program control mode. Therefore, when I started using a different pin for SlaveSelect, everything worked - answers began to come.
P.S. True, it still didn’t work….Again… :)
Therefore, I again turn to the respected author for advice (when he gets the job done) :)
The situation is this: the SEND_IF_COND command receives the response 0x01 - that means the flash drive is v2 - it seems logical - the flash drive was purchased a week ago and it is unlikely to be v1. Let's go further: I send ACMD41, i.e. APP_CMD (I get a response 0x01 - everything seems to be fine too) and APP_SEND_OP_COND - I get a response 0x05. We have an illegal command error, which means the flash drive does not accept such a command. I decided to try sending just CMD1 (suddenly the card is version v1), i.e. SEND_OP_COND - I receive a response 0x01. Those. the card does not want to be initialized, because... waiting for 0x00. Could there be other options for the initialization sequence?

I solved the problem :) I googled for a long time and found it various solutions(and some were opposite to each other: O) but nothing helped. I saw this link http://stackoverflow.com/questions/2365897/initializing-sd-card-in-spi-issues - I decided that this would not help and began to search further, but in vain... Since later, in despair, I decided to try all the solutions and added several spi_read(); commands. at the beginning of the SD_sendCommand() function and the card is finally initialized :)
P.S. In the same link there is another tip - “send ACMD41 with the bit set for the voltage you’re supplying the card with”, and this person claims that it helped him, although Physical Layer Simplified Specification Version 4.10 talks about the ACMD41 argument like this:
Argument Reserved bit HCS Reserved bits
Command Description — Sends host capacity support information and activates the card’s initialization process. Reserved bits shall be set to '0'
which clearly contradicts what was said above. So not all advice should be trusted. Perhaps mine too :)

Hello again! 🙂 While using the card, a question arose: how can we track what we write to the wrong sector? I mean, for example, there are 1,000,000 sectors on the card, and we are trying to write to 1,000,001. The card calmly accepts this - it sends a valid R1-response to the command (0x00) and a valid Data-response after receiving the data (0xE5, but this the same as 0x05, because only the lowest 7 bits are significant).
P.S. Moreover, when trying to read from the wrong sector, R1-response 0x40, i.e. Parameter Error.

stm32f103 controller? They encountered a similar problem, only in a different way and did not use SPI. I found a solution to the problem; I will describe it on the website in one of the future materials.
I sent you an email regarding other questions.

Alex_EXE, thank you for your letter. I have actively used all the links that you indicated before :) Except for the first one :) But it also looks useful and is worth adding to your bookmarks. As I understand it, you provided a link to it in this article, but only to a non-working version, so I decided to add it to the comments: http://mycontroller.ru/old_site/category/vneshnie-ustroystva/karta-pamyati-sd/default.htm
Now what’s the end of the matter :) Unfortunately, I didn’t find an answer to it :) No, I solved the problem, albeit in a different way, but it seems to me that these are unnecessary steps and it would be more concise and beautiful if the card produced a Parameter Error on an attempt to write to the wrong sector. Perhaps, somewhere in the nooks and crannies of the datasheet, the answer is still hidden and you just need to read it very carefully :) But this will be discussed further, in the next comment :)

So here it is. How I thought to solve the problem. In order not to write to a non-existent sector, you just need to know their number and check whether we have gone beyond the limit :) I know, it’s banal, but we need to solve the problem somehow :)
There is such a register CSD (The Card-Specific Data register) In it, certain bits are responsible for the size of the card C_SIZE, with: memory capacity = (C_SIZE+1) * 512KByte. Those. from here you can calculate the number of sectors. It is read using CMD9 (SEND_CSD). I probably found a dozen links (for example https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Attachments/18065/stm32_eval_spi_sd.c) in which the same thing was written (in meaning, not copied 🙂) algorithm for reading this register. The gist of it was this:
Reading the contents of the CSD register in SPI mode is a simple read-block transaction (there is exactly the same line in the datasheet, but the paragraph doesn’t end there, but apparently no one reads further :)). As a result, all links have the following sequence of actions:
CS to zero -> send CMD9 command with an empty argument -> wait for R1(0x00) -> wait for Data Token(0xFE) -> read 16 bytes of the register -> read 2 bytes of CRC -> CS to one. That’s it, we’ve received the data, all that remains is to parse it.
OK, I write the code and launch it. R1(0x00) responds to the command, everything is fine. Instead of Data Token(0xFE) comes 0x7F, and then comes 0xFF. We've arrived. I start googling, looking for what 0x7F means and who has encountered this. In general, I spent a lot of time and it was all in vain. Then I look at my code for the sector read command and stop! - in CMD17, first we send the command, and then CS to zero, but here for some reason it’s the other way around, although everywhere it is said that CMD9 is the same CMD17. I think let me try this. Aaaand... no 🙁 we still don’t get 0xFE. BUT, if earlier 0xFF followed, now there are some strange bytes. Strange, incomprehensible... And then I had an idea and went into the datasheet. And what did I see there, in the next part of the paragraph, after the line about simple read-block transaction. Here's what:
The card will respond with a standard response token followed by a data block of 16 bytes suffixed with a 16-bit CRC.
Those. The datasheet for the CMD9 command does not say anything about any Data Token! Those. immediately after R1(0x00) there are register bytes! This is what these strange bytes mean. I checked - indeed, 18 bytes (16 + CRC), and then 0xFF went. I parsed the bytes and checked and checked the datasheet, everything agrees, it’s CSD. And the size of the card also matched. Well, then it’s a matter of technology to count the number of sectors.
So, my experience on this issue, so to speak, may be useful to someone so as not to waste (like me a fool) so much time looking for errors from scratch 🙁Alex_EXE writes 10/22/2016 at 20:28

Who knows if this library is suitable for connecting a 32MB flash drive from mxic 25l to discovery?

As you know, SD memory cards are compatible with the SPI interface, so they can easily be connected to a microcontroller and communicate with them. Adapters for microSD cards are also available, from such an adapter we can make a microSD card slot for our layout. The photos below show appearance a manufactured adapter for connecting to a breadboard.

The project initially used a 1 GB microSD memory card. The microcontroller is ATmega8 or ATmega32, operating at 8 MHz from an internal RC oscillator. In addition, an RS-232 interface was used to connect the prototype to a personal computer for data monitoring. To convert the logical levels of the interface, the MAX232 chip is used. To power the circuit, a stabilized 3.3 V power supply is required (the MAX232 chip is designed for a supply voltage of 5 V, however, as practice has shown, it remains operational at 3.3 V). Connecting the memory card using a 7-wire circuit, according to the pinout (see figure).

Schematic diagram for the ATmega8 microcontroller.

Pull-up resistors R1, R2 with a nominal value of 51 kOhm of the SPI interface provide better stability when working with various cards. Zener diodes D1, D2 are designed to protect the memory card during operation of the in-circuit programmer (ISP). The pins of the MAX232 VCC and GND chip are not indicated on the diagrams, but they must be connected to the corresponding points in the diagram.

Circuit diagram for microcontroller ATmega32

Schematic diagram for the ATmega32 microcontroller (added real-time clock on the DS1307 chip)

As you noticed, the latest version of the device is powered from a 12 V source, and the board has two voltage regulators 5.0 V (LM7805) and 3.3 V (LM1117-3.3). To power the SD card interface, 3.3 V is used, the rest of the circuit is powered by a 5.0 V source. The DS1307 real-time clock chip is in the standard configuration and is connected to the I2C interface of the microcontroller.

First, the “raw” data transfer format was studied, using the example of the operations of reading any data block, reading and writing several blocks of data, erasing several blocks, writing data to any SD memory block. The device, assembled on a breadboard, was connected to the computer via the RS-232 interface. To display read data from a memory card, as well as to enter and write data to the card, use the HyperTerminal (or similar) program on a computer.

After successful implementation of data exchange without specification, the memory card was formatted (FAT32) in operating system Windows XP, then several text files, directories and other types of files were written to the card (to the root directory of the card). After this, routines and functions were written to work with the FAT32 file system to read files, to obtain a list of files on a memory card (using HiperTerminal), to obtain information about the full and free amount of memory.

View of the HiperTerminal program window with functions for working with an SD memory card:

The user is offered over 10 options for working with the memory card (for the version with a clock).

Options 0 - 4 These are low-level functions. After using options 0 - 3, you will need to reformat the card before using the FAT32 routines.
Options 5 - 9- refer to the FAT32 file system. At the moment, only short file names are supported (8 Bytes - file name, 3 Bytes - file extension). If files with long names are written, they will be displayed in the terminal program in a short format. To test these options, do not forget to format the card in the FAT32 file system and write down several directories and text files.

Description of options:

0 - Erase Blocks- erasing the selected number of blocks starting from the specified one.
1 - Write Single Block- writing data to a block with a specific address. Data is entered from the keyboard in the Hiperterminal program;
2 - Read Single Block- reading data from a block with a specific address. The read data is displayed in the terminal program window;
3 - Writing multiple blocks- recording several blocks starting from a specific address;
4 - Reading multiple blocks- reading several blocks starting from a specific address.

Note. Here, the multi-block features (options 3 and 4) are disabled due to insufficient memory on the ATmega8 microcontroller, since these features are not needed for testing the FAT32 file system. To enable these options, you must remove the macro in the SD_routines.h file (#define FAT_TESTING_ONLY). And, if you are using ATmega8, while testing options 3 and 4, the FAT32 library can be deleted in order to free up the microcontroller memory.

5 - Get File List- displays a list of available directories and files with the amount of memory they occupy (in the root directory of the card);
6 - Read File- reading the specified file and displaying the contents in the terminal program window;
7 - Create File- create/add a file with the specified name;
8 - Delete File- delete all files file with the specified name;
9 - Read SD Memory Capacity- information about the full and free capacity of the memory card (the FSinfo sector of the SD card is used).

In the terminal program, the serial port is configured for a baud rate of 19200, with no flow control and no parity check.

For the version with a real-time clock (DS1307) on the ATmega32 microcontroller, the properties of created or updated files are tied to date and time (date of creation/change), these properties are registered in the file table and can be checked using a computer, and the clock can be useful when data collection. Three options have been added to the options menu in the terminal program.

BigPack February 25, 2014 at 10:02 pm

Full-featured SDHC memory card driver for Stm32f4 (part 1)

  • System programming

What is this article for?


All embedders, sooner or later, are faced with the problem of a lack of microcontroller ROM for their projects. Well, it’s trivial, you need to develop a control system for a simple CNC machine, where the control program is stored on the device itself, or a system for collecting data, say, from the sensors of some experiment - obviously, the microcontroller was not originally intended to store such amounts of information.

There are a lot of solutions to this case, ranging from purchasing and connecting EEPROM chips to connecting a standard USB flash drive to a hardware USB host of the stone (if there is one, of course). Well, for handmade projects, the most classic SD memory card would be an excellent option. They come in different types, have different mechanisms for initialization and data transfer, and connect to the host through different interfaces (there are, however, only three of them, but more on that later). Moreover, many modern microcontrollers have hardware modules of these interfaces on board, and the developer’s work comes down to configuring them and sending the necessary commands to the card in accordance with the protocol. Well, memory cards also have the pleasant property of being easily bought at every turn.

About Secure Digital (SD) cards


I will not rewrite Wikipedia - I will provide here basic information and types of SD memory cards and their characteristics.
Secure Digital format– a popular (perhaps the most popular today) flash memory format for use mainly in portable devices. Inside each such card there is, in fact, a flash memory chip (Memory Core) and a controller with 8 registers that connects it with the outside world. The tasks of the latter are hardware implementation of external interfaces, support for information about the card (type, capacity, speed class and a bunch of other characteristics), power supply control, and, of course, management of the memory itself (addressing, reading, writing, clearing and organizing about 80 control commands ).

The SD format was created by Panasonic, SanDisk and Toshiba based on MMC cards. These companies later created the SD Card Association, which is currently developing and promoting SD technology. The main document, which thoroughly describes the interface, protocol, commands, card registers - Physical Layer Simplified Specification(Copyright 2001-2006 SD Group (Panasonic, SanDisk, Toshiba) and SD Card Association). It is this information that all sorts of R&D centers use when developing hardware and software for their future devices. The file itself is freely available on the Internet, and there are no difficulties in downloading it. So, in accordance with this document, there are the following types of memory cards:
SD cards (or also SDSC (Secure Digital Standard Capacity)) - the first generation of memory cards. Volume limitation – 2 GB. The minimum addressable space size is 1 byte.
SDHC cards (Secure Digital High Capacity) – high-capacity memory cards (up to 32 GB). They have a significant difference from the first type, namely, addressing occurs in blocks of 512 bytes and no one in this world can change this value. In other words, you can’t just take and write, for example, 71 bytes of information: the minimum packet size, I repeat, is 512 bytes. I haven’t really dug into why this is so, but there is a personal opinion that this is due to the 32-bit address space of the controller used and due to the fact that memory cards are usually formatted for one or another file system, the cluster size of which is conveniently combined with such blocks . SDHC cards also have an initialization process, which we’ll talk about a little later.
SDXC(Secure Digital eXtended Capacity) – extended capacity memory cards – theoretically up to 2TB of memory. Addressing is also 512 bytes. Here it is obtained with 32-bit space: (2^32)*512 = 2 TB.

There are specifications for each generation of cards, and at the same time, each document for a newer generation describes information about the old ones - that is, they “get fatter” with each product update. So download the Physical Layer Simplified Specification itself latest version and find there everything you need to work with all generations of cards. In addition, memory cards are divided into several classes based on data read/write speed. Well, as for all sorts of mini-, microSD, microSDXC, etc. - it's just a different case size and pinout - no internal differences from standard size cards.

And now it's important: Regardless of the type of card, capacity, manufacturer, case type, color and store where you bought it - all Security Digital cards have the same interfaces for interacting with the outside world. The commands and initialization mechanisms are different, yes, but the interfaces are the SAME. This is exactly what allows you to insert both an SD and an SDHC memory card into the camera. Well, now the time has come to discuss the language of the card, or rather three: SD And UHS-II(native speaker) and “the language of universal microprocessor communication, which every uncut dog microcontroller now knows” - SPI.

Memory card interface


As mentioned above, Security Digital cards have three external interfaces: SD, UHS-II and SPI. The first are “native” channels for data exchange with the host, and, as a result, allow for full-featured, full-speed interaction. SPI does not support a number of commands and does not provide maximum speed data exchange, but it is present in all microcontrollers (both modern and old models), which makes it possible to connect the card to anything that is not in good condition without any problems. There are tons of articles on how to do this. But, with the development of microprocessor technology, with the reduction of nanometers in the technological process of stone production, the SPI interface, as a means of communication with an SD card, is gradually dying out. Indeed, if your MK supports a hardware implementation of the SD protocol, will you bother with a less functional alternative? Fate sent me the Stm32f4 stone from STMicroelectronics for the project, which actually contains a peripheral SDIO (Security Digital Input Output) module that implements both the interface and the card protocol in hardware.

So what is the SD protocol and what is it used for? Key concepts there are three here:
team– a sequence of bits perceived by the card controller and calling it to one or another action;
response– response of the card controller to the command. It can contain both general information (card status, current state of various internal modules, etc.), and, in fact, information expected by the host (they asked for a card identifier in a command and received it in a response);
data– well, no comments here.

But before we look at the logic of the protocol, let's turn to the physics of the interface (very overview).


Pin 4 – card power supply;
Pin 3, 6 – ground;
Pin 5 – clock signal;
Pin 2 – command and response line;
Pin 1, 7, 8, 9 – lines of the 4-bit data bus.

All messages sent to the card and back are sequences of bits strictly synchronized with the clock signal transmitted over the line CLK. Recommended frequencies are described in the specifications for the card and have different meanings depending on its type and speed class. I will only note that for any card, initialization takes place at a very low frequency (compared to data transfer). The data bus can be 1-bit(only D0 works) or 4-bit– this is configured during initialization. It is important that for SD cards on the host side the data and command lines must be Push-Pull And be connected to the power supply through resistors 4.5 - 10 kOhm. Clock bus Same need to get more nutritious.

Well, now to the protocol!
There are several options for exchanging host-card information.

1) Commands without data.
All teams are divided into requiring And not requiring a response.

As you can see from the figure, if we (the host) need to send a command that does not require a response, just send it. If the command implies a certain answer, helmet, and then we wait for the answer. Almost all commands and responses are checked with a checksum, both from the host and from the card. Well, let's look at the command format:

The frame consists of 48 bits. The first – start bit – is always zero. Then, we say that the data is sent from the host to the card and send a command with an argument. Yes, yes, the command consists of an index and an argument. After the command, be sure to send a 7-bit checksum, calculated using the cyclic redundancy code (CRC) algorithm, and complete the sending with a stop bit. There are two types of commands: CMD ( basic commands) And ACMD (Application-Specific Command). They can be with or without an argument, have a response or not. There are about 80 commands in total (I didn’t count exactly, maybe more) and each of them is described in detail in the specification. We will focus only on some that are necessary for basic work with the card (initialization, reading, writing). The command index is the number that comes after the CMD or ACMD characters. 6 bits are allocated for it and 32 bits of the command argument, if one is required.

Important clarification about ACMD: their index space intersects with the indexes of CMD commands, therefore, in order for the controller to perceive the command exactly as Application-Specific, it must be preceded by CMD55!

Response (if required)– also a whole topic, if only because there are five types.

R1 (normal response command)– length 48 bits. Perhaps the most popular response.


Contains a start bit, a transmission direction bit (from card to host), 6 bits of the command index that prompted the generation of the response, card status and, of course, a checksum with a stop bit. All information in a response of this type is carried by 32 bit card status field. The specification carefully and conscientiously describes what each bit of this status means (card busy/free, blocked/unblocked, current state of the data transfer machine, readiness for a particular action, and much more).

R1b– the same format as in the case of the R1 response, only it also transmits a busy flag via the data line.

R2 (CID, CSD register)– the 136-bit long response transmits to the host the contents of the CID and CSD registers of the card controller.


Here, all useful information is contained in a 127-bit field, into which either the content is placed CID(if this is a response to a CMD2 or CMD10 command), or the content CSD register (in case of sending a CMD9 command). So what kind of registers are these that special commands were invented for them, and even with such a long response?
CID (Card identification data)– as the name suggests, it contains all the identification information about the card (serial number, manufacturer, date of manufacture, etc.). CSD (Card-specific data)– all technical information about the card (memory capacity, size of read/write blocks, maximum speed characteristics, maximum current consumption characteristics in various modes and much more). It is this information that the mobile or camera host uses to obtain all the information about the inserted card.

R3– 48 bits long, comes as a response to the ACMD41 command and carries information about the contents of the OCR (Operation Conditions Register) of the card register.


ACMD41 – card initialization command. After sending it, you must wait for this response, which will indicate the successful completion of the initialization process and report the contents of the register OCR(available voltage range, memory card type, and busy flag).

R6 (Published RCA response)- contains RCA (Relative card address) cards and some status bits.


The bus involves connecting several cards to one host. Therefore, such a concept as the card’s own address on the bus is very important. This is the content RCA register.

R7 (Card interface condition)– 48-bit response to the CMD8 command.


The card operates at a certain voltage, no more, no less. This is required before initialization validate(more on this later). In response, the card sends the voltage itself (more precisely, the value corresponding to this range) and a certain check pattern (more on that later).

2) Data.
Let me remind you (this was said a long time ago...), we looked at sending commands and receiving a response from the card. Now is the time to figure out how to send the actual data. I repeat, this is done blocks of 512 bytes(for SDHC cards) - the entire address space of the card is divided into 512 byte cells. The sending of data must always be preceded by a special command telling the card controller that the data is about to be sent. And they go, as I already said, on a 1- or 4-bit bus. Let's look at the format of sending data to the host from the card (reading).

Two modes of data transfer are possible: in one block (block read operation) and in several blocks at once (multiple block read operation). In any case, the start of the transmission and its completion occur according to a special command, please note, with a response.

The reverse procedure (writing) is carried out in a similar way, only between the packets there is always busy, signaling that the card is not ready to accept the next block (the data has not yet been written to the flash card).

Initializing the SD Memory Card


Well, we, embedders, are people accustomed to the fact that everything needs to be initialized, so the SD card is no exception to this great rule. We need to check the supported voltages, assign addresses, and in general, make sure that we can work with this card. Let's look at the initialization algorithm taken from the specification and go through it in order, block by block, in order to understand what needs to be done with the device before using it for its intended purpose.

IMPORTANT: Initialization is carried out in low speed mode! The card clock frequency is no more than 400 kHz!!!

Helmet CMD0, pay attention, without an argument and do not expect anything in the response. As a result, all cards on the line will be transferred to idle mode.

Remember when I said that voltage needs to be validated? Right! We need to tell the card what voltage we are working at and listen to everything about it from it. Helmet CMD8 with an argument in which the bits 11:8 mean host voltage and bits 7:0 check pattern– any, the specification recommends sending 10101010 . Voltage bits are set in accordance with the table:

Well, everything here is very defined and far from Low Voltage Range. Stm32f4 produces a voltage in the range of 2.7 – 3.6 V, so we put 1 on the eighth bit of the argument. So, we have a command with an argument 110101010 . Sent. We checked that everything went well and are waiting for an answer, it won’t keep us doing this for long. In the specification we saw that the answer to this command is R7 type.
If we still haven’t waited for it, then the further command ACMD41 will decide exactly how we were deceived - they slipped us a card of version 1.X of standard capacity or not an SD card at all. True, there is a possibility that we are simply doing something wrong. But let’s not talk about sad things, and let’s assume that the flash drive did respond. If everything is fine with the voltage, the card is happy, we are happy, the answer will contain everything that we sent in the argument, that is 110101010 . It's called valid response. If so, we move on to the next step, otherwise - again - either they cheated or there was a mistake somewhere.

We waited 110101010 , and it’s time for direct initialization - the command ACMD41. And then we remember IMPORTANCE: to tell the card that the command is not simple, but ACMD, we will first send CMD55. In the argument, we must indicate the address of the card for which this command is intended. But stop, we don’t have an address yet, we don’t know it. Nothing, we’ll find out... but later, but for now we’re writing zeros and a helmet. Having received a response like R1 make sure that the card is ready to accept ACMD and only after that the helmet 41 index! The command comes with an argument in which in place 30th bit we indicate 1, which indicates that the host supports SDHC cards and host voltage in place 23:0 bits (see contents of the OCR register). We are waiting for an answer R3 type. Here it is important for us to get 1 on site 31st bit in the response packet carrying the content OCR card register (busy flag). This will indicate that the card has completed the initialization process. Since this process takes a long time (much longer than the microcontroller clock cycle), it is necessary to send ACMD41 in a loop until we receive a response with the busy flag cleared. As soon as this happened, check 30 bit, and if it is one, then we have a high-capacity SDHC or SDXC card, and a standard-capacity SD card otherwise. If we waited and waited, and the bisi flag kept hanging and hanging, then, as in the case described above, it was either an unsuitable card or (most likely) our jamb.

Next is the helmet CMD2- without argument and look at the answer R2. In this case, it will carry information about the content CID register, and we will be able to subtract the manufacturer ID, card serial number and other information.

And finally, the final step is to obtain the card address ( RCA - relative
address
). As already mentioned, several cards can be connected to one bus, so each one must have its own unique local address. Helmet CMD3 and get a response like R6, in which in under 16 bits contain the card status, and in older– new RCA address. From now on, to access our card, we will have to call it by name, that is, by RCA address.

Optional item. By default, the card works with a 1-bit data bus, which, of course, is slower than with a 4-bit one. If we want to achieve maximum performance - a helmet ACMD6, with previous CMD55, of course. But first, you need to transfer the card to the state Transfer State(see below) by command CMD7 with RCA as an argument. In argument ACMD6 in place of the very first bit we write 1 – if we want to enable the 4-bit mod and 0 – to turn off. Answer R1 will indicate the success of the operation.

Example of SDHC card initialization
This example uses a homemade command sending function written for the Stm32F4 peripheral.
char SDIO_send_command(char index, unsigned int arg, char resp_type, unsigned int *resp);
index – command index;
arg - argument;
resp type – response type (0 – no response, 1 – short (48 bit) response, 2 – long (136 bit) response);
resp is an array of responses (in the case of a short response, the information is carried by the first element of the array, in the case of a long response - 4 elements).
The command returns 0 if the operation of sending a command and receiving a response was successful, and an error code otherwise.

Char SDHC_card_initialization(unsigned int *RCA) ( char result; unsigned int RESP; result = SDIO_send_command(0, 0, 0, RESP); //Send CMD0 to reset the cards if (result != 0) return result; //Check for success result = SDIO_send_command(8, 0x1AA, 1, RESP); //Send CMD8 with argument 110101010 if ((result != 0) || (RESP != 0x1AA)) return 4; //Check for success while(! (RESP&(1<<31))) //Ждем, пока флаг бизи не слезет { result = SDIO_send_command(55, 0, 1, RESP); //Шлем CMD55, тем самым, говоря, что потом будет ACMD if (result != 0) return result; result = SDIO_send_command(0x29, 0x40020000, 1, RESP); //Шлем ACMD41 if (result != 0) return result; } result = SDIO_send_command(2, 0, 3, RESP); //Шлем CMD2 и получаем инфу о карте if (result != 0) return result; result = SDIO_send_command(3, 0, 1, RESP); //Шлем CMD3 и получаем RCA номер if (result != 0) return result; SDIO->CLKCR = (0x02<<0)|(1<<11)|(1<<8)|(1<<14); //Наращиваем клок (в части 2 - подробнее) *RCA = (RESP & (0xFFFF0000)); //Маскируем отклик и получаем RCA result = SDIO_send_command(7, *RCA, 1, RESP); //Выбираем нашу карту if (result != 0) return result; result = SDIO_send_command(55, *RCA, 1, RESP); //Шлем CMD55, тем самым, говоря, что потом будет ACMD if (result != 0) return result; result = SDIO_send_command(6, 0x02, 1, RESP); //Шлем ACMD6 c аргументом 0x02, установив 4-битный режим if (result != 0) return result; if (RESP != 0x920) return 1; else return 0; //Убеждаемся, что карта находится в готовности работать с трансфером return 0; }
We run the code, make sure that the response is NULL and complete the initialization. That's it, we can work with memory and write/read information.

Data exchange


Everyone rules here SD Memory Card State Diagram (data transfer mode).


There are 6 card statuses in this mode and you can find them in the response R1 on site 12:9 bits Let's look at the specifications.


Stand by State (stby)– set after initialization instead of Idle State.
Transfer State (trans)– data transmission mode.
Receive Data State (rcv)– waiting for a packet of data from the host.
Programming State (prg)– recording the received packet in flash.
Sending Data State (data)– sending a packet of data to the host.
Disconnect State (dis)– used to select another card using the CMD7 command.

Writing data to the card
So, after successful initialization we are in the state trans, in any case, should be. Let's look at the diagram: in order to go to the state rcv, we need to send a CMD24 command with the address of the 512 byte cell that we want to write. Sent. The card has entered data standby mode. Next, we begin sending information to it over the data bus until we transfer all 512 bytes or send the CMD12 command (stop transmission). After the act is completed, the card itself will move to the state prg and will remain there for some time (while the data is recorded). We are waiting... What exactly are we waiting for? And we send it in a CMD13 loop with the card address in the argument, until the status R1 is returned in the response trans. When this finally happens, you can send another packet of data by sending CMD24 again. In addition, there is also a mode for recording several blocks at once (CMD25) and other modes - see the specification for details.
Reading data
In order to perform the reverse procedure, first of all, make sure that the card is in trans. CMD17 helmet with RCA address in argument. If everything goes well, the card will move to the state data and will begin to output information on the data line, again in a 512-byte block. The host’s task at this time is to listen carefully to the line and read the data. As soon as the parcel is finished, the card itself will move to the status trans. I think it goes without saying that reading, as well as writing, is possible in several blocks at once.

I will not provide a listing of the read/write program in this article, since it, unlike the initialization subroutine, is too heavily tied to hardware SDIO Stm32f4 microcontroller module, and this is the topic of the second part of the article.

Share: