Está en la página 1de 27

Cdigo C Eficiente para Sistemas Embebidos Pgina 1

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 Versin 2.0

Cdigo C Eficiente para Sistemas Embebidos Pgina 2

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 3

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

Cdigo C Eficiente para Sistemas Embebidos Pgina 4

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 Tamao Rango sin signo Rango con signo
Char 8 bits 0 a 255 -128 a 127
Short int 16 bits 0 a 65535 -32768 a 32767
Int 16 bits 0 a 65535 -32768 a 32767
Long int 32 bits 0 a 4294967295 -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 5

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 6

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 7

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 8

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 Cdigo
Ensamblador
Bytes Ciclos
#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


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 Cdigo Ensamblador Bytes Ciclos
UINT8 buffer[4];

PSHA
PSHX
1
1
2
2

Cdigo C Eficiente para Sistemas Embebidos Pgina 9

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 Cdigo
Ensamblador
bytes Ciclos
UINT8 buffer[4];

void
datacopy2(UINT8 * dataPtr)
{
UINT8 i;
for (i = 0; i < 4; i++)
PSHA
PSHX
PSHH
TSX
CLR ,X
LDA ,X
ADD 2,X
1
1
1
1
1
1
2
2
2
2
2
2
2
3

Cdigo C Eficiente para Sistemas Embebidos Pgina 10

{
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 Cdigo Ensamblador Bytes Ciclos
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
1
1
1
1
3
2
3
2
3
2
3
1

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 11

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 Cdigo Ensamblador Bytes Ciclos
Void
loop1(void)
{
UINT8 i;
for(i=4; i!=0; i--)
{
/* code */
}
}



PSHH
LDA #0x04
TSX
STA ,X

TSX
DBNZ ,X,*-offset
PULH
RTS



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 12

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 13


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 14


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 15


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 16

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 17


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 18


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 19


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 20


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 21


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 22

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 23


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 24

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 25

_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 26

//*********************************************************************************//
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 27

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)

También podría gustarte