best practice advice needed for T3.5 + SdFatSdioEx Logger

Status
Not open for further replies.

rubin

New member
hi all, i'm trying to log 1hr worth of sensors data (each reading is 100 bytes, sampling rate is 100Hz, so 10KB/Sec).

I have a "data-ready" interrupt (fires at 100Hz sampling rate) that sets a "data-ready-flag". In the main loop, whenever the flag is up, I acquire the data from the sensors (100 Bytes). The sensors acquisition takes 1-2ms, and therefore is done outside of the ISR. The main loop runs much faster the 100Hz, and so no data is being loss.

Using the SdFat library (by Greiman) I tried to write these 100 Bytes, after each data acquisition (that is 100 times a second). It works generally well, but every now and then there are some (well known and well reported) 150-200msec latencies at the SdFile write method.

I've been digging a lot in the forum, and came across two main solutions:
(1) implementing a ring (/FIFO) buffer, and writing to the SD only whenever it is not busy.
(2) using contiguous file, and writing multiple blocks (as in the LowLatencyLogger examples provided with the SdFat library.

My problem with option (1), is that the `sdEx.card()->isBusy()` method seems to block my process for about 1sec, and returns alway True.. (works ok with SdFatSdio but not with SdFatSdioEx). From the forums it seems like accessing the card class directly is not advisable. So how this should be done?

My problem with option (2), is that writing blocks with `sdEx.card()->writeData()` doesn't work for me. But then again, the TeensySdioDemo example suggests that using the SdFatSdioEx one can write multiple blocks natively very fast. In that case, do I still need a ring buffer? how do I time the writing process if I can't access the isBusy() method? Or maybe I can override the `yield()` method and do the sensor acquisition there? I'm a bit lost here..

So, what would be the best practice way to implement this kind of data logger?

Many many thanks in advance,
Rubin
 
Last edited:
Acquire the data in the ISR and store it in one of many buffers. (Make the buffers at least 4KB in size and a nice power of 2.) The main routine just waits for there to be a full buffer and writes it. No need to check for the SD card being busy.
 
thanks UhClem, but the problem is that sensor acquisition is through SPI, and each call takes 1-2msec, and thus can't be called from within the ISR.. (I use the ISR to raise a data-ready flag, and then acquire the data in the main loop, which is blocked at random times by the SD write command..)
 
Why can't you do it in the ISR? Do you have something else going on that you haven't mentioned?

While in general you do want to keep ISRs short, that is to keep from blocking other tasks. If there are no other tasks...
 
Oh, i didn’t realize it’s possible. Will definitely give it a try then.

I see in the docs that one should declare the ISR and pin with:

SPI.usingInterrupt(digitalPinToInterrupt(mypin));

I’m acquiring several SPI devices on a shared bus, using different SS (slave select) pins, and different interrupt pins and ISRs. Any idea how to declare the ‘usingInterrupt’ in this scenario?
 
Status
Not open for further replies.
Back
Top