8 years, 2 months ago.

Timer.read in main loop

I am using the below code for just taking timestamps and storing the time to a file on the local drive of the MBED. When i look at the CSV-file I see that the time between 2 timestamps is normally about 25us, but every 57 samples the difference between 2 timestamps is very very big (10's of ms).

Why is this?? I want to use this code to read out an ADC value and take timestamps every time it does.

#include "mbed.h"
#include "LPC17xx.h"

LocalFileSystem local("local");
 
int main(void) {
    Timer timer;
    FILE *Datalogging;
    Datalogging = fopen("/local/TEST.csv", "w");
    uint32_t i;
    
    timer.reset();
    timer.start();
    
    while(i < 10000) {
        fprintf(Datalogging,"%f\n",timer.read());
        i++;
    }
    fclose(Datalogging);
}

1 Answer

8 years, 2 months ago.

My guess is that it's caused by the file system on the SD card buffering data and writing it in blocks.

Writes to the SD card will be buffered up until you hit a certain size and then written as a block, this is both better for the card and more efficient as a whole. One line is going to be about 9 bytes of data which would work out as about 57 lines in a 512 byte buffer. Those writes will take a while and so one in every 57 fprintfs will take a lot longer to run and delay the loop execution.

If you need to log things at a fixed time interval then use an interrupt to generate the data and put it into a buffer. The main loop then reads from that buffer and writes to the SD card. As long as the buffer is large enough to store the all the data that will accumulate during an SD write (which will take even longer since you'll be interrupted during it) then you can maintain a constant sample rate, you become limited by the average write speed of the card rather than the worst case write speed.

What is the best way to program such a FIFO buffer, written in an interrupt and read in the main to save to the external file.

posted by Stefan Poels 10 Feb 2016

I am now using the following code as example. So I use a ticker to interrupt the system and fill a buffer with timestamp values. In the main-function I check if there is data in the buffer and if so I write it to the external file.

However now I still get different timestamp intervals. It seems sometimes the main is writing the 512bytes to the external file and then the ticker is no longer called. When the 512bytes have been written, the ticker was suppose to be called e.g. 20x times and so the interrupt service routine is executed 20x immediately after each other.

How to solve this problem or how to rework the code? I have already tried to increase the priority of ticker, but without result.

void TimerISR(void){
    afBuffer[BufferIndexIn++] = timer.read();  
//    fprintf(Datalogging,"%f\n",afBuffer[BufferIndexIn]);
    if(BufferIndexIn == BUFFERSIZE)
        BufferIndexIn = 0; 
    led3 = !led3;
        
}
 
int main(void) {
    led4 = 1;
    
    Datalogging = fopen("/local/TEST.csv", "w");
    
    BufferIndexIn = 0;
    BufferIndexOut = 0;
    
    timer.reset();
    timer.start();
    NVIC_SetPriority(TIMER3_IRQn, 1); // set mbed tickers to higher priority than other things
    TimerIRQ.attach_us(&TimerISR,500);
    
    bool bMeasurementRunning = TRUE;    
    while(bMeasurementRunning) {
        if (BufferIndexOut != BufferIndexIn)
        {
            fprintf(Datalogging,"%f\n",afBuffer[BufferIndexOut]);
            BufferIndexOut++;
            if(BufferIndexOut == BUFFERSIZE)
                BufferIndexOut = 0;
            led1 = !led1;
        }
        if (afBuffer[BufferIndexOut]>1)
        {
            TimerIRQ.detach();
            led2 = !led2;
            bMeasurementRunning = FALSE;   
        }
    }
    fclose(Datalogging);
}
posted by Stefan Poels 10 Feb 2016

Sorry, I just noticed that you're using LocalFileSystem, for some reason I was assuming it was an SD card. The localFileSystem is implemented almost as a debug breakpoint, the main CPU core is halted while the interface chip does the flash access. No matter what you do no interrupts will trigger during file system access.

posted by Andy A 10 Feb 2016

Hello Andy A,

Thanks for your answer. I have now changed the setup to store the data on an external SD-card and I am using the FIFO buffer. However with below code I still get very few times a delay of 100ms. Not sure where this is coming from now??

void TimerISR(void){
    afBuffer[BufferIndexIn++] = timer.read();  
    if(BufferIndexIn == BUFFERSIZE)
        BufferIndexIn = 0; 
    led3 = !led3;   
}
 
void SaveData(){
    fprintf(Datalogging,"%f\n",afBuffer[BufferIndexOut]);
    BufferIndexOut++;
    if(BufferIndexOut == BUFFERSIZE)
        BufferIndexOut = 0;
    led1 = !led1;
}
 
int main(void) {
    led4 = 1;
    led2 = 1;
    
    //Datalogging = fopen("/local/TEST.csv", "w");
    Datalogging = fopen("/sd/TEST.csv", "w");
    
    BufferIndexIn = 0;
    BufferIndexOut = 0;
    
    timer.reset();
    timer.start();
    TimerIRQ.attach_us(&TimerISR,100);
    NVIC_SetPriority(TIMER3_IRQn, 0); // set mbed tickers to higher priority than other things
    
    bool bMeasurementRunning = TRUE;    
    while(bMeasurementRunning) {
        if (BufferIndexOut != BufferIndexIn)
        {
            SaveData();
        }
        if (afBuffer[BufferIndexOut]>1)
        {
            TimerIRQ.detach();
            led2 = 0;
            bMeasurementRunning = FALSE;   
        }
    }
    fclose(Datalogging);
}
posted by Stefan Poels 10 Feb 2016

No idea. That looks to be exactly the same structure as I've used before.

Any chance of a buffer overflow? Is the dropout exactly 100ms or 102.4ms each time and your buffer 1000 or 1024 items deep? 1000 items at 100us = 100ms. Maybe add

if (BufferIndexIn  == BufferIndexOut)
  led2 = 1;

to the end of TimerISR() to turn an LED on if there is an overflow just to be sure.

posted by Andy A 10 Feb 2016

It seems there is indeed an overflow occuring. The reason is that the FIFO buffer is filled faster than it can be emptied. Because the SD writing still happens with 512bytes and stil takes several ms. Is there anyway to speed the SD-card write up. I have already increased the SPI frequency from 1MHz to the mbed max of 12.5MHz, but the write time is not decreased by 10x. So there seems to be a lot of overhead?

posted by Stefan Poels 11 Feb 2016

The bus speed will decrease the time to transfer the data but the bulk of the write time is the internal flash time of the SD card. About the only way to decrease that is to use a faster SD card.

posted by Andy A 11 Feb 2016