codigo c eficicnete para sistemas embebidos y code warrior 2011
Post on 15-Jul-2015
130 Views
Preview:
TRANSCRIPT
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 1
CeTAD – Facultad de Ingeniería - UNLP
Código C Eficiente para SistemasEmbebidos y Software Codewarrior
(Basado en el Compilador de Freescale)
Cátedra de Circuitos digitales y Microprocesadores
Autores:Ing. Jorge R. OsioIng. Walter ArózteguiIng. José A. Rapallini
Octubre de 2011 Versión 2.0
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 2
INDICE.
1. Código C Eficiente para Sistemas Embebidos…...…3
1.1. Compilador de Código C a Código de Máquina1.1.1. Creación de Código C eficiente para el MC68HC08
1.1.1.1. Modelo del Registro de la CPU081.1.1.2. Tipos de datos Básicos1.1.1.3. Variables locales Vs variables Globales1.1.1.4. Variables de Página directa1.1.1.5. Bucles1.1.1.6. Estructuras de datos
1.1.1.7. Ejemplos1.1.1.7.1. Registro 11.1.1.7.2. Copia de datos 11.1.1.7.3. Copia de datos 21.1.1.7.4. Copia de datos 31.1.1.7.5. Bucle
1.1.2. Estructura de un programa en C
2. Software CodeWarrior………...………………...12
2.1. Creación de Proyectos………………………………122.2. Generación de código mediante Processor Expert..15
2.3. Compilación y Emulación en Tiempo real ………..20
3. Interrupciones en Lenguaje C…………………...24
3.1. La directiva #pragma TRAP_PROC……………...243.2. La instrucción interrupt……………………………26
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 3
1. Código C Eficiente para Sistemas Embebidos
1.1. Compilador de Código C a Código de Máquina
1.1.1. Creación de Código C eficiente para el MC68HC08
Comparado con los otros microprocesadores la Arquitectura del HC908 seadapta bien al lenguaje de programación en C. Tiene un conjunto de instruccionesefectivas con modos de direccionamiento que permiten la eficiente implementación deinstrucciones en C. El conjunto de instrucciones incluye instrucciones para el manejodel puntero de pila. Los modos de direccionamiento, incluyen direccionamientoindexado, modos con el índice incluido y el registro índice o el registro de puntero de
pila. Estas características permiten acceso eficiente a variables locales.El lenguaje C es ideal para crear un programa para el micro HC08 [1], pero
para producir el código de máquina mas eficiente, el programador debe construir el programa cuidadosamente. En este contexto “Código Eficiente” significa tamaño de
código compacto y rápido tiempo de ejecución. A continuación se detallan algunassugerencias y consejos para ayudar al programador a escribir código C de manera queun compilador pueda convertirlo en código 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 deregistro del HC08.
Figura 1. Modelo del Registro del CPU08
Acumulador: El acumulador es un registro de 8 bits de propósito general. LaCPU 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 losmodos de direccionamiento indexado para determinar la dirección efectiva de unoperando. El registro indice puede acceder a 64 Kbytes de espacios de
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 4
direcciones en este modo. El byte mas bajo X se usa para almacenar el operando para la multiplicación y división de instrucciones. H:X para el almacenamientode la ubicación de datos temporarios.
Puntero de Pila: Los 16 bits del puntero de pila se usan para almacenar la
dirección de la próxima ubicación disponible sobre la pila. La CPU usa elcontenido del registro del puntero de pila como un índice para acceder aoperandos sobre la pila en modos de direccionamiento offset de puntero de pila.La pila puede se ubicada en cualquier dirección donde hay RAM en los 64 K
bytes de espacio de direcciones. Contador de Programa: Los 16 bits del contador de programa contienen la
dirección de la próxima instrucción u operando a ser utilizado. El contador de programa puede acceder a 64 K bytes de espacio de direcciones.
Registro de código de condición: Los 8 bits del registro de código de condicióncontienen el bit mascara de interrupción global y 5 flags (indicadores) queindican el resultado de la instrucción que ejecutada. Los bits 5 y 6 son
permanentemente sesteados a 1 lógico.
Estos registros junto con los modos de direccionamiento se encuentran biendesarrollados en el Apunte “Descripción General de un Microcontrolador (CPU)” y esnecesario conocerlos bien para poder aprovechar al máximo los consejos para lacreación de código C eficiente.
1.1.1.2. Tipos de datos Básicos
Los tipos de datos básicos son los siguientes:
Tipos de datos Básicos Tamaño Rango sin signo Rango con signoChar 8 bits 0 a 255 -128 a 127Short int 16 bits 0 a 65535 -32768 a 32767Int 16 bits 0 a 65535 -32768 a 32767Long int 32 bits 0 a 4294967295 -2147483648 a 2147483647
La mejor performance en tamaño de código y tiempo de ejecución se puedelograr definiendo el tipo de datos mas apropiado para cada variable. Esto es apropiado
para microcontroladores de 8 bits donde el tamaño de datos interno natural es de 8 bits.El tipo de datos preferido en C es el “int”. El estándar ANSI no define precisamente el
tamaño de los tipos de datos naturales, pero los compiladores para microcontroladoresde 8 bits implementan “int” como un valor de 16 bits con signo. Como losmicrocontroladores de 8 bits pueden procesar tipos de datos de 8 bits maseficientemente que de 16 bits. Los tipos de datos “int” y “long int” deben ser usados,
solo donde se requiere, por el tamaño de datos a ser representado. Las operaciones dedoble precisión y punto flotante son ineficientes y deben ser evitadas donde laeficiencia es importante. Esto quizás parece obvio, pero frecuentemente se pasa por altoy tiene un enorme impacto sobre el tamaño de código en tiempo de ejecución.
Como se sabe la magnitud del tipo de datos requeridos y el signo deben ser especificados. El estándar ANSI C especifica „int‟ con signo por defecto, pero el „char‟
no está definido y puede variar entre compiladores. Por lo tanto para crear código portable, el tipo de datos „char‟ no debe ser usado. Y para el tipo „char el signo debe ser
definido explícitamente: „unsigned char‟ o „signed char‟.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 5
Es buena práctica crear definiciones de tipos para estos tipos de datos en unencabezado de archivo que se incluye en todos los otros archivos. También vale la penacrear 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 expresión, pero algunas de estas expresionesno requieren el tamaño de datos completo o con signo de la variable. En este caso elahorro se puede hacer definiendo la variable, o parte de la expresión 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 globalesson accesibles por cualquier parte del programa y son almacenadas permanentemente enRAM. Las variables locales son accesibles sólo por la función dentro de la cual sondeclaradas y son almacenadas en la pila.
Las variables locales por consiguiente sólo ocupan RAM mientras se ejecuta lafunción a la cual pertenecen. Su dirección absoluta no se puede determinar cuando el
código es compilado y conectado así es que son ubicadas en memoria relativa al punterode pila. Para acceder a las variables locales el compilador puede usar el modo dedireccionamiento del puntero de pila. Este modo de direccionamiento requiere un byteadicional y un ciclo adicional para acceder a una variable, comparado a la mismainstrucción en el modo de direccionamiento indexado. Si el código requiere variosaccesos 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 ' estático ' modificado puede ser usado con variables locales. Estocausa que la variable local sea almacenada permanentemente en la memoria, como unavariable global, así es que el valor de la variable es preservado entre llamados afunciones. Sin embargo la variable local estática es sólo accesible por la función dentro
de la cual está declarada.Las variables globales son almacenadas permanentemente en memoria en unadirección absoluta determinada cuando el código es conectado. La memoria ocupada
por una variable global no puede ser reusada por cualquier otra variable. De cualquier manera las variables globales no están protegidas, ya que cualquier parte del programa
puede tener acceso a una variable global en cualquier momento. Esto da origen alasunto de consistencia de datos para las variables globales de más de un simple byte detamaño. Esto quiere decir que los datos variables podrían ser corrompidos si una partede la variable proviene de un valor y el resto de la variable proviene de otro valor. Losdatos inconsistentes aparecen cuando una variable global es accedida (leída 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 interrupción de hardware por ejemplo, o un sistema operativo, si se usa uno. Si la variable global es entonces accedida
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 6
por la rutina de interrupción entonces pueden aparecer los datos inconsistentes. Esto sedebe evitar si se desea la ejecución confiable del programa y se logra frecuentementedeshabilitando las interrupciones al acceder a las variables globales.
El acceso 'estático' modificado también puede ser usado con variables globales.
Esto da algún grado de protección 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 sonaccedidas a través de un puntero. El uso de variables globales generalmente no resultasignificativamente más eficiente en código que las variables locales. Hay algunasexcepciones limitadas para esta generalización, una es cuando la variable global estáubicada en la página directa.
Sin embargo, el uso de variables globales impide que una función sea recursivao entrante, y frecuentemente no hace el uso más eficiente de RAM, lo cual es un recursolimitado en la mayoría de microcontroladores. El programador por consiguiente debe
hacer una elección meticulosa en decidir que variables definir como globales en elámbito. Las ganancias importantes en eficiencia algunas veces pueden obtenersedefiniendo justamente unas pocas de las variables, más intensivamente usadas, comoglobales en el ambiente, particularmente si estas variables están ubicadas en la páginadirecta.
1.1.1.4. Variables de Página directa
El rango de direcciones $ 0000 a $ 00FF es llamado la página directa, la página base o la página cero. En los microcontroladores M68HC08, la parte inferior de la
página directa siempre contiene los registros I/O y de control y la parte superior de la página directa siempre contiene RAM. Después de un reset, el puntero de pila siemprecontiene la dirección $ 00FF. La página directa es importante porque la mayoría de lasinstrucciones del CPU08 tienen un modo de direccionamiento directo por medio del que
pueden acceder a los operandos en la página directa en un ciclo de reloj menos que en elmodo de direccionamiento extendido. Además la instrucción de modo dedireccionamiento directo requiere un byte menos de código. Algunas instruccionesaltamente eficientes sólo surtirán efecto con operandos de la página directa. Estos son:BSET, BCLR, BRSET y BRCLR. La instrucción MOV requiere que uno de losoperandos esté en la página directa.
Un compilador no puede sacar ventaja del modo de direccionamiento directo
eficiente a menos que las variables sean explícitamente declaradas para estar en la página directa. No hay en estándar ANSI modo de hacer esto y los compiladoresgeneralmente ofrecen soluciones diferentes. El compilador hiware usa una declaración#pragma:
#pragma DATA_SEG SHORT myDirectPageVarsUINT16 myDirectPageVar1; /* entero sin signo en página directa */#pragma DATA_SEG DEFAULT
Esto declara los segmentos de página directa myDirectPageVars que contienenla variable myDirectPageVar1 y puede ser accedida usando el modo de
direccionamiento directo. El programador debe acordarse de hacer la conexión alsegmento myDirectPageVars en una dirección de la página directa.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 7
La cantidad de RAM en la página directa es siempre limitada, por eso solo lasvariables más intensivamente usadas deberían estar ubicadas en la página directa.
Muchos I/O y registros de control están ubicados en la página directa y ellosdeberán 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 dirección juntos:
#define PortA (*((volatile UINT8 *)(0x0000)))#define PortB (*((volatile UINT8 *)(0x0001)))
O define los nombres del registro en un segmento de página directa y define ladirección del segmento en tiempo de conexión:
#pragma DATA_SEG SHORT myDirectPagePortRegistersvolatile 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' parael tipo bucle contador. Si el bucle debe ser ejecutado más que 255 veces, se usa'unsigned int' para el bucle contador. Esto es porque la aritmética de 8 bits es máseficiente que la aritmética de 16 bits y la aritmética sin signo es mas eficiente que consigno.
Si el valor del bucle contador es irrelevante, entonces es más eficiente elcontador para el decremento y comparar con cero que para incrementar y comparar conun valor distinto de cero. Esta optimización no es efectiva si el bucle debe ser ejecutadocon 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 debeguardar el tipo de datos más apropiado cada vez que se usa.
Cuando un bucle se ejecuta un número fijo de veces y aquel número es pequeño, como tres o cuatro, es frecuentemente más eficiente no tener un bucle. Enlugar de eso, se escribe el código explícitamente tantas veces según lo solicitado. Estodará como resultado más líneas de código C pero a cambio generará menos código
ensamblador y puede ejecutarse mucho más rápido que un bucle. Los ahorros realesvariarán, dependiendo del código a ser ejecutado.
1.1.1.6. Estructuras de datos
Al programar en C es fácil crear estructuras de datos complejas, por ejemplo unarreglo de estructuras, donde cada estructura contiene un número de tipos de datosdiferentes. Esto producirá código complejo y lento en un microcontrolador de 8 bits quetiene un número limitado de registros de CPU para usar por indexado. Cada nivel dereferencia resultará en una multiplicación del número de elementos por el tamaño delelemento, con el resultado probablemente puesto encima de la pila en orden, para hacer el siguiente cálculo. Las estructuras deberán ser evitadas donde sea posible y lasestructuras de datos mantenerse simples. Esto puede hacerse organizando datos en
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 8
simples arreglos unidimensionales de un tipo de datos simple. Esto dará como resultadoun gran número de arreglos, pero el programa podrá acceder a los datos mucho másrápidamente. Si las estructuras son inevitables, entonces no deberán hacerse pasar comoun argumento de función o un valor de retorno de función, en lugar de esto deberán
pasarse por referencia.
1.1.1.7. Ejemplos
Los siguientes ejemplos están 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 manipulación de bits para un registro en paginado directo(port A) y para un not en paginado directo (CMCR0). El Seteado o borrado de uno omas bits en una dirección que no es registro en el paginado directo requiere 7 bytes derom 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.
Código C CódigoEnsamblador
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
31212222
1
32223234
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 consigno aritméticos para calcular la dirección de cada elemento de dataPtr[ ]. Esta rutinarequiere 50 bytes de ROM y con 4 Iteraciones del bucle, ejecutados en 283 ciclos deCPU.
Código C Código Ensamblador Bytes CiclosUINT8 buffer[4]; PSHAPSHX
11
22
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 9
void
datacopy1(UINT8 * dataPtr)
{
int i;
for (i = 0; i < 4; i++)
{buffer[i] = dataPtr[i];
}
}
AIS #-2TSXCLR 1,XCLR ,XTSX
LDA 3,XADD 1,XPSHALDA ,XADC 2,XPSHAPULHPULXLDA ,XTSXLDX ,XPSHXLDX 3,SP
PULHSTA buffer,XTSXINC 1,XBNE *1INC ,XLDA ,XPSHALDX 1,XPULHCPHX #0x0004BLT *-39AIS #4
RTS
21211
2211211111113
1312211121322
1
22322
3322322222224
2424332232332
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 deCPU, 103 ciclos menos que en copia de datos 1. En este ejemplo el valor del buclecontador 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 lavariable „buffer‟ se ubica en la página directa: La instrucción „STA buffer, X‟ usadireccionamiento directo en lugar de extendido, ahorrando un byte de código y un ciclode CPU por iteración.
Código C CódigoEnsamblador
bytes Ciclos
UINT8 buffer[4];
void
datacopy2(UINT8 * dataPtr)
{UINT8 i;
for (i = 0; i < 4; i++)
PSHAPSHXPSHHTSX
CLR ,XLDA ,XADD 2,X
1111
112
2222
223
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 10
{
buffer[i] = dataPtr[i];
}
}
PSHACLRAADC 1,XPSHAPULH
PULXLDX ,XTXATSXLDX ,XCLRHSTA buffer,XTSXINC ,XLDA ,XCMP #0x04BCS *-25AIS #3
RTS
11211
1111113111222
1
21322
2212214232232
4
1.1.1.7.4. Copia de datos 3
En este ejemplo, los datos son copiados sin usar un bucle. Esta rutina requiere23 bytes de ROM y se ejecuta en 36 ciclos de CPU. Ésta usa 10 bytes menos de ROM y144 ciclos menos de CPU que en copia de datos 2. Si se copiaran 8 bytes, entonces estemétodo requeriría 10 bytes más de ROM que copia de datos 2, pero se ejecutaría en 280ciclos menos de CPU. Aunque hay ahorros potenciales que se dan si la variable „buffer‟ está ubicada en la página directa, el compilador no saca mucha ventaja de ellos en este
caso.
Código C Código Ensamblador Bytes CiclosUINT8 buffer[4];
void
datacopy3(UINT8 * dataPtr)
{
buffer[0] = dataPtr[0];
buffer[1] = dataPtr[1];
buffer[2] = dataPtr[2];
buffer[3] = dataPtr[3];
}
PSHXPULHTAXLDA ,XSTA buffer LDA 1,XSTA buffer:0x1
LDA 2,XSTA buffer:0x2LDA 3,XSTA buffer:0x3RTS
111132323
231
221243434
344
1.1.1.7.5. Bucle
Si sólo importa el número de iteraciones y no el valor del bucle contador, esmás eficiente el decremento del bucle contador y compárar la variable con cero. En esteejemplo la declaración „for‟ requiere 7 bytes de ROM, y el incremento y test del bucle
contador en dirección opuesta toman 6 ciclos de CPU por cada iteración. Esto ahorra 2 bytes de ROM y 9 ciclos de CPU por iteración comparada a la declaración „for‟ en
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 11
copia de datos 2. De cualquier forma esta optimización no puede ser aplicada a copia de
datos 2 ya que el código dentro de este bucle es ejecutado con i= 4, 3, 2 y 1.
Código C Código Ensamblador Bytes Ciclos
Voidloop1(void)
{
UINT8 i;
for(i=4; i!=0; i--)
{
/* code */
}
}
PSHHLDA #0x04TSXSTA ,X
TSXDBNZ ,X,*-offsetPULHRTS
12111211
22222424
1.1.2. Estructura de un programa en C
Un programa en C define una función llamada main. El compilador conecta el programa con el código de arranque y las funciones de librería en un archivo"ejecutable", llamado para poder ejecutarlo en su target. En resumen, un programa en Cnecesita un ambiente de target para establecer e inicializar el código de arranque en eltarget que satisface estos requisitos.
En general, su rutina principal “main” realiza algunos pasos de inicialización yejecuta 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 autónomo 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 a9600, usando una constante definida en el hc08.h. Esta constante es válida sólo si susistema usa un cristal de 10 Mhz para el HC08, así es que puede ser necesariomodificarlo. Luego, usa una función estándar C para imprimir "Hola Mundo," e ir a un
bucle infinito.
El compilador del HC08, ICC08 incluye un Editor de aplicaciones GUI quegenera código de inicialización de periféricos vía una interfase.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 12
2. Software CodeWarrior
El Codewarrior [5] es una herramienta de uso libre, que reúne un compilador, un
linkeador y un debugger de código assembler fuente, y que puede ser ampliada segúnlas necesidades del usuario.La versión "Standard Edition" ofrece ensamblado de código fuente (assembler)
en forma ilimitada y limitada a 16K bytes en código “C”, además provee capacidades de
Debugging muy interesantes aún para programadores avanzados.Esta herramienta poderosa, combina un Ambiente de Desarrollo Integrado de
Alta perfomance (I.D.E) con:
- Simulación Completa de Chip y programación de la memoria FLASH desde el sistemaEVAL08QTY.- Un Compilador ANSI C altamente optimizado y un Debugger en nivel fuente C
- Generación automática de código C con "Processor Expert" desde unidades.
Ejecutar una sección de programación o debugging con proyectos basados enentornos CodeWarrior IDE es tan simple como efectuar un doble "click" en el nombredel proyecto (El formato es "nombredelproyecto.mcp") desde el archivo almacenado.Comenzar un nuevo proyecto es un poco más complejo, pero los tutoriales, FAQs yguías rápidas de comienzo son fáciles de seguir y ayudan a construir un nuevo proyecto,usando "templates" pre-construidos, en muy poco tiempo.
Por otro lado, la nueva versión del entorno integrado de trabajo (IDE), elCodeWarrior 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, cosaque no ocurría con las antiguas versiones de CodeWarrior para HC08 y HCS08.
Para mayor información de uso, ejemplos y tutoriales ver en el Web Site deFreescale (www.freescale.com en la sección Codewarrior).
2.1. Creación de Proyectos
Para mostrar como se crea un nuevo proyecto usando el codeWarrior serealizará un ejemplo que efectúe una interrupción en forma periódica, cada “n”
milisegundos, basado en el uso del Timer en modo TOV (Timer Overflow). Estesencillo programa servirá como base para ejecutar un número de tareas más complejas
en forma periódica de modo similar a como lo haría un sistema operativo más complejo.Primeramente se configura el sistema EVAL08QTY para trabajar con el MCUMC68HC908QY4 que es el microcontrolador disponible en la placa que viene con elkit del sistema.
Configurado el sistema EVAL08QTY , se procede a iniciar el programa en elsistema CodeWarrior 5.0 efectuando los siguientes pasos:
1) Al ejecutar el CodeWarrior IDE, se abrirá una ventana de opciones como se ve en lafigura 2. Se debe elegír la opción “Create New Project” para armar el nuevo proyecto.2) Se ingresará en la pantalla de configuración del proyecto donde se elegirá la opcióngeneración de lenguaje ASSEMBLY, y se le pondrá un nombre con extención “.mcp”,
según se puede ver en la figura 3.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 13
Figura 2. Pantalla “Startup” con opciones de ayuda.
Figura 3. Pantalla de configuración del proyecto.
3) En la siguiente pantalla se debe configurar la familia y dispositivo en particular autilizar en el proyecto (MC68HC908QY4) según se puede ver en la figura 4.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 14
Figura 4. Pantalla de configuración de Familia, dispositivo y tipo de conexión.
Como se observa en la figura 4, se debe elegir la familia HC08, dispositivoMC68HC908QY4 y en cuanto a la conexión con la herramienta debe elegirse la opción“Mon08 Interface” ya que es la opción universal de conexión para los sistemas dedesarrollo como los EVAL08QTY, E-FLASH08, FLASH_POD y toda otra herramientaque no figure explícitamente en el listado de conexiones.
Figura 5. Pantalla de adición de archivos al proyecto.
4) Al hacer click en el botón “siguiente” se pasa a una pantalla (Figura 5) que permiteadicionar cualquier archivo al proyecto, para incluirlo en el trabajo. En este caso, sesaltea está opción siguiendo a la próxima pantalla.5) En la pantalla que se observa en la figura 6, se puede elegir la generación de códigode inicialización de los distintos periféricos asistida o no. En este caso se seleccionará lageneración de código asistida, por medio del aplicativo “Processor Expert”, que guía alusuario paso a paso en la inicialización de los distintos periféricos del MCU elegido.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 15
Figura 6. Pantalla de elección o no de generación de código asistido(Processor Expert).
6) Al hacer click en el botón “Finalizar”, se generarán todos los archivos del proyecto,se lanzará la pantalla principal de trabajo del mismo y se podrá ver una interfaz gráficacon los pines y los distintos módulos que constituyen el MCU (Figura 7).
2.2. Generación de código mediante Processor Expert
Figura 7. Pantalla principal del proyecto e interfaz gráfica de
Generación de código (Processor Expert).
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 16
Ahora solo queda generar el código de inicialización del Timer para producir una interrupción periódica que será la base del sistema de disparo de tareas, inicializar los puertos I/O, los registros de configuración, etc.
Para hacer esto, se debe usar el generador de código asistido “Processor Expert”
haciendo click primeramente en el modulo CPU para configurar el Clock del sistema yotros aspectos como se observa en la figura 8.
Figura 8. Pantalla del módulo de CPU.
Para este ejemplo se debe configurar el módulo 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 configuración del CPU.
A continuación se procede a configurar el módulo de Timer (TIM)ingresando al mismo como muestra en la figura 10.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 17
Figura 10. Pantalla del Módulo de Timer.
Ahora se debe configurar el módulo del TIMER según lo siguiente:• Prescaler = 32 ----- FBUS = 2,4576 MHz.• Período del timer = 100 ms• Modo de funcionamiento ----- Timer Overflow Interrupt (INT_TIMOvr).•
Overflow Interrupt = habilitado.• Nombre de la interrupción = isrINT_TIMOvr • Inicialización = Comienzo de la cuenta (arranque del timer).
Figura 11. Pantalla de configuración del TIMER
Una vez que se ha configurado el módulo de TIMER, se deben configurar los puertos I/O según lo siguiente:
PORTA ---- PTA0 ---- INPUT ----- PTA1/PTA7 DISABLE.
PORTB ---- PTB5 ---- OUTPUT --- PTB0 / PTB7 DISABLE.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 18
Figura 12. Pantallas de configuración de puertos (PORTA / PORTB).
Si luego se presiona el botón “Generation Code”, el generador de código del Processor Expert generará código y mostrará una ventana explicando los pasos a seguir para incorporarlo efectivamente al resto del programa.
Figura 13. Pantalla de generación de Código que produciráarchivos bajo el Nombre “MCUinit” para inicializar el MCU.
Figura 14. Pantalla de ayuda para integrar el código generado al proyecto.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 19
Según lo sugerido por la ventana de ayuda una vez generado el código, se procede a modificar y comentar lo siguiente:
•
Comentar en el archivo “Project.prm” la línea --- VECTOR 0 _Startup /* Resetvector. Con una barra cruzada y asterisco (/*) delante de la sentencia y luego salvarlo. • Descomentar en el archivo “main.asm” la línea “JSR MCU_int” para que de estaforma en el programa principal se pueda invocar a la sub rutina MCU_int queninicializa al MCU.
Figura 15. Ventana con código a modificar para utilizarlo.
Luego de realizar esas modificaciones sugeridas por el Processor Expert , sedeben introducir las líneas de código en la subrutina de interrupción por Timer Overflow (isrINT_TIMOvr) para realizar, por ejemplo, un Toggle (inversión deestado) del puerto PTB5 cada vez que se atienda la interrupción propiamente dicha. Eneste punto se pueden poner todas las tareas en forma de llamado a subrutina que se iránejecutando una a una cada 100 ms.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 20
Figura 16. Agregado de las líneas de código en la rutina de manejo de laInterrupción por Timer Overflow (isrINT_TIMOvr).
2.3. Compilación y Emulación en Tiempo real
Una vez introducido el código, se debe compilar haciendo click en el botón“Make” en la barra de proyecto o en la barra de herramientas general. Si no hay ningúnerror de compilación se estará en condiciones de pasar a la etapa de EMULACION ENTIEMPO REAL del programa.
Para realizar ello, primero se debe establecer una conexión entre el CodeWarrior 5.0 y el sistema de desarrollo EVAL08QTY que se irá configurando a lo largo de lassiguientes pantallas luego de hacer click en el botón “Debugger” (fecha verde en la
barra de proyecto).
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 21
Figura 17. Pantalla de selección de la interfaz con el hardware a utilizar.
En la ventana “Interface Selection” se elige la opción “Class 1 – ICS Boardwith processor installed” y luego se debe presionar el botón “ok”.
Figura 18. Pantalla de manejo de la conexión con el hardware (EVAL08QTY).
Luego se debe configurar la siguiente pantalla eligiendo el número de puertoCOM en el que esté asignado el puerto utilizado por el EVAL08QTY para la conexiónPLACA – PC y se debe asignar un Baud Rate de 9600 Bps de acuerdo a lo configuradoen el sistema anteriormente.
Como se podrá observar en la figura, también se configurará la opción deborrado y grabación de la memoria FLASH del MCU en forma previa y automáticacada vez que se quiera entrar en el modo de Debugging (Emulación en Tiempo Real) yaque es la condición necesaria para que cualquier HC908 pueda trabajar como unaverdadera herramienta de desarrollo.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 22
Se debe hacer click en el icono “contact target with these sedttings....” paraestablecer la comunicación con la placa EVAL08QTY y entrar al entorno de Debugging
propiamente dicho.
Figura 19. Ventana de borrado y Programación de la Flash
Una vez que el sistema sortea las etapas de seguridad con éxito, aparecerá unaventana (Erase and Program Flash?) preguntando por el borrado y grabación de laFLASH 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 (Emulación en Tiempo Real).
En esta instancia se posee la pantalla principal de Debugging (Emulación enTiempo Real) y solo resta correr el programa haciendo Click en el icono con la“flechita verde” (Run / Continue) para poder ver la señal cuadrada de 200 ms deperíodo que se obtiene en el puerto PTB5 del QY4 en la placa EVAL08QTY , segúnse observa en la figura 21.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 23
Figura 21. Oscilograma de la señal de salida en PTB5.
El sistema EVAL08QTY puede soportar de igual forma, herramientas deentorno integrado como el CodeWarrior de Metrowerks, asi como, el WinIDE ICS08de P&E Microsystems sin modificación alguna.
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 24
3 Interrupciones en Lenguaje C
El empleo de Interrupciones o ISR (Interrupt Service Routine, o Rutina de Serviciode Interrupciones) es indispensable en la programación de microcontroladores. Seutilizan tanto para responder a una interrupción externa, una interrupción del timer, delconversor A/D o de cualquier módulo existente en el microcontrolador que poseainterrupciones.
Hay dos mecanismos para escribir Interrupciones en C, uno es muy sencillo yfunciona solo en el compilador codewarrior y el otro es más genérico y es soportado por la mayoría de los compiladores en C. Las 2 formas mencionadas son:
• Usando la instrucción interrupt (Propietaria de Codewarrior)• Usando la directiva #pragma TRAP_PROC y el archivo de parámetros del Linker
3.1 La directiva #pragma TRAP_PROC
Esta directiva le indica al compilador que una función es una INTERRUPCIÓN.Una ISR necesita cierto código especial de entrada y de salida que la hace diferente decualquier otra función.
Ejemplo:#pragma TRAP_PROCvoid Mi_INTERRUPCION(void) {...}
Una vez preparada la función que contiene el Código a ejecutarse durante lainterrupción, es necesario indicarle al Linker (programa que une todas los “archivos” de código en un único programa) que instale la dirección de esta función en el vector correspondiente. Para ello se debe editar el archivo de parámetros del linker correspondiente al modelo de compilación que se está empleando. Por ejemplo, si secompila 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;
PLACEMENTDEFAULT_ROM, ROM_VAR, STRINGS INTO ROM;DEFAULT_RAM INTO RAM;
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 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 memoriadel micro. En el ejemplo anterior, se han definido los nombres Z_RAM para la memoriaaccesible con direccionamiento directo (hasta 0xFF), RAM para el resto de la memoriaRAM y ROM para la Flash, a excepción de las direcciones reservadas a los vectores.
El bloque titulado “PLACEMENT” permite ubicar las distintas secciones y
componentes del programa en áreas específicas de la memoria (RAM, Flash, etc)La instrucción “STACKSIZE” define el tamaño del stack (0x50 bytes en el ejemplo).
Finalmente, las instrucciones “VECTOR” permiten especificar el contenido de losvectores de interrupción del micro. La instrucción VECTOR tiene el siguiente formato:
VECTOR ADDRESS <dirección_vector> <contenido_vector>
La <dirección_vector> es una de las direcciones donde están los vectores deinterrupciones del micro. Por ejemplo en un GP32, en la dirección 0xFFFE (y 0xFFFF)se almacena el vector de reset.
El valor <contenido_vector> puede especificarse como un valor absoluto en hexa ocon el nombre de la función. Opcionalmente en este caso también puede especificarseun offset.
Ejemplo:
VECTOR ADDRESS 0xFFFE 0x1000VECTOR ADDRESS 0xFFFE StartUpVECTOR ADDRESS 0xFFFE StartUp OFFSET 2
En este caso, la función que se ha definido con #pragma TRAP_PROC se llamaMi_INTERRUPCION. Si se desea usarla para atender las interrupciones del móduloTime Base (TBM) cuyo vector se encuentra en la dirección 0xFFDC, se debe escribir:
VECTOR ADDRESS 0xFFDC Mi_INTERRUPCION
Un programa completo que use el Timebase para generar una onda cuadrada por
PTA7 tendría la siguiente forma:#define TBON 2#define TACK 8 //Ack del TBCR
#define ENABLE_INT {asm cli;}#define DISABLE_INT {asm sei;}
#pragma TRAP_PROCvoid Mi_INTERRUPCION (void){TBCR |= TACK; // Acknowledge IntPTA ^= 0x80; // invierte el estado de PTA7
}
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 26
//*********************************************************************************//void main (void){CONFIG1 = 1; //Parar COPDDRA = 0xFF; //PTA todo salida
TBCR = 0x04; //Timebase divide por 8192ENABLE_INT //Habilitar las interrupcionesTBCR |= TBON; //Prender el Timebasewhile (1) { //Hacer nada}}
3.2 La instrucción interrupt
Code Warrior tiene una instrucción especial que no se encuadra dentro del estándar ANSI-C llamada “interrupt” que permite simplificar el proceso de definición de una
interrupción [7]. Debe usarse como si fuera un calificador de tipo pero seguida de unnúmero que especifica la entrada en la tabla de vectores de interrupción que contendrála dirección de la función que se está definiendo. Si no se especifica ese número, tiene elmismo efecto que TRAP_PROC y el vector debe definirse con la sentencia VECTOR en el archivo de parámetros 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 modificación, el código de ejemplo quedaría 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 IntPTA ^= 0x80;}
//*********************************************************************************//void main (void){CONFIG1 = 1; //Parar COPDDRA = 0xFF; //PTA todo salidaTBCR = 0x04; //Timebase divide por 8192ENABLE_INT //Habilitar las interrupcionesTBCR |= TBON; //Prender el Timebasewhile (1) { //bucle infinito}}
5/13/2018 Codigo C Eficicnete Para Sistemas Embebidos y Code Warrior 2011 - slidepdf.com
http://slidepdf.com/reader/full/codigo-c-eficicnete-para-sistemas-embebidos-y-code-warrior-
Código C Eficiente para Sistemas Embebidos Página 27
Bibliografía:
[1] Stuart Robb, “Creating Efficient C Code for the MC68HC08”, Nota de Aplicación,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)
top related