AVR Assembler

Objetivos

  • Conocer las instrucciones básicas del lenguaje Ensamblador AVR
  • Comprender el uso del set de instrucciones expuesto en el datasheet del microcontrolador.

Introducción

Ensamblador es un lenguaje de bajo nivel. Consiste en una lista de instrucciones que no son de ninguna manera comparable a cualquier otro lenguaje como C, Basic o Pascal. El AVR tiene alrededor de 130 instrucciones, dependiendo del tipo, periféricos y tamaño del microcontrolador. En este link está el manual de las instrucciones con su respectiva explicación, y en este otro link se encuentra la guia de usuario de AVR Assembler. se encontrará mayor información en http://www.avrbeginners.net/ y en http://www.avrfreaks.net/

Antes de comenzar es necesario explicar el como se ejecuta un programa en el microcontrolador:

Cuando el microcontrolador se enciende, lo primero que se ejecuta es la interrupción reset, en otras palabras lo que indica es que lo vuelve a su estado inicial, por defecto esta interrupción se encuentra en la posición 0 de la memoria, en este momento el contador de programa (PC - Program Counter) se pone en cero y cada vez que se ejecuta una instrucción se suma uno de manera que ejecuta la siguiente instrucción del programa y así sucesivamente. es posible establecer la posición donde se desean almacenar los datos en la memoria, para esto se utiliza la instrucción .org, en el caso de las interrupciones como el reset se denominan vectores de interrupción.

.org 0x0000    ; la siguiente instrucción se almacenará en la posición 0
               ; Los comentarios en assembler se ponen con punto y coma (;)

Etiquetas, Saltos y Llamadas a Subrutinas

Debido a que el lenguaje ensamblador no dispone de instrucciones conocidas en otros lenguajes de programación como if, for, while, etc. es necesario hacer uso de otras herramientas para lograr estas funciones.

Etiquetas

Son palabras que reemplazan en la programación una dirección de memoria, los programas que se crean y se programan son almacenado en la memoria de programa del microcontrolador, esta memoria al igual que todas tiene unas direcciones que permiten organizar la información que allí reside, el uso de la etiqueta se hace bastante claro cuando se piensa que se debe ejecutar la instrucción que está en una posición de memoria, por tanto es más fácil utilizar una etiqueta en lugar de estar contando cuantos espacios de memoria se han utilizado para saber en que lugar de la memoria se encuentra la instrucción que se necesita, las etiquetas se escriben con una palabra que no debe pertencer al set de instrcciones es decir usar una palabra no reservada, seguida por dos puntos asi:

inicio:             ; etiqueta inicio

Saltos

Los saltos permiten cambiar el valor del PC, esto significa que es posible cambiar la instrucción que se quiere ejecutar sin que sea necesariamente la siguiente en la memoria, este tipo de instrucciones permiten tener un control sobre secuencias que se quieran programar por ejemplo si se desea crear un ciclo infinito:

inicio:             ; etiqueta inicio
rjmp inicio:        ; salto relativo a inicio

En general esisten dos instrucciones para realizar este tipo de saltos, esta rjmp y jmp, la primera se denomina salto relativo y le permite al microcontrolador cambiar la posición del PC hasta en 2K de distancia en la posición actual en la memoria, jmp le permite hasta 64k lo cual permite saltar a cualquier posición de la memoria, a pesar que parece jmp una instrucción mas robusta demora mas ciclos de reloj lo cual afecta directamente el rendimiento de la aplicación, por otro lado depende del tamaño de la aplicación puede que no sea necesario relizar saltos tan grandes.
Existen varias instrucciónes disponibles para utilizar de acuerdo a la necesidad o a la aplicación que se vaya a elaborar,(ver instrucciones branch) será responsabilidad del lector investigar el uso de las demas instrucciones.

Llamado a subrutinas

Las subrutinas pueden interpretarse como las funciones o procedimientos de otros lenguajes de programación, en donde el programador crea un trozo de código que puede llamar en cualquier momento para volverlo a ejecutar, para poder hacer esto entonces es necesario no solo ir a otra parte de la memoria y ejecutar un código sino ser capaces de volver al sitio desde donde se partió, para esto entonces los microcontroladores utilizan una memoria adicional conocida como la Pila (Stack), esta pila tiene un apuntador conocido como Stack Pointer o SP, el funcionamiento de la pila en el microcontrolador AVR es muy sencillo, la posicion inicial es la dirección superior es decir que si la pila tuviera 100 espacios la primera posicion sería la 100, cuando se almacena un registro en la pila entonces el apuntador disminuye en 1 de manera que el siguiente dato se almacene en la siguiente posicion es decir para nuestro ejemplo sería en la posición 99 así sucesivamente, cuando se saca un dato el SP aumenta para poder sacar el dato siguiente.

La capacidad de la pila cambiará de acuerdo con la referencia del microcontrolador que se esté utilizando, pero en general los microcontroladores AVR necesitan 16 bits para direccionamiento de la Pila, debido a que el microcontrolador AVR es de 8 bits entonces se hace necesario utilizar dos registros para el SP, estos son el SPH y el SPL (high and low) y se refieren a los bits mas significativos y menos significativos respectivamente.

Para poder utilizar instrucciones de llamados a subrutinas, y en general la pila del microcontrolador entonces es necesario indicarle al programa la posición inicial de la misma,esto se logra con las siguientes instrucciones:

ldi r16,high(RAMEND)     ; carga el registro 16 con los 8 bits mas significativos de RAMEND
out SPH,r16              ; copia en contenido de el registro 16 en SPH
ldi r16,low(RAMEND)      ; carga el registro 16 con los 8 bits menos significativos de RAMEND
out SPL,r16              ; copia en contenido de el registro 16 en SPL
                         ; Nota: los valores de RAMEND son tomados de manera automática cuando en Atmel Studio se selecciona el microcontrolador

Ya teniendo iniciada la pila entonces es posible hacer uso de las instrucciones de salto rcall y call que funcionan de manera similar a las instrucciones de salto con la diferencia que al utilizar una llama a subrutina es posible volver a la posición desde donde se hace el llamado mediante la instrucción ret, la posición es almacenada en la pila mientras se ejecuta la subrutina y para luego volver y poder continuar con la ejecución del código.

Teniendo esto conceptos claros entonces procedemos a crear nuestro primer programa:

Código ejemplo

En este proyecto se programa un microcontrolador ATMEGA16 para que en uno de sus puertos se genere una secuencia de contador de 8 bits, para la visualización se utilizan LEDs,

.org 0                         ;posicion del vector de interrupción RESET
rjmp reset
 
reset:
    ldi r16,high(RAMEND)
    out SPH,r16
    ldi r16,low(RAMEND)
    out SPL,r16                ; se carga la pila del microcontrolador
    ldi r16,0xFF               ; se carga el registro 16 con el valor binario 0b11111111 o  0xFF en hexadecimal
    out DDRA,r16               ; se habilita el puerto A como salida
    ldi r18,0x00               ; se carga el registro 18 con cero
loop:
    out PORTA,r18              ; se sacan los datos del registro 18 al puerto A
    inc r18                    ; se incrementa en 1 el valor de r18, r18=r18+1
    rcall retardo              ; llamado a la subrutina retardo
    rjmp loop                  ; reinicio de la secuencia
 
retardo:
    ldi r16,0xFF               ; r16=255
delay1:    
    ldi r17,0xFF               ; r17=255
delay2:                        
    dec r17                    ; decrementa r17 en 1
    brne delay2                ; si r17!=0 entonces salta a delay2
    dec r16                    ; decrementa r16
    brne delay1                ; si r16!=0 entonces salta a delay1
    ret                        ; retorno de subrutina

La subrutina retardo es necesaria en este ejemplo debido a que la velocidad a la que trabaja el microcontrolador es del orden de los megahertz por lo cual no va a ser posible visualizarla, para obtener una visualización adecuada se incluyó la secuencia.

Algunas de las instrucciones utilizadas en el ejemplo no fueron propiamente introducidas y será responsabilidad del lector investigar la función de las mismas.

Referencias

[1] http://www.avrfreaks.net/
[2] http://www.avrbeginners.net/

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License