Esta es una especie de "clásico" problema, y creo que tengo una solución, pero quiero veterinario con esta comunidad. Estoy construyendo un proyecto con el ATtiny88 microcontrolador, y estoy de programación en avr-gcc. La necesito para manejar los siguientes interrupciones:
- TWI (I2C)
- Desbordamiento Del Timer0
- Timer1 Captura
Quiero usar el Desbordamiento del Timer0 para mantener un 32-bit milisegundo marca de tiempo (similar a Arduino millis()
concepto). Para mi aplicación no puedo dejar que nada se interponga en el camino de la TWI interrupción porque mi ATtiny88 está actuando como un TWI esclavos, y como tales nunca puedo borrar las interrupciones. El Temporizador de ISRs ambos tienen que ser declarados NO_BLOCK
.
Desde el ATtiny88 es de 8 bits del procesador, el acceso a las variables que están más amplio de 8 bits están determinados a tomar varios ciclos para completar. La forma en que el Arduino núcleo controla este dilema es guardando el acceso a su interior de 32 bits timer0_millis
variable cli()
dentro de la millis()
función. Ese enfoque es desagradable para mí porque significa que yo podría perder un TWI interrupción porque yo llame a millis()
. No me importa en ocasiones falta un "tick" de la base de tiempo debido a un TWI interrupción se manejan.
Así que escribí la base de tiempo.h / base de tiempo.c con la esperanza de eludir este problema a costa de un poco más de almacenamiento, por el doble búfer.
base de tiempo.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_ */
base de tiempo.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
}
Mi pregunta es, ¿el código que he escrito aquí de resolver eficazmente el problema que he descrito? He implementado con éxito atómica de acceso a la base de tiempo sin compensación de las interrupciones? Si no, ¿por qué no, y cómo puedo alcanzar mis metas.