FEOS: Sistema operativo experimental para PDA daVinci.











Índice:
 

MOTIVACIÓN

El Procesador MC68EZ328 permite implementar a través de su lógica de CHIP-SELECT una mínima protección del kernel del sistema operativo. Sin embargo, el sistema operativo que trae el daVinci de fábrica no aprovecha en absoluto esas posibilidades, y dado que los tribunales han fallado que este sistema operativo es un plagio del Palm-Pilot, he de entender que el sistema operativo del Palm-Pilot es igualmente malo, y que si no revienta más a memudo es tan solo debido a que las aplicaciones están bien hechas.

En concreto los aspectos negativos del sistema operativo del davinci son:

Por otra parte, tenemos la implementación de Linux para sistemas 68000 sin MMU: el uCLinux. Sin embargo, los requisitos de memoria hacen que un port de este Linux al davinci sea totalmente descartado. El segmento de datos del kernel ya ocupa la práctica totalidad de la memoria RAM disponible. Además un sistema propio  de estaciones de trabajo no parece lo más adecuado para un PDA. El concepto de memoria Flash como medio de almacenamiento choca con un sistema orientado a los discos.

CARACTERÍSTICAS

El sistema operativo FEOS pretende aprovechar las posibilidades del procesador MC68EZ328 para desarrollar un sistema operativo seguro. Esto supone limitar el acceso de las aplicaciones a los recursos del sistema que podrían suponer un peligro para el kernel. Desafortunadamente el procesador dragonball no incorpora una MMU, lo que permitiría un aislamiento total entre aplicaciones, sin embargo sí que es posible tener un kernel protegido de las aplicaciones, aunque las aplicaciones no estén protegidas entre sí, y este ha sido el camino seguido para el desarrollo del FEOS.
Por otra parte he pretendido hacer un sistema multitarea, más como un reto personal que como una necesidad. Pero una vez implementada, la multitarea ha mostrado su utilidad práctica.

Las principales características  del FEOS son:

Versión 2.4

En la versión 2.4 del S.O FEOS se han realizado algunos cambios respecto a las versiones anteriores. Las
partes de este documento que hace referencia a dicha versión están escritas en color marrón.

Los principales cambios de dicha versión son:
 

DESCRIPCIÓN
 


Organización de la memoria.

Como ya he comentado antes, la organización de la memoria es distinta para el daVinci de 2Mb que para el de 256Kb. La asignación de cada área a un dispositivo concreto se consigue mediante la reprogramación de la lógica de "Chip-Select" del 68ez328, cosa que se hace inmediatamente tras el arranque.

El mapa de memoria para el daVinci de 2MB queda como sigue:

Hay que destacar que el kernel ocupa tan sólo 29Kb de los 64 que tiene reservados. Los siguientes 64Kb están reservados para la librería de funciones compartidas de las aplicaciones (ROMLIB). En la memoria flash secundaria se ubica la tabla de vectores, que ocupa sólo 1Kb, pero dado que el primer sector de la Flash es de 16Kb no podemos utilizar el resto de este sector para el sistema de ficheros 1, ya que los sistemas de ficheros deben comenzar justo en la frontera de un sector de la Flash. La memoria RAM está mapeada en dos direcciones: 0x10000000 y 0x10800000. En la primera dirección hay una proteción de acceso en modo supervisor a partir de los primeros 128Kb. En la dirección 0x10800000 la RAM está accesible en su totalidad como SÓLO LECTURA. Estas direcciones sólo se usan en el S.O. FEOS como acceso a la memoria de video desde el controlador del LCD, y sólo en tareas del kernel.

El mapa de memoria para el daVinci de 256Kb es el siguiente:

En este caso, debido a la ausencia de la memoria Flash secundaria, no existe el sistema de ficheros 1, y la tabla de vectores está ubicada en la memoria RAM en una zona no protegida de las aplicaciones. La memoria RAM también está mapeada a partir de la dirección 0x00800000 como SÓLO LECTURA, para su uso desde el controlador de video .

Scheduler

La multitarea en el sistema operativo FEOS se implementa de una forma muy simple. En primer lugar cada tarea tiene una o dos áreas de pila: una para el modo usuario y otra para el modo supervisor.  Una conmutación de tarea supone:
 

  1. Pasar a modo supervisor por una interrupción del temporizador o por TRAP #1.
  2. Guardar en la pila del supervisor de la tarea saliente el valor de todos los registros del procesador (incluyendo USP).
  3. Cambiar el valor del puntero de pila por el de la pila del supervisor de la nueva tarea.
  4. Recuperar el valor de todos los registros de la pila de la tarea nueva.
  5. Ejecutar la instrucción RTE (retorno de excepción). Esto recupera PC y SR de la pila.
Cada tarea tiene una entrada en una tabla en la que se almacena el último valor de su puntero de pila del supervisor. Además de este importante dato, en la tabla de tareas se almacena también el estado de la tarea, su prioridad, su nombre y el tiempo de CPU consumido.

Una tarea puede estar en varios estados: KILLED (-2), SLEEPED (-1), RUNNING (0) , o temporizando (>0). Las entradas de la tabla de tareas marcadas como KILLED no se corresponden con tareas en ejecución, y pueden ser reutilizadas al arrancar una nueva tarea. Las tareas en el estado SLEEPED no pasan nunca a ejecución. Tampoco pasan a ejecución las tareas que están en temporización, pero por cada interrupción de reloj se decrementa el valor de su estado, de modo que tarde o temprano cambiaran al estado RUNNING.

Para seleccionar la siguiente tarea que pasará a ejecución de entre todas las tareas en el estado RUNNING se debe tener en cuenta su prioridad. Para ello cada tarea tiene un contador al que se suma el valor de su prioridad cada vez que dicha tarea sea rechazada al seleccionar la nueva tarea.  Se elige por lo tanto la tarea con el mayor valor de contador, a la vez que dicho contador pasa a cero. De este modo las tareas con mayor prioridad pasan a ejecución más frecuentemente que las de baja prioridad, y todas las tareas tienen alguna probabilidad de ejecutarse.

Cuando no hay ninguna tarea en el estado RUNNING se pasa a la tarea número 0 (idle), que detiene el reloj del 68000 hasta la siguiente interrupción para reducir el consumo de corriente.

Las conmutaciones de tarea pueden deberse a las interrupciones de reloj o a que una tarea dada renuncie a su cuanto de CPU. En el primer caso tenemos el temporizador de propósito general del 68ez328 que genera 64 interrupciones por segundo. Este temporizador funciona en el modo "free running" a una frecuencia 1/8 de la de la CPU, y también se utiliza para llevar un recuento del tiempo de CPU consumido por las tareas en una variable de 64 bits. El tiempo de CPU de la tarea 0 (idle) nos da una idea del consumo de CPU del sistema.

Cuando una tarea no puede continuar su ejecución por esperar un evento ajeno a ella, pasa al estado SLEEPED y ejecuta una instrucción TRAP #1, que conmuta a otra tarea.

Por último, hay que destacar que la interrupción del temporizador del 68ez328 es muy prioritaria (nivel 6), de modo que podría interrumpir a rutinas de  interrupción de menor prioridad que necesiten una atención urgente, como es por ejemplo el caso de la interrupción de la UART (nivel 4). Para evitar largas esperas por parte de estas rutinas, que no finalizarían hasta que la tarea conmutada pase de nuevo a ejecución, en la rutina de interrupción del temporizador se comprueba el valor del registro  SR y si se detecta que se ha interrumpido a otra interrupción se evita la conmutación de tareas, que queda aplazada hasta la finalización de la rutina de interrupción de menor prioridad.

Llamadas al Sistema

Las aplicaciones que se ejecutan en modo usuario necesitan pasar a modo supervisor cuando pretenden utilizar alguno de los recursos protegidos. Las llamadas a las funciones del kernel se realizan a través de la instrucción TRAP #0. Los parámetros, y el código que identifica la función llamada se pasan en la pila de usuario de la tarea. La función, en lenguaje C, que realiza la llamada al sistema es la siguiente:

int syscall(int cix,...)
{
        asm volatile ("trap #0");
}

Los códigos de función están definidos en "syscall.h ", y para ver los parámetros de cada función puede analizarse el código de "ksyscall.c ".
Tras la ejecución de TRAP #0 la pila del usuario de la tarea queda de la siguiente forma:

Si la llamada se realiza en un programa escrito en lenguaje ensamblador se puede ignorar el valor del "PC de retorno" y llamar directamente a TRAP #0. Tras la llamada hemos de restaurar la pila. Sirva el siguiente ejemplo de "prim_dv.asm ":

                              * Buscamos 16Kb de memoria para matriz
        pea.l    $4000        * Tamaño del bloque
        pea.l    2            * KMALLOC
        pea.l    0            * Dir de retorno (no importa el valor)
        trap     #0           * SYSCALL
        lea.l    12(sp),sp    * Restauramos la pila
        move.l   d0,a0        * El valor retornado está en D0

Terminales Virtuales.

Los terminales virtuales nos permiten conmutar la consola de una aplicación a otra simplemente pulsando la tecla "find" o a través del menú de tareas. Pulsando en la parte superior de la pantalla táctil se conmuta al terminal de la tarea "shell". Cada terminal incluye memoria para la pantalla, que puede funcionar en modos de 2, 4 o 16 niveles de gris, información del modo de video, del estado y posición del cursor, y una cola de eventos desde la que llegarán a la tarea propietaria del terminal las pulsaciones del teclado o de la pantalla táctil.

Sólo uno de los terminales permanece en primer plano. Gracias a la posibilidad de cambiar la base de la memoria de video del 68ez328 resulta fácil la conmutación de un terminal virtual a otro.

Hay que señalar un problema (posiblemente BUG) del 68ez328, que compromete la seguridad de los terminales de las tareas en modo supervisor: La zona reservada para la memoria de video debe estar ubicada siempre en la memoria RAM del usuario, ya que si se ubica en la memoria del supervisor aparece basura en la pantalla mientras la CPU ejecuta tareas en modo usuario. Este problema se debe sin duda a que las lineas FC0-FC2 durante los accesos de DMA son generadas por la CPU y no por el controlador de DMA como debería ser (otro suspenso para los diseñadores del 68ez328). Como resultado de este problema resulta que las tareas en modo usuario pueden corromper la pantalla de tareas de modo supervisor pues la memoria de video se ubica en la zona de RAM no protegida.

Este problema se ha solventado con un doble mapeo de la memoria RAM en la versión FEOS 2.4. En esta versión la memoria de video de las aplicaciones en modo supervisor se encuentra en la zona protegida de la memoria RAM, pero el controlador de video la accede desde una dirección superior (offset=0x800000) donde la RAM está accesible para todas las tareas como sólo lectura. Hay que destacar que este "workaround" ha sido posible gracias al diseño de la lógica de selección de la memoria RAM en el daVinci. Esta solución puede que no sea viable en otros PDAs como los Palm.

Colas de Eventos

En el sistema FEOS la interacción con el usuario del daVinci se realiza a través de eventos. El sistema maneja dos tipos de eventos: los eventos "crudos" y los "cocinados". Los primeros se generan en rutinas de interrupción y pueden ser debidos a las siguientes causas:

Estos eventos se añaden a una cola de donde son extraídos y procesados por la tarea "eventd". Esta tarea tiene como función convertir los eventos de bajo nivel en otros más elaborados ("eventos cocinados") y rutarlos a la tarea cuyo terminal virtual está en primer plano. Cada terminal virtual incluye por lo tanto una cola de eventos cocinados.

Una de las principales funciones de "eventd" es la de procesar las pulsaciones en la pantalla táctil, que supone en primer lugar una conversión de coordenadas desde los valores de los conversores A/D del chip "nexus" a unidades de la pantalla. Para ello se necesitan datos de la calibración de la pantalla táctil, aunque por defecto se usan unos parámetros que son buenos para mi daVinci particular, pero que pueden no serlo para otros. A continuación, dependiendo de las coordenadas obtenidas para la pulsación, se puede generar un evento EV_LCD_TAP_PRESS  si la pulsación cae sobre el área del LCD, o se realiza la emulación del teclado si la pulsación cae sobre el área inferior de la pantalla táctil (EV_KEYBOARD).

La tarea eventd también realiza funciones de registrador ("log"). Para ello mantiene abierto un terminal virtual que puede localizarse pulsando el botón "find" (es la propia tarea eventd la que cambia el terminal que está en primer plano). Cuando una tarea termina debido a una excepción eventd nos informa del tipo de excepción y del valor del PC cuando se produjo la excepción, lo que puede ayudar a investigar las causas del problema.

Las interrupciones del RTC pueden "despertar" al daVinci y generar eventos como el de cambio de día y el de alarma (despertador). El primer evento se emplea para actualizar el año en la fecha del S.O. y sólo tiene efecto la noche de fin de año. La interrupción de alarma del RTC se produce cuando la fecha y hora del RTC coincide con la programada en sus registros de alarma. Los eventos de alarma, una vez filtrados por eventd, podrían usarse en aplicaciones de tipo despertador, planner, etc.

Emulación del Teclado.

El teclado se emula pulsando con el lápiz en el área de la pantalla táctil que queda bajo el LCD, y que originalmete se usaba  para el reconocedor de caractéres. Para no teclear a ciegas es necesario colocar la plantilla de la siguiente figura sobre la pantalla táctil: (keyboard.ps )

Los botones del cursor del daVinci también generan eventos de teclado, idénticos a los que se obtienen pulsando sobre las teclas de las flechas.
 

Programación de la Memoria FLASH.

La programación y el borrado de las memorias Flash requiere ciertas precauciones. En primer lugar hay que señalar que el propio sistema operativo reside en una Flash, y que durante las operaciones de programación y borrado dicha Flash no se puede leer. Por lo tanto las rutinas de programación y borrado de la flash residen en la memoria RAM, donde se copian al arrancar el sistema junto con las variables estáticas no inicializadas (sección ".data", ver flash_prg.s ). Mientras dura la programación o el borrado de las memorias flash no esta permitida ninguna interrupción, ya que la tabla de vectores o las propias rutinas de interrupción pueden no estar presentes al no poder leerse las memorias Flash.

Sistema de Ficheros.

El sistema operativo FEOS puede manejar uno o dos sistemas de ficheros residentes en las memorias flash. El primer sistema de ficheros ocupa la misma memoria que el sistema operativo, mientras que el segundo ocupa la mayor parte de la flash secundaria y sólo está presente en el daVinci 2MB.

Cada sistema de ficheros debe comenzar en un sector de la memoria Flash. Esto es así ya que el borrado de la memoria flash se realiza sector a sector, y por ello no queremos que un sector de la flash contenga además del sistema de ficheros otros datos.

La estructura del sistema de ficheros es sumamente simple. Un fichero no es más que una zona de datos, no fragmentada, precedida de una cabecera. En dicha cabecera se almacena información relativa al fichero, como su tipo, tamaño y nombre. La secuencia de ficheros forma una lista que se va incrementando cada vez que se añade un fichero. Cuando se borra un fichero lo que en realidad se hace es cambiar su tipo por el valor 0. Aprovechamos para ello una de las características de las memorias flash, que una vez borradas contienen todos sus bits en 1, y que al programarse escriben los bits 0 de los datos.

Los ficheros borrados no retornan al sistema de ficheros el espacio ocupado, dado que siguen estando presentes en la memoria flash. Para recuperar este espacio es necesario realizar una desfragmentación de los sistema de ficheros. La utilidad necesaria para dicha desfragmentación está incluida en la tarea "shell", y no conviene abusar de ella, ya que supone un riesgo para los datos. Durante la desfragmentación los ficheros no borrados y sus cabeceras se copian a la memoria RAM, se borran los sectores de la flash ocupados por el sistema de ficheros, y finalmente se vuelve a programar la memoria flash con los ficheros que estaban en RAM. Esta operación, en principio parece simple, pero hay que tener en cuenta que el sistema de ficheros puede ser mucho mayor que la memoria RAM disponible, lo que complica las cosas. Antes de relizar la desfragmentación conviene asegurarse de que las pilas tienen suficiente carga, que está libre al menos la mitad de la memoria RAM del supervisor, y que no se están transfiriendo ficheros desde el PC. Cuantas menos tareas estén en marcha antes de la desfragmentación mucho mejor.
 

Comunicaciones.

Las comunicaciones del daVinci con el PC se realizan a través de la UART del 68ez328. El formato elegido para los datos es de 8 bits sin paridad y un único bit de stop. La velocidad es la máxima posible en el PC: 115200 baudios. En el sistema operativo FEOS se utiliza la interrupción de la UART para implementar el protocolo SLIP mediante una "máquina de estados". Asimismo se aprovechan las ventajas de las FIFOS de la UART para reducir el número de interrupciones.

Sobre el protocolo SLIP no se ha implementado ningún otro protocolo como IP, ICMP, UDP o TCP,  ya que en una comunicación como ésta no es necesario pues complica mucho el sistema operativo y enlentece las comunicaciones por el gran tamaño de las cabeceras de los paquetes.

La tarea remoted se encarga de atender a las peticiones realizadas desde el PC, y por lo tanto opera como servidor. Mediante la tarea remoted se pueden leer los ficheros del daVinci, se pueden pasar desde el PC ficheros nuevos y se pueden capturar fotos de la pantalla del daVinci. El protocolo es muy simple: "remoted" espera una orden del PC, y contesta con el resultado de la ejecución de dicha orden. Cada mensaje ocupa un único paquete SLIP, de tamaño inferior o igual a 256 bytes de datos útiles (configurable) . Los códigos de los comandos (ver "remote.h ") son de 16 bits para mantener los datos de los paquetes alineados a direcciones pares.

Por supuesto, en el PC se debe ejecutar una aplicación cliente. Se ha escrito dicho cliente ("dvtrf.c ") para sistemas Linux con procesador "Little Endian" (es decir para PC's y tal vez alphas. Para procesadores "Big Endian", como SPARC, hay que reescribir las funciones "swapw" y "swapl"). En dicha aplicación se implementa el protocolo SLIP, de modo que no es necesario configurar un interfaz SLIP en el puerto serie del cradle.

A continuación se comenta el uso de "dvtrf" para comunicar el daVinci y el PC:

Para leer todos los ficheros del daVinci al PC se ejecutará en el PC:

dvtrf get 0 0

Los argumentos que siguen a "get" son el tipo y subtipo de los ficheros y actúan como filtro (ver "file.h "). El valor 0 significa todos los tipos o todos los subtipos. Si por ejemplo queremos recuperar sólo los ficheros de tipo texto (3) y todos los subtipos ejecutaríamos:

dvtrf get 3 0

Hay que destacar que en el daVinci no es necesario arrancar ninguna aplicación de tipo "smart/dumb Sync" para atender al PC, ya que la tarea "remoted" está siempre a la escucha. Es la ventaja de la multitarea.

Para pasar ficheros del pc al daVinci se utiliza "dvtrf put <ficheros>", como en el siguiente ejemplo:

dvtrf put prim_dv.pic frank.4bpp

El programa dvtrf genera el tipo y subtipo de los ficheros a partir de la extensión de los mismos. Así  ".pic" significa "código máquina ejecutable, independiente de la posición" y ".4bpp" significa "Volcado de pantalla de 4 bits por pixel (16 niveles de gris)". Los nombres de los ficheros se truncan si superan los 15 caracteres (sin extensión), pero no pasa nada aunque se tengan nombres repetidos (aunque no es una buena idea a la hora de identificar los ficheros).

Por último, para obtener una foto de la pantalla del daVinci ejecutaremos:

dvtrf dump foto.pgm

Esto generará un fichero "foto.pgm" que puede ser convertido a otros formatos con aplicaciones como "xv" o "gimp".
 
 

Aplicaciones

En el sistema operativo FEOS podemos tener  dos tipos de aplicaciones:

  1. Tareas de modo supervisor del kernel.
  2. Ficheros ejecutables.
Entre las aplicaciones del primer tipo tenemos tareas como "eventd", el procesador de eventos, "remoted", el servidor de comunicaciones con el PC, el propio entorno de menús o "shell", y los visores de ficheros de texto y gráficos. Todas estas tareas funcionan siempre en modo supervisor, de modo que no están sujetas a las protecciones del kernel, y pueden obviar todo el mecanismo de las llamadas al sistema, aumentando por lo tanto su velocidad de ejecución. Por otra parte han de ser sumamente fiables, pues una simple excepción en una de estas tareas echaría abajo todo el sistema.

Las otras aplicaciones son los ficheros ejecutables que pueden cargarse en el daVinci mediante la aplicación dvtrf. Aunque hay previstos varios tipos de ficheros ejecutables, hasta el momento el único tipo soportado es el de "Código Máquina independiente de la posición" (extensión .pic para dvtrf). Estos ficheros se ejecutan en modo usuario, con una pila de 4Kb de largo, y los direccionamientos empleados deben ser tales que se ejecuten correctamente en cualquier posición de la memoria, pues no sabemos a priori cual va a ser su ubicación en la Flash. En el directorio "feos/pic " se encuentra el código fuente de las aplicaciones que se proporcionan con el sistema.

Para generar aplicaciones .pic se necesita un compilador cruzado especial, que genere este tipo de código independiente de la posición. Las aplicaciones pueden llamar a las funciones del kernel a través de TRAP #0 (función syscall), pero también pueden llamar a otras funciones de librería que aunque residan permanentemente en la Flash del sistema se ejecutan en modo usuario (ROMLIB ). De este modo se compraten entre aplicaciones parte del código reduciéndose el tamaño de las mismas. Por supuesto, una aplicación puede usar sus propias librerías sin recurrir a las funciones de ROMLIB.
 

Visores de Texto y Gráficos:

El S.O. incluye unas aplicaciones rudimentarias que permiten la visualización de los ficheros de texto y gráficos. Estas aplicaciones se ejecutan como tareas en modo supervisor, de modo que no ocupan la memora de modo usuario, y se arrancan desde el menú de ficheros. Para ello basta con seleccionar un fichero de texto o gráfico y picar en "VER".

En la versión 2.4 el visor de gráficos admite fotos con compresión DCT. Este algoritmo de compresión es similar al JPEG: se basa en la transformada discreta del coseno, que se realiza con aritmética entera, y en una codificación de los coeficientes que es un híbrido entre una codificación de Huffman y una RLE. La rutina de descompresión es totamente reentrante y puede llamarse en modo usuario. Una llamada al sistema puede retornar a la aplicación que lo necesite la dirección de dicha rutina de descompresión.
 
 

Entrada de Audio

A partir de la versión 2.3 el sistema operativo FEOS incorpora la posibilidad de digitalizar audio mediante un conversor ADC externo. Este conversor es sumamente barato y sencillo. Se basa en la generación de pulsos cuya duración depende proporcionalmente de la tensión de la entrada de audio. La duración de dichos pulsos se mide mediante el temporizador de propósito general del daVinci a través de la entrada de interrupción IRQ6. La frecuencia de muestreo nominal es de 8000 Hz, lo que acaba generando nada menos que 16000 interrupciones por segundo, que sin embargo son atendidas por el procesador Dragonball sin problemas.

El esquema del modulador de anchura de pulsos (PWM) es el de la siguiente figura. Aunque el integrado 4069 contiene 6 inversores CMOS el uso que se hace de los mismos es más analógico que digital. U1a, U1b y U1c forman un oscilador de onda triangular compuesto de un integrador (U1a, R1, C1) y de un disparador de Schmitt (U1b, U1c, R2,R3). La salida triangular se suma con la entrada de audio mediante las resistencias R4 y R5 antes de atacar a los inversores U1d y U1e, que funcionan como comparadores a la referencia Vdd/2. El condensador C2 aísla la componente contínua de la entrada.  Gracias a la simplicidad de los inversores el circuito funciona alimentado con los 3.3 voltios del daVinci, y el consumo medido es de sólo 25 µA, suficientemente pequeño como para no preocuparse de tenerlo siempre conectado.

El en daVinci se genera una interrupción por cada flanco de la señal PWM generada. En los flancos de subida se registra el valor del temporizador, y la diferencia con el flanco de subida anterior se utiliza para medir con precisión la frecuencia de muestreo del conversor. En el flanco de bajada se mira de nuevo el temporizador y se le resta el valor registrado en el flanco de subida. El resultado, que es proporcional al ancho del pulso, se trunca a 8 bits sin signo y se añade a una cola circular en la memoria de usuario de la aplicación receptora de las muestras de audio.

Las tareas que deseen digitalizar audio deben llamar al sistema con:

syscall(AUDIO_START,buffer[],longitud);

Si esta llamada tiene éxito se comienzan a introducir muestras en el buffer de inmediato. Para saber por donse se llega el puntero del buffer tenemos un nuevo syscall "rápido" implementado a través de "trap  #2":

extern inline char *get_audio_pointer()
{
char *pa;
asm volatile("trap #2\n move.l %%d0,%0":"=a"(pa));
return pa;
}

Por último, tenemos también una llamada para detener el muestreo:

syscall(AUDIO_STOP);

y otra para medir la frecuencia de muestreo cuando la captura está en marcha y no hay señal en la entrada:

frec=syscall(AUDIO_MEAS_FREC);    // Resultado en Hz
 

Salida de Audio PWM.

El procesador 68EZ328 ya trae incorporado un modulador PWM para la generación de audio, de modo que me he limitado a configurarlo para una frecuencia de muestreo de 8096 Hz. También he tenido que escribir su correspondiente rutina de interrupción, también de nivel 6. En esta rutina se hace uso de la FIFO del modulador PWM, de modo que las muestras se escriben de 4 en 4. El buffer de RAM debe comenzar en una dirección par, y su tamaño también debe ser par. Las llamadas al sistema son similares a las de la digitalización de audio:

syscall(PWM_START,buffer[],longitud);    // Arranca la reproducción.
syscall(PWM_STOP);                       // Para la reproducción.

También hay una llamada rápida con "trap #3" para obtener el valor del puntero de reproducción:

extern inline char *get_pwm_pointer()
{
char *pa;
asm volatile("trap #3\n move.l %%d0,%0":"=a"(pa));
return pa;
}

El modulador PWM también se utiliza para generar tonos rectangulares (syscall SOUND). Por ello mientras se está reproduciendo sonido digitalizado no es posible la ejecución del syscall SOUND, que queda aplazado hasta la ejecución de PWM_STOP.

Por último queda recordar la mala calidad del sonido reproducido, que se debe al altavoz piezoeléctrico del daVinci. Aún así tengo la esperanza de poder usar esta salida para obtener tonos DTMF.
 

La librería compartida (ROMLIB).

En la dirección de memoria 0x10C2000C se ha creado una tabla con punteros a las funciones de librería del sistema, que de este modo quedan accesibles a las aplicaciones de los usuarios, que no necesitan incluirlas en su propio código con el consiguiente ahorro de espacio. Estas funciones se supone que son reentrantes, y aunque no las he probado todas he eliminado las que claramente no lo son, como "strtok". La librería desde el punto de vista del usuario es una simple tabla de saltos (lib/librom.a), que se linka con la aplicación. Las entradas de librom.a son como la siguiente:

           .globl printf
printf:    movea.l 0x10c20018,%a0
           jmp (%a0)

La mayor parte de las funciones de la librería actual son las de libgcc.a, que incluyen la aritmética entera de 32 y 64 bits y de coma flotante. Le siguen otras funciones de libm.a (funciones trigonométricas, etc) y las funciones de manejo de cadenas de <string.h>. Además de estas funciones se proporcionan también printf, sprintf y syscall de /userland/ulib.c.

No se descarta la posibilidad de aumentar esta librería en un futuro.

Hay que señalar que las llamadas a esta librería son distintas de las llamadas "syscall" puesto que el código de la librería se sigue ejecutando en modo usuario, mientras que una llamada syscall conlleva un cambio a modo supervisor.