Sie sind auf Seite 1von 27

CeTAD Facultad de Ingeniera - UNLP

Cdigo C Eficiente para Sistemas Embebidos y Software Codewarrior


(Basado en el Compilador de Freescale)

Ctedra de Circuitos digitales y Microprocesadores

Autores: Ing. Jorge R. Osio Ing. Walter Arztegui Ing. Jos A. Rapallini Octubre de 2011
Cdigo C Eficiente para Sistemas Embebidos

Versin 2.0
Pgina 1

INDICE.

1. Cdigo C Eficiente para Sistemas Embebidos...3


1.1. Compilador de Cdigo C a Cdigo de Mquina
1.1.1. Creacin de Cdigo C eficiente para el MC68HC08 1.1.1.1. Modelo del Registro de la CPU08 1.1.1.2. Tipos de datos Bsicos 1.1.1.3. Variables locales Vs variables Globales 1.1.1.4. Variables de Pgina directa 1.1.1.5. Bucles 1.1.1.6. Estructuras de datos 1.1.1.7. Ejemplos
1.1.1.7.1. Registro 1 1.1.1.7.2. Copia de datos 1 1.1.1.7.3. Copia de datos 2 1.1.1.7.4. Copia de datos 3 1.1.1.7.5. Bucle

1.1.2. Estructura de un programa en C

2.

Software CodeWarrior......12
2.1. Creacin de Proyectos12 2.2. Generacin de cdigo mediante Processor Expert..15 2.3. Compilacin y Emulacin en Tiempo real ..20

3.

Interrupciones en Lenguaje C...24


3.1. La directiva #pragma TRAP_PROC...24 3.2. La instruccin interrupt26

Cdigo C Eficiente para Sistemas Embebidos

Pgina 2

1. Cdigo C Eficiente para Sistemas Embebidos 1.1. Compilador de Cdigo C a Cdigo de Mquina
1.1.1. Creacin de Cdigo C eficiente para el MC68HC08
Comparado con los otros microprocesadores la Arquitectura del HC908 se adapta bien al lenguaje de programacin en C. Tiene un conjunto de instrucciones efectivas con modos de direccionamiento que permiten la eficiente implementacin de instrucciones en C. El conjunto de instrucciones incluye instrucciones para el manejo del puntero de pila. Los modos de direccionamiento, incluyen direccionamiento indexado, modos con el ndice incluido y el registro ndice o el registro de puntero de pila. Estas caractersticas permiten acceso eficiente a variables locales. El lenguaje C es ideal para crear un programa para el micro HC08 [1], pero para producir el cdigo de mquina mas eficiente, el programador debe construir el programa cuidadosamente. En este contexto Cdigo Eficiente significa tamao de cdigo compacto y rpido tiempo de ejecucin. A continuacin se detallan algunas sugerencias y consejos para ayudar al programador a escribir cdigo C de manera que un compilador pueda convertirlo en cdigo de maquina eficiente.

1.1.1.1. Modelo del Registro de la CPU08


Para visualizar mejor los consejos en la figura 1 se detalla el modelo de registro del HC08.

Figura 1. Modelo del Registro del CPU08 Acumulador: El acumulador es un registro de 8 bits de propsito general. La CPU lo usa para almacenar los operando o resultados de operaciones. Registro ndice: El registro ndice de 16 bits es llamado H:X y es usado por los modos de direccionamiento indexado para determinar la direccin efectiva de un operando. El registro indice puede acceder a 64 Kbytes de espacios de Pgina 3

Cdigo C Eficiente para Sistemas Embebidos

direcciones en este modo. El byte mas bajo X se usa para almacenar el operando para la multiplicacin y divisin de instrucciones. H:X para el almacenamiento de la ubicacin de datos temporarios. Puntero de Pila: Los 16 bits del puntero de pila se usan para almacenar la direccin de la prxima ubicacin disponible sobre la pila. La CPU usa el contenido del registro del puntero de pila como un ndice para acceder a operandos sobre la pila en modos de direccionamiento offset de puntero de pila. La pila puede se ubicada en cualquier direccin donde hay RAM en los 64 K bytes de espacio de direcciones. Contador de Programa: Los 16 bits del contador de programa contienen la direccin de la prxima instruccin u operando a ser utilizado. El contador de programa puede acceder a 64 K bytes de espacio de direcciones. Registro de cdigo de condicin: Los 8 bits del registro de cdigo de condicin contienen el bit mascara de interrupcin global y 5 flags (indicadores) que indican el resultado de la instruccin que ejecutada. Los bits 5 y 6 son permanentemente sesteados a 1 lgico.

Estos registros junto con los modos de direccionamiento se encuentran bien desarrollados en el Apunte Descripcin General de un Microcontrolador (CPU) y es necesario conocerlos bien para poder aprovechar al mximo los consejos para la creacin de cdigo C eficiente.

1.1.1.2. Tipos de datos Bsicos


Los tipos de datos bsicos son los siguientes: Tipos de datos Bsicos Char Short int Int Long int Tamao 8 bits 16 bits 16 bits 32 bits Rango sin signo 0 a 255 0 a 65535 0 a 65535 0 a 4294967295 Rango con signo -128 a 127 -32768 a 32767 -32768 a 32767 -2147483648 a 2147483647

La mejor performance en tamao de cdigo y tiempo de ejecucin se puede lograr definiendo el tipo de datos mas apropiado para cada variable. Esto es apropiado para microcontroladores de 8 bits donde el tamao de datos interno natural es de 8 bits. El tipo de datos preferido en C es el int. El estndar ANSI no define precisamente el tamao de los tipos de datos naturales, pero los compiladores para microcontroladores de 8 bits implementan int como un valor de 16 bits con signo. Como los microcontroladores de 8 bits pueden procesar tipos de datos de 8 bits mas eficientemente que de 16 bits. Los tipos de datos int y long int deben ser usados, solo donde se requiere, por el tamao de datos a ser representado. Las operaciones de doble precisin y punto flotante son ineficientes y deben ser evitadas donde la eficiencia es importante. Esto quizs parece obvio, pero frecuentemente se pasa por alto y tiene un enorme impacto sobre el tamao de cdigo en tiempo de ejecucin. Como se sabe la magnitud del tipo de datos requeridos y el signo deben ser especificados. El estndar ANSI C especifica int con signo por defecto, pero el char no est definido y puede variar entre compiladores. Por lo tanto para crear cdigo portable, el tipo de datos char no debe ser usado. Y para el tipo char el signo debe ser definido explcitamente: unsigned char o signed char. Cdigo C Eficiente para Sistemas Embebidos Pgina 4

Es buena prctica crear definiciones de tipos para estos tipos de datos en un encabezado de archivo que se incluye en todos los otros archivos. Tambin vale la pena crear definiciones de tipos para todos los otros tipos de datos usados, por consistencia, y para permitir portabilidad entre compiladores. Se puede usar algo as: typedef unsigned char UINT8; typedef signed char SINT8; typedef unsigned int UINT16; typedef int SINT16; typedef unsigned long int UINT32; typedef long int SINT32; Una variable se usa en mas de una expresin, pero algunas de estas expresiones no requieren el tamao de datos completo o con signo de la variable. En este caso el ahorro se puede hacer definiendo la variable, o parte de la expresin que contiene la variable, al tipo de datos mas apropiado.

1.1.1.3. Variables locales Vs variables Globales


Las variables pueden estar clasificadas por su alcance. Las variables globales son accesibles por cualquier parte del programa y son almacenadas permanentemente en RAM. Las variables locales son accesibles slo por la funcin dentro de la cual son declaradas y son almacenadas en la pila. Las variables locales por consiguiente slo ocupan RAM mientras se ejecuta la funcin a la cual pertenecen. Su direccin absoluta no se puede determinar cuando el cdigo es compilado y conectado as es que son ubicadas en memoria relativa al puntero de pila. Para acceder a las variables locales el compilador puede usar el modo de direccionamiento del puntero de pila. Este modo de direccionamiento requiere un byte adicional y un ciclo adicional para acceder a una variable, comparado a la misma instruccin en el modo de direccionamiento indexado. Si el cdigo requiere varios accesos consecutivos a las variables locales, entonces el compilador transferir el puntero de pila al registro ndice de 16 bits y usar direccionamiento indexado en lugar de este. El acceso ' esttico ' modificado puede ser usado con variables locales. Esto causa que la variable local sea almacenada permanentemente en la memoria, como una variable global, as es que el valor de la variable es preservado entre llamados a funciones. Sin embargo la variable local esttica es slo accesible por la funcin dentro de la cual est declarada. Las variables globales son almacenadas permanentemente en memoria en una direccin absoluta determinada cuando el cdigo es conectado. La memoria ocupada por una variable global no puede ser reusada por cualquier otra variable. De cualquier manera las variables globales no estn protegidas, ya que cualquier parte del programa puede tener acceso a una variable global en cualquier momento. Esto da origen al asunto de consistencia de datos para las variables globales de ms de un simple byte de tamao. Esto quiere decir que los datos variables podran ser corrompidos si una parte de la variable proviene de un valor y el resto de la variable proviene de otro valor. Los datos inconsistentes aparecen cuando una variable global es accedida (leda o escrita) por una parte del programa y antes de que cada byte de la variable haya sido accedido el programa se interrumpe. Esto se puede deber a una interrupcin de hardware por ejemplo, o un sistema operativo, si se usa uno. Si la variable global es entonces accedida Cdigo C Eficiente para Sistemas Embebidos Pgina 5

por la rutina de interrupcin entonces pueden aparecer los datos inconsistentes. Esto se debe evitar si se desea la ejecucin confiable del programa y se logra frecuentemente deshabilitando las interrupciones al acceder a las variables globales. El acceso 'esttico' modificado tambin puede ser usado con variables globales. Esto da algn grado de proteccin a las variables como restringir el acceso a la variable para esas funciones en el archivo en el cual la variable ha sido declarada. El compilador generalmente usar el modo de direccionamiento extendido para acceder a las variables globales o el modo de direccionamiento indexado si son accedidas a travs de un puntero. El uso de variables globales generalmente no resulta significativamente ms eficiente en cdigo que las variables locales. Hay algunas excepciones limitadas para esta generalizacin, una es cuando la variable global est ubicada en la pgina directa. Sin embargo, el uso de variables globales impide que una funcin sea recursiva o entrante, y frecuentemente no hace el uso ms eficiente de RAM, lo cual es un recurso limitado en la mayora de microcontroladores. El programador por consiguiente debe hacer una eleccin meticulosa en decidir que variables definir como globales en el mbito. Las ganancias importantes en eficiencia algunas veces pueden obtenerse definiendo justamente unas pocas de las variables, ms intensivamente usadas, como globales en el ambiente, particularmente si estas variables estn ubicadas en la pgina directa.

1.1.1.4. Variables de Pgina directa


El rango de direcciones $ 0000 a $ 00FF es llamado la pgina directa, la pgina base o la pgina cero. En los microcontroladores M68HC08, la parte inferior de la pgina directa siempre contiene los registros I/O y de control y la parte superior de la pgina directa siempre contiene RAM. Despus de un reset, el puntero de pila siempre contiene la direccin $ 00FF. La pgina directa es importante porque la mayora de las instrucciones del CPU08 tienen un modo de direccionamiento directo por medio del que pueden acceder a los operandos en la pgina directa en un ciclo de reloj menos que en el modo de direccionamiento extendido. Adems la instruccin de modo de direccionamiento directo requiere un byte menos de cdigo. Algunas instrucciones altamente eficientes slo surtirn efecto con operandos de la pgina directa. Estos son: BSET, BCLR, BRSET y BRCLR. La instruccin MOV requiere que uno de los operandos est en la pgina directa. Un compilador no puede sacar ventaja del modo de direccionamiento directo eficiente a menos que las variables sean explcitamente declaradas para estar en la pgina directa. No hay en estndar ANSI modo de hacer esto y los compiladores generalmente ofrecen soluciones diferentes. El compilador hiware usa una declaracin #pragma: #pragma DATA_SEG SHORT myDirectPageVars UINT16 myDirectPageVar1; /* entero sin signo en pgina directa */ #pragma DATA_SEG DEFAULT Esto declara los segmentos de pgina directa myDirectPageVars que contienen la variable myDirectPageVar1 y puede ser accedida usando el modo de direccionamiento directo. El programador debe acordarse de hacer la conexin al segmento myDirectPageVars en una direccin de la pgina directa. Cdigo C Eficiente para Sistemas Embebidos Pgina 6

La cantidad de RAM en la pgina directa es siempre limitada, por eso solo las variables ms intensivamente usadas deberan estar ubicadas en la pgina directa. Muchos I/O y registros de control estn ubicados en la pgina directa y ellos debern estar declarados como tal, as el compilador puede usar el modo de direccionamiento directo donde sea posible. Dos formas posibles de hacer esto son: Defina el nombre del registro y su direccin juntos: #define PortA (*((volatile UINT8 *)(0x0000))) #define PortB (*((volatile UINT8 *)(0x0001))) O define los nombres del registro en un segmento de pgina directa y define la direccin del segmento en tiempo de conexin: #pragma DATA_SEG SHORT myDirectPagePortRegisters volatile UINT8 PortA; volatile UINT8 PortB; #pragma DATA_SEG DEFAULT

1.1.1.5.

Bucles

Si un bucle debe ser ejecutado menos de 255 veces, se usa 'unsigned char' para el tipo bucle contador. Si el bucle debe ser ejecutado ms que 255 veces, se usa 'unsigned int' para el bucle contador. Esto es porque la aritmtica de 8 bits es ms eficiente que la aritmtica de 16 bits y la aritmtica sin signo es mas eficiente que con signo. Si el valor del bucle contador es irrelevante, entonces es ms eficiente el contador para el decremento y comparar con cero que para incrementar y comparar con un valor distinto de cero. Esta optimizacin no es efectiva si el bucle debe ser ejecutado con el bucle contador igual a cero, como cuando el bucle contador se usa para indexar un arreglo de elementos y el primer elemento debe ser accedido. Si se usa el bucle contador en expresiones dentro del bucle, entonces se debe guardar el tipo de datos ms apropiado cada vez que se usa. Cuando un bucle se ejecuta un nmero fijo de veces y aquel nmero es pequeo, como tres o cuatro, es frecuentemente ms eficiente no tener un bucle. En lugar de eso, se escribe el cdigo explcitamente tantas veces segn lo solicitado. Esto dar como resultado ms lneas de cdigo C pero a cambio generar menos cdigo ensamblador y puede ejecutarse mucho ms rpido que un bucle. Los ahorros reales variarn, dependiendo del cdigo a ser ejecutado.

1.1.1.6.

Estructuras de datos

Al programar en C es fcil crear estructuras de datos complejas, por ejemplo un arreglo de estructuras, donde cada estructura contiene un nmero de tipos de datos diferentes. Esto producir cdigo complejo y lento en un microcontrolador de 8 bits que tiene un nmero limitado de registros de CPU para usar por indexado. Cada nivel de referencia resultar en una multiplicacin del nmero de elementos por el tamao del elemento, con el resultado probablemente puesto encima de la pila en orden, para hacer el siguiente clculo. Las estructuras debern ser evitadas donde sea posible y las estructuras de datos mantenerse simples. Esto puede hacerse organizando datos en Cdigo C Eficiente para Sistemas Embebidos Pgina 7

simples arreglos unidimensionales de un tipo de datos simple. Esto dar como resultado un gran nmero de arreglos, pero el programa podr acceder a los datos mucho ms rpidamente. Si las estructuras son inevitables, entonces no debern hacerse pasar como un argumento de funcin o un valor de retorno de funcin, en lugar de esto debern pasarse por referencia.

1.1.1.7. Ejemplos
Los siguientes ejemplos estn basados en las siguientes definiciones de tipos: typedef unsigned char UINT8; typedef signed char SINT8; typedef unsigned int UINT16; typedef int SINT16; 1.1.1.7.1. Registro 1 Este ejemplo muestra manipulacin de bits para un registro en paginado directo (port A) y para un not en paginado directo (CMCR0). El Seteado o borrado de uno o mas bits en una direccin que no es registro en el paginado directo requiere 7 bytes de rom y 9 ciclos de CPU. El Seteado o borrado de un simple bit en un registro en el paginado directo requiere 2 bytes de rom y 4 ciclos de CPU. Cdigo C
#define PORTA (*((volatile UINT8 *)(0x0000))) #define CMCR0 (*((volatile UINT8 *)(0x0500))) void register1(void) { CMCR0 &= ~0x01; /* clr bit1 */ PORTA |= 0x03; /* set b1,2 */ PORTA &= ~0x02; /* clr bit2 */ } LDHX #0x0500 LDA ,X AND #0xFE STA ,X LDA 0x00 ORA #0x03 STA 0x00 BSET 0,0x00 RTS 3 1 2 1 2 2 2 2 1 3 2 2 2 3 2 3 4 4

Cdigo Bytes Ciclos Ensamblador

1.1.1.7.2. Copia de datos 1 Este es un ejemplo del uso inapropiado de int para la variable i que se usa en el bucle contador y en el arreglo ndice. El compilador es forzado a usar 16 bit con signo aritmticos para calcular la direccin de cada elemento de dataPtr[ ]. Esta rutina requiere 50 bytes de ROM y con 4 Iteraciones del bucle, ejecutados en 283 ciclos de CPU. Cdigo C
UINT8 buffer[4];

Cdigo Ensamblador
PSHA PSHX

Bytes
1 1

Ciclos
2 2

Cdigo C Eficiente para Sistemas Embebidos

Pgina 8

void datacopy1(UINT8 * dataPtr) { int i; for (i = 0; i < 4; i++) { buffer[i] = dataPtr[i]; } }

AIS #-2 TSX CLR 1,X CLR ,X TSX LDA 3,X ADD 1,X PSHA LDA ,X ADC 2,X PSHA PULH PULX LDA ,X TSX LDX ,X PSHX LDX 3,SP PULH STA buffer,X TSX INC 1,X BNE *1 INC ,X LDA ,X PSHA LDX 1,X PULH CPHX #0x0004 BLT *-39 AIS #4 RTS

2 1 2 1 1 2 2 1 1 2 1 1 1 1 1 1 1 3 1 3 1 2 2 1 1 1 2 1 3 2 2 1

2 2 3 2 2 3 3 2 2 3 2 2 2 2 2 2 2 4 2 4 2 4 3 3 2 2 3 2 3 3 2 4

1.1.1.7.3. Copia de datos 2 En este ejemplo, el bucle contador y la variable son optimizados para un unsigned char'. Esta rutina ahora requiere 33 bytes de ROM, 17 bytes menos que en copia de datos 1. Con cuatro iteraciones, la copia de datos 2 ejecuta en 180 ciclos de CPU, 103 ciclos menos que en copia de datos 1. En este ejemplo el valor del bucle contador es importante; El bucle debe ejecutarse con i = 0, 1, 2 y 3. No se obtiene Ninguna mejora significante, en este caso, por decrementar el bucle contador en lugar de incrementarlo. Tampoco, se obtiene ninguna mejora significante, en este caso, si la variable buffer se ubica en la pgina directa: La instruccin STA buffer, X usa direccionamiento directo en lugar de extendido, ahorrando un byte de cdigo y un ciclo de CPU por iteracin. Cdigo C
UINT8 buffer[4]; void datacopy2(UINT8 * dataPtr) { UINT8 i; for (i = 0; i < 4; i++)

Cdigo Ensamblador
PSHA PSHX PSHH TSX CLR ,X LDA ,X ADD 2,X

bytes
1 1 1 1 1 1 2

Ciclos
2 2 2 2 2 2 3

Cdigo C Eficiente para Sistemas Embebidos

Pgina 9

{ buffer[i] = dataPtr[i]; } }

PSHA CLRA ADC 1,X PSHA PULH PULX LDX ,X TXA TSX LDX ,X CLRH STA buffer,X TSX INC ,X LDA ,X CMP #0x04 BCS *-25 AIS #3 RTS

1 1 2 1 1 1 1 1 1 1 1 3 1 1 1 2 2 2 1

2 1 3 2 2 2 2 1 2 2 1 4 2 3 2 2 3 2 4

1.1.1.7.4. Copia de datos 3 En este ejemplo, los datos son copiados sin usar un bucle. Esta rutina requiere 23 bytes de ROM y se ejecuta en 36 ciclos de CPU. sta usa 10 bytes menos de ROM y 144 ciclos menos de CPU que en copia de datos 2. Si se copiaran 8 bytes, entonces este mtodo requerira 10 bytes ms de ROM que copia de datos 2, pero se ejecutara en 280 ciclos menos de CPU. Aunque hay ahorros potenciales que se dan si la variable buffer est ubicada en la pgina directa, el compilador no saca mucha ventaja de ellos en este caso. Cdigo C
UINT8 buffer[4]; void datacopy3(UINT8 * dataPtr) { buffer[0] = dataPtr[0]; buffer[1] = dataPtr[1]; buffer[2] = dataPtr[2]; buffer[3] = dataPtr[3]; } PSHX PULH TAX LDA ,X STA buffer LDA 1,X STA buffer:0x1 LDA 2,X STA buffer:0x2 LDA 3,X STA buffer:0x3 RTS

Cdigo Ensamblador

Bytes
1 1 1 1 3 2 3 2 3 2 3 1

Ciclos
2 2 1 2 4 3 4 3 4 3 4 4

1.1.1.7.5. Bucle Si slo importa el nmero de iteraciones y no el valor del bucle contador, es ms eficiente el decremento del bucle contador y comprar la variable con cero. En este ejemplo la declaracin for requiere 7 bytes de ROM, y el incremento y test del bucle contador en direccin opuesta toman 6 ciclos de CPU por cada iteracin. Esto ahorra 2 bytes de ROM y 9 ciclos de CPU por iteracin comparada a la declaracin for en Cdigo C Eficiente para Sistemas Embebidos Pgina 10

copia de datos 2. De cualquier forma esta optimizacin no puede ser aplicada a copia de datos 2 ya que el cdigo dentro de este bucle es ejecutado con i= 4, 3, 2 y 1. Cdigo C
Void loop1(void) { UINT8 i; for(i=4; i!=0; i--) { /* code */ } }

Cdigo Ensamblador
PSHH LDA #0x04 TSX STA ,X TSX DBNZ ,X,*-offset PULH RTS

Bytes

Ciclos

1 2 1 1 1 2 1 1

2 2 2 2 2 4 2 4

1.1.2. Estructura de un programa en C


Un programa en C define una funcin llamada main. El compilador conecta el programa con el cdigo de arranque y las funciones de librera en un archivo "ejecutable", llamado para poder ejecutarlo en su target. En resumen, un programa en C necesita un ambiente de target para establecer e inicializar el cdigo de arranque en el target que satisface estos requisitos. En general, su rutina principal main realiza algunos pasos de inicializacin y ejecuta un bucle infinito. Como ejemplo, se examinar el archivo hello.c en el directorio \icc\examples.08: #include < hc08.h> //#Include "vectors.c" //es un programa autnomo que provee los vectores de registros main () { setbaud (BAUD9600); printf ("Hola Mundo\n"); while (1) ; } Como se puede ver, ste es un programa muy simple que coloca el baud rate a 9600, usando una constante definida en el hc08.h. Esta constante es vlida slo si su sistema usa un cristal de 10 Mhz para el HC08, as es que puede ser necesario modificarlo. Luego, usa una funcin estndar C para imprimir "Hola Mundo," e ir a un bucle infinito. El compilador del HC08, ICC08 incluye un Editor de aplicaciones GUI que genera cdigo de inicializacin de perifricos va una interfase.

Cdigo C Eficiente para Sistemas Embebidos

Pgina 11

2.

Software CodeWarrior

El Codewarrior [5] es una herramienta de uso libre, que rene un compilador, un linkeador y un debugger de cdigo assembler fuente, y que puede ser ampliada segn las necesidades del usuario. La versin "Standard Edition" ofrece ensamblado de cdigo fuente (assembler) en forma ilimitada y limitada a 16K bytes en cdigo C, adems provee capacidades de Debugging muy interesantes an para programadores avanzados. Esta herramienta poderosa, combina un Ambiente de Desarrollo Integrado de Alta perfomance (I.D.E) con: - Simulacin Completa de Chip y programacin de la memoria FLASH desde el sistema EVAL08QTY. - Un Compilador ANSI C altamente optimizado y un Debugger en nivel fuente C - Generacin automtica de cdigo C con "Processor Expert" desde unidades. Ejecutar una seccin de programacin o debugging con proyectos basados en entornos CodeWarrior IDE es tan simple como efectuar un doble "click" en el nombre del proyecto (El formato es "nombredelproyecto.mcp") desde el archivo almacenado. Comenzar un nuevo proyecto es un poco ms complejo, pero los tutoriales, FAQs y guas rpidas de comienzo son fciles de seguir y ayudan a construir un nuevo proyecto, usando "templates" pre-construidos, en muy poco tiempo. Por otro lado, la nueva versin del entorno integrado de trabajo (IDE), el CodeWarrior 5.0 ha sido pensada para simplificar el manejo de este poderoso entorno por parte de usuarios no habituados a los ambientes profesionales de desarrollo, cosa que no ocurra con las antiguas versiones de CodeWarrior para HC08 y HCS08. Para mayor informacin de uso, ejemplos y tutoriales ver en el Web Site de Freescale (www.freescale.com en la seccin Codewarrior).

2.1. Creacin de Proyectos


Para mostrar como se crea un nuevo proyecto usando el codeWarrior se realizar un ejemplo que efecte una interrupcin en forma peridica, cada n milisegundos, basado en el uso del Timer en modo TOV (Timer Overflow). Este sencillo programa servir como base para ejecutar un nmero de tareas ms complejas en forma peridica de modo similar a como lo hara un sistema operativo ms complejo. Primeramente se configura el sistema EVAL08QTY para trabajar con el MCU MC68HC908QY4 que es el microcontrolador disponible en la placa que viene con el kit del sistema. Configurado el sistema EVAL08QTY, se procede a iniciar el programa en el sistema CodeWarrior 5.0 efectuando los siguientes pasos: 1) Al ejecutar el CodeWarrior IDE, se abrir una ventana de opciones como se ve en la figura 2. Se debe elegr la opcin Create New Project para armar el nuevo proyecto. 2) Se ingresar en la pantalla de configuracin del proyecto donde se elegir la opcin generacin de lenguaje ASSEMBLY, y se le pondr un nombre con extencin .mcp, segn se puede ver en la figura 3. Cdigo C Eficiente para Sistemas Embebidos Pgina 12

Figura 2. Pantalla Startup con opciones de ayuda.

Figura 3. Pantalla de configuracin del proyecto. 3) En la siguiente pantalla se debe configurar la familia y dispositivo en particular a utilizar en el proyecto (MC68HC908QY4) segn se puede ver en la figura 4.

Cdigo C Eficiente para Sistemas Embebidos

Pgina 13

Figura 4. Pantalla de configuracin de Familia, dispositivo y tipo de conexin. Como se observa en la figura 4, se debe elegir la familia HC08, dispositivo MC68HC908QY4 y en cuanto a la conexin con la herramienta debe elegirse la opcin Mon08 Interface ya que es la opcin universal de conexin para los sistemas de desarrollo como los EVAL08QTY, E-FLASH08, FLASH_POD y toda otra herramienta que no figure explcitamente en el listado de conexiones.

Figura 5. Pantalla de adicin de archivos al proyecto. 4) Al hacer click en el botn siguiente se pasa a una pantalla (Figura 5) que permite adicionar cualquier archivo al proyecto, para incluirlo en el trabajo. En este caso, se saltea est opcin siguiendo a la prxima pantalla. 5) En la pantalla que se observa en la figura 6, se puede elegir la generacin de cdigo de inicializacin de los distintos perifricos asistida o no. En este caso se seleccionar la generacin de cdigo asistida, por medio del aplicativo Processor Expert, que gua al usuario paso a paso en la inicializacin de los distintos perifricos del MCU elegido.

Cdigo C Eficiente para Sistemas Embebidos

Pgina 14

Figura 6. Pantalla de eleccin o no de generacin de cdigo asistido (Processor Expert). 6) Al hacer click en el botn Finalizar, se generarn todos los archivos del proyecto, se lanzar la pantalla principal de trabajo del mismo y se podr ver una interfaz grfica con los pines y los distintos mdulos que constituyen el MCU (Figura 7).

2.2. Generacin de cdigo mediante Processor Expert

Figura 7. Pantalla principal del proyecto e interfaz grfica de Generacin de cdigo (Processor Expert). Cdigo C Eficiente para Sistemas Embebidos Pgina 15

Ahora solo queda generar el cdigo de inicializacin del Timer para producir una interrupcin peridica que ser la base del sistema de disparo de tareas, inicializar los puertos I/O, los registros de configuracin, etc. Para hacer esto, se debe usar el generador de cdigo asistido Processor Expert haciendo click primeramente en el modulo CPU para configurar el Clock del sistema y otros aspectos como se observa en la figura 8.

Figura 8. Pantalla del mdulo de CPU. Para este ejemplo se debe configurar el mdulo de CPU para: Clock ---- Externo ---- 9,8304Mhz (lo inyectar el EVAL08QTY por pin OSC1). LVI ----- Habilitado ---- 3V trip point ----- LVI deshabilitado en modo STOP. Interrupciones Habilitadas. Vector de Reset apuntando a la etiqueta _Startup Pin de Reset externo no disponible.

Figura 9. Pantalla con los detalles de configuracin del CPU. A continuacin se procede a configurar el mdulo de Timer (TIM) ingresando al mismo como muestra en la figura 10.

Cdigo C Eficiente para Sistemas Embebidos

Pgina 16

Figura 10. Pantalla del Mdulo de Timer. Ahora se debe configurar el mdulo del TIMER segn lo siguiente: Prescaler = 32 ----- FBUS = 2,4576 MHz. Perodo del timer = 100 ms Modo de funcionamiento ----- Timer Overflow Interrupt (INT_TIMOvr). Overflow Interrupt = habilitado. Nombre de la interrupcin = isrINT_TIMOvr Inicializacin = Comienzo de la cuenta (arranque del timer).

Figura 11. Pantalla de configuracin del TIMER Una vez que se ha configurado el mdulo de TIMER, se deben configurar los puertos I/O segn lo siguiente: PORTA ---- PTA0 ---- INPUT ----- PTA1/PTA7 DISABLE. PORTB ---- PTB5 ---- OUTPUT --- PTB0 / PTB7 DISABLE.

Cdigo C Eficiente para Sistemas Embebidos

Pgina 17

Figura 12. Pantallas de configuracin de puertos (PORTA / PORTB). Si luego se presiona el botn Generation Code, el generador de cdigo del Processor Expert generar cdigo y mostrar una ventana explicando los pasos a seguir para incorporarlo efectivamente al resto del programa.

Figura 13. Pantalla de generacin de Cdigo que producir archivos bajo el Nombre MCUinit para inicializar el MCU.

Figura 14. Pantalla de ayuda para integrar el cdigo generado al proyecto. Cdigo C Eficiente para Sistemas Embebidos Pgina 18

Segn lo sugerido por la ventana de ayuda una vez generado el cdigo, se procede a modificar y comentar lo siguiente: Comentar en el archivo Project.prm la lnea --- VECTOR 0 _Startup /* Reset vector. Con una barra cruzada y asterisco (/*) delante de la sentencia y luego salvarlo. Descomentar en el archivo main.asm la lnea JSR MCU_int para que de esta forma en el programa principal se pueda invocar a la sub rutina MCU_int quen inicializa al MCU.

Figura 15. Ventana con cdigo a modificar para utilizarlo. Luego de realizar esas modificaciones sugeridas por el Processor Expert, se deben introducir las lneas de cdigo en la subrutina de interrupcin por Timer Overflow (isrINT_TIMOvr) para realizar, por ejemplo, un Toggle (inversin de estado) del puerto PTB5 cada vez que se atienda la interrupcin propiamente dicha. En este punto se pueden poner todas las tareas en forma de llamado a subrutina que se irn ejecutando una a una cada 100 ms.

Cdigo C Eficiente para Sistemas Embebidos

Pgina 19

Figura 16. Agregado de las lneas de cdigo en la rutina de manejo de la Interrupcin por Timer Overflow (isrINT_TIMOvr).

2.3. Compilacin y Emulacin en Tiempo real


Una vez introducido el cdigo, se debe compilar haciendo click en el botn Make en la barra de proyecto o en la barra de herramientas general. Si no hay ningn error de compilacin se estar en condiciones de pasar a la etapa de EMULACION EN TIEMPO REAL del programa. Para realizar ello, primero se debe establecer una conexin entre el CodeWarrior 5.0 y el sistema de desarrollo EVAL08QTY que se ir configurando a lo largo de las siguientes pantallas luego de hacer click en el botn Debugger (fecha verde en la barra de proyecto).

Cdigo C Eficiente para Sistemas Embebidos

Pgina 20

Figura 17. Pantalla de seleccin de la interfaz con el hardware a utilizar. En la ventana Interface Selection se elige la opcin Class 1 ICS Board with processor installed y luego se debe presionar el botn ok.

Figura 18. Pantalla de manejo de la conexin con el hardware (EVAL08QTY). Luego se debe configurar la siguiente pantalla eligiendo el nmero de puerto COM en el que est asignado el puerto utilizado por el EVAL08QTY para la conexin PLACA PC y se debe asignar un Baud Rate de 9600 Bps de acuerdo a lo configurado en el sistema anteriormente. Como se podr observar en la figura, tambin se configurar la opcin de borrado y grabacin de la memoria FLASH del MCU en forma previa y automtica cada vez que se quiera entrar en el modo de Debugging (Emulacin en Tiempo Real) ya que es la condicin necesaria para que cualquier HC908 pueda trabajar como una verdadera herramienta de desarrollo.

Cdigo C Eficiente para Sistemas Embebidos

Pgina 21

Se debe hacer click en el icono contact target with these sedttings.... para establecer la comunicacin con la placa EVAL08QTY y entrar al entorno de Debugging propiamente dicho.

Figura 19. Ventana de borrado y Programacin de la Flash Una vez que el sistema sortea las etapas de seguridad con xito, aparecer una ventana (Erase and Program Flash?) preguntando por el borrado y grabacin de la FLASH antes de ingresar al modo de Debugging propiamente dicho. Se debe hacer Click en el icono Yes para proceder a borrar y grabar el programa en la memoria flash e ingresar al modo Debugging.

Figura 20.- Pantalla de Debugging (Emulacin en Tiempo Real). En esta instancia se posee la pantalla principal de Debugging (Emulacin en Tiempo Real) y solo resta correr el programa haciendo Click en el icono con la flechita verde (Run / Continue) para poder ver la seal cuadrada de 200 ms de perodo que se obtiene en el puerto PTB5 del QY4 en la placa EVAL08QTY, segn se observa en la figura 21.

Cdigo C Eficiente para Sistemas Embebidos

Pgina 22

Figura 21. Oscilograma de la seal de salida en PTB5. El sistema EVAL08QTY puede soportar de igual forma, herramientas de entorno integrado como el CodeWarrior de Metrowerks, asi como, el WinIDE ICS08 de P&E Microsystems sin modificacin alguna.

Cdigo C Eficiente para Sistemas Embebidos

Pgina 23

3 Interrupciones en Lenguaje C
El empleo de Interrupciones o ISR (Interrupt Service Routine, o Rutina de Servicio de Interrupciones) es indispensable en la programacin de microcontroladores. Se utilizan tanto para responder a una interrupcin externa, una interrupcin del timer, del conversor A/D o de cualquier mdulo existente en el microcontrolador que posea interrupciones. Hay dos mecanismos para escribir Interrupciones en C, uno es muy sencillo y funciona solo en el compilador codewarrior y el otro es ms genrico y es soportado por la mayora de los compiladores en C. Las 2 formas mencionadas son: Usando la instruccin interrupt (Propietaria de Codewarrior) Usando la directiva #pragma TRAP_PROC y el archivo de parmetros del Linker

3.1

La directiva #pragma TRAP_PROC

Esta directiva le indica al compilador que una funcin es una INTERRUPCIN. Una ISR necesita cierto cdigo especial de entrada y de salida que la hace diferente de cualquier otra funcin.
Ejemplo: #pragma TRAP_PROC void Mi_INTERRUPCION(void) { ... }

Una vez preparada la funcin que contiene el Cdigo a ejecutarse durante la interrupcin, es necesario indicarle al Linker (programa que une todas los archivos de cdigo en un nico programa) que instale la direccin de esta funcin en el vector correspondiente. Para ello se debe editar el archivo de parmetros del linker correspondiente al modelo de compilacin que se est empleando. Por ejemplo, si se compila un programa para el Micro GP32, este archivo se llamar GP32-FLASH.PRM [6]. El contenido es el siguiente:
NAMES END SECTIONS /* Z_RAM = READ_WRITE 0x0040 TO 0x00FF; */ /* 0xF0 to 0xFF reserved for Monitor stacking */ Z_RAM = READ_WRITE 0x0040 TO 0x00EF; RAM = READ_WRITE 0x0100 TO 0x023F; ROM = READ_ONLY 0x8000 TO 0xFDFF; PLACEMENT DEFAULT_ROM, ROM_VAR, STRINGS INTO ROM; DEFAULT_RAM INTO RAM;

Cdigo C Eficiente para Sistemas Embebidos

Pgina 24

_DATA_ZEROPAGE INTO Z_RAM; END STACKSIZE 0x50 VECTOR ADDRESS 0xFFFE _Startup

El bloque titulado SECTIONS sirve para asignar nombres a las reas de memoria del micro. En el ejemplo anterior, se han definido los nombres Z_RAM para la memoria accesible con direccionamiento directo (hasta 0xFF), RAM para el resto de la memoria RAM y ROM para la Flash, a excepcin de las direcciones reservadas a los vectores. El bloque titulado PLACEMENT permite ubicar las distintas secciones y componentes del programa en reas especficas de la memoria (RAM, Flash, etc) La instruccin STACKSIZE define el tamao del stack (0x50 bytes en el ejemplo). Finalmente, las instrucciones VECTOR permiten especificar el contenido de los vectores de interrupcin del micro. La instruccin VECTOR tiene el siguiente formato:
VECTOR ADDRESS <direccin_vector> <contenido_vector>

La <direccin_vector> es una de las direcciones donde estn los vectores de interrupciones del micro. Por ejemplo en un GP32, en la direccin 0xFFFE (y 0xFFFF) se almacena el vector de reset. El valor <contenido_vector> puede especificarse como un valor absoluto en hexa o con el nombre de la funcin. Opcionalmente en este caso tambin puede especificarse un offset. Ejemplo:
VECTOR ADDRESS 0xFFFE 0x1000 VECTOR ADDRESS 0xFFFE StartUp VECTOR ADDRESS 0xFFFE StartUp OFFSET 2

En este caso, la funcin que se ha definido con #pragma TRAP_PROC se llama Mi_INTERRUPCION. Si se desea usarla para atender las interrupciones del mdulo Time Base (TBM) cuyo vector se encuentra en la direccin 0xFFDC, se debe escribir:
VECTOR ADDRESS 0xFFDC Mi_INTERRUPCION

Un programa completo que use el Timebase para generar una onda cuadrada por PTA7 tendra la siguiente forma:
#define TBON 2 #define TACK 8 //Ack del TBCR #define ENABLE_INT {asm cli;} #define DISABLE_INT {asm sei;} #pragma TRAP_PROC void Mi_INTERRUPCION (void) { TBCR |= TACK; // Acknowledge Int PTA ^= 0x80; // invierte el estado de PTA7 }

Cdigo C Eficiente para Sistemas Embebidos

Pgina 25

//*********************************************************************************// void main (void) { CONFIG1 = 1; //Parar COP DDRA = 0xFF; //PTA todo salida TBCR = 0x04; //Timebase divide por 8192 ENABLE_INT //Habilitar las interrupciones TBCR |= TBON; //Prender el Timebase while (1) { //Hacer nada } }

3.2

La instruccin interrupt

Code Warrior tiene una instruccin especial que no se encuadra dentro del estndar ANSI-C llamada interrupt que permite simplificar el proceso de definicin de una interrupcin [7]. Debe usarse como si fuera un calificador de tipo pero seguida de un nmero que especifica la entrada en la tabla de vectores de interrupcin que contendr la direccin de la funcin que se est definiendo. Si no se especifica ese nmero, tiene el mismo efecto que TRAP_PROC y el vector debe definirse con la sentencia VECTOR en el archivo de parmetros del linker, tal como se vio antes. Ejemplo:
interrupt 17 void Mi_INTERRUPCION();

Instala Mi_INTERRUPCION en la entrada 17 de la tabla de vectores, correspondiente al Timebase Module. Con esta modificacin, el cdigo de ejemplo quedara de la siguiente forma:
#define TBON 2 #define TACK 8 //Ack del TBCR #define ENABLE_INT {asm cli;} #define DISABLE_INT {asm sei;} interrupt 17 void Mi_INTERRUPCION(void) { TBCR |= TACK; // Acknowledge Int PTA ^= 0x80; } //*********************************************************************************// void main (void) { CONFIG1 = 1; //Parar COP DDRA = 0xFF; //PTA todo salida TBCR = 0x04; //Timebase divide por 8192 ENABLE_INT //Habilitar las interrupciones TBCR |= TBON; //Prender el Timebase while (1) { //bucle infinito } }

Cdigo C Eficiente para Sistemas Embebidos

Pgina 26

Bibliografa:
[1] Stuart Robb, Creating Efficient C Code for the MC68HC08, Nota de Aplicacin, East Kilbride, Scotland, 2000. [2] Embedded C Development tools, http://www.imagecraft.com, 1994. [3] Reference Manual: Software ICCHCxx, ImageCraft Creations Inc.,2000. [4] Ing. Gabriel Dubatti, http://www.ingdubatti.com.ar, 2007 [5] User Guide: PROCESSOR EXPERT FOR MOTOROLA HC(S)08 FAMILY Codewarrior V 1.4 may,2004 [6] MC68HC908GP32 Technical Data (Motorola) [7] Motorola HC08 Compiler (Metrowerks) [8] Manual Smart Linker (Metrowerks)

Cdigo C Eficiente para Sistemas Embebidos

Pgina 27

Das könnte Ihnen auch gefallen