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. 



sábado, 12 de noviembre de 2016

TrumScript: El lenguaje de programación de Donald Trump

Sam Shadwell y Chris Brown participaron en un Hackaton en la Universidad de Rice, bajo el lema "Make Python Great Again", en 20 horas desarrollaron un nuevo lenguaje de programación: TrumpScript. En ese entonces (principio de año) el país ya se estaba dividiendo entre pro y anti Trumps, y estos programadores quisieron dar su mensaje, inventando este lenguaje.

En la página de Sam se describe la misión de TrumpScript:

"TrumpScript es un lenguaje basado en el ilustre Donald Trump..", "... descubrimos que en el campo actual de los lenguajes de programación, no hay ninguno que aprobaría el dorado y glorioso combover de Trump".

Este es un lenguaje que el mismo Donald Trump aprobaría. Debido a que Donald Trump quiere hacer América grande otra vez, este lenguaje pretende hacer a la programación grande otra vez.

Algunas de las características (y de las más divertidas) son las siguientes:

  • No existe punto flotante, solo enteros, América nunca deja las cosas a media hacer.
  • Todos lo números debe ser estrictamente mayores a 1 millón. Las cosas pequeñas son insignificantes para los americanos. 
  • No se permite ningún tipo de importación. Todo el código tiene que ser casero y americano. 
  • En vez de True o False, se utiliza Fact y Lie (Hecho y Mentira).
  • Se pueden utilizar  solo se pueden utilizar como nombre de variables las palabras favoritas de Trump y nombre de políticos actuales.
  • Todo programa debe terminar con America is great.
  • Los mensajes de error son frases hechas por Trump.
  • No es compatible con Windows, ya que Trump no es una clase de tipo que confiaría en una PC. 
  • Es insensible a mayúsculas o minúsculas.
  • Si se corre el programa desde una computadora en China o Mexico, no se compilará. Prefieren que no roben los secretos tecnológicos de América.
  • No funciona en modo root, ya que América no necesita ayuda ya que es grande. Trump es todo lo que ellos necesitan.

 Instalación

Para instalar se debe descargar el zip desde github haciendo:

git clone  https://github.com/samshadwell/TrumpScript.git

Se debe agregar al PATH del sistema haciendo:








Temporalmente: export PATH=$PATH:/path/to/

TrumpScript/bin to terminal.
Permanentemente:  export PATH=$PATH:/path/to/TrumpScript/bin al final de tu ~/.bashrc file.



 Fuente del lenguaje: https://github.com/samshadwell/TrumpScript





martes, 25 de octubre de 2016

Semáforos vs Mutex - FreeRTOS

El semáforo sirve para sincronizar tareas. Es una simple Queue, de extensión 1. Puede estar vacía o llena. La tarea va a tratar de leer el semáforo y lo verá vacio, entonces se bloquea. Cuando llega la interrupción, esta da ('give') el token al semáforo, es decir llena la queue. Entonces ahora la tarea que estaba bloqueada ya puede venir a tomar ('take')​ el token del semáforo. Realiza su tareas. Al finalizar, vuelve a leer el semáforo, al no tener nada se bloquea.

En el semáforo, la tarea no devuelve el token, es decir que no vuelve a rellenar la queue (el semáforo)
Para aquellos que recién comienzan con el desarrollo en freeRTOS, y en particular a aquellos que nos gusta leer la teoría, antes de ir a la programación, se puede dar una pequeña confusión entre Mutex y Semáforos, ya que aparentemente utilizan el mismo medio: Una cola de lenght 1.

La Mutual Exclusion, es una Técnica, que permite que no exista una inconsistencia en la utilización de recursos compartidos. Y se pueden utilizar varias estrategias para asegurar la Mutual Exclusion.
  1. Entrando en secciones críticas. 
  2. Suspendiendo el scheduler. A mi parecer es lo mismo que el anterior. 
  3. Utilizando Mutex.
Mutex es implementado a través de una especie de semáforo (Queue de extensión 1 que puede estar vacia o llena). La diferencia radica en que las tareas que utilizan un recursos compartido, primero van a mirar el mutex, si está "lleno" toman el token (y dejan el semáforo vacio). Si otra tarea quiere tocar el recurso, verá que el mutex está vacio, por lo tanto se bloquea.

Aqui va la diferencia primordial: para el caso del MUTEX, se tiene que devolver el token. Es decir, esta especie de "semáforo", se vuelve a llenar.

lunes, 24 de octubre de 2016

ARGENTOS, Nuevo lenguaje esotérico bien argento

Introducción

Argentos nació como producto del concurso CALESYTA 2016 (Concurso Argentino de Lenguajes Esotéricos y Tarpits). En un principio iba a ser un lenguaje más “clásico”, pero me aburrí de lo mismo.

Así fue que en una tarde, mientras desarrollaba unas de mis partidas de ajedrez más importante… bueno no, iba en el bondi, y en una de esas epifanías que tienen los que hacen programación, me surgió la idea de hacer una tablero de ajedrez, y tratar de programar con el movimiento de una de las piezas. Me pareció interesante hacerlo con el caballo… hacer… el lenguaje.

Características principales

  • El control de todo el programa se realiza moviendo una pieza del ajedrez: el caballo.
  • Existen tres campos de movimiento, basados en el tablero de ajedrez: el principal, el de variables y el de caracteres.
  • Las coordenadas de los campos (8x8) son 'A’, ‘R’, ‘G’, ‘E’, ‘N’, ‘T’, ‘O’, ‘S’.
  • Las variables se almacenan en el campo de variables (matriz 8x8), solo se pueden almacenar 64 variables.
  • Las variables son de 1 Bytes.
  • Para asignar valores a las variables, se debe utilizar el campo de caracteres. 
  • Los únicos flujos de control son: condicional y repetitivo.

 Fundamentos

Para lograr cumplir con lo esperado de un lenguaje, como control de flujo, almacenar variables, realizar operaciones; fue necesario crear varios campos o tableros de ajedrez.

Para ello  ARGENTOS proporciona un campo de movimiento, que llevaría el flujo principal del programa, y donde se encuentran los códigos principales de control (salto de linear, retorno de carro, espacio, +, -, <, >, =, etc).

Para hacerlo más interesante, la libertard del programador tendría ciertas limitaciones, lo que representa un divertido desafío.

En primer lugar todos los datos que se ingresan en un programa (caracteres, numeros) ya son previstos por ARGENTOS. Para almacenar datos en memoria, también tiene sus limitaciones. Los datos se almacenan en un tablero 8x8 y es necesario recordar la posición en la que esa variable fue almacenada.

 El campo donde se encuentran los caracteres se llama campo de caracteres y el campo donde se almacenan las variables se llama campo de variables.

Campo de movimiento

Argentos es un lenguaje basado en el movimiento del caballo del ajedrez. Se debe imaginar un tablero 8x8, cuyas coordenadas son las letras ‘A’, ‘R’, ‘G’, ‘E’, ‘N’, ‘T’, ‘O’, ‘S’. A continuación se muestra la representación:




Las coordenadas de cada casillero se nombra FILA x COLUMNA. Es decir, el primer casillero (el (0,0)) tiene la coordenada [A,A].

El caballo inicia desde la posición normal del caballo izquierdo, en la posición SR.




El caballo se debe mover respetando el movimiento del ajedrez (en L) .

Rellenando el campo de movimiento


Todos los casilleros se rellenan siguiendo el código ASCII.

Desde el casillero [A,A] hasta el casillo [N,T] está formado por los símbolos de control, incluyendo los operadores matemáticos y lógicos. El mapeo se muestra en la siguiente figura.


 

Campo de caracteres


El campo de caracteres es utilizado para cuando se necesita imprimir por pantalla una cadena de caracteres, o bien almacenar en memoria una cadena. También en esta tabla se encuentran los números.

La idea es la misma, un tablero 8x8, el caballo comienza en la coordenada [S,R].



Para ingresar al campo de caracteres se debe llevar al caballo a la posición [T,A].

Primer Programa

ARCHIVO

El archivo fuente escrito en argentos, debe tener la extensión .argentos.


Ejemplo:
holamundo.argentos

 

ARGENTOS

Todo programa debe empezar y terminar con el comando ARGENTOS.

ARGENTOS

% Tu código aquí

ARGENTOS

Una vez colocado el comando inicial, y antes de cualquier sentencia, se debe mover el caballo hacia cualquier posición, es decir abrir el juego. Para finalizar el script, antes del comando final ARGENTOS, se debe volver al caballo a la posición inicial.

Comandos reservados

Todos los comandos se forman con la combinación de los siguientes caracteres: ‘A’, ‘R’, ‘G’, ‘E’, ‘N’, ‘T’, ‘O’, ‘S’. A continuación se listan los comandos reservados:


argentos Comando para iniciar y finalizar el script
argento Comando para mover el caballo. Comando (espacio) coordenada. Ej: argento tg
ss Comando para ingresar a los campos (de variables, caracteres, etc.).
oo Comando para salir de los campos (de variable, caracteres, etc.).
aaa Con este comando se aceptan las sentencias, coordenadas
ge Print. Se empieza y terminar con el comando ge. Ej “ge ‘algo para print’ ge” → algo para print
rr Se indica que se va a almacenar una variable, en la posición actual del puntero.
nn Se indica que se va a leer una variable de posición actual del puntero.
tt Aumenta el puntero del campo de variables
gg Diminuye el punter del campo de variables
arg Asigna valor a variable (=)
ent Extrae variable

Comentarios

Los comentarios empiezan con %.


% Esto es un comentarios

%Estas son dos líneas

% de comentario

Hola Mundo

A continuación se muestra el clásico “Hola Mundo”

ARGENTOS

argento tg

ge

argento ER argento TA aaa %ingreso al campo de variables

argento OG argento NR aaa % 'h'

argento OG argento TA aaa % 'o'

argento NG argento TN argento OO argento NT aaa  % 'l'

argento TE argento EG aaa %'a'

oo% 'salgo del campo de caracteres'

argento NA aaa % 'espacio'

argento TG argento ER argento TA aaa % Ingreso al campo de caracteres

argento OG argento TN argento NO aaa % 'm'

argento TN argento ET argento TO aaa  % 'u'

argento ET argento NS aaa % 'n'

argento ET aaa % 'd'

argento NE argento OG argento TA aaa %'o'

ge %imprimo


ARGENTOS


Salida:

hola mundo


Campo variables


ARGENTOS brinda una pila 64 Bytes para el almacén de variables. Todas las variables se almacenan dentro de esta pila. No se puede definir variables. Para acceder a esas variables es neceario la utilización de un puntero:

rr Se indica que se va a almacenar una variable, en la posición actual del puntero.
nn Se indica que se va a leer una variable de posición actual del puntero.
tt Aumenta el puntero del campo de variables
gg Diminuye el punter del campo de variables


Es importante recordar a qué posición apunta el puntero de variables. AL comenzar el puntero apunta a la posición 0. Se utiliza el comando rr para indicar que se va a almacenar una variable

En el ejemplo siguiente se muestra como almacenar dos variables en el campo de variables:

%…
nn argento OE argento NN argento argento OT aaa %Se almancena el 1 en la posición 0
tt %Se aumenta el puntero del campo de variables
nn argento SE aaa % Se almacena el 7 en la posición 1 del campo de variables
tt

%…

Flujo selectivo


El lenguaje ARGENTOS permite llevar a cabo un control selectivo. Esto es similar al IF en los demás lenguajes clásicos (como C/C++, Python, etc).

Para empezar un flujo selectivo se debe mover la pieza dos veces, seguidos de tres caracteres, operador de la izquierda, operando y el operador de la derecha. Para salir del flujo selectivo se debe volver a la posición de inicio del flujo.

En pseudo-lenguaje sería de la siguiente manera:

Mover una posición de la pieza

Mover una posición de la pieza

Aceptar la secuencia con ‘aaa’

Ingresar al campo de variables o campo de caracteres

Ingresar el primer operador y aceptar con ‘aaa’

Salir del campo y buscar dentro del campo principal el operando que corresponda. Aceptar con ‘aaa’

Ingresar al campo de variables o campo de caracteres

Ingrear el segundo operador y aceptar con ‘aaa’

Aceptar todo el flujo con ‘aaa’

Escribir el código que corresponda

Mover la pieza del caballo al punto inicial del flujo.

Aceptar la secuencia con ‘aaa’

 

 Flujo repetitivo

El flujo repetitivo es similar al flujo selectivo. Para ingresar a este se debe mover tres posiciones de la pieza. Luego ingresar la cantidad de veces a repetir. Para finalizar el flujo se debe volver al punto de inicio del mismo.

En pseudo-lenguaje sería de la siguiente manera:

Mover una posición de la pieza

Mover una posición de la pieza

Mover una posición de la pieza

Aceptar la secuencia con ‘aaa’

Ingresar al campo de variables o campo de caracteres

Llegar hasta el valor deseado (tiene que ser un número necesariamente) aceptar el valor con ‘aaa’

Aceptar todo el flujo con ‘aaa’

Escribir el código que corresponda

Mover la pieza del caballo al punto inicial del flujo y finalizar el flujo con ‘aaa’.


Conclusión 

Hasta ahora está un poco (¿?) inmaduro pero va tomando forma, en estos días estaré actualizando el post, de manera  de ir completandolo. El compilador, ese es el problema.