sábado, 12 de agosto de 2017

Introducción a la escritura de código en C para XMEGA (AVR1000)

 

1. Introducción

Cortos tiempo de desarrollo y requerimientos de productos electrónicos de alta calidad han hecho de los lenguajes de programación de alto nivel un requisito. La principal razón es que los lenfuajes de alto nivel hacen más facil el mantenimiento y la reutilización del código debido a la gran portabilidad  y legibilidad.

La simple elección del lenguaje de programación no asegura una alta legibilidad y reusabilidad; el buen estilo de codificación sí. Así pues, los perifericos XMEGA, los archivos cabecera y los controladores estan diseñados teniendo esto en cuenta.

El lenguaje de programacíón mas ampliamente usado para microcontroladores AVR es C, y esta nota de aplicación (AVR1000) se enfoca en la programación en C. Para proporcionar soporte a muchos de los compiladores de C para AVR disponibles los ejemplos son en la medida de lomposible escritos en ANSI C. Algunos de los ejemplo son especificados para IAR Embedded Workbench, pera la idea y metodos pueden ser uados para otros compiladores con cambios menores.

 

Ejemplo de codificación – AVR GCC

image

 

 

2. Módulos XMEGA

Un AVR XMEGA esta conpuesto de varios bloques básicos. Un CPU AVR, SRAM, Flash, EEPROM, y una serie de perifericos. Esos bloques son llamados “tipos de módulo”. Un XMEGA puede tener una o más instancias de un tipo de módulo dado. Todas las instancias de un tipo de módulo tienen las mismas caracteristicas y funciones.

Algunos de los módulos pueden ser un subconjunto de otros tipos de módulos. Estos módulos heredan un subconjunto de caracteristicas del módulo superior, todas las caracteristicas heredadas son completamente compatibles. Esto se aplica por ejemplo a los timer y puertos de entrada y salida. Un subconjunto de módulos para un timer significa que este tiene menos canales de captura y comparación que un timer completo. Similarmente, un puerto IO puede tener menos de ocho pines.

Un tipo de módulo puede ser un “USART”, mientras una instancia de este tipo puede ser “USARTC0”, donde el sufijo C0 indica que la instancia es el USART 0 en el puerto C. Cada módulo tiene un número de registros que contienen bits de control o de estado. Todos los módulos de un tipo dado contienen el mismo conjunto (o subconjunto) de registros, y todos estos registros contienen el mismo conjunto (o subconjunto) de bits de control y estado.

 

Tipo de módulo, instancias, registros y bits.

image

 

Cada módulo tiene una dirección base fija en el mapa de memoria I/O y todos los registros contenidos en el módulo tienen direcciones de desplazamiento fijas relativas a dirección base del módulo. De esta manera, cada registro no sólo tendra una dirección absoluta en el espacio de memoria, sino también una dirección relativa definida por un offset. Los desplazamientos de las direcciones de registros son iguales para todas las instancias de un tipo de módulo, simplificando la tarea de escribir controladores que puedan ser usados para todos los modulos de un tipo especifico.

 

2.1 Convención de nomenclatura de registros

 

Los registros están divididos en registros de control, registros de estado y registros de datos y el nombre de dichos registros refleja esto.

Un registro de control de propósito general del módulo es llamado CTRL. Sí existen múltiples registrol de control en un módulo ellos tendrán un caracterer como sufijo. En este caso el registro de control será llamado CTRLA, CTRLB, CTRLC etc. Esto también aplica a los registros de estado (STATUS).

Para registros que tienen una función específica el nombre de estos refleja esta funcionalidad. Por ejemplo, un registro de control que controla los niveles de interrupción de un módulo es llamado INTCTRL.

Ya que el bus de datos AVR es de 8bits, los registros mas grandes son implementados usando varios registros de 8 bits. Para un registro de 16 bits, el alto (High) y bajo (Low) son accesados agregando una “H” o “L” respectivamente al nombre del registro. Por ejemplo, el registro de cuenta de 16 bits del Timer/Counter son llamados CNT. Los dos bytes son llamados CNTL y CNTH.

Para registros más grandes de 16 bits, los bytes son numerados desde el byte menos significativo. Por ejemplo, el registro de calibración de 32 bits del ADC es llamado CAL. Los cuatro bytes son llamados CAL0, CAL1, CAL2 y CAL3 (desde el menos al más significativo). Muchos de los compiladores de C ofrecen un manejo automatico en el acceso a multiples bytes. En el caso del timer el nombre CNT, sin sufijos “H” o “L”, puede ser usado para realizar un acceso al registro de cuenta (CNT). Esto también se aplica en el caso de los registros de 32 bits.

 

2.2 Convención de nomenclatura de bits

 

Los bits en los registros pueden tener una función individual o ser parte de un grupo de bits que tienen una función conjunta: Un bit individual puede ser un bit que habilita un modulo, ej. el USART ENABLE bit. Un grupo de bits puede consistir de dos o más bits que juntos seleccionan una configuracion especifica del modulo al cual pertenecen. Un grupo de bits ofrecen hasta 2^n posibles opciones, donde n es el número de bits en el grupo. Los dos bits que controlan el nivel de interrupción de recepción completa del USART, RXINTLVL[1:0], es un ejemplo de un grupo de bits. Esos dos bits ofrecen las siguientes secciones:

 

Bits RXINTLVL y los correspondientes niveles de interrupción

image

 

Solamente los bits que forman parte de un grupo tendrán como sufijo un número. El registro de control D de un Timer/Counter tiene dos grupos de bits. EVACT y EVSEL. Los bits de esos grupos tienen un número como sufijo, mientras que el bit EVDLY, que no forma parte de un grupo, no tiene sufijo.

 

image

 

 

3. Escribiendo codigo en C para XMEGA

 

 

 

 

…..escribiendo…..

jueves, 10 de agosto de 2017

Empezando con XMEGA (AVR1005)


1. Introducción:


Desde que Atmel (ahora microchip) amplio su portafolio de productos con la familia XMEGA surgieron muchas preguntas, si esta es una nueva arquitectura, cómo transferir los conocimientos de megaAVR a AVR XMEGA, etc. Aquí trataremos brevemente las similitudes y diferencias entre las dos familias, y proporcionaremos una visión general de las herramientas disponibles.

Los usuario de AVR ocasionalmente mencionaron que ellos querían dispositivos con un menor consumo de potencia, periféricos más potentes, más timers, DMA, multiples niveles de interrupción, más memoria y un mejor rendimiento del CPU. Bien, con XMEGA ahora tienes todo esto, Adicionalmente tienes el sistema de eventos (Event System), motor de encriptación (Crypto Engine), ADC y DAC de 12-bit, calibración de los osciladores en tiempo real, chequeo CRC, y otras características.

Adicionalmente, los periféricos dentro de una familia son similares y están organizados de la misma manera para todos los miembros de la familia, haciendo que portar código de un XMEGA a otro sea una tarea sencilla.




2. Introducción a XMEGA(diferencias y similitudes con los megaAVR)


Esencialmente el XMEGA es un AVR de 8 bits. XMEGA usa la arquitectura y CPU AVR, pero con características adicionales y periféricos mejorados. XMEGA usa el mismo conjunto de instrucciones, las mismas herramientas de desarrollo y compiladores que megaAVR. El CPU puede funcionar más rápido que antes y con un voltaje más bajo.


2.1 Preguntas comunes acerca de XMEGA


  • XMEGA y megaAVR no son compatible en pines. Esto no fue posible de alcanzar debido al deseo de hacer el dispositivo más modular.

  • XMEGA opera con voltajes desde 1.6V hasta 3.6V. Esto se debe en parte al proceso de fabricación, el cual es seleccionado desde el punto de vista del bajo consumo de energía. La operación a 5V no es posible. El menor voltaje de funcionamiento no significa un menor rendimiento del CPU ya que XMEGA puede correr hasta 32MHz desde los 2.7V.

2.2 Estructuras y migración


Los XMEGA están estructurados para fácilmente portar entre dispositivos. Por ejemplo, PORTA y PORTB serán dedicados a las interfaces analógicas ADC y DAC o a dos Comparadores Analogicos. PORTC, D y E serán para interfaces seriales. También, todos los módulos están definidos en estructuras (typedef struct). Esto quiere decir que para acceder a los registros del ADC se debe hacer mediante la estructura ADC. Además, dado que el ADC es definido es una estructura, la idea es que esta estructura será la misma para todos los dispositivos de la misma familia. Entonces sí tu empezaste con un ATxmega64A4, debería ser una tarea sencilla migrar a un ATxmega128A4 o un ATxmega256A1; ya que tu estas usando la misma estructura y así tu puedes usar el exactamente el mismo código. Con megaAVR no podemos hacer una estructura de un módulo para definir todos ellos ya que los diferentes dispositivos podrían tener diferentes diseños.

Las familias XMEGA son distinguibles por una letra: La primera familia es ATxmega[###]A[#](Familia A). Antes de la letra de la familia se encuentra un número el cual representa el tamaño de la memoria flash, y después de la letra de la familia encontraras otro número que será el ID de la familia, el cual identifica dispositivos individuales. Dispositivos con el mismo ID tiene exactamente las mismas características y el mismo número de pines pero pueden estar disponibles en diferentes tamaños de memoria.


2.3 Manual y Hoja de datos


La estructura de los XMEGA hace posible hacer un gran manual para describir todos los módulos y periféricos dentro de una familia. Los detalles que harán un dispositivo diferente otro, como características y periféricos disponibles serán descritos en una pequeña hoja de datos.


Hoja de datos
image

Manual
image


Por ejemplo, se podrían recopilar todas las funciones descritas para todos los dispositivos A1, A3 y A4 en la familia XMEGA-A. Así pues el manual XMEGA A es un documento profundo para todos los módulos que están disponibles en la familia A. Por otro lado la hoja de datos para la sub familia A3 que no son comunes con A1 y A4.


2.4 Sistema de eventos (Event System)


El sistema de eventos es un características totalmente nueva de los XMEGA. No encontraras Event System in megaAVR. El sistema de eventos es comunicación entre los periféricos del XMEGA. Un canal de eventos no es un bus, sino un canal dedicado en el que sólo se puede señalar un evento a la vez. Ya que los eventos están en un canal dedicado, estos serán muy predecibles y rápidos. Realmente, habrá un máximo de 2 ciclos de reloj. Con los eventos, el CPU no está involucrado y no hay interrupciones (ISRs). Finalmente, el sistema de eventos es extremadamente poderoso ya que este no ocupa el CPU y puede ahorrar energía e incrementar el rendimiento en el sistema debido a que se reduce el número de interrupciones.


XMEGA Event System trata sobre la comunicación entre perifericos
image


Veamos un ejemplo. Tu puede por ejemplo usar el sistema de eventos para enlazar dos timer de 16 bits y obtener uno de 32 bits. O puedes usar un evento para sincronizar dos módulos. Por ejemplo, puedes usar el evento de cambio para realizar un conversión con el ADC y una captura de la entrada con el timer para obtener el tiempo exacto de cada conversión. Aún más, otro ejemplo podría ser permitir que un evento dispare conversiones ADC para muestrear música desde un micrófono y cuando la conversión se haya completado el DMA copiará los datos a la RAM. Cuando el usuario presione un switch se generará un evento que copiará los bytes al DAC para reproducir lo previamente grabado. Todo esto se puede hacer estando el XMEGA en modo sleep.



2.5 Segunda Generación PicoPower


Los XMEGA llevan la tecnología PicoPower al siguiente nivel. Todos los XMEGA son probados para operar a 1.6V. Eso significa que todos los periféricos y módulos que pueden correr a 3.6V también pueden correr a 1.6V. Un menor voltaje implica un menor consumo de corriente. Hay nuevos diseños para el watchdog para el circuito Brown Out (BOD). El watchdog corre típicamente con 1uA. La corriente de consumo para el BOD es también de 1uA. De todos las características de bajo consumo, quizá la mejor sería reducir el tiempo en modo activo y remplazar este trabajando más a menudo en IDLE modo usando el DMA y el Sistema de eventos.


2.6 Sistema de reloj


La fuente de reloj y frecuencia pueden ser cambiadas mientras el XMEGA está funcionando. Se puede seleccionar un oscilador interno(RC) de 2MHz y uno de 32MHz. El RC de 2MHz es la fuente de reloj por defecto cuando el XMEGA inicia. Este inicia rápidamente en contraste a cristales externos y resonadores cerámicos los cuales necesitan bastante tiempo para empezar a oscilar. El dispositivo puede comenzar ejecutando el código de inicialización mientras el oscilador externo se estabiliza. Una vez que el oscilador externo está listo para ser usado el cambio de fuente de reloj debe ser realizado por el programa. La frecuencia de reloj puede ser cambiada en cualquier momento mediante el uso del PLL y prescalers.

Si usamos el PLL interno, la señal de reloj puede ser multiplicada (x1, x2, x3,…, x31). Tú puedes incrementar la señal de reloj principal (max 32MHz) o incrementa la velocidad de los periféricos, por ejemplo se puede alcanzar 128MHz como señal de entrada de un Timer/Counter para obtener un señal PWM con alta resolución.

Adicionalmente, el “Monitor de fallas de la fuente de reloj externa” puede detectar si la señal de reloj falla(ej: debido a daño físico del cristal) y automáticamente cambiar al RC interno de 2MHz.


2.7 Controlador de Interrupciones Multinivel.


Ya que los XMEGA tiene más fuentes de interrupción que un megaAVR, se ha adicionó un controlador de interrupciones multinivel. Esto facilita el manejo de muchas fuentes de interrupciones de manera oportuna de acuerdo con las prioridades establecidas. Si por ejemplo una fuente de interrupción con una alta frecuencia es atendida con tanta frecuencia que las otras interrupciones en el mismo nivel no son atendidas, entonces puede ser buena idea bajar la prioridad de la primera fuente de interrupción, ósea la de alta frecuencia.

2.8 Principales Funciones Analogicas.


Con XMEGA se introducen algunas características importantes para un MCU de 8 bits. Tanto el ADC como el DAC y tienen una resolución de 12 bits. El ADC puede alcanzar hasta 2 millones de muestras por segundo. También hay una característica llamada “event or interrupt on conversion complete”, la cual sólo generará una interrupción de conversión completa cuando el resultado se encuentre por debajo o por encima de un cierto límite.

El DAC puede dar dos salidas incluso cuando sólo se usa un módulo. Esto es gracias a que se cuenta con un circuito separado de muestreo y retención que permitirá, por ejemplo, una salida estéreo con sólo un DAC.

El Comparador Analógico (AC) tiene una nueva característica llamada “windows mode”(modo ventana) cuando se usan dos módulos AC a la vez. Entonces, tu puedes ingresar dos limites (nivel bajo y alto) y la señal de entrada a ser comparada. El resultado estaría debajo, dentro o sobre la ventana. El resultado la comparación también se puede reflejar en un pin de salida.


2.9 Interfaz de Bus Externo (EBI).


El EBI disponible en XMEGA soporta memorias hasta de 16MB. Son soportadas las memorias SRAM y SDRAM. Las memorias SDRAM son de bajo costo y gran capacidad, pero no es posible combinarlas con otras unidades mapeadas que requieran una interfaz de bus tipo SRAM. Debido al soporte para grandes memorias, el tiempo de ejecución de cada instrucción que accede a memorias ha cambiado ligeramente. Además, cuando se compila para memorias de gran capacidad el tipo de dato usado para direccionar cambia de 16bits a 24bits.


2.10 Motor de Encriptación (Crypto Engine).


Para la comunicación con protocolos, ya sea alámbrico o inalámbrico, la encriptación de la información es necesaria para una comunicación segura.

XMEGA implementa tanto AES como DES, y puede realizar tanto la encriptación como la desencriptación. AES es un hardware que libera al CPU de toda la carga. Este módulo puede proveer 1.25Mbps de comunicación encriptada con una llave de 128bits.



3 Que herramientas usar?.



Para la escritura de código se puede usar el ya muy conocido Atmel Studio. Se recomienda leer la nota de aplicación AVR1000 (Getting Started Writing C-code for XMEGA) que es una introducción al estilo de codificación que se ha elegido y también describe como acceder a los periféricos.
Los programadores/depuradores recomendados son el ATMEL-Ice ó el JTAGICE3 (ya no está en producción).






lunes, 17 de abril de 2017

CREANDO COMPONENTE ISIS - PROTEUS



El video muestra la creación de un componente(FT232HL). El componente es creado para la creación de PCBs, no para simulaciones.




RING BUFFER UART - ATmega328p


PARTE 1




PARTE 2




Link: EJEMPLO

lunes, 28 de marzo de 2016

I2C + RTC DS3231 usando C


En el siguiente post mostraré cómo leer y escribir, mediante I2C, un rtc DS3231 de Maxim integrated.

El DS3231 es un RTC serial con una exactitud muy alta gracias a su oscilador interno de 32KHz que es compensado ante los cambios de temperatura (TCXO u Osciladores de Cristal Compensados por Temperatura). La hoja de datos nos dice que podemos tener una exactitud de ±2ppm que podemos traducir en unos 126 seg por año.
La lectura y escritura de registros del DS3231 se realiza mediante la interfaz I2C a una velocidad de 400KHz.

El ejemplo presentado en este post es para un ATmega32, pero puede ser fácilmente adaptado a otros microcontroladores. 
En este post anterior (I2C con ATmega8) se explica el funcionamiento del bus I2C, aquí sólo mostraré y explicare las librerías I2C y RTC necesarias para la escritura y lectura del DS3231.


I2C ATmega

El ATmega32 cuenta con 4 registros los cuales son mostrados en la figura 1 y que debemos conocer . En ellos se configura la velocidad del bus, se controla el bus, se tiene acceso a los estados del bus y de puede leer/escribir los datos recibidos/enviados.

Figura 1.image


PARTE 1. Files I2C

file i2c.h.  Contiene las definiciones necesarias para configurar el bus I2C.
  • En la figura 2 se calculan los posibles valores del registro TWBR en base a la velocidad del bus I2C (400KHz).

Figura 2.image

  • En la figura 3 se selecciona el correcto valor del registro TWBR y de los bits de pre-escaler (TWPSX).

Figura 3.image

  • En la figura 4 se crean los prototipos de las funciones necesarias para el manejo del bus.

Figura 4.image



file i2c.c  Contiene la implementación de las funciones declaradas en el archivo de cabecera .h.

  • En I2C_Init se configura la velocidad del bus I2C.

Figura 5.image

  • I2C_Start envía una condición de start y espera que el envío se haya realizado. Retorna un 1 si el envío fue satisfactorio.
  • I2C_ReStart envía una nueva condición de start y espera que el envío se haya realizado. Retorna un 1 si el envío fue satisfactorio.

Figura 6.image


  • I2C_Stop envía una condición de stop y espera a que se haya ejecutado.

Figura 7.
image


  • I2C_Write envía el dato hacia el esclavo y retorna un 1 si el envío fue realizado y se ha recibido un ACK.

Figura 8.
image

  • I2C_Read espera que el bus se encuentre habilitado para iniciar una lectura y enviar un ACK o NACK de acuerdo al valor de la variable ACK_NACK.

Figura 9.image



PARTE 2. Files RTC

Antes de empezar con los files rtc.h y rtc.c explicaré brevemente lo que son las estructuras y las uniones.
  • Una estructura es un agrupamiento de variables bajo un nombre común. Estos agrupamientos pueden contener diferentes tipos de datos. Para definir una estructura se hace uso de la palabra reservada “struct”.
La estructura ejemplo contiene 3 miembros de diferente tipo (uint8_t, int16_t y un array int8_t).
La declaración de variable de tipo estructura es como sigue:
struct ejemplo var1: Aquí “var1” es una variable del tipo estructura ejemplo.
struct ejemplo
{
    uint8_t c;
    int16_t i;
    int8_t k[4];
};
Para acceder a los miembros de la estructura se hace uso del operador punto (.).
var1.c; var.i; var1.k[0], var1.k[1], var1.k[2] y var1.k[3].
Algo mas sencillo al momento de crear estructuras es la declaración de un alias usando la palabra cable “typedef”. Con esto evitaremos poner “struct ejemplo” cada ve que se quiera declarar una nueva variable.
Será suficiente colocar “ejemplo var2”.
typedef struct
{
    uint8_t c;
    int16_t i;
    int8_t k[4];
}ejemplo;
Las estructuras también pueden ser punteros y apuntadas por punteros tan igual como las tipos nativos (char, int, etc).  En estos casos se accede  a los miembros mediante el operador fecha (->).
variable: ejemplo var1.puntero: ejemplo *pt= &var1;
uso: pt->c; pt->i; pt->k[0], pt->k[1], pt->k[2] y pt->k[3].


  • Una union es similar a una estructura, pero estas difieren en que cada elemento en las estructuras tiene un espacio de memoria mientras en las uniones todos los elementos ocupan el mismo espacio de memoria. El tamaño de la unión depende del miembro mas grande.
La union mostrada en la parte derecha ocupa sólo 4 bytes.
Después de la asignación los valores quedan distribuidos como en la siguiente figura en donde el byte mas significativo esta último ya que ATmel usa little endian.
                  image
El usuario verá las variables como en la siguiente figura.

             image

Creación:

         typedef union
         {
              uint8_t u8;
              uint16_t u16;
              uint32_t u32;
         }ejemplo;


Declaración:

            ejemplo var1;

Asignación:

           var1.u32 = 0x01234567

Ahora si pasaremos a los archivos rtc.

file rtc.h
  • En la figura 10 se crean las estructuras para hora y fecha. También hay una tercera estructura (RTC_t) que esta conformada por las estructuras Hora_t y Fecha_t.

Figura 10.image

  • En la figura 11 se definen las direcciones de los registros internos de DS3231. También una mascara para filtrar los datos leídos desde el DS3231. Finalmente, y ya que la dirección del DS3231 es 0b1101000, se define DS3231_READ y DS3231_WRITE para las lecturas y escrituras desde y hacia el RTC.

Figura 11.image

  • En la figura 12 se declaran los prototipos de las funciones para leer/escribir el RTC. Las 6 últimas funciones tienen un puntero a estructura(Hora_t, Fecha_t y RTC_t) .

Figura 12.image


file rtc.c
  • RTC_Init sólo inicializa el bus I2C.

Figura 13.image

  • En la figura 14 se muestran las funciones de lectura/escritura para cualquier registro del DS3231.

Figura 14.image

  • RTC_SetHora escribe una nueva hora en el DS3231. La nueva hora proviene de una estructura del tipo Hora_t. Del mismo modo RTC_SetFecha escribe una nueva fecha en el DS3231.

Figura 15.image

  • RTC_GetHora leer la hora del DS3231 y lo guarda en una estructura del tipo Hora_t que es apuntada por el puntero hora. RTC_GetFecha hace una tarea similar con la fecha.

Figura 16.image

  • RTC_GetTime hace uso de las funciones ya mencionadas para leer la hora y la fecha y guardarla en la estructura apuntada por el puntero rtc de tipo RTC_t. RTC_SetTime se encarga de escribir la hora y fecha de manera similar.

Figura 17.image



PARTE 3. main

En el main se configura el uart para enviar/recibir la hora y la fecha hacia/desde un programa hecho en Visual C#.
También se configura una interrupción cada 1 segundo para leer el DS3231.

Figura 18.image


Aquí presento el programa.

  • En la figura 19 se muestran los includes que necesita el main.

Figura 19.image

  • En la figura 20 se muestra la definición de la union TRAMA_t que une una estructura y un array de 10 elementos. Este nuevo tipo de dato (TRAMA_t) servirá para el envío y recepción de información hacia y desde el programa en la PC. En la linea 28 se crea la variable “tx_trama”.
  • En la linea 27 se declaran dos variables(rtc y rx_rtc) del tipo RTC_t. En la variable rtc se almacena la hora y fecha leidas del DS3231 cada 1 segundo. rx_rtc sirve para almacenar la hora y fecha recibidas desde el programa en la PC antes de ser enviadas al DS3231.
  • Las variables update_rtc y send_rtc son actualizadas en la interrupción del uart y sirven para actualizar el DS3231 o enviar la hora y fecha hacia la PC.

Figura 20.image

  • En las lineas 37-40 (Figura 21) se configura el uart.
  • En las lineas 42-44 se configura la interrupción del timer1 cada 1 segundo.
  • En las lineas 48 y 49 se inicializan las variables update_rtc y send_rtc.
  • También se inicializa la variable tx_trama y se activa el bit de interrupción global.

Figura 21.image

  • Sí el programa de la PC envía una nueva actualización para el RTC esta será guardada en rx_rtc (en la interrupción por recepción) y el RTC será actualizado en el while. También se enviará la hora y fecha actual hacia el PC si es requerido.

Figura 22.image

  • En la figura 23 se muestra la interrupción por recepción del uart. Aquí se reciben todos los datos, se hace un chequeo de integridad de los datos y de acuerdo al comando de lectura (‘R’) o escritura (‘W’) se actualizará las variables ‘update_rtc’ y ‘send rtc’.

Figura 23.image

  • Finalmente, en la interrupción del timer1 se lee la hora y fecha del rtc. También se muestran las funciones del lectura y escritura en el uart.

Figura 24.image


Enlaces de programas:

Programa RTC DS3231
HORA+FECHA.exe





sábado, 12 de marzo de 2016

Primer proyecto con Atmel Studio 7


Para iniciar la programación de uC AVR necesitamos instalar la Plataforma Integrada de Desarrollo (IDP) de ATmel, me refiero al Atmel Studio 7.
Aquí el enlace para la descarga : Atmel Studio 7.0.790
Instalado el software, pasaremos a crear nuestro primer proyecto.
Una vez abierto el software, en la parte izquierda veremos la figura 1 donde debemos dar click en “New Project”.


Figura 1.image


Luego debemos seleccionar el tipo de proyecto y el lenguaje (C, C++, ASM). En este ejemplo usaremos el lenguaje C como lo vemos en la figura 2.


Figura 2.image



Una vez seleccionado el lenguaje, debemos darle un nombre al proyecto, en nuestro caso lo llamaremos “First_project” (Figura 3). El software creará una carpeta con el nombre del proyecto en la ruta “C:\Users\user\Documents\Atmel Studio”.

Figura 3.image


Ahora debemos seleccionar el dispositivo que deseamos usar, en este caso seleccionamos el ATmega32.

Figura 4.image



A la derecha de la misma ventana veremos (figura 4) veremos una lista de las herramientas de depuración y programación que se pueden usar en el microcontrolador seleccionado. También un enlace a la hoja de datos del dispositivo (Figura 5).

Figura 5.image


Luego de dar click en en botón aceptar veremos el archivo main.c tal como en la figura 6. Aquí es donde debemos escribir nuestro programa. 

Figura 6.image



En la figura 7 se muestra la aplicación desarrollada. En esta programa se tendrán dos entradas para dos pulsadores en el puerto B, y dos salidas para dos leds en el puerto D.

  • En 11 se declaran dos variables de tipo unsigned char (uint8_t) para guardar en estado actual y el estado pasado de un pin de entrada.
  • En 15 se ponen los el puerto B como entradas.
  • En 16 activamos las resistencias pull up de los pines PB0 y PB1.
  • En 17 se ponen los pines PD7 y PD3 como salidas para los led.
  • En 20 preguntamos sí el pin PB0 fue presionado
  • En 21 se pondrá a 1 el pin PD7 sí PB0 es 0. El código de la linea 22 es igual al de la linea 21.
  • En 24 se pondr’a a 0 el pin PD7 si PB0 es 1. El código de la linea 25 es igual al de la linea 24.
  • En 27 se guarda el valor anterior del pin PB1.
  • En 28 se guarda el valor actual del pin PB1.
  • En 29 se pregunta sí ocurrió un flanco de subida.
  • En 31 se conmuta, usando un xor (^), el pin PD3. El código de la linea 32 es igual al de la linea 31.

Figura 7.image


En C podemos usar el operador :?, y gracias a esto podemos reducir las lineas 20 a 25 por el código de la figura 8.



Figura 8.image



En la figura 9 se muestra la equivalencia entre un if-else y el operador :?.

Figura 9.image



Luego debemos compilar el programa usando el botón de la figura 10.

Figura 10.image


Finalmente, tendremos como salida el archivo .hex (Figura 11) para poder programar nuestro microcontrolador.

Figura 11.image



Link Proyecto




Si queremos ver la numeración de lineas en nuestro ventana de edición tenemos que ir a Tools>Options (Figura 12).
Figura 12.image


Luego en “All Languages” seleccionamos “Line numbers”  (Figura 13).

Figura 13.image

Espero este post sea útil.
Hasta la próxima.

viernes, 11 de marzo de 2016

Bootloader USBasp


Ya muchos conocemos el programador USBasp (gracias a Thomas Fischl) y lo bien que funciona este. El USBasp debe ser uno de los programadores mas conocidos para descargar código a un ATmega, esto gracias a que usa un muy económico ATmega8, que aun no teniendo puerto USB, es capaz de trabajar con una gran cantidad de dispositivos. … y lo mejor de todo: “Es gratis”.
Personalmente lo vengo usando desde el año 2010. Ahora tengo un AVRISPmk2(al parecer ya descontinuado) y un JTAGICE3 (que ya fue remplazado por el Atmel-ICE) y aún en algunas ocasiones uso mi USBasp.

Bueno, es este post mostraré cómo usar el “USBasp“  como bootloader.

Un programador USBasp consta básicamente de un ATmega8 que ha sido programado, en la sección de aplicación de su flash, con un código que permite comunicación USB (low speed 1.5Mbps) con el programador y programar otros uCs. Los anteriormente descrito se muestra en la figura 1, donde la sección de booteo del uC (ATmega8) no es usada.
 
Figura 1.image
 

Pero cuando hablamos de usar el “USBasp” cómo bootloader tendremos un esquema similar a la figura 2. Aquí, el código, “USBasp” , que realizará la comunicación con el programa en la PC (ej. AVRDUDE) es localizado en la sección de booteo de la flash, y es este código el que nos permite poner nuestra aplicación en la sección de aplicación de la flash (usando instrucciones SPM y LPM).
Es decir que no necesitaremos un programador USBasp ya que este lo tendremos integrado en el mismo uC. Lo mejor de todo es que lo podemos poner un diferentes uCs y con diferentes osciladores. Personalmente ya lo he probado con ATmega8 (a 12 y 16MHz), ATmega32(a 12 y 16MHz) y ATmega324P (a 12,16 y 20 MHz).
 
Figura 2.image
 
El hardware necesario los muestro en la figura 3. Aquí se debe tener algunas consideraciones tales como.
  • D+ debe necesariamente ir conectado al pin INT0.
  • D- puede ser cualquier pin del puerto D.
  • El jumper para iniciar el bootloader puede ser cualquier pin.

Figura 3.
image
 

En la figura 4 se muestra el diagrama del flujo del bootloader.
Despues de un reset se inicia en bootloader y este se ejecutara sí:
  • La fuente de reset es externa (MCUCSR & (1 <<  EXTRF)).
  • Si el jumper esta colocado ((PINB & (1 << JUMPER_BIT)) == 0).
En otras palabras, para ejecutar el bootloader hay que colocar el jumper y presionar el boton de reset.
Para salir del bootloader sólo hay que quitar el jumper.
 
    Figura 4.image
     

    Antes de programar el bootoalder debemos debemos modificar los siguientes fuses.
    • En High Fuse debemos seleccionar una de las secciones que tengan como mínimo 1024 words (2048 bytes) ya que el bootloader ocupa más de 1900 bytes. También debemos seleccionar “Boot Reset Enable” para que el programa inicie en la sección de booteo y no en la de aplicación. Para ATmega8 recomiendo 0xC8.
    • En Low Fuses debemos seleccionar alguna de las opciones Ext. Crystal/Resonator High Freq. Para un ATmega8 recomiendo 0xFF.



    Figura 5.
    image
     
    En la figura 6 se muestra el mapa de memoria de la sección de booteo de un ATmega8. Como ya se dijo antes, de esta usaremos mas de 1900 bytes, por ello en los fuses se seleccionará la mayor área.
     
    Figura 6.image

    SOFTWARE


    El código original lo pueden encontrar en el siguiente enlace link.
    Aquí les dejo el proyecto en ATMEL STUDIO 7 USBasp-boot. El proyecto esta configurado para un ATmega8 a 12MHz, pero puede ser cambiado facilmente a otros dispositivos.
    Las modificaciones necesarias para usarlo con otros dispositivos son las siguientes:
    • Sí se quiere usar otras frecuencias de oscilador debemos hacer el cambio en Toolchain>Symbols. Las frecuencia pueden ser de 12,15,16,18 y 20 MHz. En las figuras 7 y 8 se muestran los lugares donde se deben realizar los cambios de frecuencia.



    Figura 7.
    image



    Figura 8.
    image
     
    También debemos decirle al compilador que el código generado debe iniciar en el sección de booteo seleccionada en los High Fuses. En el ejemplo de la figura 5 se selecciono “Boot start address=0x0C00” donde 0xC00 es la dirección, en words, de inicio de la sección de booteo.
    Tenemos dos formas de reasignar el inicio del código:
    En la figura 9 se hace la reasignación usando el inicio de la dirección en words (0x0C00).
    En la figura 10 se hace la reasignación usando el inicio de la dirección en bytes (0x1800).
    Nosotros debemos seleccionar sóla una de las dos formas (Figura 9 o 10).
    Hay que tener en cuenta que 0x0C00 words = 0x1800 bytes.
     
    Figura 9.image
     
    Figura 10.image
     

    En la figura 11 se muestra parte del código generado. Aquí vemos que el inicio es en la dirección 0x1080 (para 2014 bytes). Cuando el código generado es para la sección de aplicación la dirección de inicio es 0x0000.
     
    Figura 11.image
     

    En la figura 12 se indica que el se usará PD3 para conectar D- del USB. Esto lo podemos cambiar a algún otro pin en el mismo puerto.
     
    Figura 12.image
     

    En la figura 13 se indica el pin que se usará para el jumper de inicio del bootloader. Este puede ser cualquier pin que no se esté usando.
     
    Figura 13.image


    En la figura 14 se activa la resistencia pull up correspondiente al pin del jumper.
     
    Figura 14.image
     

    En la figura 15 se evalúa la condición para permanecer o salir del área de booteo.
     
    Figura 15.image


    En los caso de la figura 14 y 15 se pueden usar el pin y el puerto que se deseé.
    Si el ATmega que queremos usar  no se encontrase en la lista de la figura 16 corresponde agregarlo con sus respectivos “SIGNATURE BYTES”.
     
    Figura 16.image
     

    El proyecto es para un ATmega8, cómo cambiamos de dispositivo ?
     
    • Damos click en l icono         image
    • Click en “Change Device…”    image
    • Seleccionamos el nuevo dispositivo.    image
    • Ya habremos cambiado nuestro nuevo dispositivo. image
    • Luego sólo queda compilar y tendremos el .hex del bootloader para poder programarlo.
    Finalmente, y cuando el bootolader se encuentre instalado, podremos usar programas como SinaProg para descargar nuestra aplicación sin afectar el bootloader.
    hay que resaltar que el bootloader no permite hacer cambio de los fuses.
    En resumen:
    1. Preparar el hardware (figura 3).
    2. Con un programador cualquiera cambiar los fuses del uC (figura 5).
    3. Hacer los cambios en el software, sólo si son requeridos: F_CPU (figuras 7 y 8), .text (figura 9 ó 10), D- (figura 12), JUMPER_BIT (figura 13), PORT/PIN JUMPER (figuras 14 y 15).
    4. Agregar un nuevo uC si falta (figura 16).

    Espero que esto les sea de utilidad, ya que no necesitar un programador puede ser muy útil.