6 years, 6 months ago.

Best way to structure a data logger?

Hello all,

I've decided that i'd like to create a digital dashboard and data logger for my track car. I'm using an LPC4088 and dev base board along with an external 16 channel ADC on a SPI bus. I also have the adafruit 24led light bar to use as a shift light on I2C.

Here are my goals/requirements: -calculate/log slow signals like temperatures at 1hz -calculate/log medium signals like oil pressure at 5hz -calculate/log RPM and vehicle speed at 5hz -calculate/log fast signals like accelerometer at 500hz

How can i implement several different sample rates at once? Would this be asking too much of Tickers? What happens if a Ticker interrupts a Ticker?

Here's my preliminary plan:

-Capture the slow signals in the main "while(1)" loop using a simple delay for a time difference to achieve a 1hz loop. -Use a Ticker at 5hz. Inside the 5hz Ticker function, I'll call the medium signal and RPM/VS functions -Use a second Ticker at 500hz

Also, since the tach and VS signals are pulse trains, I plan to use an interrupt on their input pins. I have a counter function that counts the interrupts and the 5hz Ticker function will check on the total, save it, and reset the counter.

Does this make any sense? I'm sure there's a better way, any clues?

Thanks!

6 Answers

6 years, 6 months ago.

3 tickers should be fine, I don't know how many the mbeds can handle, but I have used 8 before( all around 440hz) on the mbedLPC1768. If you want to use less, setup the fastest ticker you need, and use a counter to divide it down for the slower rates. Just remember that everything will need to be done before the next tick comes in and you may have to do all operations in one interrupt.

6 years, 6 months ago.

I personaly would recommend 1 ticker. driving a schedule.

So evey other tick. You do your fastest test. then the other interleaved ticks you spread out the other tasks

some of which can be processing data. Creating a CSV file saving to SD.

Then use XCEL to do the graph etc

note ther will be ticks that do nothing and some that might need 2 or more ticks

ceri

Yeah, using a scheduler is a good way to spread the load. depends on how much time you have spare and how accurate you need your timing for deciding how you spread it. you can also use the scheduler to prioritise your tasks if you don't have time to do them all.

posted by Chris Dick 27 May 2014
6 years, 6 months ago.

If possible avoid writing to the log file in a ticker or any other interrupt. Capture the data on a ticker/interrupt and put it into a buffer.

In your main function have a while (1) {...} loop that checks if there is data waiting in the buffer and if there is writes it to the log file.

Remember to declare the counter used to indicate that there is data in the buffer as being volatile. Without it the main loop may not pick up value changes made by an interrupt.

agreed, Definitely avoid writing to the log during an interrupt.

posted by Chris Dick 27 May 2014
6 years, 6 months ago.

Tickers are pretty light-weight. Why not just use one per sample rate, and just sleep in the main loop?

As for the pulse trains, you'd be better off using the built-in timer hardware to count them. Just use a timer input pin for each of the pulse trains, and read the timers' counter in your 5Hz interrupt handler.

TIM3 is used for the microsecond timer.

Thanks. I think because my functions are pretty lightweight, i can try just running a Ticker per task and letting it do its thing.

What happens though when two tickers go off at the same time? Say the 5hz and the 10hz Ticker? Or can I stagger initializing the ticker so that they are offset in time? Such as:

Time 0ms: Start 5hz Ticker ( every 200ms) Time 20ms: Start 10hz Ticker (every 100ms)

If i draw it out and think on it a bit i can probably optimize the staggering to maximize the amount of processing time for each.

posted by Dan D. 29 May 2014
6 years, 5 months ago.

I have one working with a main loop running at 10 Hz where i process the data serially polled from ECU send over bluetooth and write down to usb. ADC conversions for temp, pressure and accelerometer are done in tickers at their rates.

Badly coded years ago as my first project, but still working strong.

6 years, 5 months ago.

The following method of scheduling works very good for my program which involves critical functions. Note: I do not use the printf-function on this. I only use putc and take care that my buffer is not filled up. Modserial provides neat functions to check how much of the buffer is used. I have experienced "blocking" or something like that if I try to send or store too much data.

http://mbed.org/users/AjK/code/MODSERIAL/

#define     SLOW    1
#define     MEDIUM  10
#define     FAST    400

Ticker      SlowTick,
            MediumTick,
            FastTick;

bool TickSlowVar, TickMediumVar, TickFastVar;
int main()
{
    SlowTick.attach_us(&SlowTickFunction, 1000000/SLOWFREQ);
    MediumTick.attach_us(&MediumTickFunction, 1000000/SLOWFREQ);
    FastTick.attach_us(&FastTickFunction, 1000000/FASTFREQ);
    while(1){
        if(TickFastVar==1){
            TickFastVar=0;
            //run 400Hz code here
        }
        if(TickMediumVar==1){
            TickMediumVar=0;
            //run 10Hz code here
        }
        if(TickSlowVar==1){
            TickSlowVar=0;
            //run 1Hz code here
        }
    }


void SlowTickFunction()
{
    TickSlowVar=1;
}

void MediumTickFunction()
{
    TickMediumVar=1;
}

void FastTickFunction()
{
    if(TickFastVar==1){
        //Ticker called again before the tick was "used" and code was able to run.. Report/do something/debug code.
    }
    TickFastVar=1;
}

One change I would make to that would be to put the 400Hz code directly into FastTickFunction() rather than in main.

Currently if your code run on a slow tick plus the code on a medium tick takes longer than one fast tick period you'll miss the fast tick. If you put the fastest code in the interrupt function and only do the slow and medium in the main loop then the fast code will take priority and always get done. This is making the assumption that your fast code can reliably be done quickly enough, if there is any risk of the fast tick function taking all or even most of a 400Hz cycle then putting it in the interrupt is bad idea.

Also the three Tick[speed]Var flags should probably be declared as volatile bools.

posted by Andy A 12 Jun 2014

Yeah now as you mention it, they are volatile bool in my code. Forgot about that one.

Anyways, would not putting the 400hz code inside the ticker create a problem if there are any other interrupt functions going on? Can other interrupts interrupt while the 400Hz ticker function is running? And what happens if another interrupt function interrupt for such a long time that the 400Hz interrupt function gets called again?

For me it seems like a perhaps problematic part doing it your way, and in my code (which is a multicopter platform) it is very important that the code running does not crash. I added a small part which checks if the 400Hz function has completed its cycle or not. If it didn't complete it, then I'm notified that something went wrong and I can manually fix that part of the code instead. The code will continue running, but at a slower than specified rate.

posted by Tomas Johansen 12 Jun 2014