Modificación del modulo btaudio.c para la obtención de 896000 muestras por segundo con el ADC del Bt878A
|
|
¡Novedades! 08-2005
Soporte
ALSA para el Bt878a y Fedora Core 4
Aplicación:
Mi
primer Receptor "Software Defined Radio" (SDR)
Antecedentes: En mi pasado artículo Convertidor Analógico Digital de 16 bits y 448000 muestras por segundo basado en el Bt878A se narran los pasos a seguir para poder digitalizar señales analógicas utilizando el Convertidor Analógico Digital (ADC) que incorpora el chip Bt878A a velocidades de hasta 448000 muestras por segundo. Ahora describo una sencilla modificación al modulo btaudio.c para obtener mayor velocidad de digitalización.
Objetivo: Estudiar el sistema utilizado en la selección de la velocidad de sampleo en la etapa de audio del chip Bt878 y obtener velocidades superiores a 448000 muestras por segundo, que es la estándar.
Método: Recompilamos el modulo forzando el registro DA_SDR con valores inferiores a 4, que es el valor mínimo según datasheet del fabricante.
1 - Preparación:
- Seguir los pasos explicados en
el pasado
artículo (haz click aquí).
- Será necesario compilar un modulo, por lo que necesitamos tener instaladas las
fuentes del Kernel y un Linux Mandrake 9.1
2 - Lectura del datasheet del Bt878A
El datasheet del Fusion 878A de Conexant es ambiguo para responder a la pregunta: ¿A que velocidad puede digitalizar el ADC de audio del Bt878A?. De su lectura podemos extraer esta información:
En el apartado 2.18.7 Audio Data Formats observamos la siguiente figura:
El stream de audio digitalizado pasa a través de un "Decimation Low Pass Filter". Un diezmador no es mas que una etapa digital que divide el numero de muestras por un determinado valor para obtener una cantidad menor. Por ejemplo, en un stream de audio digital de 1000 muestras por segundo (Sps), un diezmado igual a 2, significa que obtendremos a la salida un stream de 500 muestras por segundo o lo que es lo mismo: que despreciamos una muestra de cada dos. Con un diezmado igual a 4, dividimos por 4 con un resultado de 250 Sps, etc. La señal digitalizada es la misma pero con un numero menor de Sps y por este motivo, el ancho de banda útil de la señal también se reduce, produciéndose un filtrado pasa bajo. Por ejemplo, si nuestra señal originalmente podía transporta un ancho de banda de 500 Hz aprox., al reducir los Sps a 500, esta frecuencia se reduce a 250 Hz aprox. y así sucesivamente.
En el apartado 6.3 Local Registers (Memory Mapped) donde se muestra la descripción de los registros de control de la etapa de sonido "0x10C-Audio Control Register (GPIO_DMA_CTL)" encontramos:
Bits |
Type | Default | Name | Description |
[13] | RW | 0 | DA_ES2 |
Enables Digital Decimation Filter (DDF). |
[11:8] | RW | 0000 | DA_SDR |
Specifies the DDF first stage and decimation rate. Range: 4 to 15. |
En el momento de escribir estas líneas, se desconoce la función exacta del registro DA_ES2 pero por otro lado, queda clara la del registro DA_SDR. Su misión es especificar al Bt878a el valor por el cual deseamos dividir el stream digital, ósea, el valor de diezmado. Dentro de un rango de 4 hasta 15.
También encontramos:
"2.18.2 PCI
Bus Latency Tolerance for Audio Buffer
The latency-effective size of the audio FIFO is essentially 32 DWORDs or 64
samples of 16-bit audio. This allows for a maximum PCI bus latency of 286 µs at
224 kHz (381 µs at 149 kHz) sample rate before overflow will occur. This latency
drops to 143 µs when in 8-bit mode, because the rate is 4X and the number of
bits
is half. The digital audio input tolerates a maximum latency of 667 µs at 48 kHz
16-bit L,R or 122 µs at 1 MBps data before FIFO overflow."
Aquí el fabricante relaciona la latencia del bus PCI con la frecuencia de 224 KHz. Si la multiplicamos por 2 obtenemos: 224000 * 2 = 448000. Nos quedamos con este dato.
3 - Lectura del README del btaudio.c
En el README del btaudio.c encontramos que:
"The analog mode supports mono only. Both 8 + 16
bit. Both are _signed_
int, which is uncommon for the 8 bit case. Sample rate range is 119 kHz
to 448 kHz. Yes, the number of digits is correct. The driver supports
downsampling by powers of two, so you can ask for more usual sample rates
like 44 kHz too."
El creador del modulo nos dice que la velocidad máxima de digitalización es de 448 KHz, ósea 448000 Sps.
4 - Lectura de la salida del btaudio en el /var/log/syslog
Al cargar el modulo en memoria con la opción de Debug activada (#insmod btaudio debug=1) provocamos que el modulo nos informe de varios parámetros de su funcionamiento interno. Veamos unos ejemplos:
Activamos una captura a 448000 Sps:
# sox -w -r 448000 -t ossdsp /dev/dsp1 -t .wav test.wav
(nota: el parámetro /dev/dsp1 depende de vuestra configuración de hardware).
Y el mensaje en el syslog es:
May 15 19:07:16 lab kernel: btaudio: open analog dsp [19]
May 15 19:07:16 lab kernel: btaudio: fmt: bits=16
May 15 19:07:16 lab kernel: btaudio: stereo=0 channels=1
May 15 19:07:16 lab kernel: btaudio: rate: req=448000 dec=4
shift=0 hwrate=448000 swrate=448000
May 15 19:07:16 lab kernel: btaudio: bufsize=131072 - bs=8192 bc=16 - ls=2048,
lc=64
May 15 19:07:16 lab kernel: btaudio: bufsize=131072 - bs=8192 bc=16 - ls=2048,
lc=64
May 15 19:07:16 lab kernel: btaudio: recording started
May 15 19:07:18 lab kernel: btaudio: recording stopped
Destacamos que el parámetro dec es igual a 4.
Activamos una captura a una velocidad inferior:
# sox -w -r 440000 -t ossdsp /dev/dsp1 -t .wav test.wav
En este caso el comando SOX nos informa de que el modulo no le puede proporcionar la velocidad de 440000 "sox: Unable to set audio speed to 440000 (set to 448000)" y la fuerza a 448000 nuevamente. Apareciendo este mensaje en el syslog con dec nuevamente igual a 4:
May 15 19:07:40 lab kernel: btaudio: open analog dsp [19]
May 15 19:07:40 lab kernel: btaudio: fmt: bits=16
May 15 19:07:40 lab kernel: btaudio: stereo=0 channels=1
May 15 19:07:40 lab kernel: btaudio: rate: req=440000 dec=4 shift=0
hwrate=448000 swrate=448000
May 15 19:07:40 lab kernel: btaudio: bufsize=131072 - bs=8192 bc=16 - ls=2048,
lc=64
May 15 19:07:40 lab kernel: btaudio: bufsize=131072 - bs=8192 bc=16 - ls=2048,
lc=64
May 15 19:07:40 lab kernel: btaudio: recording started
May 15 19:07:43 lab kernel: btaudio: recording stopped
Ahora activamos una captura a la velocidad de 358400 Sps:
# sox -w -r 358400 -t ossdsp /dev/dsp1 -t .wav test.wav
El comando SOX no genera ningún mensaje de error y aparece el siguiente mensaje en el syslog:
May 15 19:08:24 lab kernel: btaudio: open analog dsp [19]
May 15 19:08:24 lab kernel: btaudio: fmt: bits=16
May 15 19:08:24 lab kernel: btaudio: stereo=0 channels=1
May 15 19:08:24 lab kernel: btaudio: rate: req=358400 dec=5 shift=0
hwrate=358400 swrate=358400
May 15 19:08:24 lab kernel: btaudio: bufsize=131072 - bs=8192 bc=16 - ls=2048,
lc=64
May 15 19:08:24 lab kernel: btaudio: bufsize=131072 - bs=8192 bc=16 - ls=2048,
lc=64
May 15 19:08:24 lab kernel: btaudio: recording started
May 15 19:08:26 lab kernel: btaudio: recording stopped
Observamos que en este caso dec = 5. Podemos repetir esta prueba con las siguientes velocidades y comprobamos los cambios en el registro del diezmador. Para hwrate = 298666 el valor dec = 6. Para hwrate = 256000, dec = 7. Para hwrate = 224000, dec = 8, etc.
Llegados a este punto, resulta evidente que el modulo ajusta el valor del registro DA_SDR para generar la velocidad mas cercana a la solicitada por el usuario, comenzando por DA_SDR = 4 para la velocidad de 448000 Sps. Esto desprende un dato significativo: Si al digitalizar a 448000 estamos dividiendo por 4, la velocidad real del ADC (antes del diezmado) es de 4*448000 = 1792000 Sps (1,792 MHz).
Una velocidad y un dato muy atractivos, si no fuera por lo leído anteriormente en el apartado 2, de que el contenido del registro DA_SDR tiene el rango de 4 a 15. ¿Que ocurre si se configura con valores por debajo de 4?
5 - Modificación experimental del modulo btaudio.c
No es posible forzar velocidades superiores a 448000, ni el valor de DA_SDR externamente, por lo que será necesario realizar una pequeña modificación en el modulo btaudio.c
Primero, modificaremos la línea 1109 de la fuente:
printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n",
Y añadiremos un pequeño comentario en el texto. Por ejemplo:
printk(KERN_INFO "btaudio: driver version 0.7 (test) loaded [%s%s%s]\n",
El objetivo de esta modificación es asegurarnos de que, tras la ejecución del #insmod ./btaudio.o debug=1, sea nuestra versión de modulo la que se ha cargado en memoria y no la que acompaña al Kernel por defecto.
Segundo, entre la línea 650 y la línea 651, insertamos una línea con el siguiente texto: i = 3; siendo 3 el valor con el que cargaremos inicialmente el registro DA_SDR y el valor que mas adelante cambiaremos a 2 y a 1 posteriormente. Quedando así:
--------------------------------cut---
bta->sampleshift = s;
i = 3;
bta->decimation = i;
--------------------------------cut---
Guardamos el fichero, descargamos el modulo de la memoria, compilamos y lo cargamos nuevamente de la siguiente manera:
# rmmod btaudio
# gcc -O2 -DMODULE -D__KERNEL__ -c btaudio.c -isystem /lib/modules/2.4.21-0.13mdk/build/include/
# insmod ./btaudio.o debug=1
Nótese que para la carga del modulo, especificamos la localización exacta del binario que acabamos de compilar. De esta forma evitamos que insmod cargue el modulo almacenado en el directorio del Kernel. Comprobamos que el modulo ha cargado correctamente y que se trata de nuestra versión modificada, mediante la lectura del /var/log/syslog del siguiente mensaje:
May 15 19:09:36 lab kernel: btaudio: driver version 0.7 (test) loaded
[digital+analog]
May 15 19:09:36 lab kernel: PCI: Found IRQ 10 for device 00:09.1
May 15 19:09:36 lab kernel: PCI: Sharing IRQ 10 with 00:09.0
May 15 19:09:36 lab kernel: btaudio: Bt878 (rev 17) at 00:09.1, irq: 10, latency:
32, mmio: 0xde001000
May 15 19:09:36 lab kernel: btaudio: using card config "default"
May 15 19:09:36 lab kernel: btaudio: registered device dsp0 [digital]
May 15 19:09:36 lab kernel: btaudio: registered device dsp1 [analog]
May 15 19:09:36 lab kernel: btaudio: registered device mixer0
Recuerda ajustar el
volumen cada vez que se carga el modulo en memoria.
6 - Pruebas a diferentes velocidades
Se han realizado pruebas de digitalización (recompilando el modulo cada vez) con dec igual a 3, 2 y 1. También se ha probado dec = 0 pero el modulo falla con error "Divide by Zero". En los tres casos validos el comando SOX funciona correctamente y se crea un fichero .wav sin ningún problema perceptible.
La señal de prueba consiste en acercar el extremo de un cable a un aparato de televisión encendido (como si fuera una antena) y conectar el otro extremo al ADC. De esta manera capturamos la frecuencia de 15625 Hz y sus armónicos.
dec=3 hwrate=597333
# sox -w -r 597333 -t ossdsp /dev/dsp1 -t .wav test.wav
Se realiza digitalización sin problemas y se observa la entrada de la señal de prueba hasta los 295276 Hz.
dec=2 hwrate=896000
# sox -w -r 896000 -t ossdsp /dev/dsp1 -t .wav test.wav
Se realiza digitalización sin problemas y se observa la entrada de la señal de prueba hasta los 442915 Hz.
dec=1 hwrate=1792000
# sox -w -r 1792000 -t ossdsp /dev/dsp1 -t .wav test.wav
En este caso sucede algo diferente. Se ha digitalizado la señal sin problemas, llegando a 885830 hz, pero en el momento de analizarla solo aparece ruido. Es un ruido peculiar al cual no he encontrado explicación por el momento.
7 - Pruebas a 896000 Sps
Por ahora asumimos que la velocidad de 1792000 Sps no es valida y nos centramos en 896000 Sps, que es la mas alta de "las recién llegadas".
Desconectamos cualquier cable de la entrada del ADC (conector al aire), realizamos una nueva captura y la analizamos con SpectraPLUS (Average = 10).
¡Sorpresa! Lejos de obtener el típico espectro con un poco de ruido y algunas "portadoras" a unas frecuencias estables provocadas por la electrónica del PC, aparece un conjunto de portadoras distribuidas por toda la señal de forma regular y una curiosa carga de ruido en la parte alta de la señal.
Las frecuencias visibles en este gráfico están separadas unos 12620 Hz de media y por ahora su origen es desconocido. La carga de ruido desplazada a la parte superior de la frecuencia recuerda la distribución del ruido de un ADC delta-sigma ¿Será este nuestro caso?. Todo un misterio para mis pobres conocimientos en la materia. Por fortuna, si la señal que deseamos digitalizar tiene el nivel suficiente, podemos ignorar estas señales parasitarias.
Acto seguido inyectamos una señal de ruido procedente del sintonizador de la tarjeta TV (descrito en el articulo anterior) sin ningún canal sintonizado y nuevamente realizamos un análisis de espectro, lo cual nos da una idea de cual puede ser la respuesta del ADC a esta nueva velocidad:
La línea roja corresponde al espectro de la señal anterior (conector abierto) y creo que lo podemos considerar el "ruido de fondo". La línea amarilla el espectro de la señal de ruido de la TV.
8 - Conclusión
Creo que ha quedado claro que el Bt878A ha superado la limitación inicial de los 448000 Sps, que puede digitalizar perfectamente a 896000 Sps y nos ofrece 442 KHz de ancho de banda útil. No esta mal ¿eh?. Mas adelante realizaremos nuevas pruebas para profundizar en las posibilidades reales de este chip (alguien dice que solo tiene 10 bits ;)
¡Novedades! 08-2005
Soporte
ALSA para el Bt878a y Fedora Core 4
- Agradecimientos:
Eduardo Alonso
Luis Padilla
Gerd Knorr
- Autor:
Juan Domenech Fernandez
http://www.domenech.org
v1.4 01-mayo-2006
v0 14-mayo-2004