miércoles, 25 de enero de 2017

Introducción a los Timers de AVR

La mayoría de los microcontroladores cuentan con Timers. Un timers (en AVR) es un simple registro con una resolución de 8 bits a 16 bits dependiendo del Timer. En el Atmega2560 existen 2 Timers de 8 bits y 4 de 16 bits. En este post vamos a trabajar con el Timer más simple, el Timer0. 

El Timer0 es un registro contador, que incrementa o decrementa su valor automáticamente en un tiempo (rate) determinado (esto lo vamos a setear). Lo interesente es que la operación del Timer no ncesita de la intervención de la CPU, es decir que hay un HW dedicado a esto. 

Como los Timer trabajan independiemente de la CPU, puede ser utilizado para medir el tiempo. Cuando el contador del Timer llega a un cierto valor (es decir, se cumple una condición), este le puede avisar automáticamente a la CPU, a través de una interrupción; o puede tomar una derminada acción. Lo más sencillo que puede ocurrir es que el contador produzca un overflow. Esta situación se da cuando el contador llega a 255, cuando quiere saltar al próximo valor produce una interrupción (overflow) y se vuelve a setear en 0. Nosotros como programadores deberíamos escribir una Rutina de Servicio de Interrupción (en ingles, ISR -> Interruption Service Routine) para manejar el desborde (interrupción).

Diagrama de bloque del Timer

Clock

Para que funcione el contador, necesita de un reloj (clock). Este clock genera un señal, que producen que el Timer0 incremente/decremente su valor. Este clock puede ser:

  1. El clock interno, que como máximo se puede generar 16Mhz
  2. Algún clock externo.
  3. Un prescaled clock
El prescaler clock es un mecanismo para generar una señal utilizando el clock de la CPU. Lo que se hace es dividir la frecuencia del clock de la CPU y producir una señal para el Timer. 

Registros del TIMER0

Existen varios registros que son utilizados por el Timer0. El Timer/Counter (TCNT0) y el Output Compare Register (OCR0A y OCR0B) son registros de 8 bits. Las interrupciones son visibles en el Timer Interrupt Flag Register (TIFR0). Las interrupciones son enmascaradas con el Timer Interrupt Mask Register (TIMSK0). Los registros OCR0A y OCR0B están comparando en todo momento el valor del contador TCNT0. El resultado de la comparación puede ser usado por el Waveform Generator, registro que es utilizado para generar PWM. Los Timer/Counter Control Register 0 (TCCR0A y TCCR0B) son utilizados para configurar el contador. 

TCCR0A

Este registro se utilizan para configurar el contador.


Bits 7:6 – COM0A1:0: Compare Match Output A Mode
Estos bits son utilizados para configurar el comportamiento del Pin de Comparación de Salida  A (OC0A),




Bits 5:4 – COM0B1:0: Compare Match Output B Mode

Similar a lo anterior pero afecta al OC0B.



Bits 1:0 – WGM01:0: Waveform Generation Mode

Para mayor información sobre este modo sería bueno mirar este post.


TCCR0B

Este registro también se utiliza para configurar el contador. 



Bits 2:0 – CS02:0: Clock Select
Estos bits son utilizados para elegir la fuente del clock.

TCNT0 - Timer/Counter Register

Es el registro que lleva el contador.

OCR0A - Output Compare Register A

Este registro contiene un valor de 8 bits que continuamente es comparado con el TCNT0. En caso que los valores coincidan se produce una interrupción. 

OCR0B- Output Compare Register B

Similar al OCR0A.

TIMSK0 – Timer/Counter Interrupt Mask Register

Este registro es para activar las interrupciones. Si el bit 0 está activo signifca que está permitido las interrupciones de overflow. Si el bit 1 está activo, significa que cuando se compare el valor del OCR0A y TCNT0, y sean iguales, entonces se disparará una interrupción. Igualmente si está en 1 el bit 3, ocurre lo mismo pero con el OCR0B.

Código de ejemplo


domingo, 22 de enero de 2017

PWM avr III: Generación de señal pwm con AVR - práctica.

En este tutorial les voy a mostrar como generar una señal PWM en AVR. Antes sería bueno que lean mis post anteriores sobre PWM:

  1. Introducción a PWM
  2. PWM avr II - Generación de señal pwm con AVR
En este tutorial vamos a trabajar con el TIMER0. Lo primero que haremos será setean el TIMER0 en modo fast PWM. Para ello se debe configurar el Timer Counter Control Register 0 (TCCR0). En el atmega2560, este registro se encuentra dividido en dos registros TCCR0A y TCCR0B (8 bits cada uno).  Los registros se pueden ver a continuación.



COM - Compare Match Output

Este bit controla el comportamiento del pin Output Compare (OC0A). Si ambos pin son seteados a 1, el pin OC0A tiene el comportamiento normal. Cuando el pin OC0A está conectado al pin, la función del bin COM0A1:0 dependenderá del valor de los bits WGM02:0


En este ejemplo pondremos el valor del COM0A1 en 0 y el COM0A0 en 0.

WGM - Waveform Generation Mode

Según el datasheet para configurar el TIMER0 en modo fast pwm se deben colocar los bits WGM00 y WGM01 en 1. Estos bits (mas el WGM02 del TCCR0B) controlan la secuencia de conteo del contador, el valor máximo del contador, y la forma de la señal que se genera. 



CS - Clock Select

Este bit que se encuentra en el TCCR0B se utiliza para seleccionar un clock de entrada para el TIMER. Seteamos en 1 al CS0. 

Programa de ejemplo

Para ver lo que hace este código, habría que conectar un led en el PB7 (digital pin 13 del Arduino Mega) y se vería que prende y apaga, haciendo variar el brillo de la luz. 

martes, 10 de enero de 2017

PWM avr II - Generación de señal pwm con AVR

En el post anterior se vió una introducción sobre PWM, cómo un dispositivo digital podría generar una señal analógica, mediante la técnica de modulación de ancho de pulso de sus salidas "especiales". El ATmega2560 de AVR tiene algunas salidas con esas capacidades.

Antes de continuar sería interesate que se lean el siguiente artículo
Introducción a PWM

La generación de una señal PWM se lleva a cabo através de Hardware dedicado. Tener HW dedicado para realizar este tipo de trabajo, disminuye la sobrecarga desde el lado del software y CPU. Una vez que la CPU indica que se tiene que producir una salida determinada, el HW dedicado envía la señal hacia los pines de salida, mientras que la CPU se dedica a otra cosa.

En AVR las señales PWM se generan a través de Timers. En esteejemplo utilizaré el TIMER0 del Atmega2560 para generar pwm (Esto también puede ser utilizado en el ATmega16 y ATmega32).

En primer lugar, se tiene un contador de 8 bits, es decir que va desde 0 a 255. Se puede apreciar en la figura la representación gráfica del contador.


El periodo del contador depende del prescalar que se elija en la configuración del TIMER. Existe un registro que vamos a utilizar que se denomina OCR0 (Output Compare Register Zero, cero porque depende del TIMER0, vamos a tener un OCR1, OCR2, etc... dependiendo del TIMER). OCR0 es un número cualquiera (que seteamos) entre 0 y 255. Por ejemplo tomemos el número 30. Esto lo vemos en la figura como una línea recta roja horizontal.


¿Para qué sirve el OCR? Cuando se encuentra configurado el modo "fast PWM", mientras el valor del TCNT0 del TIMER0 se encuentra por encima del valor del OCR0, el pin de salida OC0 es puesto en cero. En cambio, cuando el contador (TCNT0) se encuentra entre cero y el valor de OCR0, el PIN OC0 es puesto en HIGH.

Con esto podemos calcular el ciclo de trabajo 30/256 = 11.7%. Entonces se puede setear el valor de OCR0 y con esto calcular el PWM del ciclo de trabajo  de OCR0/256. Nótese que un OCR0 = 0 es un ciclo de trabajo de 0% y un OCR0 = 255, es un ciclo de trabajo del 100%, es decir 5V.

En la siguiente imagen se puede observar mejor lo que se trató de eplicar anteriormente.

Fuente: http://extremeelectronics.co.in/avr-tutorials/pwm-signal-generation-by-using-avr-timers/

Con esta introducción a la Generación de señal PWM, ya podemos pasar a la práctica, que lo haremos en el siguiente post.

domingo, 8 de enero de 2017

PWM avr I - Introducción

En un dispositivo digital, como lo es un microcontrolador  (MCU), todas las entradas y salidas tiene solo dos estados, prendido o apagado (0 ó 1). Por lo tanto se pueden hacer facilmente aplicaciones para prender y apagar un LED, prender y apagar algún otro dispositivo, transmitir 0 y/o 1. Pero estas aplicaciones no son las únicas que se pueden realizar, en algunos casos necesitaremos controlar el brillo de una lampara (o LED), hacer girar un motor, etc. Para estos ejemplos, con prender y apagar algo no es suficiente, se necesitan aplicar otra técnica y esta es llamada  PWM  o Modulación de Ancho de Pulso (Pulse Width Modulation).

Esta técnica es utilizada para generar señales analógicas mediante la utilización de un dispositivo digital ( como el MCU). En esta entrada les voy a explicar funciona el PWM, en un Atmega2560 (Arduino Mega).

En esta entrada voy a utilizar un Arduino Mega 2560, pero no utilizaré el lenguaje Arduino, sino que utilizaré el entorno eclipse, y programaré directamente en lenguaje C. Material interesante es el datasheet de avr.

PWM - Modulación de Ancho de Pulso

La mayoría de los dispositivos digitales generan dos tipos de salidas. Encendido ó HIGH que son 5 V, y apagado ó LOW que es representado con 0 V. Pero, ¿qué sucede si quisiéramos generar una salida de 2V o 3.2V? La solución es la utilización de la técnica de PWM. 

Normalmente, la señal de salida de un MCU tiene una forma cuadrada, que tiene algunas características a notar:
  • La señal se encuentra en un intervalo de tiempo en HIGH. (Ton)
  • La señal se encuentra en un intervalo de tiempo en LOW.  (Toff)
  • Cuando la señal se encuentra en HIGH la salida es de 5V.
  • Cuando la señal se encuentra en LOW la salida es de 0V.

Figura 1: Señal cuadrada de la salida normal de un MCU

Duty Cycle (ciclo de trabajo)

El ciclo de trabajo se define con la siguiente fórmula:

(Ton/Ttotal) * 100 = Duty Cycle

Esto es el porcentaje del tiempo que la señal se encuentra en HIGH. Como se puede observar en la Figura 1 el Ton = Toff  = Mitad del tiempo del periodo. Si la frecuencia de la salida (5V) es alta, entonces se obtendría  2.5V.

Por ejemplo si se quiere generar 1V como salida, se tendría que hacer un simple despeje de fórmulas y una regla de 3 simple,  se obtendría el ciclo de trabajo necesario para generar 1 Volt.

Si 5V -> 100% of Vcc
    1V -> x = 20%

Entonces el ciclo de trabajo es 20%.

Haciendo

(20/100)*1 = 0.2 -> Ton.

Otro ejemplo,  si se tiene un Duty cycle de 75% se tiene un 75% del Vcc de salida, es decir 3.75V.

En próximas entradas mostraré como generar una señal PWM con un AVR.