Leyendo un temporizador de 16 bits en una MCU de 8 bits

6

Dado que una MCU de 8 bits no puede leer el temporizador completo de 16 bits en un ciclo, esto crea una condición de carrera en la que la palabra baja puede pasar entre las lecturas. ¿Tiene la comunidad un método preferido para evitar estas condiciones de raza? Actualmente estoy considerando detener el temporizador durante las lecturas, pero me gustaría saber si hay una solución más elegante.

Para su información, esto es para un PIC16F690 .

    
pregunta ajs410

4 respuestas

9

Windell tiene razón, si está hablando de PIC, la hoja de datos (y el hardware) ya lo manejan por usted.

Si no estás usando un PIC, el método general que utilizo es hacer esto:

byte hi, lo;
word timer_value;

do {
    hi = TIMER_HI;
    lo = TIMER_LO;
} while(hi != TIMER_HI);

timer_value = (hi << 8) | lo;

Lo que esto hace es leer el byte superior seguido del byte inferior, y continuar haciéndolo hasta que el byte alto no cambie. Esto maneja fácilmente el caso donde el byte bajo del valor de 16 bits se desborda entre lecturas. Se supone, por supuesto, que no hay efectos secundarios al leer el registro TIMER_HI varias veces. Si su microprocesador en particular no lo permite, es hora de tirarlo y usar uno que no sea tan inteligente. :-)

Este método TAMBIÉN asume que su temporizador no está cambiando tan rápidamente que corre el riesgo de desbordar los 8 bits bajos dentro de un ciclo de recuperación de procesador o dos. Si está ejecutando un temporizador tan rápido (o un microprocesador tan lento), es hora de repensar su implementación.

    
respondido por el akohlsmith
10

Revise su hoja de datos! Habrá hablar de esto, en detalle sangriento, para tu chip en particular.

No estoy seguro de que esto sea cierto para todos los registros de contador / temporizador de 16 bits en todos los PIC (¡tal vez alguien más pueda responder eso!) pero al menos para el PIC 18F que uso, la hoja de datos habla específicamente de cómo esto se maneja

Cuando lee el byte bajo, almacena el byte alto en un registro temporal para el byte alto, de modo que cuando lea el byte alto a continuación, le brinde una instantánea completa del valor del temporizador.

El mismo proceso básico se usa en AVR (y, por supuesto, en Arduino), y para la mayoría de los casos en los que necesita leer o escribir registros de dos bytes a la vez en MCU de 8 bits.

    
respondido por el Windell Oskay
3

El texto al que hizo referencia en su comentario (Sección 6.5.1) se refiere a la operación del temporizador asíncrono, donde el temporizador se sincroniza desde una fuente externa al microcontrolador.

El descargo de responsabilidad sugiere iniciar y detener el temporizador porque el método general de Andrew (en realidad, cualquier método) no funcionará porque puede haber muchas marcas (más de 256, incluso) del reloj externo y, por lo tanto, el temporizador en un solo ciclo del procesador. Supongo que no se está ejecutando con este caso de borde.

Si, en cambio, estás usando el oscilador interno como referencia, estarás bien. Incluso con un valor anterior a 1, tiene hasta 255 ciclos después de leer el byte alto para leer el byte bajo. Esto debería ser una operación de 2 ciclos. Aún necesita el bucle hacer / mientras que su byte alto cambia (¿Cuál es la diferencia entre 'hi' y 'TIMER_HI' si el valor de 'lo' es 0?) Entre estos tiempos. Con una precalificación de 2 o más, no necesita más esta prueba. Es solo con precalentadores mucho menos que 1 que comienza a convertirse en un problema, y esto es imposible sin el reloj externo.

    
respondido por el Kevin Vermeer
1

Hay un ejemplo en el Manual de referencia de la familia de MCU de rango medio PIC para lectura y Escribiendo Timer1 en modo de contador asíncrono.

Ejemplo: leer un temporizador de ejecución libre de 16 bits

; All interrupts are disabled
MOVF TMR1H, W ; Read high byte
MOVWF TMPH ;
MOVF TMR1L, W ; Read low byte
MOVWF TMPL ;
MOVF TMR1H, W ; Read high byte
SUBWF TMPH, W ; Sub 1st read with 2nd read
BTFSC STATUS,Z ; Is result = 0
GOTO CONTINUE ; Good 16-bit read
;
; TMR1L may have rolled over between the read of the high and low bytes.
; Reading the high and low bytes now will read a good value.
;
MOVF TMR1H, W ; Read high byte
MOVWF TMPH ;
MOVF TMR1L, W ; Read low byte
MOVWF TMPL ;
; Re-enable the Interrupt (if required)
CONTINUE ; Continue with your code
    
respondido por el Daniel Grillo

Lea otras preguntas en las etiquetas