6. implementacióndel microcontrolador:...

Click here to load reader

Upload: others

Post on 21-Oct-2019

11 views

Category:

Documents


0 download

TRANSCRIPT

  • 6. Implementación delmicrocontrolador:ATMega1281.java

    6.1. Introducción

    En esta sección se va a presentar el trabajo realizado para la implementación delmicrocontrolador de la plataforma AvrZigbit en Avrora: ATMega1281. Es una de lasdos partes fundamentales de la plataforma, conjuntamente con el dispositivo radio.Es importante realizar una buena codificación de toda su estructura interna paraque, a la hora de simularlo, se obtenga el comportamiento más aproximado posibleal que tendría el propio hardware real, que es el objetivo final de la simulación.

    Para realizar la implementación, dos han sido las herramientas fundamentalesque se han utilizado:

    En primer lugar se dispone de la hoja de características del ATMega1281[16], que es la referencia básica donde se han consultado y encontradolas características más relevantes del mismo (pines, módulos, puertos,interrupciones, etc.).La segunda fuente a la que recurrir es el archivo ATMega128.java. Estearchivo contiene la implementación del modelo antecesor del que se estátratando. Ambos dispositivos presentan numerosas similitudes y por ello hasido minuciosamente estudiado para poder así aprovechar el trabajo realizadopreviamente para este proyecto. Ha sido un recurso muy valioso que se haconsultado en numerosas ocasiones y ha servido para aclarar varios problemasy puntos complejos del desarrollo.Para la creación de la nueva MCU se utiliza la base proporcionada por Avrora,

    esto es, una serie de clases que encapsulan toda la funcionalidad disponible para unmicrocontrolador de la serie ATMega. Una descripción detallada de dichas clases sepuede consultar en el capítulo 4.

    El código desarrollado se encuentra en el archivoATMega1281.java1 (que esdonde se encuentran ubicados todos los microcontroladores soportados en Avrora).En sucesivas subsecciones, se irá despiezando el esqueleto de la implementación en

    1Ubicado en: /avrora/sim/mcu

    73

  • Capítulo 6 Implementación del microcontrolador: ATMega1281.java

    las diversas partes de las que se compone y se describirán detenidamente para lamejor comprensión por parte del lector.

    6.2. Definición de parámetros relevantes delmicrocontrolador

    Al inicio de ATMega1281.java se definen una serie de constantes relaciona-das con diversas características del microcontrolador y que son importantes para sucodificación. Entre ellas caben destacar los pines, registros, interrupciones, tamañode las memorias internas y los modos de operación del ATMega1281. A continua-ción, en las siguientes subsecciones, se describirá cómo se han implementado todasellas dentro del código.

    Número de pines, registros e interrupciones

    En primer lugar se indica el número de pines de los que consta elmicrocontrolador, el número de registros internos que incluye y el número deinterrupciones que soporta.

    Para hallar dichos valores se debe recurrir a la hoja de características deldispositivo. En primer lugar, el número de pines es 652.

    public static final int ATMEGA1281_NUM_PINS = 65;

    En cuanto a los registros internos, es necesario consultar el mapa de memoriadel dispositivo3 para obtener este valor. Los registros comienzan en la posición dememoria 0x20 y se extienden hasta la 0x1FF (las 32 posiciones de memoria inferiores,de 0x00 a 0x1F, corresponden a 32 registros de propósito general utilizados por laALU para realizar operaciones de forma muy rápida, usualmente un ciclo de reloj).Este rango proporciona en total 512-32 = 480 registros I/O.

    public static final int ATMEGA1281_IOREG_SIZE = 512 - 32;

    Por último, el número de fuentes de interrupción se halla a partir de latabla de vectores de interrupción del micro4. Hay que tener en cuenta que estahoja de características comprende cinco modelos de microcontroladores Atmel:ATMega640, ATMega1280, ATMega1281, ATMega2560 y ATMega2561. Por ello,en esta tabla se listan todas las posibles interrupciones que abarcan todos los

    2Hoja de características del ATMega1281, pág. 4.3Hoja de características del ATMega1281, pág. 23.4Hoja de características del ATMega1281, pág. 105.

    74

  • 6.2 Definición de parámetros relevantes del microcontrolador

    modelos de microcontrolador antes citados, donde hay algunos más complejos queel ATMega1281, como puede ser el ATMega1280. Este último dispone de másdispositivos internos que el ATMega1281, por ejemplo, dispone de 4 USART, 5temporizadores, etc. y hay interrupciones específicas para estos elementos, por loque no se deben de tener en consideración para el caso del ATMega1281. Teniendoen cuenta lo anterior, el número de interrupciones del sistema es de 39.

    public static final int ATMEGA1281_NUM_INTS = 39;

    Capacidad de memoria interna

    De la misma manera que en el caso anterior, se debe especificar en el código lasconstantes que representan el tamaño de las distintos elementos de almacenamientoque posee. El microcontrolador dispone de sólo tres tipos de memoria interna:

    Memoria flash de 128 Kb que sirve para guardar el programa a ejecutar.

    4 Kb EEPROM, útil para el almacenamiento permanente de datos.

    8 Kb SRAM, donde se guardarán las variables y datos creados dentro delprograma en ejecución.

    Las definiciones de dichas memorias dentro del código se muestran a continuación:

    public static final int _1kb = 1024;public static final int ATMEGA1281_SRAM_SIZE = 8 * _1kb;public static final int ATMEGA1281_FLASH_SIZE = 128 * _1kb;public static final int ATMEGA1281_EEPROM_SIZE = 4 * _1kb;

    Modos de operación del microcontrolador

    Aparte del modo fundamental y básico de operación del ATMega1281, existenuna serie de modos especiales de bajo consumo en los que puede funcionar. En estosmodos se “apagan” determinados módulos que no están siendo utilizados. Todo ellose hace para reducir el consumo al mínimo posible.

    El ATMega1281 presenta 6 modos de bajo consumo:

    Idle: Se detiene el reloj que controla la CPU (CLKcpu) y el reloj quegobierna la operación de la flash (CLKflash), pero el interfaz SPI, USART,el comparador analógico, ADC, TWI, temporizadores, WatchDog y el sistemade interrupciones siguen funcionando.

    75

  • Capítulo 6 Implementación del microcontrolador: ATMega1281.java

    ADCNRM: Se paran CLKcpu, CLKflash y CLKI/O(que se utiliza para manejartodos los módules de entrada/salida, como puedan ser USART, SPI otemporizadores). Solo siguen funcionando ADC, TWI, interrupciones externas,temporizador 2 y WatchDog.Power-down: Se desactiva el oscilador externo. Solo continúan funcionandoTWI, interrupciones externas y WatchDog.Power-save: Idéntico al anterior, solo que se permite además que eltemporizador 2 esté activo.Standby: Idéntico a Power-down con las salvedades de que no se detiene eloscilador externo (modo recomendado para el uso del micro con un osciladorexterno) y que el temporizador 2 se desactiva.Extended standby: Idéntico a Power-save, excepto que se permite que eloscilador externo continúe funcionando (modo recomendado para el uso delmicro con un oscilador externo). El temporizador 2, al igual que en power-save, continua activo.La implementación del microcontrolador soporta la definición de los modos de

    bajo consumo. Serán identificados por un nombre y se les asigna un valor numérico:

    public static final int MODE_IDLE = 1;public static final int MODE_ADCNRED = 2;public static final int MODE_POWERDOWN = 3;public static final int MODE_POWERSAVE = 4;public static final int MODE_RESERVED1 = 5;public static final int MODE_RESERVED2 = 6;public static final int MODE_STANDBY = 7;public static final int MODE_EXTSTANDBY = 8;

    protected static final String[] idleModeNames = {"Active","Idle","ADC Noise Reduction","Power Down","Power Save","RESERVED 1","RESERVED 2","Standby","Extended Standby"};

    Nota: Los modos RESERVED1 Y RESERVED2 no son modos de bajo consumoreales, son posibles valores del registro SMCR (Sleep Mode Control Register) que esel que gestiona el modo en el que se encuentra.

    76

  • 6.3 Creación de la clase ATMega1281

    6.3. Creación de la clase ATMega1281

    La clase sobre la que se soporta toda la estructura del microcontroladorATMega1281 se llama «ATMega1281». Como ya se ha comentado, hace uso deconceptos ya definidos en otras clases (ver capítulo 4) para construir el modelosoftware de la MCU. Para ello, hereda todas las características ya incluidas en dichasclases:

    public class ATMega1281 extends ATMegaClassic

    Una vez creada esta clase y dentro de la propia simulación, se podrá definirun objeto perteneciente a esta clase que represente al microcontrolador y todas suscaracterísticas y que será capaz de realizar las acciones necesarias para ejecutar unprograma determinado.

    En secciones posteriores se irán introduciendo cada uno de los subsistemasy elementos de los que se compone este microcontrolador (por ej. pines, registros,contadores, etc.) dentro de la propia implementación.

    6.4. Descripción de parámetros generales delmicrocontrolador

    6.4.1. Consumo de los distintos modos de ahorro

    Se encuentran definidas una serie de constantes (una para cada modo deahorro) que fijan el consumo que tendrá el microcontrolador en dicho modo. Estasconstantes son útiles para una funcionalidad muy concreta que Avrora proporciona:medir el consumo del nodo y de cada uno de sus dispositivos mediante el monitor«energy». Este instrumento se encuentra monitorizando constantemente el estadode los elementos del nodo y toma nota del tiempo que transcurre en cada estado.Al finalizar la simulación, ofrece el valor del consumo de energía que obtendrásimplemente como resultado de multiplicar el tiempo en cada estado por su dato deconsumo.

    Estos valores de consumo se han obtenido consultando la hoja de característicasdel ATMega12815:

    5Hoja de características del ATMega1281, pág. 52-54 y 385-394

    77

  • Capítulo 6 Implementación del microcontrolador: ATMega1281.java

    private static final double[] modeAmpere = {0.018, // Active0.008, // Idle0.0009884, // ADC Noise Reduction0.0001158, // Power-down0.0001237, // Power-save0.0, // Reserved 10.0, // Reserved 20.0001, // Standby0.0002433 // Extended standby

    }

    6.4.2. Registros principales de control

    En el ATMega1281 existen dos registros fundamentales que gobiernan suoperación global y es necesario tener una referencia de cada uno dentro de lasimulación. Uno de ellos es MCUCR (Registro de control de la MCU)6; esteregistro contiene ciertos bits de control para funciones generales del micro (porej. activar/desactivar interfaz JTAG, acciones relacionadas con la ubicación de losvectores de interrupción en memoria, etc).

    protected final ActiveRegister MCUCR_reg;

    Otro registro importante es SMCR (Registro de control de los modos deahorro)7. Este registro permite que la MCU entre en un modo de bajo consumocuando ejecuta la instrucción “SLEEP” y seleccionar, de entre todos los posibles,dicho modo.

    protected final ActiveRegister SMCR_reg;

    6.5. Definición de pines

    La figura 6.1 muestra la configuración de pines del ATMega1281. Para cadapin se puede observar que tiene asignado un identificador numérico y uno o variosnombres (cada uno corresponde a las distintas funciones que puede desempeñardicho pin).

    6Hoja de características del ATMega1281, pág. 677Hoja de características del ATMega1281, pag. 56

    78

  • 6.5 Definición de pines

    Figura 6.1.: Pines del ATMega1281

    Para poder manipularlos y gestionarlos individualmente dentro de la simu-lación, es conveniente almacenarlos en algún tipo de estructura de manera que sepueda asociar un elemento determinado (en este caso un número) con uno o variosnombres. La solución utilizada para ello es la implementación del conjunto de pinesmediante el contenedor “Map” de Java, en el que se almacenarán parejas de clave-valor, donde valor representa el número del pin y clave un nombre para el mismo(pueden existir, como ya se ha comentado, varios nombres para un solo pin). Senecesita dotar al mapa de capacidad suficiente para almacenar todas las posiblesclaves que se puedan dar (es decir, todas las posibles funciones de todos los pines).Se ha escogido un valor de 150 que resulta adecuado para guardar todas las parejasque existen.

    HashMap pinAssignments = new HashMap(150);

    El siguiente paso será almacenar cada pin con cada una de sus respectivasfunciones asociadas en el mapa. Para ello, se hace uso de un método auxiliarque simplemente hace esta tarea: para cada labor del pin, almacena la parejanombre_función - pin. Este proceso debe repetirse con todos y cada uno de los65 pines.Véase el siguiente ejemplo:

    addPin(pinAssignments, 1, "PG5", "OC0B");

    79

  • Capítulo 6 Implementación del microcontrolador: ATMega1281.java

    En la línea de código se declara el pin número 1 de la MCU. Éste tiene dosfunciones definidas en la hoja de características:

    PG5: Pin número 5 del puerto de entrada/salida G.OC0B: Salida externa del módulo de comparación del temporizador 0.

    Por lo tanto, en el mapa se debe almacenar dos parejas, una para cada cometido delpin:

    PG5 - 1OC0B - 1

    6.6. Definición de las interrupciones

    Para un correcto funcionamiento de la simulación, es necesario dar soporte alas interrupciones que se pueden producir dentro del microcontrolador. En la figura6.2 se incluye una tabla donde se listan todos los posibles vectores de interrupcióndel ATMega1281.

    Figura 6.2.: Conjunto de interrupciones del ATMega1281

    Es conveniente apuntar que no todas las interrupciones son pertenecientes aeste microcontrolador. Debido a que la hoja de características del ATMega1281

    80

  • 6.7 Definición de los registros

    comprende varios tipo de microcontroladores Atmel, hay interrupciones que soloexisten para los modelos más avanzados. Más concretamente, las referidas a lostemporizadores 4 y 5 no se incluyen, simplemente porque no existen dichos módulosen el 1281; lo mismo para «USART2» y «USART3». Por último, «PCINT1»y «PCINT2» tampoco están soportadas (no existen los pines asociados para estafunción).

    La manera de definir las interrupciones dentro de la simulación es muy similara como se hizo con los pines. Se guarda en un Map parejas del tipo nombreinterrupción-número de interrupción. Ambos elementos son fácilmente identificablesen la figura 6.2. La definición del mapa se hace en la línea de código:

    HashMap interruptAssignments = new HashMap(40);

    La manera de añadir una interrupción al mapa es llamar al método «addInte-rrupt(mapa, nombre_interrupción, número_interrupción)», cuya únicalabor es almacenar en mapa la pareja nombre_interrupción-número_interrupción.Como ejemplo, véase como se agrega la interrupción “Reset”:

    addInterrupt(interruptAssignments, "RESET", 1);

    6.7. Definición de los registros

    Los registros son un elemento muy importante dentro del sistema puestoque el funcionamiento del microcontrolador se gobierna casi totalmente medianteel conjunto de sus registros internos. Gracias a ellos, se puede modificar elcomportamiento que tiene el micro en cada situación y adaptarlo a las necesidadesconcretas de cada aplicación. Los registros pueden contener parámetros defuncionamiento, de configuración o, simplemente, se utilizan para almacenar datosque, o bien serán empleados para llevar a cabo algún tipo de operación o serviránpara guardar sus resultados. Como se expuso en la sección 6.2, el ATMega1281consta de un número total de 480 (muchos de ellos están reservados y no sonaccesibles). Cada uno de ellos controla características determinadas o subsistemasconcretos de la MCU. Por ejemplo, hay una serie de registros que gestionanel interfaz SPI (activarlo/desactivarlo, seleccionar la velocidad de transferencia,flags de interrupción...), otro conjunto de ellos manejan el temporizador de 8 bits"Timer0" (seleccionan el modo y la frecuencia de operación, los flags de interrupciónasociados...), etc.

    Dentro de la memoria SRAM del dispositivo, el ATMega1281 posee unespacio de memoria exclusivo para sus registros que se representa en la figura 6.3.Esta porción del mapa de memoria comprende el rango 0x20-0x5F (64 registros

    81

  • Capítulo 6 Implementación del microcontrolador: ATMega1281.java

    bajos de entrada/salida) y de 0x60-0x1FF (416 posiciones de memoria para losregistros extendidos de entrada/salida), resultando un total de 480, como se dijoanteriormente. El primer tipo son aquellos que controlan el funcionamiento básicode la MCU, mientras que los extendidos están relacionados con funcionalidadesadicionales. Respecto a los registros extendidos se ha de precisar que no todas las416 posiciones se encuentran ocupadas. Muchas están reservadas y no está permitidoacceder a ellas.

    Figura 6.3.: Mapa de memoria de datos del ATMega1281

    Un registro está completamente definido por su dirección de memoria y porun nombre que lo identifique (posiblemente también será necesario especificar lossubregistros que los componen). Ésta es la idea que se va a utilizar para su integracióndentro del simulador.

    En la implementación del ATMega1281 en Avrora, es necesario definir todosy cada uno de estos registros para que estén disponibles dentro de la simulacióny puedan ser utilizados para gestionar el funcionamiento de la MCU. El procesollevado a cabo se describe a continuación:

    En primer lugar es necesario crear un esquema de registros (tambiénllamado layout, que representa la distribución de los registros en la memoriadel microcontrolador). Este elemento se encarga de almacenar informaciónrelativa a las direcciones de memoria (dentro del mapa de memoria delATMega1281) de los registros de entrada/salida. Realiza un mapeo de susnombres y direcciones, conteniendo además información sobre qué camposestán almacenados en qué registros. Este concepto se implementa en laclase «RegisterLayout». Para crear un objeto de este tipo se llamará alconstructor de dicha clase con dos parámetros: el primero es el número deregistros que contendrá; el segundo, el tamaño, en bits, de los registros.

    RegisterLayout rl = new RegisterLayout(ATMEGA1281_IOREG_SIZE, 8);

    Una vez creado el "contenedor" de todo el conjunto de los registros delsistema, se deben definir e incluir uno a uno manualmente. Para añadir un

    82

  • 6.8 Propiedades de la MCU

    nuevo registro al layout con un nombre y dirección concretos, se empleael método «addIOReg(name, addr)». Existe una variante del métodoanterior, «addIOReg(String n, int ior_num, String format)», quees útil cuando se desean especificar los campos contenidos dentro del registro(subregistros). En este caso se le proporciona una cadena que se usa paragenerar automáticamente una instancia de dicho registro que ubicará los bitsapropiados en los campos apropiados cuando se escribe el registro.

    En la hoja de características del microcontrolador8 se muestra un listadocompleto de los registros que componen el microcontrolador, su dirección de memoriay sus subregistros. Siguiendo esta referencia se van añadiendo uno a uno. Acontinuación se presentan un par de ejemplos para aclarar todo el proceso:

    Registro sin subregistros. En la línea de código mostrada a continuación seincluye en el layout el registro PINA, que sirve para leer el valor de los pinesdel puerto A. Su dirección de memoria es la 0x00.

    rl.addIOReg("PINA", 0x00);

    Registro con subregistros. En el siguiente ejemplo se añade el registro TIFR0,que gestiona varias interrupciones procedentes del contador 0. Su dirección dememoria es la 0x15. Posee 3 subregistros que se declaran como tales: OCF0B yOCF0A son banderas de interrupción relacionadas con las unidades A y B decomparación del contador 0; TOV0 es la bandera que indica el desbordamientodel contador 0. A la hora de indicar los subregistros, se deben especificar todosy cada uno de los 8 bits de los que se compone el mismo (comenzando porel más significativo). Si algún subregistro ocupa más de 1 bit, se indica comosi fuese un array de bits. Si hay algún bit reservado y que, por tanto, noes accesible, se indicará mediante un punto. En el caso del registro TIFR0,los bits del 7 al 3 están reservados y, en la implementación, esto se indicamediante cinco puntos. Los tres bits restantes, se nombran de acuerdo a comose especifica en la hoja de características del ATMega1281: el bit 2 es OCF0B,el bit 1 es OCF0A y el bit 0 es TOV0.

    rl.addIOReg("TIFR0", 0x15, ".....,OCF0B,OCF0A,TOV0");

    6.8. Propiedades de la MCU

    Para concluir con la definición de la estructura del ATMega1281, el simuladorproporciona una clase llamada «AVRProperties» que sirve para englobar todas

    8Hoja de características del ATMega1281, pág. 411.

    83

  • Capítulo 6 Implementación del microcontrolador: ATMega1281.java

    las características incluídas en secciones precedentes: tamaño de los registros deI/O, tamaño de la memoria SRAM, EEPROM y flash, número de pines, númerode interrupciones, manera de realizar el almacenamiento en memoria y tres mapas,uno con la asignación de pines, otro con la de los registros y otro con la de lasinterrupciones. Con la creación de este objeto, se tendrá un elemento que representala organización hardware del dispositivo y que será utilizado posteriormente paracrear instancias del mismo.El código correspondiente a este apartado es el siguiente:

    props = new AVRProperties(ATMEGA1281_IOREG_SIZE, // number of io registersATMEGA1281_SRAM_SIZE, // size of sram in bytesATMEGA1281_FLASH_SIZE, // size of flash in bytesATMEGA1281_EEPROM_SIZE, // size of eeprom in bytesATMEGA1281_NUM_PINS, // number of pinsATMEGA1281_NUM_INTS, // number of interruptsnew ReprogrammableCodeSegment.Factory(ATMEGA1281_FLASH_SIZE, 7),pinAssignments, // the assignment of names to physical pinsrl, // the assignment of names to IO registersinterruptAssignments);

    6.9. Constructor de la clase «ATMega1281»

    Una vez creada la clase «ATMega1281», el constructor se utilizará paracrear instancias que representen al microcontrolador objeto de este proyecto. Una vezcreados este nuevo tipo de objeto, se podrán integrar en la simulación y manipularseconvenientemente dentro de la misma.

    public ATMega1281(int id, Simulation sim, ClockDomain cd, Program p)

    El constructor toma 4 parámetros:id: Identificador numérico del simulador del dispositivo.sim: Objeto de tipo "Simulation" que representa la simulación de la que elmicrocontrolador formará parte.cd: Conjunto de relojes que proporcionan la señal de sincronismo a la MCU.p: Programa que será cargado en el microcontrolador.A continuación, se llama al constructor de la clase padre («ATMegaClassic»),

    que a su vez llamará a los constructores de sus clases antecesoras. Los parámetrosque se le pasan como argumentos son:

    cd: Dominio de relojes antes descrito.props: Conjunto de propiedades que definen unívocamente al microcontroladory su estructura interna.

    84

  • 6.9 Constructor de la clase «ATMega1281»

    FiniteStateMachine: Soporte para la creación de una máquina de estados finitaque permite hacer un seguimiento del estado del dispositivo. Se incluye el relojprincipal del sistema, el modo de operación por defecto, una lista de los modosde bajo consumo y los tiempos asociados al cambio entre dichos estados.El siguiente paso es la creación de un objeto de tipo «Simulator» que lleva a

    cabo la implementación de un completo simulador del ATMega1281 para el conjuntode instrucciones de los microcontroladores de la gama AVR y otro objeto, de tipo«AtmelInterpreter», que es el encargado de ejecutar las instrucciones para laarquitectura actual (AVR) y almacenar el estado del programa en ejecución: valoresde los registros, flags, etc.

    simulator = sim.createSimulator(id, LegacyInterpreter.FACTORY, this, p);interpreter = (AtmelInterpreter)simulator.getInterpreter();

    Seguidamente, se obtienen dos referencias a dos registros fundamentales quegobiernan parte del funcionamiento del micro (en la sección 6.4.2 se hizo una pequeñaintroducción):

    MCUCR: Registro de control de la MCU. Controla dos aspectos fundamental-mente:

    • 1. Activar/desactivar el interfaz «JTAG».• 2. Permitir o prohibir que se produzcan interrupciones en el sistema.

    SMCR: Registro de control de los modos de bajo consumo. Se encarga de lagestión de dichos estados. Mediante los bits que lo componen se puede indicara cuál de estos modos de ahorro cambiará el microcontrolador.

    MCUCR_reg = getIOReg("MCUCR");SMCR_reg = getIOReg("SMCR");

    Como ya se expuso en el capítulo 2 de esta memoria, un parámetro muyimportante de un nodo es su consumo. Para tener una estimación del consumodel microcontrolador dentro del entorno del propio simulador, se hace uso de laclase «Energy». En Avrora, esta clase proporciona un control y monitorización delconsumo energético de todo dispositivo con una serie de posibles estados de operacióny un consumo asociado a cada uno (es apropiado tanto para el microcontroladorcomo para la radio). Cada dispositivo que se desee monitorizar debe poseer un objetode dicha clase. Únicamente es necesario indicarle cuál es el consumo aproximado encada uno de los estados. Este objeto almacenará todos los cambios de estado relativosa consumo que se hayan producido y el número de ciclos que han transcurridoen cada uno de ellos. Cuando termine la simulación y, habiendo seleccionadopreviamente el monitor «energy», se mostrarán todos los resultados (Consumo

    85

  • Capítulo 6 Implementación del microcontrolador: ATMega1281.java

    total = Sum(Consumo en el estado X · Ciclos en el estado X), para todos losestados posibles del microcontrolador).

    new Energy("CPU", modeAmpere, sleepState,simulator.getEnergyControl())

    El constructor de la MCU termina con sendas llamadas a dos métodos bastanterelevantes. El primero de ellos es «installPins()» cuya labor es que, para todo elconjunto de pines del ATMega1281, realiza la encapsulación del pin físico (real) delmicrocontrolador en un objeto de la clase «Pin». Este objeto permitirá realizarla conexión, en el entorno simulador, de los distintos dispositivos que conforman laplataforma Zigbit9.

    El otro método ejecutado es «installDevices()». Este método integra elresto de subsistemas internos del microcontrolador que aún no han sido incluídos enla implementación. Entre ellos cabe destacar los puertos I/O, los puertos serie, lostemporizadores, etc. En las siguientes subsecciones se presenta el código desarrolladoa tal efecto.

    6.9.1. Temporizadores/Contadores

    El ATMega1281 integra 4 módulos temporizadores/contadores:Timer0: De 8 bits. Permite conseguir una temporización precisa en la ejecuciónde programas (gestión por eventos) y generación de formas de onda. Disponede dos unidades comparadoras independientes (A y B) y proporciona soportepara realizar PWM10.Timer1 y Timer3: De 16 bits. Al igual que con el anterior, se logra unatemporización exacta en la ejecución de un programa y generación de formasde onda. Presenta la novedad de poder realizar medidas de tiempo sobreseñales. Integra tres unidades comparadoras independientes (A, B y C), unaunidad para realizar comparaciones con la señal de entrada, PWM, contadorde eventos externos, etc.Timer2: De 8 bits. Es similar a Timer0 en prestaciones, pero presenta unaparticularidad: puede obtener su señal de sincronismo tanto del reloj internosíncrono de la MCU como de un reloj externo asíncrono a través de dos pinesde entrada específicos.Se han desarrollado tres nuevas clases que implementan correctamente

    estos contadores. Todo ello será presentado y explicado con más detenimientoen el capítulo 7 “Implementación de los temporizadores/contadores:ATMegaClassic”.

    9Véase el capítulo 5 “Implementación de la plataforma AvrZigbit.java”10Modulación de ancho de pulsos

    86

  • 6.9 Constructor de la clase «ATMega1281»

    Para añadir nuevos dispositivos internos al microcontrolador, se hace uso delmétodo «protected void addDevice(AtmelInternalDevice d)» de la clase«AtmelMicrocontroller», donde d es un objeto que representa al dispositivoque se desea añadir. Para recuperarlos posteriormente, sólo es necesario realizar unallamada a «public AtmelInternalDevice getDevice(String name)» de dichaclase, indicando el nombre de dicho dispositivo. En el siguiente extracto de códigose muestra cómo se integran los temporizadores a la instancia que representa almicrocontrolador:

    addDevice(new NewTimer0());addDevice(new Timer1(3));addDevice(new NewTimer2());addDevice(new Timer3(3));

    La explicación de dicho código es sencilla. Se ha creado un objeto para cadacontador de la clase correspondiente: Para el contador 1 y el 3 se han utilizado clases(«Timer1» y «Timer3») que ya se encontraban implementadas y que los definenperfectamente. El parámetro “3” que se le pasa a cada constructor indica el númerode unidades comparadoras de las que dispone el dispositivo. En cambio, para el 0y el 2, como se ha hecho hincapié anteriormente, ha habido que desarrollar otrasclases nuevas que se ajustaran a sus nuevas características, concretamente al númerode unidades comparadoras que se soportan. Una vez creados estos cuatro objetos,se añaden cada uno a la instancia «ATMega1281» con el método «addDevice»presentado anteriormente. En cualquier momento posterior, si así se requiere, sepuede obtener una referencia a dicho dispositivo utilizando el método «getDevice»indicando, solamente, el nombre del temporizador/contador que se desea obtener.

    6.9.2. Puertos I/O

    Los puertos de entrada/salida son interfaces programables de la MCU quese utilizan para comunicarse con otros dispositivos. Como se indica en la hojade características11, el ATMega1281 dispone de 7 puertos de entrada/salida depropósito general: A, B, C, D, E, F y G. Todos ellos son puertos de 8 pines exceptoel puerto G, que tiene 6. Cada pin de cada puerto de I/O puede ser programadocomo entrada o salida. Para ello, tiene asociado 3 registros:

    DDxn12: Registro de dirección. Permite configurar el puerto como entrada osalida.

    PORTxn: Registro de datos. Si se configura como salida, el valor que se escribaen el bit correspondiente a este pin quedará en la salida. Si se dispone como

    11Hoja de características del ATMega1281, pag. 512“x” es el número de puerto y “n” el número de pin.

    87

  • Capítulo 6 Implementación del microcontrolador: ATMega1281.java

    entrada y se escribe un “1” se habilita la resistencia de pull-up asociada adicho pin.

    PINx: Registro de entrada. Si el pin se configura como entrada, el valor quese encuentre en el pin se leerá al acceder a este registro.

    Además del manejo básico, los puertos tienen otras funcionalidades alternativasque pueden ser consultadas en la hoja de características del ATMega1281.

    Para añadir un puerto al microcontrolador dentro de Avrora, es necesariohacer uso del método «buildPort(char p)» (para el puerto G, usar la versión«buildPort(char, int)» para indicarle el número de pines que tiene, que es distintode los 8 por defecto) de la clase «ATMegaFamilyNew», donde p es la letra quelo identifica (puede ser A, B, C, D, E, F o G, para el caso del ATMega1281). Estemétodo se encarga de crear los registros asociados que se han descrito antes (DDxn,PORTxn y PINx) y los pines necesarios para cada puerto. Cualquier manipulacióno consulta posterior del puerto se debe hacer a través de los pines y de los registrosde configuración correspondientes al mismo.

    buildPort(’A’);buildPort(’B’);buildPort(’C’);buildPort(’D’);buildPort(’E’);buildPort(’F’);buildPort(’G’, 6);

    6.9.3. Puertos USART’s

    USART13 es un dispositivo altamente flexible para la comunicación serie. ElATMega1281 dispone de dos puertos serie idénticos: USART0 y USART1. Cada unode ellos tiene las siguientes propiedades:

    Comunicación full-duplex, gracias a registros independientes para transmisióny recepción.

    Modo de operación síncrono o asíncrono. Generador de alta precisión de tasade transmisión/recepción.

    Soporte de tramas serie con 5 a 9 bits de datos y 1 o 2 bits de parada.

    Generación de paridad par o impar y soporte hardware para su verificación.

    Detección de error de trama.13USART: Transmisor y Receptor serie Síncrono y Asíncrono Universal

    88

  • 6.9 Constructor de la clase «ATMega1281»

    La implementación software de este elemento dentro de Avrora se localiza enavrora/sim/mcu/USART.java. Para añadirlos al microcontrolador, de nuevo se haceuso de «addDevice()», al que se le proporciona un objeto de tipo «USART»que representa al dispositivo que se desea añadir. Para crear dicho objeto, se llamaal constructor de la clase «USART» con dos parámetros: el primero de ellos esun número que identifica al puerto serie y el segundo es una referencia al objeto«AtmelMicrocontroller» del que formará parte.

    addDevice(new USART("0", this));addDevice(new USART("1", this));

    6.9.4. EEPROM

    El ATMega1281 contiene 4 Kb de memoria de datos EEPROM14. Como ya seconoce, es una memoria no volátil, por lo que conserva su contenido aún cuando nose encuentre alimentada. Soporta, al menos, 100000 ciclos de escritura/borrado, porlo que hay que tener especial cuidado al almacenar datos de forma incontrolada enella. El acceso entre la CPU y la EEPROM se controla por una serie de registrosasociados:

    Registros de dirección: EEARH y EEARL . Especifican una direccióndeterminada dentro de los 4 Kb de memoria EEPROM.

    Registro de datos: EEDR. En modo escritura, contiene el valor que se va aescribir en la dirección de memoria indicada por EEARH y EEARL. En modolectura, contiene el valor leído de la posición de memoria indicada por EEARHy EEARL.

    Registro de control: Gestiona y configura el acceso a la memoria EEPROM,tanto para lectura como para escritura.

    La implementación software de este elemento dentro de Avrora se localiza enavrora/sim/mcu/EEPROM.java. Para incluir la memoria EEPROM dentro de laimplementación del microcontrolador, es necesario previamente crear un objeto detipo «EEPROM» que admite dos parámetros: uno es el tamaño de dicha memoriay otro una referencia al objeto «AtmelMicrocontroller» donde será integrado ycon este objeto, llamar al método «addDevice()»:

    addDevice(new EEPROM(properties.eeprom_size, this));

    14EEPROM: Electrically Erasable Programmable Read-Only Memory

    89

  • Capítulo 6 Implementación del microcontrolador: ATMega1281.java

    6.9.5. Interfaz SPI

    El interfaz SPI15 permite transferencia síncrona de datos a alta velocidad entreel ATMega1281 y otros dispositivos que posean interfaz SPI. Entre sus característicasmás relevantes, se pueden destacar:

    Comunicación full-duplex.Configuración de la interfaz como maestro o esclavo.Distintos valores de tasa de transferencia seleccionables.Posibilidad de comenzar la transmisión por el MSB o LSB.Bandera indicando fin de transmisión.El manejo de este dispositivo se hace mediante 4 pines: /SS, MOSI, MISO y

    SCK. El maestro inicia la comunicación poniendo a nivel bajo la señal /SS conectadaal esclavo. Genera en SCK los pulsos de reloj necesarios para llevar a cabo elintercambio de datos. Para el envío de datos desde el maestro al esclavo se utilizael pin MOSI y para recibir desde el esclavo se usa MISO. Los registros asociados aeste módulo se detallan a continuación:

    SPCR: Es el registro de control del SPI. En él se pueden configurar distintosparámetros, como por ejemplo, la velocidad de transferencia que se usará,si se comportará como maestro o esclavo, permitir que se pueda producir lainterrupción asociada a la comunicación o si se permite el funcionamiento delpropio dispositivo (activarlo o desactivarlo).SPSR: Registro de estado del SPI. En él se ubica la bandera de interrupcióndel interfaz. También permite seleccionar el modo de funcionamiento de doblevelocidad (período de SCK será el doble que el período de la CPU).SPDR: Registro de datos del SPI. Si el maestro desea enviar un byte al esclavo,lo escribe en este registro. Si por el contrario ha recibido un byte procedentedel esclavo, lo lee de este lugar.La implementación software de este elemento dentro de Avrora se localiza en

    avrora/sim/mcu/SPI.java. Para integrar este dispositivo dentro del microcontrola-dor solo es necesario llamar al método «addDevice()» al que se le suministra unobjeto de la clase «SPI»:

    addDevice(new SPI(this));

    6.9.6. Interrupciones

    Una vez se han definido en la sección 6.6 el conjunto de posibles interrupcionesque se pueden dar en el sistema, es necesario tener un control preciso de15SPI: Serial Peripheral Interface

    90

  • 6.9 Constructor de la clase «ATMega1281»

    cuando se produce una interrupción para así poder actuar en consecuencia, todoello dentro de la propia simulación. Para este cometido se utiliza el método«buildInterruptRange()» de la clase padre «ATMegaFamilyNew». Estemétodo asocia un registro de flags y otro con la máscara de interrupción a un rangode interrupciones determinado. El método «buildInterruptRange()» recibe unaserie de parámetros:

    Una bandera que indica si el número de vector de interrupción aumenta con elbit del correspondiente registro. Es decir, si al bit 0 del registro le correspondela interrupción N, al bit 1 le corresponderá la N+1, y así sucesivamente.

    Dirección del registro que contiene la máscara de interrupción.

    Dirección del registro que almacena los flags de interrupción.

    Número de vector de interrupción inicial.

    Número de vectores de interrupción asociados a este rango.

    El parámetro flag es importante definirlo correctamente. Como se ha explicado,si el flag es “true” significa que el número de vector de interrupción aumenta conel número de bit del registro de máscara de interrupción. En caso contrario, no secumple lo anterior y el número del vector de interrupción decrece con el númerode bit del registro de máscara de interrupción. En el caso particular de que elconjunto de vectores de interrupción de un registro de máscara de interrupciónno vaya en orden (creciente o decreciente) sino desordenado, se debe definir de lamisma manera que viene impuesta por la arquitectura del microcontrolador. Paraello, se creará un array donde se indica el número de vector de interrupción en elmismo orden a como se establece en el registro de máscara de interrupción. Si el bitdel registro de máscara está reservado, se indicará con el valor “-1” . Tanto parael caso de que exista un orden preestablecido o no, el objetivo final es obtener unareferencia tanto para el registro de flags como para el de máscara de interrupcionesde un rango determinado para así manejar cómodamente las interrupciones que seproduzcan dentro de la simulación. En el caso de que se haya utilizado el método«buildInterruptRange()», devolverá un registro de banderas. El de la máscarase consigue creando un objeto de tipo «MaskRegister» al que se le proporcionael nombre del registro adecuado. Para el caso de un rango de interrupciones noordenado, se deberá crear manualmente un objeto de tipo «FlagRegister» yotro «MaskRegister» con sus nombres correspondientes. Para clarificar todo loexplicado respecto a las interrupciones, se presentan dos ejemplos. El primero deellos trata el conjunto de interrupciones referidas al Timer0.

    Los dos registros asociados son TIFR0 y TIMSK0. En primer lugar se crea elrango de interrupciones asociado a estos registros, obteniendo el objeto TIFR0_regque representa al registro de banderas. TIMSK0_reg se obtiene posteriormente dellayout de registros del ATMega1281.

    91

  • Capítulo 6 Implementación del microcontrolador: ATMega1281.java

    TIFR0_reg = buildInterruptRange(false, "TIMSK0", "TIFR0", 22, 3);TIMSK0_reg = (MaskRegister)getIOReg("TIMSK0");

    El segundo ejemplo que se quiere mostrar es el referido al Timer1. Se debe crearun mapeado entre el número de interrupción de la arquitectura del microcontroladory el bit correspondiente de los registros de banderas y máscara porque no existe unorden como en el caso anterior.

    int[] TIFR1_mapping = {19, 16, 17, 18, -1, 15, -1, -1};TIFR1_reg = new FlagRegister(interpreter, TIFR1_mapping);TIMSK1_reg = new MaskRegister(interpreter, TIFR1_mapping);

    Ambos registros se crean como objetos de la clase correspondiente: «Fla-gRegister» y «MaskRegister», que representan, respectivamente, al registro quecontiene las banderas de interrupción referentes al Timer1 y al que almacena lamáscara asociada.

    92

    6 Implementación del microcontrolador: ATMega1281.java6.1 Introducción6.2 Definición de parámetros relevantes del microcontrolador6.3 Creación de la clase ATMega12816.4 Descripción de parámetros generales del microcontrolador6.4.1 Consumo de los distintos modos de ahorro6.4.2 Registros principales de control

    6.5 Definición de pines6.6 Definición de las interrupciones6.7 Definición de los registros6.8 Propiedades de la MCU6.9 Constructor de la clase «ATMega1281»6.9.1 Temporizadores/Contadores6.9.2 Puertos I/O6.9.3 Puertos USART's6.9.4 EEPROM6.9.5 Interfaz SPI6.9.6 Interrupciones