domingo, 22 de diciembre de 2013

Hercules Launchpad #4 - Interrupciones (Interrupts) Parte 2

En la parte 1 de esta entrada vimos cómo el procesador puede reaccionar a las interrupciones generadas por cambios en el estado de un bit (el bit del push button). Ahora veremos cómo el procesador puede reaccionar a las interrupciones generadas por el HET (High End Timer) y por el módulo RTI (Real Time Interrupt). Este último módulo está especialmente diseñado para medir cuentas de tiempo.
En este ejemplo vamos a hacer que se prendan los dos LEDs que tiene la tarjeta, pero con diferente frecuencia. Uno de los LEDs va a ser el resultado de las interrupciones del HET y el otro del RTI.

Paso 1:
Abrimos y configuramos HALcoGen de la siguiente manera. Primero en la pestaña de Driver Enable habilitamos los drivers RTI, GIO y HET.

Luego nos vamos a la pestaña de RTI y en la subpestaña que dice "RTI1 Compare" configuramos el comparador 0 para que mande una interrupción cada 200ms, por ejemplo.


Nota 1: El RTI puede interrumpir por desbordamiento o por comparación. Es decir, puede interrumpir cuando el contador llega a su límite y debe comenzar desde cero o cuando la cuenta es igual a la constante que definimos para comparar.

Ya que tenemos eso, nos vamos a configurar el HET. Configuramos el PWM0 para que tenga un período de 1 segundo con un ancho de pulso del 80% para que se vean bien los cambios.


Luego en la subpestaña que dice "Pwm Interrupts" habilitamos las interrupciones que dicen "End of duty" y "End of period" en High Level. Habilitamos las dos para que el LED se encienda cuando termina el ciclo de trabajo (la parte alta) y se apague el resto del periodo.


Nota 2: El HET tiene 3 modos de interrupción: cuando acaba el ciclo de trabajo, cuando acaba el periodo o cuando detecta un flanco (de subida o bajada) en alguno de los pines si es que estos están configurados como entradas.

Ahora habilitamos el LED (Bit 8) en la subpestaña que dice "Pins 8-15" para que sea una salida.


Luego en la pestaña que dice "GIO" configuramos el bit 2 (el que está conectado al otro LED) como salida.


Por último en la subpestaña que dice "VIM Channel 0-31" dentro de la pestaña principal (RM42L432PZ) habilitamos el canal 2 (RTI Compare 0) y el canal 10 (HET Level 0).


Estas han sido todas las configuraciones necesarias de HALcoGen. Ya podemos generar los archivos (F5).

Paso 2:
Ahora comencemos con el código. Dentro de Code Composer Studio creamos nuestro nuevo proyecto igual como le hemos estado haciendo (Paso 5 Paso 6 del primer tutorial). Luego, en el archivo "sys_main.c" escribimos lo siguiente.
Paso 2.1 (includes):
Los archivos que hay que incluir son los siguientes






Paso 2.2 (main()):
En el main hay que inicializar los módulos y las interrupciones (ya que no parece haber manera de que se inicializen desde el principio usando HALcoGen). También hay que hacer que el contador 0 del módulo RTI comience a contar.















Paso 2.3 (control de interrupciones):
Luego hay que irnos al archivo "notifications.c" para ver qué hacemos con las interrupciones. Dentro del control de interrupciones del RTI escribimos lo siguiente












Nota 3: En este pedazo de código pueden ver cómo las funciones del GIO pueden controlar los pines del módulo HET.

Dado que no tenemos ninguna otra fuente de interrupciones del RTI, no hay que ponerle ningún if para ver de dónde vienen las interrupciones. Lo mismo sucede con el control de interrupciones del HET (pwmNotification).










Y pues ya con esto tenemos todo el código que necesitamos. Si lo corremos en la tarjeta, podemos ver que los dos LED prenden y apagan a velocidades distintas, pero sincronizadas. Llega un punto donde los dos LEDs encienden y apagan al mismo tiempo, ya que 200ms es múltiplo de 1 seg y el 80% de 1 segundo son 200ms!!!

Les dejo los archivos.
https://www.mediafire.com/?4i1y1jdm4clt88h

My Github
https://github.com/DiegoRosales

Nota 4: El manual de ayuda de HALcoGen es de gran ayuda. Viene extremadamente bien documentado y trae algunos ejemplos.

lunes, 16 de diciembre de 2013

Hercules Launchpad #3 - Interrupciones (Interrupts) Parte 1

Ahora vamos a rediseñar el programa anterior para que funcione con interrupciones y sea más eficiente. 
El microcontrolador que trae la tarjeta tiene dos prioridades para las interrupciones: prioridad alta (High) y prioridad baja (Low). Como ustedes sabrán (o no), las interrupciones son causadas por eventos fuera del flujo normal del programa (pulsar un botón, por ejemplo). Cuando se genera la interrupción, el programa salta inmediatamente a algo llamado "Interrupt Service Rutine" (rutina de servicio a las interrupciones) o SCR, que es un espacio en la memoria con instrucciones que responden a la interrupción según lo que queramos.
Este microcontrolador posee algo llamado "Vectored Interrupt Manager" y es el módulo que nos ayuda a configurar y reaccionar a las interrupciones. Si nos vamos al manual, podemos ver lo siguiente

Los 96 canales son las fuentes de interrupción y todas se pueden configurar a través de HALcoGen, así que comencemos.

Paso 1:
Abrimos HALcoGen, creamos nuestro proyecto y habilitamos únicamente el GIO Driver. Luego nos vamos a la pestaña de GIO y habilitamos la salida del bit 2 (LED) y en el bit 7 habilitamos la interrupción con flanco de subida (Rising Edge) y baja prioridad (Low Priority)


Paso 2:
Ahora hay que configurar el VIM. Para esto nos vamos a la pestaña del microcontrolador (RM42L432PZ) y nos vamos a la subpestaña que dice "VIM Channel 0 - 31". Ahí mismo nos vamos al número 23 que dice "GIO Int B".

Nota: "GIO Int B" se usa para las interrupciones de baja prioridad (Low Priority), mientras que "GIO Int A" se usa para las interrupciones de alta prioridad (High Priority).

Ya que tenemos configurado todo, generamos el código (F5).

Paso 3:
Ya que generamos los archivos, abrimos Code Composer Studio y creamos un nuevo CCS Project con nuestras especificaciones y lo configuramos para que acepte los archivos de HALcoGen.
Luego abrimos el archivo "notification.c" para configurar lo que queremos que el micro haga cuando genere nuestra interrupción. Como podrán ver, el archivo está casi vacío, por lo que es evidente que está diseñado para que nosotros escribamos nuestro código. Si nos vamos a donde está el comentario 19, podemos observar que éste se encuentra dentro de la función "gioNotification". Si vemos el manual de ayuda de HALcoGen, podemos ver que la función acepta 2 parámetros: el puerto y el número de bit. Por lo tanto, para saber si la interrupción fue generada por el botón, hay que escribir el código siguiente

void gioNotification(gioPORT_t *port, sint32 bit)
{
/*  enter user code between the USER CODE BEGIN and USER CODE END. */
/* USER CODE BEGIN (19) */
// Checa si el botón generó a interrupción
if((port==gioPORTA) && (bit==7))
{
// Enciende y apaga el LED
gioToggleBit(gioPORTA, 2);
}
/* USER CODE END */
}
Paso 4:
Ahora nos vamos al archivo "sys_main.c" e incluimos la librería del GIO.

/* USER CODE BEGIN (0) */
#include "gio.h"

/* USER CODE END */

Y más abajo escribimos

void main(void)
{
/* USER CODE BEGIN (3) */
// Inicializa los módulos
gioInit();
_enable_IRQ();

// Ciclo infinito
while(1);
/* USER CODE END */
}

Noten que en el programa principal sólo hay que inicializar los drivers y crear un ciclo infinito, ya que el VIM se encarga de controlar las interrupciones. Esto hace que el microcontrolador no esté checando constantemente si el botón fue presionado mientras está en el programa principal, sino que lo hace como que en paralelo.

Les dejo el código que hice

http://www.mediafire.com/download/i32fbdbub7vsvv4/Tutorial%203.zip

My Github
https://github.com/DiegoRosales

viernes, 13 de diciembre de 2013

Hercules Launchpad #2 - GPIO (GIO)

Ahora les voy a mostrar lo que he aprendido de los General Propouse Input Output (GIO o GPIO). Esta tarjeta tiene un chorro de pines que pueden ser controlados como queramos, uno de los cuales está conectado a un push-button que podemos usar para lo que queramos. Otro de los pines está conectado a un LED que también podemos ocupar. Genial, no? Les voy a enseñar como usar el push-button para controlar el LED, pero sin usar interrupciones (por ahora).


Paso 1:
Comencemos configurando los archivos usando HALcoGen. Lo primero es seleccionar los drivers que queremos. En este caso será solo el GIO Driver.




Luego hay que habilitar el pin al cual está conectado el LED como salida. Este pin es el GIOA2, como viene marcado en la tarjeta. Esto significa que de los 8 bits que tiene el puerto GIO A, el LED está conectado al bit número 2. El botón está conectado al bit 7 de este puerto.



Al bit 7 no hay que moverle nada ahorita, ya que siempre tienen la entrada habilitada.
Ahora hay que generar los archivos (F5).

Nota: El GIO tiene sus propios puertos, pero eso no significa que se limite a controlar únicamente sus puertos. También puede controlar los puertos del HET y mandar y recibir bits a su voluntad.

Paso 2:
Ya que tenemos los archivos generados, abrimos un nuevo proyecto y lo configuramos como la vez anterior (Paso 5 y Paso 6 del tutorial anterior). Ya que lo tenemos configurado, abrimos el archivo "sys_main.c" y comenzamos a escribir nuestro código.

Paso 2.1:
Hay que incluir las librerías necesarias para acceder a las funciones del GIO. Esta vez sólo utilizaremos "gio.h". El código se verá así


/* USER CODE BEGIN (0) */
#include "gio.h" // Incluimos la librería del GIO
/* USER CODE END */


Paso 2.2:
Ahora hay que escribir el código que reaccione al botón y encienda y apague el LED.
Para que el programa "lea" lo que está haciendo el botón, usamos la función "gioGetBit(gioPORTA, 7)". Les explico cómo funciona. "gioGetBit" es una función que lee un bit de un determinado puerto. En este caso, el puerto es el gioPORTA, que dentro del archivo "reg_gio.h" está declarado como 

#define gioPORTA ((gioPORT_t *)0xFFF7BC34U)

El 7 significa que es el bit número 7.
Para hacer que el bit encienda y apague, habrá que utilizar la instrucción "gioToggleBit(gioPORTA, 2)". Esto es muy parecido a lo anterior. La función "gioToggleBit" hace que si el bit está en "1", lo vuelve "0" y viceversa.
Finalmente el código quedaría

void main(void)
{
/* USER CODE BEGIN (3) */

// Inicializa el driver GIO
gioInit();

// Declaramos la variable para el loop
int i;
while(1)
{
if(gioGetBit(gioPORTA, 7)==1)
{
// Enciende y apaga el LED
gioToggleBit(gioPORTA, 2);

// Se espera un poco para volver
// a encender y apagar el LED
for (i=0; i<1000000; i++)
{
// Aquí no hacemos nada
}
}
else
{
// Si no presionamos el botón
// El led se vuelve cero
gioSetBit(gioPORTA, 2, 0);
}
}
/* USER CODE END */

}

Si compilan este código, debería parpadear el LED cuando presionan el botón y permanecer apagado mientras no lo presionan.



Les dejo el link para que puedan descargar el código

https://www.mediafire.com/?l58uja983dx2xwr

My Github
https://github.com/DiegoRosales

lunes, 9 de diciembre de 2013

Hercules Launchpad #1 - LED Parpadeante (Project 0)

Pues a penas me compré un Hercules Launchpad en Newark y les voy a enseñar lo que he aprendido. Este tutorial se consistirá en hacer parpadear uno de los LEDs que trae la tarjeta utilizando los timers que tiene el procesador.

Nota 1: para comenzar a desarrollar en esta tarjeta hay que instalar el compilador/debugger de Texas Instruments llamado Code Composer Studio. A mi me costó un chin*** instalarlo, pero (por si les interesa) lo logré instalar estando en el modo seguro de Windows. Este programa es gratis para desarrollar en esta tarjeta sin límites de ningún tipo.
También necesitarán de una herramienta llamada HALcoGen (HAL Code Generator). Este también es un programa de Texas Instruments (gratuito) y lo que hace es que genera todos los archivos de configuración por nosotros.

Paso 1:
Debemos abrir el mítico HALcoGen y nos va a aparecer lo siguiente


Después le damos en File -> New -> New Project y seleccionamos la familia y el procesador correspondiente. Le damos un nombre y la ubicación y dado que vamos a usar Code Composer Studio, en Tools seleccionamos "Texas Instruments Tools" y le damos "Ok".


Paso 2:
Nos va a aparecer una ventana medio friki con un montón de pestañas. Para este tutorial debemos ir a la pestaña de "Driver Enable" y desmarcamos todas las cajitas y marcamos solo la que dice HET. Les debe quedar así



Nota 2: HET significa High End Timer y es una especie de subsistema que controla todo lo que tenga que ver con timers. Este módulo posee 30 poderosas instrucciones para ser controlado.

Continuemos....

Paso 3:
Ahora nos vamos a la pestaña que dice HET. Como podrán ver, aquí es donde se configura todo lo del timer. Vamos a configurar un PWM para poder prender un LED con un periodo de 1 segundo. Para esto nos vamos a la pestaña que dice "Pwm 0-7" y ponemos el periodo del primer PWM de 1'000,000us con un ciclo de trabajo del 50% para que podamos ver que si funciona. Luego le damos clic en el cuadrito de enable con salida al pin 8, que es el pin al cual está asignado uno de los LEDs.


Paso 4:
Ahora lo que hay que hacer es habilitar el pin 8 para que funcione como salida. Para eso nos vamos a la pestaña que dice "Pin 8-15" y marcamos la cajita que se encuentra junto a "DIR:". Esto habilita el pin como salida.



Paso 5:
Ya con esto hemos configurado todo. Ahora hay que generar el código en File -> Generate code o tecleando F5. Ya que generamos el código, abrimos Code Composer Studio. Cuando nos pregunte por el Workspace, le decimos que sea en la dirección exacta donde se generó nuestro código. Luego nos vamos a Project -> New CCS Project. En el nombre del proyecto hay que escribir el nombre que usamos en HALcoGen. En la variante seleccionamos "Cortex R" y "RM42L432" y en la conexión seleccionamos "Texas Instruments XDS100v2 USB Emulator". Por último, seleccionamos la opción de "Empty Project".


Paso 6:
Ya que creamos nuestro proyecto, hay que configurarlo para que funcione con el código que generamos en HALcoGen. Para esto, nos vamos a "Project Explorer" y le damos clic derecho a la carpeta con el nombre de nuestro proyecto y luego a propiedades. En la ventana que aparece nos vamos a Build -> ARM Compiler -> Include Options y en el cuadro que dice "Add dir to #include search path" le damos clic en "Add". En la ventana que aparece le damos clic en Workspace y seleccionamos la carpeta "Nombre_del_proyecto" -> include.


Le damos a OK a las dos ventanas y en las propiedades nos vamos a "General" y verificamos que donde diga "Runtime support library" esté la opción de "automatic".

Paso 7:
Ahora si nos vamos a programar. Abrimos el archivo "sys_main.c" que se encuentra en la carpeta "source" y vemos que nos aparece un poco de código ya escrito.

Nota 3: Todos los archivos que genera HALcoGen tienen secciones de comentario que dicen 
/* USER CODE BEGIN (0) */
/* USER CODE END */
Nuestro código debe ir en estas secciones. Esto es porque es posible que tengamos que regresar a HALcoGen varias veces para cambiar algo y volver a generar el código. HALcoGen va a reescribir todo el código que no se encuentre dentro de estas secciones. Por eso es importante escribir nuestro código dentro de estos espacios.

Sigamos...

En el USER CODE BEGIN (0) hay que incluir la librería del HET. para esto escribimos

/* USER CODE BEGIN (0) */
#include "het.h";
/* USER CODE END */

Luego, en el USER CODE BEGIN (3), que es el código principal, hay que inicializar el HET. Esto se hace con la instrucción hetInit(). Por último, hacemos que nuestro código no termine con un while(1). Al final se debe ver algo así

void main(void)
{
/* USER CODE BEGIN (3) */
hetInit();
while(1);
/* USER CODE END */
}

Paso 8:
Ya que escribimos nuestro código, podemos cargarlo al microcontrolador y "debuggearlo". Esto se hace en Run -> Debug o picándole en el bichito verde. Una vez que ya se cargó el programa podemos comenzar a correrlo dándole clic en Resume (F8) y verán la magia de los sistemas embebidos hacer lo suyo.


Y pues esto ha sido todo. Eventualmente iré subiendo tutoriales de cosas más cool, ya que esta tarjeta da para mucho (deja al Arduino y todos esos micros muy muy atrás).

Por si les interesa, aquí les dejo el link de Newark

Y les dejo el link para descargar los archivos de este tutorial
http://www.mediafire.com/download/ujg9jqjc04nrjdh/Tutorial%201.zip

My Github
https://github.com/DiegoRosales

sábado, 2 de noviembre de 2013

Tutorial: cómo crear sub circuitos en OrCAD en 12 simples pasos

Ok, esto va a ser largo, así que al punto. Quieres crear una librería con sub circuitos para usarlos en tus otros circuitos y nomás no hallas cómo. Pues ahí te va.

Paso 1
Crea un nuevo proyecto en OrCAD y llámalo como gustes




Paso 2
Arma el circuito que quieras configurar como sub circuito




Paso 3
Añade los puertos de entrada y de salida en Place -> Hierarchical Port y renómbralos.
Estas serán los puertos de tu sub circuito





Paso 4 (opcional)
Renombra tu proyecto




Paso 5
Crea un netlist en Tools -> Create Netlist...





Dale clic en Aceptar y espera a que se cree. Puede que te aparezca un Warning como este



Esto quiere decir que no pusiste ninguna tierra en tu circuito, pero no pasa nada.


Paso 6
Crea la parte en Tools -> Generate Part y al final cambia lo que gustes y dale clic en Save (que onda con el spanglish de esta cosa, ¿verdad?)






Paso 7
Una vez que ya hayas creado tu sub circuito, vamos a modificar su apariencia.
En Outputs va a aparecer tu circuito con extensión .OLB. Expándelo y en el archivo que aparece dale clic derecho y pícale en Edit Part.



Te va a aparecer algo así



Ahora dale vuelo a tus dotes artísticos y dibuja tu cajita como se te antoje y al final guarda todo.


Paso 8
Ahora que ya tienes tu sub circuito bien chulo, vamos a probarlo.
Crea un nuevo proyecto con otro nombre





Paso 9
Ahora, del lado derecho aparece un cuadrito para añadir una librería. Dale clic en ese cuadrito y busca lo que se generó del archivo anterior. Es un archivo con extención .OLB




Ahora vamos a añadirle una fuente de prueba y una resistencia al final



Paso 10
Crea un nuevo perfil de simulación y añádele los parámetros que quieras.




Paso 11
Ahora vete a la pestaña que dice Options y en la categoría que dice Library, dale clic en Browse. Ahora busca el archivo .LIB que también se generó hace rato y dale clic en Add to Design. Esto lo vas a tener que hacer cada vez que quieras usar una nueva librería. Supongo que si le das clic en Add as Global, sólo lo tendrás que hacer una vez, pero no lo he probado.






Paso 12
Una vez añadido el diseño, podemos correr la simulación


¡Pero que chulo ha quedado! Ahora puedes hacer todo lo que se te antoje con tu sub circuito.

Por cierto, estoy usando la versión 16.3 de OrCAD.

Aquí les dejo los archivos de la simulación y del sub circuito

http://www.mediafire.com/?job5ommy94e74xl

domingo, 27 de octubre de 2013

Bloques lógicos útiles en VHDL #4 RAM basada en LUTs (asíncrona)

Como ustedes sabrán (o no), hace como 10 minutos aprendí que practicamente todos los FPGAs tienen unos módulos especiales para almacenar datos y leerlos. A estos módulos en inglés se les llama "Look Up Table" o LUT. Esto en cristiano significa algo así como "Ve a ver si ya puso la marrana", pero pues a pesar de que esto lo decimos con el fin de que se vayan a dejar de "molestar", ya que muy probablemente la marrana no ha puesto nada, en el mundo de los FPGAs, la marrana muy probablemente ya puso algo que necesitamos. El caso es que estos módulos almacenan datos y los podemos usar y ordenar como queramos. Un dato importante es que a este tipo de memoria, también se le llama RAM distribuida (Distributed RAM). Para el caso del Spartan 3E, que es el que usa el Basys2, esta memoria varía entre 15 y 38Kbytes, dependiendo cuánto quieras pagar.

Usar esta RAM es algo realmente fácil, y lo hacemos todo el tiempo cuando almacenamos constantes y cosas así, pero ahora la vamos a usar como se debe (más o menos). En estos ejemplos vamos a construir un bloquecito de RAM de 8x8 (8 registros de 8 bits). Este ejemplo es cuando queremos leer la RAM de manera asíncrona. Más adelánte postearé un tutorial de RAM con lectura síncrona

RAM Asíncrona

Primero comenzamos con la declaración de librerías y de puertos.
























Necesitamos declarar ciertas constantes para que nuestro código se pueda adaptar fácilmente. Los puertos que necesitamos son la dirección de la memoria, el dato a enviar, una señal que nos indique cuándo podemos escribir y por último la lectura de la memoria en la dirección deseada.

Ahora nos vamos a la parte de la arquitectura. El truco aquí es crear una matriz de datos (8x8), por lo que necesitamos declarar un nuevo tipo. Llamémosle "tipo_ram". También hay que declarar una señal con este tipo









Por último hay que declarar la manera en la que se va escribir y accesar la memoria.














Nótese que la escritura es síncrona y está controlada por la entrada "escribir". Si esta entrada esta en '0', no escribe y nada más lee. Hay que realizar cambios de tipos, ya que la entrada "dir" esta en "std_logic_vector", pero el índice de la variable "ram" que es "tipo_ram" debe ser "integer".


Como pordán ver la simulación funciona de maravilla. El dato se escribe cuando tenemos un flanco positivo en el reloj y cuando "escribir" es '1'.

Este ejemplo lo saqué de un libro titulado "FPGA Prototyping by VHDL Examples - Xilinx Spartan 3 Version", aunque le modifiqué algunas cosas, como el tamaño de el bloque de la RAM.

Ahora les dejo el código .vhd y los archivos de la simulación

Código .vhd


Simulación usando ActiveHDL


My Github
https://github.com/DiegoRosales