6 votos

Simultaneidad de tiempo Base ISR

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.

20voto

Bash Puntos 1680

Juzgando a partir de un rápido vistazo, el doble búfer parece un buen enfoque. Sin embargo, creo que aún puede suceder que usted recibe un "no válido" valor devuelto. Teóricamente el T0 interrupción podría desencadenar varias veces mientras que tener acceso a la marca de tiempo en el timebase_now() (función de si la ejecución se retrasa >1ms por otro ISR) y haría que su "doble" buffering inútil.

Estás seguro de que es incluso necesario para hacer su Timer0 ISR sin bloqueo? Ya que el hardware es el manejo de todos los de bajo nivel de TWI funciones y el máximo de velocidad de transferencia de datos es de 400 khz, debe haber tiempo suficiente para manejar TWI datos. La actualización de los 4 bytes de marca de tiempo variable, sólo se tarda un par de ciclos de reloj. En qué supuesto se espera que perder TWI interrupciones?

Usted dice que la marca de tiempo de precisión no es crítica, por lo tanto, otra solución podría ser establecer un indicador (o 1 byte contador) en el T0 ISR y manejar la actualización de la marca de tiempo en el bucle principal. Sin embargo, esto sólo funciona si timebase_now() no se supone que se puede llamar desde dentro de cualquier ISR.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X