El temporizador de ATtiny13A parece ser muy impreciso, ¿es normal? [cerrado]

Escribí este programa de parpadeo para mi ATtiny13A e intenté medir la precisión con un Arduino Uno, pero el temporizador parece ser bastante inexacto. En el ATtiny estoy corriendo en el internal 128KHzreloj y usando temporizadores para hacer pin0alto y bajo a una frecuencia de 1Hz.

Aquí está el código ATtiny:

int main(void){

  DDRB = 0;
  TCCR0A = 0;
  PORTB = 0;

  DDRB |= (1 << DDB0);      // pin0 output

  TCCR0A |= (1 << WGM01);   //CTC mode
  TCCR0A |= (1 << COM0A0);  //toggle OC0A on compare match

  TCCR0B |= (1 << CS02) | (1 << CS00); //1024 prescalar
  OCR0A = 124;              //1Hz @ 128KHz internal clock

  while(1){ 
  }

  return 0;
}

En Arduino, estoy usando interrupciones para medir el tiempo entre cada señal alta/baja. Es un Uno estándar con un cristal externo de 16Mhz. Aquí está el código de Arduino:

unsigned long lastHigh = 0;

void setup() {
  Serial.begin(9600);
  const byte interruptPin = 2;
  attachInterrupt(digitalPinToInterrupt(interruptPin), myISR, CHANGE);
}

void loop() {
}

void myISR(){
  unsigned long temp = micros();    //store it ASAP to minimize delay
  Serial.println(temp - lastHigh);
  lastHigh = temp;
}

He conectado pin 2el Arduino a tierra con una resistencia de 1K y lo he conectado pin 0al ATtiny13A.

Esperaba leer unos 1 perfectos entre cada parpadeo, pero aquí están mis lecturas (en microsegundos):

1063616 1062696 1063608 1062696 1063636 1062692 1063608 1062680 1063576 1062580 1063512 1062676 1063576 1062660 1063584 1062680 1063580 1062672 1063596 1062700 1063596 1062688 1063604 1062680 1063596 1062612 1063528 1062668 1063580 1062680 1063588 1062684

Como puede ver, el temporizador no solo está apagado en aproximadamente 60 milisegundos, sino que también se mueve mucho.

Leí en Internet que el reloj interno es inexacto, pero no estoy seguro de si ~ 60 ms es demasiado inexacto o no.

Además de estar apagado, los tiempos también son muy nerviosos. Van desde un mínimo de 106 2 580 hasta un máximo de 106 3 680 microsegundos.

Soy bastante inexperto y tengo mucha curiosidad si este nivel de imprecisión se considera normal o no. Lo encontré extraño porque los nervios de 1000us hacen que las funciones micros()o _delay_us()sean bastante inútiles.

Tal vez su salida de depuración cause esa inestabilidad. Serial.println() implica otro ISR, que realiza la comunicación en serie. Almacene el valor de diferencia calculado en algún lugar y realice la comunicación en serie en el bucle principal. De esa manera, puede perder algunos puntos de datos, pero la medición en sí no se ve afectada por la comunicación en serie.

Respuestas (2)

Entonces, está viendo una desviación de aproximadamente +6% y una fluctuación de ±0.05%.

la devacion

No pude encontrar nada en el oscilador interno de 128 kHz, pero el oscilador interno de 4,8/9,6 MHz tiene una precisión predeterminada de ±10 % a un voltaje y una temperatura específicos. Consulte la sección 18.4.1 (página 119) de la hoja de datos :

Tabla con información de calibración del oscilador

Sospecho que el oscilador de 128 kHz es similar, por lo que sospecho que +6% está dentro de las especificaciones para mí. Puede calibrar el oscilador interno para obtener una mayor precisión, consulte la nota de aplicación de Atmel AVR053: Calibración interna del oscilador RC para dispositivos tinyAVR y megaAVR .

También debe mirar la forma en que está usando el temporizador; No tiene un controlador de interrupción definido, por lo que creo que está provocando un reinicio suave del pequeño cuando expira el temporizador. Esto significa que cualquier código de inicialización avr-glibc se vuelve a ejecutar, al igual que su código de configuración del temporizador. Esto tomará algunos ciclos y aumentará su tiempo de ciclo, causando una desviación positiva.

Intente configurar un ISR que parpadee y vea si eso hace la diferencia. O incluso pruebe un bucle de retardo calibrado en lugar del temporizador.

El nerviosismo.

En cuanto al jitter, ±0.05% me parece bastante. Pero para ser honesto, no estoy seguro de qué tan estables son esos osciladores RC.

Un sospechoso importante es su println()transmisión en serie. println()tiene que hacer bastante trabajo para convertir su número a base 10, y la cantidad exacta de trabajo depende del número que se imprima. Además, la transmisión en serie debe sincronizarse con su computadora y esto puede causar demoras que son semialeatorias para su Arduino.

Intente almacenar aproximadamente 20 mediciones en la memoria y úselas solo Serial.println()después de que todas las mediciones hayan finalizado.

Además, no estoy del todo seguro de qué tan preciso es Arduino micros(). Tal vez hay un problema de precisión allí. Si tiene acceso a un osciloscopio, puede usarlo para medir la frecuencia de salida del diminuto, eliminando el Arduino como una posible fuente de errores.

¡Actualizar! ¿El consumo de energía del LED influye en el oscilador RC?

¡Ajá, noté un patrón en tu nerviosismo! Estás midiendo 106 3 6xx y 106 2 6xx de forma alterna. Entonces, la mayor parte de su fluctuación es una variación de 1 ms entre ciclos pares e impares.

Sospecho que esto puede deberse a que está encendiendo un LED, que consume corriente, lo que afecta la resonancia en el tanque RC utilizado para el oscilador interno. Eso puede ser interesante.

¿Puede intentar repetir su medición original dos veces más, una vez sin el LED y otra vez con él?

Si quitar el LED hace que el problema desaparezca, es posible que desee usar mucho desacoplamiento en el diminuto y evitar que el diminuto disco se cargue directamente, pero siempre almacene las salidas con transistores. Si la precisión del reloj es lo suficientemente importante para la situación, de todos modos.

Gracias @marcelm. He intentado definir un ISR pero he tenido el mismo resultado. Publiqué este ejemplo porque tenía la menor cantidad de código. Con respecto al println()problema, el Arduino funciona a 16 MHz y tiene 1 segundo entre cada parpadeo del ATtiny. println()¿Seguirá siendo relevante el tiempo requerido para ?
@PouriaP Asegúrese de verificar la actualización de mi respuesta (la tercera sección), podría haber encontrado el problema;)
@PouriaP Imprimir un número implica convertirlo a base 10, lo que requiere divisiones repetidas por 10. Dado que los AVR no tienen división de hardware, esto debe hacerse en software, usando muchas instrucciones. Puede ser relevante.
¡Sí! Quité el LED y el jitter bajó a ~100us desde ~1000. Y después de agregar un capacitor entre VCC y GND, bajó más a aproximadamente 50 us (perdón, olvidé agregarlo antes). Aunque todavía hay un patrón como el que notaste, solo que más pequeño. Es inestable también. Por ejemplo, si muevo un poco la placa de prueba, la inestabilidad vuelve a ser mala. ¿Tal vez es extremadamente sensible?

El error del 6% suena razonable para un oscilador en chip no calibrado.

De hecho, las Figuras 19-65 y 19-66 en la página 157 de la hoja de datos indican que la frecuencia del "oscilador Watchdog de 128 kHz" no se acerca a 128 kHz.

Si desea una mayor precisión, debe usar como mínimo el oscilador "calibrado" 4.8/9.6, y tal vez hacer su calibración en cada unidad. Una vez calibrado, se mantendrá dentro del ±2% sobre la temperatura y el voltaje (consulte la Tabla 18-2 en la página 119), y puede hacerlo mucho mejor si puede regular uno o ambos parámetros.