SISTEMA DE SIMULACIÓN PARA UN MICROCONTROLADOR

Anuncio
Ponencia Antonio Luque
SISTEMA DE SIMULACIÓN PARA UN MICROCONTROLADOR
ELECTRÓNICO BASADO EN LAS HERRAMIENTAS DE
DESARROLLO GNU
J. M. Benítez, A. Luque
Departamento de Ingeniería Electrónica, Universidad de Sevilla, Spain
aluque@gte.esi.us.es
En este artículo se presenta un entorno modular de simulación de sistemas electrónicos
construidos alrededor de un microcontrolador. A partir de unas herramientas que
propociona el depurador GDB, se han desarrollado simuladores de periféricos y de
dispositivos electrónicos simples que pueden conectarse a un microcontrolador. Se
describe la arquitectura general del sistema, que consta de: simuladores de periféricos,
simuladores de módulos externos, interfaz de usuario, y sistema de comunicaciones
entre las partes.
Palabras clave: microcontrolador, simulación, GDB, periférico.
1. Introducción
Los microcontroladores son las piezas fundamentales de los sistemas empotrados, que en los
últimos tiempos se han convertido en casi ubicuos. Un microcontrolador es un dispositivo
electrónico parecido a un microprocesador, pero más completo que éste en muchos aspectos.
Al igual que un microprocesador, un microcontrolador (uC) posee una unidad aritméticológica (ALU), y una serie de registros internos. Estos elementos forman la unidad central de
proceso (CPU). Un microprocesador no contiene nada más (salvo quizá memoria de
almacenamiento), pero un microcontrolador integra en el mismo circuito integrado una serie
de periféricos, que lo dotan de funcionalidad completa. Estos periféricos son, por ejemplo,
contadores, puertos serie, temporizadores, memorias, puertos de E/S, etc. Un
microcontrolador no necesita de más componentes electrónicos para funcionar, mientras que
un microprocesador sí. Es por esto, que los microcontroladores son el componente más
utilizado para construir sistemas empotrados, en los que el tamaño y el coste son factores
determinantes (VanSickle2001).
Normalmente, estos sistemas empotrados carecen de los interfaces que presentan los
ordenadores de propósito general, como teclado o monitor, por lo que la programación de los
microcontroladores que los integran no puede hacerse directamente. Lo usual es escribir y
compilar el programa en un ordenador personal y luego descargar una imagen binaria del
mismo a la memoria interna del microcontrolador. La depuración de los programas es
extremadamente difícil en un sistema empotrado, al no poseer éste los mecanismos de
interfaz con el exterior antes descritos, siendo muy habitual el proceso de prueba y error para
depurar un programa. Conscientes de este problema, muchos fabricantes de
microcontroladores han desarrollado emuladores, dispositivos que, situados en el sistema
electrónico en el mismo lugar en que estaría el microcontrolador, y conectados a su vez a un
PC, se comportan desde el punto de vista eléctrico de la misma forma que lo haría el
microcontrolador que se pretende emular. Estos emuladores suelen tener un precio
prohibitivo, que los hace inviables para muchas aplicaciones.
El proceso de depuración usando el hardware real es caro y tedioso. Se comprende la
necesidad de contar con un simulador que se ejecute enteramente en un PC y que sea capaz de
leer e interpretar un programa compilado para el microcontrolador, y proporcionar las mismas
salidas que proporcionaría este. Usando simuladores, el ciclo de desarrollo se puede acortar
sensiblemente y el coste fijo asociado al proyecto es bastante menor.
En este artículo se describe un sistema de simulación desarrollado por los autores para los
microcontroladores de la familia M.CORE de Motorola (MMC2000). El sistema está basado
en las herramientas GNU, como GCC y GDB que han sido aportadas por el fabricante del
microcontrolador, a las que los autores han añadido las rutinas suficientes para simular el
microcontrolador completo.
La familia M.CORE consta de varios microcontroladores diferentes construidos alrededor de
una CPU RISC (Reduced Instruction Set Code). Su característica más destacada es el bajo
consumo, lo que los hace ideales para aplicaciones móviles o que necesiten baterías. Cada
miembro de la familia es ligeramente diferente en los periféricos que incorpora, pero en
general se cuenta con puertos serie síncronos (SPI) y asíncronos (SCI), memoria Flash,
memoria RAM estática (SRAM), temporizadores, convertidores analógico-digitales, y
puertos digitales de entrada/salida, entre otros.
2. Diseño general del sistema
La compañía Motorola, fabricante del microcontrolador, proporciona un simulador de la CPU
del mismo para ser embebido en el depurador GDB. Por otra parte, algunos empleados de la
misma han contribuido a la comunidad de software libre una versión del compilador GCC y
del resto de herramientas de desarrollo GNU adaptadas para producir código M.CORE.
El simulador aportado por Motorola se limita exclusivamente a la CPU del microcontrolador,
por lo que es apropiado únicamente para calcular los tiempos de ejecución de un determinado
programa. En este aspecto es muy preciso, como se puede comprobar en la Tabla 1, en la que
se comparan los ciclos de reloj que toma la ejecución de varios programas en el simulador del
que tratamos con los que toma según las pruebas internas de Motorola. La compañia afirma
que la precisión del simulador para cualquier programa está en torno al 0.5%.
ciclos reales
ciclos sim
Diferencia
Programa 1
366101
366102
0.00%
Programa 2
4461476
4462938
0.03%
Programa 3 255551
255547
0.00%
Tabla 1. Comparación de ciclos de reloj usados por varios programas,
en la realidad y en el simulador de Motorola. Los programas son:
algoritmos de ordenación, resolución de ecuaciones y compresión de
datos. Fuente: Motorola, Inc.
El concepto central del sistema descrito en este artículo es la construcción, en torno al
simulador de Motorola, un sistema que sea capaz de simular los periféricos del
microcontrolador, y al que se puedan conectar dispositivos externos, de la misma forma que
se haría con un sistema electrónico real. El usuario del simulador es capaz de especificar qué
dispositivos están conectados en qué pines del microcontrolador, y el simulador se encarga de
que estos dispositivos reflejen el estado actual del sistema. En la sección 5 se incluye un
ejemplo simple.
Para lograr el objetivo descrito, son necesarias dos simulaciones adicionales a la de la CPU.
Por una parte, hay que simular todos los periféricos internos al microcontrolador, como
contadores, puertos, etc. Y por otra, hay que añadir un conjunto de módulos que se puedan
conectar externamente al simulador del microcontrolador completo. Estos módulos pueden
ser LEDs, displays de 7 segmentos, terminales serie, motores paso a paso, o cualquier cosa
que se pueda inventar. Estas dos nuevas simulaciones se describirán con detalle en las
secciones 3 y 4.
Con el objeto de no limitar arbitrariamente el sistema, la prioridad en el diseño del mismo ha
sido la modularidad. Los autores han desarrollado únicamente algunos módulos que se
pueden conectar al microcontrolador, pero han dotado al sistema de la capacidad de poder ser
extendido simplemente escribiendo el código de nuevos módulos. Para esto se ha diseñado
una interfaz de comunicación entre el simulador y los módulos externos, de forma que sea
muy fácil añadir nuevos módulos en cualquier momento.
En la Fig. 1 se muestra la arquitectura general del sistema. Las partes sombreadas han sido
desarrolladas por los autores dentro de este proyecto, mientras que las que tienen fondo
blanco se encuentran disponibles bajo licencia libre.
Figura 1. Estructura general del proyecto
3. Simulación de periféricos
La principal característica de la simulación de los periféricos, al igual que la del resto del
sistema, es su modularidad. No todos los microcontroladores de esta familia presentan los
mismos dispositivos periféricos, de manera que el diseño de estos dispositivos sigue un
patrón modular. Los elementos periféricos se representan como módulos independientes al
microcontrolador, para conseguir así una estructura flexible que puede simular cualquier
elemento microcontrolador de la familia. De esta forma, además, se facilita la incorporación
de nuevos periféricos al simulador.
Para que la flexibilidad no derive en problemas de incompatibilidad entre los distintos
elementos que forman el simulador se ha definido una interfaz de acceso a los dispositivos
periféricos. La estandarización del acceso a estos periféricos permite que la adición de un
nuevo elemento que se ajuste a esta interfaz definida no implique cambios adicionales en el
resto de la estructura del simulador.
La combinación del diseño modular en la simulación de los periféricos junto con la definición
de un acceso estándar a ellos consigue que el microprocesador vea a los periféricos como
cajas negras, sin que tenga que conocer nada acerca de cuál es su estructura interna o cómo se
ha implementado su funcionalidad. Lo único que conoce el microprocesador es la manera de
acceder a esas cajas negras.
La directriz que suele seguir Motorola en la arquitectura de sus microcontroladores es mapear
todos los periféricos en memoria, de manera que no hay diferencia entre acceder a una
posición de memoria y acceder a un dispositivo externo, del mismo modo que no hay
diferencia entre acceder a un periférico y acceder a otro. Esta arquitectura viene a redundar en
la idea de que el microprocesador considere a los periféricos como cajas negras que se
distinguen entre sí tan sólo por la dirección mediante la cual son accedidas.
Éste ha sido, pues, el diseño que se ha seguido en la definición de la interfaz de acceso a los
periféricos, por ser la que habitualmente emplea Motorola, pero podría cambiarse fácilmente
a otras arquitecturas usadas por otros fabricantes, como puede ser Intel, que diferencia entre
accesos a memoria y accesos a periféricos.
Cada uno de los periféricos desarrollados en el proyecto posee su propio código, que trata de
imitar la lógica propia del componente hardware real. Así por ejemplo, un contador posee un
código que decrementa continuamente a intervalos regulares un cierto registro y activa un bit
en otro cuando la cuenta ha llegado a cero. El programa que se ejecuta en el simulador puede
leer este bit para saber si la cuenta ha acabado, o acceder en cualquier momento de forma
transparente al valor actual de la cuenta.
4. Interfaz de usuario
El uso de interfaces de usuario se hace especialmente útil en el desarrollo de sistemas
empotrados, pues éstos carecen de mecanismos de interfaz con el exterior como ocurre con
los sistemas para computadores. De esta manera, el poder visualizar de algún modo cuáles
son las salidas que proporcionan los programas que ejecuta el microcontrolador se convierte
en una ayuda inestimable para el desarrollo de tales sistemas.
La interfaz de usuario desarrollada refleja la doble vertiente de la naturaleza del desarrollo de
sistemas empotrados. Por un lado, dispone de todos los elementos habituales de un sistema de
depuración convencional para programas que se ejecuten en computadores, como puede ser la
ejecución controlada o la posibilidad de comprobar el valor de las variables que conforman el
programa.
Por otro lado, la incorporación al simulador de los dispositivos periféricos que forman el
microcontrolador hace necesario que la interfaz de usuario no sólo trabaje con el programa
que ejecuta el microprocesador, sino que también muestre el estado de los distintos
periféricos. De esta manera, podemos comprobar, por ejemplo, el estado del puerto serie o de
los distintos registros de salida.
Finalmente, y para conseguir que el simulador se ajuste lo más posible a la realidad, del
mismo que podemos conectar físicamente distintos elementos a la salida del microcontrolador
para comprobar su estado, la interfaz de usuario permite hacer lo mismo con el simulador,
mediante una serie de módulos independientes que representan elementos externos al
microcontrolador. Toda esta estructura se ha diseñado teniendo presente la necesidad de que
el conjunto sea fácilmente extensible, de forma que se puedan incorporar nuevos módulos si
el usuario de la interfaz lo cree necesario.
La interfaz de usuario es la capa más externa en la estructura del sistema desarrollado por los
autores. Se trata de una sencilla aplicación gráfica que pone a disposición del usuario toda la
potencia y capacidad que ofrece la API de comunicación con GDB. Dicha aplicación está
implementada con la completa librería de componentes Qt que ofrece Trolltech (Kalle2002).
Se ha elegido esta librería por la enorme flexibilidad y funcionalidad que provee el
mecanismo de signals y slots para la comunicación entre objetos.
Hay que hacer notar que la aplicación gráfica está perfectamente separada de la API, por lo
que no es necesario utilizar aquélla si queremos usar esta última. La API está presentada
mediante una serie de llamadas que obtienen toda la funcionalidad que ofrece GDB, por lo
que es posible desarrollar cualquier otro tipo de aplicación gráfica que haga uso de dicha
interfaz de programación. La aplicación desarrollada por los autores, aun siendo una interfaz
de usuario completa y totalmente funcional, puede servir de muestra a otras futuras
aplicaciones y a lo que éstas pueden conseguir si se utiliza la API.
La aplicación gráfica tiene un diseño convencional compuesto por un menú, una barra de
herramientas y una serie de vistas y panales. En la vista principal se puede ver el código del
programa que se quiere simular. Mediante el menú o directamente en la barra de
herramientas, el usuario de la aplicación gráfica puede controlar cómo se ejecuta el programa,
mediante la inserción y eliminación de puntos de ruptura y mediante los comandos de control
de flujo de ejecución.
Se dispone también de una serie de ventanas adicionales en las que se puede ir siguiendo la
evolución de varios componentes del programa. Así, se dispone de vistas para obtener el
valor de variables, de la pila de llamadas, de los registros internos del microprocesador y de
cualquier dirección de memoria del microcontrolador. Es esta serie de vistas la que da sentido
y utilidad al uso del simulador, puesto que se puede comprobar que todos estos parámetros
toman los valores que quiere el programador a medida que ejecuta su programa.
Por último y para hacer más útil el uso de esta herramienta, se ha provisto a la interfaz un
modo gráfico en el que el usuario puede añadir a la salida del microcontrolador elementos
externos como los que puede conectar en la realidad. De esta forma, se pretende conseguir
que el simulador refleje lo más fielmente posible el comportamiento real del
microcontrolador, comprobando el funcionamiento de elementos externos en lugar de una
serie de valores numéricos.
Toda esta funcionalidad se obtiene a través de la API de comunicación con GDB. Esta
interfaz de programación ofrece toda una serie de llamadas que ponen a disposición de los
programadores todo lo que GDB ofrece mediante su interfaz de comandos. En el sistema
desarollado por los autores se ha puesto especial hincapié en los aspectos más relevantes del
diseño de sistemas empotrados y que podemos apreciar en la interfaz de usuario, como puede
ser la obtención del estado de los registros internos del microprocesador o la obtención del
valor almacenado en una posición cualquiera de memoria.
Esta interfaz de programación no está ligada al microcontrolador M.CORE, es decir, es
independiente del microprocesador que se utilice, pudiéndose utilizar con cualquier otro
simulador que provea GDB.
El funcionamiento de la librería se basa en la creación de dos procesos que se comunican
mediante tuberías (pipes). Uno de estos procesos, el hijo, ejecuta el depurador GDB, mientras
que el otro, el proceso padre, se encarga de realizar las peticiones y presentarlas de manera
adecuada al exterior. También se utiliza otro mecanismo de comunicación entre procesos,
como son las señales, que se emplean para informar a la API de que han sucedido eventos
significativos, como puede ser el cambio de estado de los periféricos.
Para comunicarse con GDB se utiliza la interfaz GDB/MI, que es una interfaz orientada al
uso de GDB como una parte de un conjunto mayor (Stallman1994).
5. Ejemplo de aplicación
En esta sección se pretende ilustrar con un ejemplo las capacidades del sistema. Se va a
conectar un módulo externo en algunos pines de salida del microcontrolador simulado y se va
a proceder a simular un programa que acceda a dichas salidas.
Uno de los módulos desarrollados en el proyecto es el conjunto de LEDs. Se trata de un
número de diodos emisores de luz que se pueden conectar a cualquier pin de salida del
microcontrolador. Cuando el programa que se está ejecutando establece un valor lógico alto
en uno de esos pines, el LED correspondiente se ilumina en pantalla, y cuando el valor lógico
es bajo, permanece apagado. En este ejemplo, el conjunto de LEDs se conecta al puerto A del
microcontrolador (MMC2000).
Una vez se ha hecho esto, se compila el siguiente programa, que hace parpadear uno de los
LEDs del conjunto (se han omitido algunas inicializaciones de los registros del
microcontrolador, que no aportan nada al ejemplo).
int main(void)
{
set_led(OFF);
for(i=0;i<=10;++i) {
set_led(ON);
delay1();
set_led(OFF);
delay1();
}
}
En el programa anterior, la función set_led() únicamente pone un valor lógico alto o bajo
en un registro interno del microcontrolador, en función de su único parámetro, como se
muestra en el código siguiente.
void set_led(unsigned char v)
{
if(v)
reg_PORTA.reg|=0x01;
else
reg_PORTA.reg&=0xFE;
}
Este registro en un microcontrolador real se redirige inmediatamente a un conjunto de pines
de salida (el puerto A). En este sistema, es el simulador del periférico correspondiente al
puerto A el que informa al módulo de los LEDs de que el valor del registro ha cambiado. El
módulo entonces actualiza la imagen en pantalla, dando al usuario la impresión de que un
LED se enciende o apaga.
Por supuesto, son posibles simulaciones más complejas. Por ejemplo, los autores han
desarrollado también un módulo externo que simula un terminal serie, que se puede conectar
al puerto serie asíncrono del microcontrolador simulado. De esta forma, es posible la
visualización en pantalla de los caracteres transmitidos por el programa del microcontrolador.
6. Conclusiones
Se ha presentado un sistema apropiado para la simulación de sistemas electrónicos sencillos
basados en microcontroladores. El sistema descrito está orientado a la simulación de un
microcontrolador concreto, pero es fácilmente portable a otros para los que existan
simuladores de sus CPUs (GDB proporciona varios).
La gran ventaja del sistema descrito es la modularidad, que permite escribir nuevos módulos
que conectar al microcontrolador simulado con gran facilidad.
Las líneas de desarrollo futuro del proyecto se centran en la creación de una mayor cantidad
de módulos externos para ampliar el rango de sistemas electrónicos simulables. Otra
característica que los autores están estudiando es la posibilidad de conectar dos o más
microcontroladores simulados a través de sus puertos serie (síncronos o asíncronos) con el
objeto de simular un sistema de comunicaciones completo.
Referencias
(Kalle2002) Matthias Kalle Dalheimer, Programming with Qt, 2nd ed., O'Reilly, 2002.
(MMC2000) MMC2107 Technical Data, Motorola Inc., 2000.
(Stallman1994) Richard M. Stallman and Roland H. Pesch, Debugging with GDB, Free
Software Foundation, 1994.
(VanSickle2001) Ted Van Sickle, Programming microcontrollers in C, 2nd ed., LLH
Publishing, 2001.
Descargar