Sunteți pe pagina 1din 4

Esqueleto básico para programas en ensamblador IAR MSP430:

; ******************************************************************************
; PROGRAMA : Nombre de programa (v?.?)
; TARGET : Donde se va a ejecutar el código (ej.MSP430F169 en simulador)
; DESCRIPCION : Función que realiza el programa.
; AUTOR : XXXXXX YYYYYYY
; FECHA : XX-YY-ZZ
; ESQUEMA : (No hace falta conectar a la placa)
; ******************************************************************************

#include "msp430x16x.h" ; Definición de etiquetas

; ------------------------------------------------------------------------------
; PROGRAMA PRINCIPAL
; ------------------------------------------------------------------------------
ORG DIRFLASH ; Programa en FLASH
Main mov.w #DIRRAM,SP ; Inicializa base pila
mov.w #WDTPW+WDTHOLD, &WDTCTL ; Desactiva WDT
; Inicialización de modo de funcionamiento, periféricos, variables…
……
; Código principal
……
; Bucle infinito(1) o modo de espera a interrupción en bajo consumo(2)
eint
fin jmp fin ; Bucle sin fin(opción 1)

; Modo de espera a interrupción en bajo consumo(opción 2)


bucle bis #CPUOFF+GIE,SR ; Activa el modo LPM y habilita interrupc.
nop ; Necesaria para depuración

; ------------------------------------------------------------------------------
; SUBRUTINAS (se llaman con “call #subrutinaX”)
; ------------------------------------------------------------------------------
subrutina1 código subrutina1
……
ret ; Vuelve al programa principal
subrutina2 código subrutina2
……
ret ; Vuelve al programa principal
……
; ------------------------------------------------------------------------------
; RUTINAS DE INTERRUPCIÓN (ISRs ó RTIs)
; ------------------------------------------------------------------------------
RTIPeriferico1 código RTI/ISR
……
reti
RTIPeriferico2 código RTI/ISR
……
reti
……
; ------------------------------------------------------------------------------
; DEFINICIÓN DE VARIABLES
; ------------------------------------------------------------------------------
ORG DIRRAM ; Dirección en RAM (no solapar con pila)
variable1word DC16 val1word ; Variable Word en RAM con valor inicial
variable2byte DC8 val2byte ; Variable Byte en RAM con valor inicial
variablesbyte DS.B N ; N bytes sin inicializar
variablesword DS.W M ; M words sin inicializar
; ------------------------------------------------------------------------------
; VECTORES DE INTERRUPCIÓN
; ------------------------------------------------------------------------------
ORG 0FFE0h+RESET_VECTOR ; Reset
DW Main

ORG 0FFE0h+PORT1_VECTOR ; Puerto 1


DW RTIPuerto1

ORG 0FFE0h+PERIFERICON_VECTOR ; Periferico N


DW RTIPerifericoN
……
END Main

1
Partes del “esqueleto”:

• CABECERA: Descripción del programa. Nombre; versión; en que placa y con


que micro se piensa ejecutar (TARGET); utilidad; fecha de última modificación.
Esquema de conexiones a los pines (si hay pocas).

(la cabecera no es imprescindible para que funcione el programa, pero si


aconsejable. Todas las líneas deben ir comentadas – empezar por “;”)

• INCLUDES: (#include "msp430x16x.h"). Ficheros externos a añadir al programa.


Suele ser necesario añadir, al menos, el fichero que contiene las definiciones
de las direcciones de los registros y programación de periféricos 
"msp430xMMx.h" donde “MM” es el modelo de micro empleado. Nosotros usaremos

MM=16.

• PROGRAMA PRINCIPAL: Rutina que define el funcionamiento inicial del


sistema; el estado de las variables; programación de periféricos; y actividades
“normales” que ejecuta el sistema (frecuentemente la actividad normal es “no
hacer nada” hasta que llegue una interrupción). Partes principales:

o ORG DIRFLASH: Indica donde vamos a colocar el código del programa


principal en memoria. DIRFLASH debe ser una dirección de FLASH,
generalmente baja. Hay que mirar en el mapa de memoria del micro. En
el MSP430F169, la FLASH ocupa desde 1100h hasta 0FE00h. Una
buena elección sería 1100h ó 1200h (si se quiere dejar algo de espacio
al principio).

o Instrucciones iniciales imprescindibles:

1. Inicialización base de pila: move #dirRAM,SP. Donde dirRAM es


una dirección de memoria RAM, que depende del tamaño
máximo de la pila. Para una pila de tamaño máximo M, poner
dirRAM  #200h+M, ya que 200h es la primera dirección RAM.
Se recomienda colocar una etiqueta (por ejemplo Main) en la
primera instrucción del programa.

2. Desactivación WATCHDOG (no es necesario en el simulador).


Tras un RESET, el WATCHDOG arranca activo con una cuenta
de 32ms, provocando un nuevo RESET si no se para antes. La
instrucción mov.w #WDTPW+WDTHOLD, &WDTCTL ; Desactiva WDT

desactiva el WDT.

o A partir de aquí el código dependerá de los periféricos y/o variables que


se usen en la aplicación; se suele colocar el código de configuración y
puesta en marcha de los periféricos usados (por ejemplo, mov
#TASSEL_2+MC_2+ID_3,&TACTL arrancaría el TIMERA en modo continuo
controlado por el reloj SMCLK a frecuencia tras RESET (800KHz) pero
dividida entre 8). También es aconsejable dar un valor inicial a las

2
variables que se vayan a utilizar (clr variable1 ó mov.b #50,variable2, por
ejemplo).

o Si la aplicación no se basa en interrupciones para su funcionamiento, a


continuación iría el código que determina lo que hace el programa
(buscar un dato en una tabla, sumar datos, copiar un programa a una
zona de memoria, etc…), y acabaría en una instrucción con un bucle sin
fin (fin jmp fin). El bucle sin fin es necesario para evitar que la CPU siga
recorriendo la memoria buscando instrucciones donde no hemos
colocado nada.

o Si la aplicación se basa en interrupciones, hay dos opciones:

1. Habilitar interrupciones (eint), y dejar el programa en un bucle sin


fin, en espera de interrupciones (fin jmp fin);

2. Poner al sistema en modo de bajo consumo (CPU parada), y


habilitar interrupciones. En este caso no hace falta bucle sin fin,
ya que la CPU se “congela” hasta que llegue una interrupción.
Esto se consigue con la instrucción bis #CPUOFF+GIE,SR

o dos instrucciones consecutivas eint , bis #CPUOFF,SR . La

instrucción que viene después (nop) solo tiene como objetivo la


colocación de puntos de ruptura y similares en modo
depuración.

El segundo método tiene como ventaja que la CPU no consume nada


(al estar parada), mientras espera la llegada de una interrupción.
Cuando llega la interrupción, saca a la CPU de su estado, acude a la
rutina de atención a la interrupción (RTI/ISR), la ejecuta completamente
y vuelve a entrar en estado de espera, con la CPU parada y las
interrupciones habilitadas.

La única ventaja del primera vendría cuando deseamos que la CPU


ejecute instrucciones mientras espera la llegada de interrupciones, algo
que no podría hacer en el primer caso.

• SUBRUTINAS: Son grupos de instrucciones que se tienen que ejecutar en


muchos lugares del código. Para reducir el tamaño de este, solo se escriben
una vez y se llaman, desde donde se deseen usar, con call #subrutinaX . La

subrutina debe empezar con la etiqueta subrutinaXa antes de la primera


instrucción de ésta. Cada subrutina tiene que terminar con la instrucción ret ,
que vuelve al programa principal, a la instrucción posterior a la llamada call.

• RUTINAS DE TRATAMIENTO DE INTERRUPCIÓN (RTI) o ISR (Interrupt


Server Routine). Son subprogramas que indican la respuesta del sistema ante
la llegada de una interrupción. Se debe definir su inicio con una etiqueta (por

3
ejemplo, RTI_TIMERA0), y esta etiqueta colocarse en el vector de interrupción
de la interrupción a la que responde la RTI. Esto se hace con la directiva ORG
FFFEh+OFFSET seguido de la directiva DW ETIQUETA_RTI. OFFSET está
relacionado con el origen de la interrupción a la que se asocie la etiqueta;
normalmente hay unos nombres definidos en el fichero “msp430x16x.h” , por
ejemplo “PORT1_VECTOR” para el puerto 1, RESET_VECTOR para la int de
RESET, TIMERA0_VECTOR para la 1era int. del TIMERA…..

Por ejemplo, ORG FFFEh+PORT1_VECTOR

DW RTI_PORT1

Definiría que la rutina que empieza en la etiqueta RTI_PORT1, se llamará


cuando se produzca una interrupción del puerto 1.

Las RTI/ISR deben finalizar con la instrucción reti.

• DEFINICION DE VARIABLES. (Hay gente que coloca esta sección antes incluso
del programa principal). ORG DirRAM para que las variables estén colocadas en
memoria RAM. Cuidado con no solapar la zona de variables con la pila!!
Recordad además que la pila crece hacia direcciones mas bajas y las variables
se definen hacia direcciones mas altas, por eso colocar la pila desde la dirección
280h, y las variables en la 200h sería una mala idea…..Para definir una variable
utilizar la directiva DCXX valor(con XX=16 para una Word y XX=8 para un byte, y
valor el valor inicial de la variable). Se recomienda colocar una etiqueta y acceder
a la variable mediante esa etiqueta. (por ejemplo, contador DC16 50, define una
variable contador con un valor inicial de 50 ). Se pueden definir varias variables
vacías de golpe con DS.X num (con X=W para num variables tamaño WORD, y
X=B para num variables tamaño BYTE) Si colocamos una etiqueta, podremos
acceder a la primera variable definida a través de ella, para acceder al resto de
variables se puede usar el modo de direccionamiento indexado.

• VECTORES DE INTERRUPCIÓN: Es necesario definir vectores para todas las


interrupciones que pensemos utilizar en el programa (al menos siempre para la
int RESET!). Permiten asociar una RTI a una interrupción (ver apartado RTI).

• END: Siempre es necesario colocarlo al final del código. Cualquier cosa que
aparezca después no será tenida en cuenta.

Ignacio Herrero Reder, Octubre 2007, v1.0

S-ar putea să vă placă și