# Time Base ISR Concurrency

This is sort of a "classic" problem, and I think I have a solution, but I want to vet it with this community. I am building a project using the ATtiny88 microcontroller, and I'm programming in avr-gcc. I need it to handle the following interrupts:

• TWI (I2C)
• Timer0 Overflow
• Timer1 Capture

I want to use the Timer0 Overflow to maintain a 32-bit millisecond timestamp (similar to Arduino's millis() concept). For my application I can't have anything get in the way of the TWI interrupt because my ATtiny88 is acting as a TWI slave, and as such I can't ever clear interrupts. The Timer ISRs both have to be declared NO_BLOCK.

Since the ATtiny88 is an 8-bit processor, access to variables that are wider than 8-bits are certain to take multiple cycles to complete. The way the Arduino core handles this dilemma is by guarding access to its internal 32-bit timer0_millis variable with a cli() inside the millis() function. That approach is unpalatable to me because it means I might miss a TWI interrupt because I call millis(). I don't care about occasionally missing a "tick" of the timebase because of a TWI interrupt being handled.

So I wrote timebase.h / timebase.c in hopes of circumventing this problem at the expense of a little extra storage, by double buffering.

timebase.h

/*
* timebase.h
*
*  Created on: Dec 3, 2012
*      Author: vic
*/

#ifndef TIMEBASE_H_
#define TIMEBASE_H_

// timer 0 is set up as a 1ms time base
#define TIMER0_1MS_OVERFOW_PRESCALER 3     // 8MHz / 64 = 125 kHz
#define TIMER0_1MS_OVERFLOW_TCNT     131   // 255 - 131 + 1 = 125 ticks

void timebase_init();
uint32_t timebase_now();

#endif /* TIMEBASE_H_ */


timebase.c

/*
* timebase.c
*
*  Created on: Dec 3, 2012
*      Author: vic
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "timebase.h"

// double buffered timestamp
volatile uint32_t timestamp_ms_buf[2] = {0, 1};
volatile uint8_t  timestamp_ms_buf_volatile_idx = 0;

void timebase_init(){
// set up the timer0 overflow interrupt for 1ms
TCNT0  = TIMER0_1MS_OVERFLOW_TCNT;
TIMSK0 = _BV(TOIE0);

// start timer0
TCCR0A = TIMER0_1MS_OVERFOW_PRESCALER;
}

// fires once per millisecond, don't block
// can't miss TWI interrupts for anything
ISR(TIMER0_OVF_vect, ISR_NOBLOCK){
TCNT0 = TIMER0_1MS_OVERFLOW_TCNT;

// modify the volatile index value
timestamp_ms_buf[timestamp_ms_buf_volatile_idx] += 2;

// change the volatile index
timestamp_ms_buf_volatile_idx = 1 - timestamp_ms_buf_volatile_idx; // always 0 or 1
}

uint32_t timebase_now(){
uint8_t idx = timestamp_ms_buf_volatile_idx; // copy the current volatile index
return timestamp_ms_buf[1 - idx];            // return the value from the non-volatile index
}


My question is, does the code I've written here effectively solve the problem I've described? Have I successfully implemented atomic access to the timebase without clearing interrupts? If not, why not, and how can I achieve my goals.

Judging from a quick look at it, the double buffering looks like a good approach. However, I believe it can still happen that you get an "invalid" value returned. Theoretically the T0 interrupt could fire multiple times while you access the timestamp in the timebase_now() function (if execution is delayed >1ms by another ISR) and would make your "double" buffering useless.
You say that timestamp accuracy is not critical, so another solution could be to just set a flag (or 1-byte counter) in the T0 ISR and handle updating the timestamp in the main loop. However, this only works if timebase_now() is not supposed to be callable from within any ISR.