2
\$\begingroup\$

I'm making a data logger project with 5 different sensors which includes a 3-axis sensor runs at 800 Hz. My requirement is to log the data to an SD card. Here I have to log 3-axis sensor @ 800 Hz and all the other sensors @ 1 Hz.

Since sensors running at different frequencies I used ticker interrupts for each sensor except 3-axis. I made 3-axis to run in while loop. Now everything is OK. I should be able to log as per my requirement. The problem is that after logging for 10 mins, sometimes 30 mins, the logging stops.

One important aspect here: fopen and fclose are done outside by using an interrupt. That means initially I open SD card and I write the data for 2 mins; later on, I close that file using tickers and I create a new file.

Below you can see my code sample.

// tickers used to create a new SD file at regular intervals.

 void onFileUpdate(void) 
    {    
        static int fileNumber = 0;
        if (logFile)
        fclose(logFile);
        char fileName[20];
        sprintf(fileName,"/sd/PCE-DL%03d.txt",fileNumber++);
        logFile = fopen(fileName,"w");
    }

// Ticker object for Light sensor which run at 1HZ by an inturrupt.

void onLight(void)
 {  
  LUX = max44009.getLUXReading();
   fprintf(logFile,"\r\n                                 %f  ",LUX);
 }

 // RTC ticker

 void onRtc(void)
 { 
    seconds = mktime(&t);
    rtc8564.get_time_rtc(&t);   // read RTC data
    strftime(buf, 40, "%I:%M:%S %p (%Y/%m/%d)", localtime(&seconds)); 
    fprintf(logFile,"\r\n %s", buf);
 } 

// my while loop

 while(1) { 
   accelerometer.getOutput(readings);
   fprintf(logFile,"\r\n%i,%i,%i", (int16_t)readings[0], (int16_t)readings[1], (int16_t)readings[2]); 

      }
  }

I don't know why it is hanging up. It may be timing problem ...

\$\endgroup\$
  • 1
    \$\begingroup\$ There are millions of different MCUs with equally as many peculiarities which can make your program hang. Can you enighten us which MCU you are using? \$\endgroup\$ – Ariser Jul 5 '16 at 7:39
  • \$\begingroup\$ Did you allocate a big enough buffer to deal with delays of, say, a couple hundred ms? \$\endgroup\$ – Spehro Pefhany Jul 5 '16 at 7:49
  • 6
    \$\begingroup\$ It appears that you are writing asynchronously. You may need to serialize everything. Maybe synchronize the writing with a mutex. It would be better to log everything to a buffer in memory, and then dump to the file at intervals. \$\endgroup\$ – Mark Jul 5 '16 at 7:53
11
\$\begingroup\$

Never, never, never put file I/O in an interrupt routine - unless it is the only routine to do file I/O. And then still don't do it!

An interrupt can interrupt anything: including file I/O. And interrupts should be quick, quick, quick! File I/O just isn't.

You need to use the tickers to store the data in memory buffers, then write the data inside loop().

\$\endgroup\$
  • 1
    \$\begingroup\$ With ARMv6-M or ARMv7M, it is quite reasonable to have all functional code in interrupt routines, and only an empty (wfi) thread loop. Interrupts are only interrupted by a new arrival having higher priority. You're right in one sense, the thread loop might not get a look in if the interrupts back up and tail-chain. \$\endgroup\$ – Sean Houlihane Jul 5 '16 at 7:59
  • 4
    \$\begingroup\$ "it is quite reasonable to have all functional code in interrupt routines" - I strongly disagree. It is possible if you design for it, but it's neither reasonable nor intended to be done. \$\endgroup\$ – JimmyB Jul 5 '16 at 11:56
  • \$\begingroup\$ @JimmyB I'm not going to bother asking, but I'm fairly sure that is an intended use model. If you look into the architected sleep states, they support this model (sleep on exit). \$\endgroup\$ – Sean Houlihane Jul 5 '16 at 12:32
  • 5
    \$\begingroup\$ @SeanHoulihane both John & Jimmi are right here: you can do it, but the general INT design is to do as little as possible in them; since a) interrupting an INT is highly problematic, b) each INT has to preserve prior CPU state, incurring an execution time penalty, c) threading model (esp. I/O threads) gets more complicated once you introduce large mutable data needed for complex interrupt handlers - it's rather unwise to do heavy lifting in INTs. The common uC idiom is to only set flags, counters, or do light I/O in INTs - for the very reasons outlined above. \$\endgroup\$ – user20088 Jul 5 '16 at 12:36
5
\$\begingroup\$

Your file pointer can be changed (by an interrupt) on the middle of the fprintf. All of the other output routines will tail-chain rather than be interrupted (assuming they have the same priority), but your while loop needs to be interruptable.

As a test, move the file update to fire every 48000 loop iterations, within the loop (and dont do writes for the other sensors of this count is at the end value)

\$\endgroup\$
1
\$\begingroup\$

Because other answers explained the problem already, i just describe my solution.

Set flags in the interrupt routines. Check in the main routine if a flag is set (if yes: do something).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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