28.11.2014 Views

Compilación de programas en lenguaje C para el microcontrolador ...

Compilación de programas en lenguaje C para el microcontrolador ...

Compilación de programas en lenguaje C para el microcontrolador ...

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Compilación <strong>de</strong> <strong>programas</strong> <strong>en</strong> l<strong>en</strong>guaje C <strong>para</strong> <strong>el</strong> <strong>microcontrolador</strong><br />

AVR<br />

1. Com<strong>en</strong>zando<br />

Las herrami<strong>en</strong>tas <strong>de</strong> <strong>de</strong>sarrollo <strong>de</strong> aplicaciones provi<strong>en</strong><strong>en</strong> <strong>de</strong> GNU y funcionan <strong>en</strong> Linux. Para arrancar este<br />

sistema operativo <strong>en</strong> los or<strong>de</strong>nadores <strong>de</strong>l laboratorio hay que esperar que arranqu<strong>en</strong> <strong>de</strong> la red (pue<strong>de</strong>n tardar<br />

unos 20 seg.) y luego, <strong>en</strong> <strong>el</strong> m<strong>en</strong>ú que se muestra s<strong>el</strong>eccionar “3) Linux”.<br />

Tras <strong>el</strong> arranque <strong>de</strong> Linux hay que <strong>en</strong>trar <strong>en</strong> la cu<strong>en</strong>ta <strong>de</strong> prácticas:<br />

Login: **********<br />

Password: *******<br />

D<strong>en</strong>tro <strong>de</strong> la cu<strong>en</strong>ta <strong>de</strong> prácticas cada grupo t<strong>en</strong>drá su propio subdirectorio.<br />

Este es un listado <strong>de</strong> las herrami<strong>en</strong>tas <strong>de</strong> <strong>de</strong>sarrollo y otras aplicaciones útiles:<br />

avr-gcc: compilador <strong>de</strong> C <strong>para</strong> AVR.<br />

avr-as: <strong>en</strong>samblador <strong>para</strong> AVR.<br />

avr-ld: linker.<br />

avr-objcopy: conversor <strong>de</strong> formatos <strong>de</strong> ficheros ejecutables.<br />

avr-objdump: <strong>de</strong>s<strong>en</strong>samblador <strong>para</strong> AVR.<br />

make: gestor <strong>de</strong> proyectos.<br />

avrprg: programador <strong>para</strong> <strong>el</strong> prototipo <strong>de</strong>l <strong>microcontrolador</strong> (<strong>de</strong>fecto: COM1)<br />

terminal: terminal <strong>para</strong> <strong>el</strong> puerto serie (<strong>de</strong>fecto: COM2, 9600 baudios)<br />

nedit: editor <strong>de</strong> texto <strong>para</strong> <strong>programas</strong> <strong>en</strong> C.<br />

1


2. Programa <strong>de</strong> ejemplo<br />

En <strong>el</strong> directorio “ejemplo” hay un conjunto <strong>de</strong> ficheros que mustran <strong>de</strong> forma básica como g<strong>en</strong>erar imág<strong>en</strong>es<br />

<strong>de</strong> memoria <strong>para</strong> <strong>el</strong> <strong>microcontrolador</strong> AVR a partir <strong>de</strong> código fu<strong>en</strong>te <strong>en</strong> C y <strong>en</strong> <strong>en</strong>samblador. Para compilar <strong>el</strong><br />

programa <strong>de</strong> ejemplo <strong>en</strong> primer lugar copiaremos los ficheros a otro directorio y luego siemplem<strong>en</strong>te ejecutaremos<br />

<strong>el</strong> comando “make”. Los ficheros <strong>de</strong>l ejemplo son:<br />

main.c: programa <strong>en</strong> C que incluye la función “main”.<br />

Makefile: <strong>de</strong>p<strong>en</strong><strong>de</strong>ncias y control <strong>de</strong> la compilación.<br />

El proceso <strong>de</strong> la compilación queda repres<strong>en</strong>tado <strong>de</strong> forma gráfica <strong>en</strong> la sigui<strong>en</strong>te figura:<br />

inicialización<br />

linker−script<br />

código fu<strong>en</strong>te<br />

main.c<br />

avr−gcc<br />

crts2313.o<br />

objeto ELF<br />

main.o<br />

avr2.x<br />

ejecutable ELF<br />

avr−ld<br />

avr−objcopy<br />

co<strong>de</strong>.<strong>el</strong>f<br />

ejecutable<br />

hexa<strong>de</strong>cimal<br />

(int<strong>el</strong>−hex)<br />

co<strong>de</strong>.ihx<br />

cabeceras<br />

io.h<br />

interrupt.h<br />

librerías<br />

libgcc.a<br />

libc.a<br />

ld.map<br />

mapa <strong>de</strong> memoria<br />

En la compilación intervi<strong>en</strong><strong>en</strong> tanto nuestro código fu<strong>en</strong>te como otros ficheros que se <strong>en</strong>cu<strong>en</strong>tran conv<strong>en</strong>i<strong>en</strong>tem<strong>en</strong>te<br />

instalados <strong>en</strong> <strong>el</strong> servidor. Estos últimos son los ficheros <strong>de</strong> cabecera, las librerías <strong>de</strong>l gcc (libgcc.a) y<br />

estándar (libc.a), <strong>el</strong> código <strong>de</strong> inicialización <strong>de</strong>l programa (crts2313.o) y <strong>el</strong> “linker-script” (avr2.x) que controla<br />

<strong>el</strong> proceso <strong>de</strong> <strong>en</strong>lazado. Las <strong>de</strong>p<strong>en</strong><strong>de</strong>ncias <strong>en</strong>tre ficheros y los comandos que se han <strong>de</strong> ejecutar <strong>para</strong> g<strong>en</strong>erarlos<br />

están <strong>de</strong>tallados <strong>en</strong> <strong>el</strong> fichero “Makefile”, que conti<strong>en</strong>e líneas como las sigui<strong>en</strong>tes:<br />

ACFLAGS = -Os -mmcu=at90s2313<br />

OBJS = main.o<br />

En estas líneas se <strong>de</strong>fin<strong>en</strong> algunas variables que se utilizarán a continuación. En particular la variable ACFLAGS<br />

conti<strong>en</strong>e las opciones que se pasarán al compilador “avr-gcc”, tales como <strong>el</strong> niv<strong>el</strong> <strong>de</strong> optimización (-Os) y <strong>el</strong><br />

mo<strong>de</strong>lo <strong>de</strong>l <strong>microcontrolador</strong> <strong>para</strong> <strong>el</strong> que se va a g<strong>en</strong>erar <strong>el</strong> código (-mmcu=at90s2313). La variable OBJS<br />

conti<strong>en</strong>e una lista <strong>de</strong> los ficheros objeto que intervi<strong>en</strong><strong>en</strong> <strong>en</strong> la compilación. En este caso tan sólo hay un fichero<br />

objeto (main.o).<br />

2


co<strong>de</strong>.ihx:(tab) co<strong>de</strong>.<strong>el</strong>f<br />

(tab)<br />

avr-objcopy -O ihex $< $@<br />

En estas líneas se indica que “co<strong>de</strong>.ihx” se obti<strong>en</strong>e a partir <strong>de</strong> “co<strong>de</strong>.<strong>el</strong>f” y que <strong>el</strong> comando que hay que ejecutar<br />

<strong>para</strong> g<strong>en</strong>erar “co<strong>de</strong>.ihx” es “avr-objcopy ...”. Las variables “$


• -O0 : sin optimización.<br />

• -O1 : optimización <strong>de</strong> transfer<strong>en</strong>cias <strong>en</strong>tre registros.<br />

• -O2 : más optimizaciones.<br />

• -O3 : a<strong>de</strong>más se incluy<strong>en</strong> funciones como “inline”<br />

• -Os : optimización <strong>para</strong> reducir <strong>el</strong> espacio <strong>de</strong> memoria ocupado por <strong>el</strong> código.<br />

-mmcu=: S<strong>el</strong>ecciona <strong>el</strong> conjunto <strong>de</strong> instrucciones a<strong>de</strong>cuado <strong>para</strong> <strong>el</strong> tipo <strong>de</strong> <strong>microcontrolador</strong><br />

especificado.<br />

-Wl,,,... : Permite pasar opciones al linker.<br />

avr-ld<br />

-T : Indica <strong>el</strong> fichero que se usará <strong>para</strong> controlar <strong>el</strong> proceso <strong>de</strong> <strong>en</strong>lazado. En este<br />

fichero se <strong>de</strong>talla la organización <strong>de</strong> la memoria.<br />

-Map : g<strong>en</strong>era un listado <strong>de</strong>l mapa <strong>de</strong> memoria <strong>en</strong> <strong>el</strong> fichero indicado.<br />

avr-objcopy<br />

-O : indica <strong>el</strong> formato <strong>de</strong>l fichero <strong>de</strong> salida (<strong>el</strong> fichero <strong>de</strong> <strong>en</strong>trada está <strong>en</strong> formato ELF). Los<br />

formatos que nos pue<strong>de</strong>n interesar son:<br />

• srec : Formato hexa<strong>de</strong>cimal <strong>de</strong> Motorola.<br />

• ihex : Formato hexa<strong>de</strong>cimal <strong>de</strong> Int<strong>el</strong>.<br />

• binary : Imag<strong>en</strong> <strong>de</strong> la memoria <strong>en</strong> binario.<br />

avr-objdump<br />

-d : <strong>de</strong>s<strong>en</strong>samblar secciones <strong>de</strong> código <strong>de</strong>l fichero objeto o ejecutable ELF que se indique.<br />

-D: <strong>de</strong>s<strong>en</strong>samblar todas las secciones <strong>de</strong>l fichero.<br />

4. Particularida<strong>de</strong>s <strong>de</strong>l compilador GCC <strong>para</strong> AVR<br />

Tipos <strong>de</strong> datos:<br />

Las longitu<strong>de</strong>s <strong>de</strong> los tipos <strong>de</strong> datos <strong>para</strong> avr-gcc son:<br />

4


Tipo <strong>de</strong> dato<br />

char<br />

short<br />

int<br />

long<br />

float<br />

double<br />

Longitud<br />

8 bits<br />

16 bits<br />

16 bits<br />

32 bits<br />

32 bits<br />

32 bits<br />

Las variables <strong>de</strong> coma flotante aunque estén soportadas por <strong>el</strong> compilador no son nada recom<strong>en</strong>dables, ya<br />

que su uso requiere incluir <strong>en</strong> <strong>el</strong> programa las rutinas <strong>de</strong> emulación <strong>de</strong> coma flotante <strong>de</strong> “libgcc.a”, que ocupan<br />

mucha memoria.<br />

Modificadores<br />

volatile<br />

Este modificador indica que la variable a la que hace refer<strong>en</strong>cia pue<strong>de</strong> modificarse por causas aj<strong>en</strong>as al<br />

programa, y por lo tanto <strong>el</strong> compilador no <strong>de</strong>be optimizar sus accesos a dichas variables. Este modificador <strong>de</strong>be<br />

usarse, por ejemplo, cuando se acce<strong>de</strong> a los registros <strong>de</strong> los periféricos, o cuando una variable pue<strong>de</strong> modificarse<br />

<strong>de</strong>s<strong>de</strong> una rutina <strong>de</strong> interrupción.<br />

Ejemplo:<br />

dato=*(volatile unsigned char *)0x30; // lectura <strong>de</strong> PIND<br />

En la dirección 0x30 está <strong>el</strong> puerto <strong>de</strong> E/S PIND y su valor <strong>de</strong>p<strong>en</strong><strong>de</strong> <strong>de</strong> las t<strong>en</strong>siones aplicadas a los pines <strong>de</strong>l<br />

<strong>microcontrolador</strong>. Por lo tanto <strong>el</strong> puntero a dicha dirección <strong>de</strong> memoria se <strong>de</strong>be <strong>de</strong>clarar como “volatile”.<br />

inline, extern inline<br />

Si una función se <strong>de</strong>clara como “inline” <strong>el</strong> compilador no g<strong>en</strong>era llamadas a la subrutina <strong>de</strong> dicha función.<br />

En su lugar <strong>el</strong> código <strong>de</strong> la función se inserta <strong>en</strong> cada ocasión <strong>en</strong> la que se llama a la función <strong>en</strong> <strong>el</strong> programa.<br />

Esto pue<strong>de</strong> hacer los <strong>programas</strong> más largos, pero más rápidos al evitar los tiempos <strong>de</strong> llamada y retorno <strong>de</strong><br />

subrutinas. Este modificador es particularm<strong>en</strong>te útil con funciones muy cortas. Cuando la función <strong>en</strong> cuestión<br />

se <strong>de</strong>clara como “inline” todavía se g<strong>en</strong>era una subrutina por si acaso es llamada <strong>de</strong>s<strong>de</strong> otros ficheros objeto<br />

que se puedan <strong>en</strong>lazar con <strong>el</strong> programa. Esto se evita <strong>de</strong>fini<strong>en</strong>do la función como “extern inline”. En este caso<br />

no se g<strong>en</strong>era dicha subrutina.<br />

5


Código <strong>en</strong> <strong>en</strong>samblador<br />

En los <strong>programas</strong> <strong>en</strong> C se pue<strong>de</strong> insertar directam<strong>en</strong>te código <strong>en</strong> <strong>en</strong>samblador mediante la palabra clave<br />

“asm” o “asm volatile”. Ejemplo:<br />

asm volatile (“sei”);<br />

// Habilitamos interrupciones<br />

El modificador “volatile“ fuerza al compilador a insertar nuestro código exactam<strong>en</strong>te <strong>en</strong> la parte <strong>de</strong>l programa<br />

<strong>en</strong> la que se <strong>en</strong>cu<strong>en</strong>tra. El comando “asm” es mucho más sofisticado y permite <strong>el</strong> paso <strong>de</strong> parámetros <strong>en</strong>tre <strong>el</strong><br />

código <strong>en</strong> C y <strong>en</strong> <strong>en</strong>samblador, como ocurre <strong>en</strong> <strong>el</strong> ejemplo sigui<strong>en</strong>te:<br />

a=100; b=20;<br />

asm volatile ("swap %0\n\tadd %0, %1":"+r"(b):"r"(a));<br />

que <strong>el</strong> compilador convierte <strong>en</strong>:<br />

ldi r24,lo8(100)<br />

ldi r25,lo8(20)<br />

swap r25<br />

add r25,r24<br />

don<strong>de</strong> vemos que las variables “a” y “b” han sido almac<strong>en</strong>adas <strong>en</strong> los registros “r24” y “r25”. La sintaxis <strong>de</strong> la<br />

línea “asm” es como sigue:<br />

asm volatile (“código <strong>en</strong>samblador” : parámetros <strong>de</strong> salida : parámetros <strong>de</strong> <strong>en</strong>trada);<br />

Don<strong>de</strong>, <strong>en</strong> <strong>el</strong> código <strong>en</strong> <strong>en</strong>samblador hacemos refer<strong>en</strong>cia a los parámetros como “ %0” <strong>para</strong> <strong>el</strong> primero <strong>de</strong><br />

las listas, “ %1” <strong>para</strong> <strong>el</strong> sigui<strong>en</strong>te y así sucesivam<strong>en</strong>te. Las listas <strong>de</strong> parámetros <strong>de</strong> <strong>en</strong>trada y/o salida se <strong>de</strong>fin<strong>en</strong><br />

como:<br />

“modificadores” (variable), “modificadores” (variable)....<br />

Los modificadores indican:<br />

“=” : se sobreescribe la variable.<br />

“+” : se lee y modifica.<br />

“r” : la variable resi<strong>de</strong> <strong>en</strong> un registro.<br />

“m” : la variable es una posición <strong>de</strong> memoria.<br />

“i” : la variable es un operando inmediato (constante).<br />

6


Funciones <strong>de</strong> interrupción<br />

Las funciones <strong>de</strong> interrupción son especiales ya que están concebidas como manejadores <strong>de</strong> interrupciones.<br />

Esto significa que difier<strong>en</strong> <strong>de</strong> las funciones normales <strong>en</strong> los sigui<strong>en</strong>tes aspectos:<br />

Guardan todos los registros que modifican <strong>en</strong> la pila, incluy<strong>en</strong>do SREG, al comi<strong>en</strong>zo <strong>de</strong> la función.<br />

Recuperan los valores originales <strong>de</strong> los registros <strong>de</strong> la pila al finalizar la función.<br />

Retornan con la instrucción “RETI”.<br />

Para que una función actúe como rutina <strong>de</strong> at<strong>en</strong>ción a una interrupción se <strong>de</strong>be <strong>de</strong>clarar mediante la macro<br />

ISR() tal y como se muestra <strong>en</strong> <strong>el</strong> ejemplo:<br />

ISR(TIMER0_OVF0_vect)<br />

{<br />

nirqs++;<br />

}<br />

La macro ISR <strong>de</strong>l ejemplo proporciona un manejador <strong>de</strong> interrupciones <strong>para</strong> <strong>el</strong> <strong>de</strong>sbordami<strong>en</strong>to <strong>de</strong>l temporizador<br />

“TIMER0”. Este manejador lo único que hace es increm<strong>en</strong>tar una variable global <strong>de</strong>l programa. Las<br />

funciones <strong>de</strong> interrupción no ti<strong>en</strong><strong>en</strong> parámetros ni <strong>de</strong>vu<strong>el</strong>v<strong>en</strong> resultados. Des<strong>de</strong> estas funciones no se <strong>de</strong>be<br />

llamar a ninguna otra función <strong>de</strong>l programa pues se podría alterar <strong>el</strong> valor <strong>de</strong> algún registro que no ha sido<br />

previam<strong>en</strong>te guardado <strong>en</strong> la pila.<br />

Los nombres <strong>de</strong> los manejadores <strong>de</strong> interrupción <strong>de</strong>p<strong>en</strong><strong>de</strong>n <strong>de</strong>l <strong>microcontrolador</strong>. Para <strong>el</strong> at90s2313 son los<br />

sigui<strong>en</strong>tes:<br />

Nombre <strong>de</strong>l Manejador<br />

N o <strong>de</strong>l vector<br />

INT0_vect 1<br />

INT1_vect 2<br />

TIMER1_CAPT1_vect 3<br />

TIMER1_COMP1_vect 4<br />

TIMER1_OVF1_vect 5<br />

TIMER0_OVF0_vect 6<br />

UART_RX_vect 7<br />

UART_UDRE_vect 8<br />

UART_TX_vect 9<br />

ANA_COMP_vect 10<br />

7


Como recom<strong>en</strong>daciones g<strong>en</strong>erales <strong>para</strong> la escritura <strong>de</strong>l código <strong>de</strong> rutinas <strong>de</strong> interrupción po<strong>de</strong>mos <strong>de</strong>stacar:<br />

No llamar a otras funciones <strong>de</strong>s<strong>de</strong> una rutina <strong>de</strong> interrupción.<br />

Recordar <strong>de</strong>clarar como “volatile” todas las variables globales que modifique la rutina <strong>de</strong> interrupción.<br />

No hacer retardos <strong>de</strong>ntro <strong>de</strong> una rutina <strong>de</strong> interrupción. Evitar los bucles.<br />

Cuando una rutina <strong>de</strong> interrupción modifique una variable <strong>de</strong> 16 o 32 bits hay que garantizar un acceso<br />

atómico a dicha variable <strong>en</strong> <strong>el</strong> programa principal, lo que implica:<br />

• Apagar las interrupciones: cli();<br />

• Leer la variable: valor=var_global;<br />

• Activar las interrupciones: sei();<br />

Si la rutina <strong>de</strong> interrupción acce<strong>de</strong> a algún registro <strong>de</strong> E/S <strong>de</strong> 16 bits <strong>de</strong>l temporizador también hay<br />

que garantizar un acceso atómico <strong>de</strong>s<strong>de</strong> <strong>el</strong> programa principal a TODOS los registros <strong>de</strong> 16 bits <strong>de</strong><br />

temporizador. Ello se <strong>de</strong>be a que la interrupción pue<strong>de</strong> alterar <strong>el</strong> valor <strong>de</strong> un registro temporal <strong>de</strong> 8 bits<br />

que se usa <strong>para</strong> sincronizar <strong>el</strong> acceso a la parte alta <strong>de</strong>l dato <strong>de</strong> 16 bits.<br />

Acceso a registros <strong>de</strong> E/S<br />

Los registros <strong>de</strong> <strong>en</strong>trada y salida <strong>de</strong>l AVR 90S2313 están <strong>de</strong>finidos <strong>en</strong> <strong>el</strong> fichero <strong>de</strong> cabecera “”. El<br />

cont<strong>en</strong>ido <strong>de</strong> este fichero varía <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do <strong>de</strong>l mo<strong>de</strong>lo <strong>de</strong> <strong>microcontrolador</strong> que se especifice <strong>en</strong> la compilación<br />

(avr-gcc -mmcu=....). Los registros están <strong>de</strong>findos como posiciones fijas <strong>de</strong> la memoria <strong>de</strong> datos, tal y como se<br />

muestra <strong>en</strong> <strong>el</strong> ejemplo sigui<strong>en</strong>te:<br />

#<strong>de</strong>fine UBRR (*(volatile unsigned char *)0x29)<br />

Por lo tanto, <strong>en</strong> nuestros <strong>programas</strong>, los nombres <strong>de</strong> los registros <strong>de</strong> E/S <strong>de</strong> <strong>microcontrolador</strong> repres<strong>en</strong>tan a<br />

variables a las que se pue<strong>de</strong>n asignar valores y que pue<strong>de</strong>n interv<strong>en</strong>ir <strong>en</strong> expresiones aritméticas y logicas. El<br />

compilador es sufici<strong>en</strong>tem<strong>en</strong>te int<strong>el</strong>ig<strong>en</strong>te <strong>para</strong> convertir las refer<strong>en</strong>cias a dichas variables <strong>en</strong> instrucciones “IN”<br />

y “OUT”, como <strong>en</strong> <strong>el</strong> sigui<strong>en</strong>te ejemplo:<br />

UBRR=64;<br />

que se compila como:<br />

ldi r24,0x40<br />

out 0x09,r24<br />

8


También <strong>el</strong> compilador pue<strong>de</strong> <strong>de</strong>tectar un cambio <strong>de</strong> un único bit <strong>en</strong> estas variables y utilizar las instrucciones<br />

<strong>de</strong> manejo <strong>de</strong> bit SBI/CBI, como <strong>en</strong> este ejemplo:<br />

PORTD|=(1<


prog_int16_t <strong>de</strong>f_val[3]={1234,4237,25315};<br />

prog_int32_t <strong>de</strong>f_val32[4]={1234567,10000000,99999999,87654321};<br />

...<br />

int val;<br />

long v32;<br />

val=__LPM_word(&<strong>de</strong>f_val[1]);<br />

val=pgm_read_word(&<strong>de</strong>f_al[1]);<br />

// val=4237<br />

// sinónimo<br />

v32=__LPM_dword(&<strong>de</strong>f_val32[2]); // v32=99999999<br />

v32=pgm_read_dword(&<strong>de</strong>f_val32[2]);<br />

//sinónimo<br />

Organización <strong>de</strong> la memoria<br />

La memoria <strong>en</strong> los <strong>programas</strong> compilados con gcc queda organizada <strong>en</strong> secciones, como se muestra <strong>en</strong> la<br />

sigui<strong>en</strong>te figura:<br />

0x7ff<br />

memoria <strong>de</strong><br />

programa<br />

Libre<br />

0xdf<br />

memoria <strong>de</strong><br />

datos<br />

Pila<br />

.data<br />

se copia<br />

al arrancar<br />

Libre<br />

.text<br />

_<strong>en</strong>d<br />

.bss<br />

0x0<br />

.progmem<br />

.init<br />

0x60<br />

.data<br />

regs. E/S, CPU<br />

Cada sección conti<strong>en</strong>e un tipo distinto <strong>de</strong> datos. Estos son:<br />

.init : tabla <strong>de</strong> saltos <strong>de</strong> interrupciones y código <strong>de</strong> inicialización.<br />

.progmem : Constantes <strong>en</strong> la memoria <strong>de</strong> programa.<br />

.text : Código <strong>de</strong>l programa.<br />

.data : Valores iniciales <strong>de</strong> variables estáticas inicializadas. Estos valores son copiados a la RAM antes<br />

<strong>de</strong> llamar a la función “main”.<br />

.bss : variables estáticas sin inicializar. Su valor inicial es 0.<br />

El símbolo “_<strong>en</strong>d” nos indica la primera posición libre <strong>de</strong> la memoria RAM.<br />

10


Uso <strong>de</strong> los registros<br />

Paso <strong>de</strong> parámetros <strong>en</strong> funciones <strong>de</strong>l l<strong>en</strong>guaje C.<br />

f() : función que se llama <strong>de</strong>s<strong>de</strong> <strong>el</strong> programa<br />

p8<br />

: parámetro <strong>de</strong> 8 bits (char), (short)<br />

p16 : parámetro <strong>de</strong> 16 bits (int), punteros<br />

p32 : parámetro <strong>de</strong> 32 bits (long)<br />

Ejemplos <strong>de</strong> asignación <strong>de</strong> registros a parámetros (or<strong>de</strong>n <strong>de</strong> los parámetros: f(pr1,pr2,pr3,...);):<br />

Param. 1 Param. 2 Param. 3 Param. 4<br />

f(p8)<br />

R24<br />

f(p8,p8,p8,p8) R24 R22 R20 R18<br />

f(p16,p16) R25:R24 ◦ R23:R22<br />

f(p16,p16,p16) R25:R24 R23:R22 R21:R20<br />

f(p32,p32) R25:R24:R23:R22 ◦ R21:R20:R19:R18<br />

f(p32,p32,p32) R25:R24:R23:R22 R21:R20:R19:R18 R17:R16:R15:R14<br />

f(p8,p16,p32) R24 R23:R22 R21:R20:R19:R18<br />

f(p32,p16,p8) R25:R24:R23:R22 R21:R20 R18<br />

◦ MSB izq, LSB <strong>de</strong>r.<br />

Como po<strong>de</strong>mos ver los parámetros se asocian a registros <strong>de</strong> modo que su byte m<strong>en</strong>os significativo queda<br />

siempre <strong>en</strong> un registro par.<br />

Valor <strong>de</strong> retorno (si lo hubiese):<br />

p8


Registro Uso (código C) Acción<br />

R0 temporal Se pue<strong>de</strong> cambiar<br />

R1 valor 0 Debe valer 0 al retornar<br />

R2-R17 variables Se <strong>de</strong>b<strong>en</strong> PRESERVAR<br />

R18-R25 variables/parámetros Se pue<strong>de</strong>n cambiar<br />

R26:R27 Puntero X Se pue<strong>de</strong>n cambiar<br />

R28:R29 Puntero Y Se <strong>de</strong>b<strong>en</strong> PRESERVAR<br />

R30:R31 Puntero Z Se pue<strong>de</strong>n cambiar<br />

Los registros marcados como "se pue<strong>de</strong> cambiar" pue<strong>de</strong>n usarse <strong>en</strong> subrutinas escritas <strong>en</strong> l<strong>en</strong>guaje <strong>en</strong>samblador<br />

como varables temporales y su valor inicial no necesita ser recuperado antes <strong>de</strong> retornar.<br />

Al compilador avr-gcc se le pue<strong>de</strong> instruir <strong>para</strong> que no utilice <strong>de</strong>terminados registros a la hora <strong>de</strong> g<strong>en</strong>erar <strong>el</strong><br />

código. Esto se hace mediante opciones <strong>de</strong>l tipo “gcc -avr -mmcu=at90s2313 -ffixed-r3 -ffixed-r4 ...”. En este<br />

ejemplo <strong>el</strong> compilador nos garantiza que no utilizará los registros R3 y R4. Eso no significa que no se utilic<strong>en</strong><br />

<strong>en</strong> algunas funciones <strong>de</strong> librería, así que esta opción <strong>de</strong>be usarse con cuidado.<br />

12

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!