2
\$\begingroup\$

I am using nucleo-f401re board for my project and I want to write sensor data to SD card. I am writing data when sensor interrupts occur, and that happens at 408 Hz, so I have around 2 ms to write data. I am using SPI at max frequency to communicate with SD card reader, I am using micro SD card reader module for mounting SD card. I am only using 1 interrupt which reads sensor data and sets flag, writing is occurring in while(1). Everything seems to work fine and writing finishes before next interrupt arrives, but every 8-9 writing cycle, writing function takes way longer than normally and I lose 1 data sample: enter image description here

As you can see, yellow signal is my while cycle and that short pulse is writing time, except when 1 writing cycle takes 2.34 ms. Blue is my interrupt, I must write during low state of blue and finish it before new high level arrives. Why this keep happening? As I said, this longer writing occurs every 8, sometimes 9 writing cycle. Is there a way to fix it, or this is FATFS problem? I know that this occurs during FATFS write because I debugged it, I keep my file open all the time when I am gathering data.

\$\endgroup\$
3
  • \$\begingroup\$ Can help ? community.st.com/t5/stm32-mcus-products/… \$\endgroup\$
    – Antonio51
    Commented Mar 14 at 8:30
  • \$\begingroup\$ How much data there is from sensor every 408 Hz? Why are you not buffering the sensor data? Why are you using SPI to SD card as the F401 has native SD card bus interface? The problem might not be the FATFS because it likely writes when there is a whole block to write. The SD card will take different amount for finishing each write as it has to manage the flash, possibly erasing a block internally before it is possible to write again to it. \$\endgroup\$
    – Justme
    Commented Mar 14 at 11:51
  • \$\begingroup\$ I am sending 1 uint32_t sample number, 7 float numbers and 1 uint32_t number, all as a string every write cycle. I am using SPI because I was using this example: 01001000.xyz/2020-08-09-Tutorial-STM32CubeIDE-SD-card \$\endgroup\$
    – Dominykas
    Commented Mar 14 at 13:53

2 Answers 2

6
\$\begingroup\$

SD card are not a realtime medium. You need to buffer the writes to it.

Internally the SD card prefers full blocks. It then applies wear leveling. You have no control over this. So sometimes the writes will take longer.
If it has no free blocks it has to erase one, this takes several milliseconds when brand new. Or longer when worn out.

The standard allows a latency in hundreds of milliseconds.

\$\endgroup\$
2
  • \$\begingroup\$ so best solution would be buffer that missed sample and write it after that longer write ? \$\endgroup\$
    – Dominykas
    Commented Mar 14 at 9:10
  • \$\begingroup\$ @Dominykas you need to decouple the steps. Have a thread sample your data. And have some other asynchronous thread write the data. With enough buffer you should be able to write to the card assuming your samplerate does not exceed the cards speed class. \$\endgroup\$
    – Jeroen3
    Commented Mar 14 at 9:47
5
\$\begingroup\$

In addition to Jeroen3's answer, here are a few things that I found helped make SD card latency more predictable:

  • Buffer the data so that you always write whole blocks (usually 512 bytes, though it might be more), never partial blocks. While I initially thought that writing one block at a time would minimise latency at the cost of throughput, it turned out that writing 32 blocks at once minimized the peak latency in my application, so you might want to experiment with that value.
  • Ensure the card is properly formatted. Not all tools generate a volume that aligns properly with physical sectors. Use the official SD assocation tool, or f_mkfs() from FatFs.
  • Don't delete files to make space (to avoid fragmenting the filesystem), format the card instead.
  • If you know the maximum file size, you can try preallocating the file (the drawback is you then need to truncate the end when you close it).

To be honest, 2 ms sounds very tight, I'm not sure if that is achievable without a multi-core microcontroller or a real-time OS.

\$\endgroup\$
3
  • \$\begingroup\$ A packet of data comes in every 2.45 ms. Depending on if that is a few bytes or a few thousand bytes determines if it is doable at all, over SPI, and with any card. If it is only a few bytes every 2.45ms, on average, it will be achievable without multi-core MCU and without RTOS. \$\endgroup\$
    – Justme
    Commented Mar 14 at 12:20
  • \$\begingroup\$ @Justme what I found was that latency remained somewhat spiky, even when following all the above practices, so it needed about a 2x to 3x margin above the mean to always complete on time. This meant the sampling had to be on a different thread/core. \$\endgroup\$ Commented Mar 14 at 13:25
  • \$\begingroup\$ Storing your data in binary and then having a separate application to convert to a human readable format after the fact should help too by letting you fit more data into each block. \$\endgroup\$ Commented Mar 15 at 6:07

Not the answer you're looking for? Browse other questions tagged or ask your own question.