Está en la página 1de 7

Ingeniero en Informática

ESTRUCTURA DE LOS COMPUTADORES II


Práctica
Universidad E. T. S.
Digitalización de sonido mediante las Departamento
de Granada Ingeniería tarjetas PCL-812PG y SoundBlaster Arquitectura y
Informática Curso 2002-2003 Tecnología de
Computadores
© Antonio Cañas Vargas, 2001-2003

Objetivos.
• Comprender e implementar las tres técnicas de E/S: mediante programa ("polling" o sondeo),
mediante interrupciones, y mediante DMA ("Direct Memory Access" o acceso directo a memoria).
• Conocer los detalles de programación de una tarjeta de adquisición de datos (en concreto la PC-
LabCard 812PG), o bien de una tarjeta de sonido SoundBlaster.
• Comprender y programar el controlador de DMA 8237.
• Realizar temporizaciones con el circuito 8253.

Enunciado
Realizar tres programas EXE para digitalizar sonido utilizando bien la tarjeta de adquisición de datos PCL-
812PG, bien la SoundBlaster:
• El primero utilizará E/S por programa (fácil, y lenta en un PC lento).
• El segundo usará E/S por interrupciones (ligeramente más compleja, pero más rápida),
• El tercero E/S por DMA (la más compleja de implementar y la más rápida).
Las muestras digitales adquiridas se guardarán en un búfer en memoria y se escribirán en un archivo en
disco en formato WAV. Para ello se utilizará la técnica de "doble búfer" (dos búferes de 8 KB cada uno;
cuando la interrupción o el DMA escribe en uno, se graba el otro en disco).
Opcionalmente, el programa puede reproducir el sonido que se está digitalizando como se hacía en
la práctica de ensamblador “reproducción de sonido”.

Documentación incluida (sólo en la versión impresa)


Se incluye documentación sobre:
• La tarjeta de adquisición de datos PCL-812PG.
• La tarjeta de conectores PCLD-780.
• El controlador de DMA programable 8237.
(en estos tres documentos se han remarcado los párrafos interesantes)

Información adicional

Controlador de DMA en el PC.


El registro de dirección actual se encuentra en la dirección CANAL_DMA*2 (donde CANAL_DMA es 0, 1, 2
ó 3), el registro contador actual en CANAL_DMA*2+1, el registro de máscara está en la dirección 0x0A, el
registro de modo en la 0x0B, el flip-flop "byte pointer" en la 0x0C.

El controlador de DMA (DMAC) sólo puede transferir datos dentro de una página física de memoria.
El mapa de memoria está dividido en páginas físicas de 64 KB cada una. Para 1 MB de memoria, está
dividido en 16 páginas como sigue:
Segmento Dirección Segmento:Offset
0 0000:0000 -> 0000:FFFF
1 1000:0000 -> 1000:FFFF
2 2000:0000 -> 2000:FFFF
... ...
E E000:0000 -> E000:EFFF
F F000:0000 -> F000:FFFF

Como ejemplo, un conjunto de muestras almacenado en las direcciones segmento-offset


6C00:0000 a 6C00:5FFF está residiendo realmente en 2 páginas físicas:

1/7
• La parte final de la página física 6 desde el offset 0xC000 hacia delante.
• El parte inicial de la página 7 hasta el offset 0x1FFF.
El DMAC no puede ser programado para transferir el conjunto de datos de una vez si no están
dentro de la misma página física. En este caso los datos deben ser manejados en 2 bloques. El máximo
número de datos que pueden ser transferidos cada vez es 64 KB.

El contador de datos del DMAC es siempre 1 byte menos que el número real de bytes a transferir.
Así:
Contador_de_datos = número_real_de_datos – 1
Por ejemplo, para transferir un byte de datos, Contador_de_datos = 0. Para transferir 64 KB de datos,
Contador_de_datos = 65535 (0xFFFF).

Los parámetros para programar el DMAC son:

• Número de página: La dirección de página física de los datos para el DMA.


• Dirección base: Un valor de 2 bytes para el offset de los datos en la página física. El LSB
va primero, y después el MSB.
• Contador de datos: Un valor de 2 bytes. El LSB va primero.
• Modo de transferencia: Un byte que indica la dirección de transferencia (leer de o escribir en
memoria) y otros parámetros.
El DMAC es programado a través de unos pocos puertos de E/S. El procedimiento a seguir es el
siguiente:
1. Enmascarar canal.
2. Borrar flip-flop "byte pointer".
3. Fijar el modo en escritura en memoria y transferencia simple.
4. Sacar el LSB de la dirección base.
5. Sacar el MSB de la dirección base.
6. Sacar el número de página física.
7. Sacar el LSB del número de datos.
8. Sacar el MSB del número de datos.
9. Habilitar canal.

La dirección la página física se escribe en un puerto de un byte que se encuentra en una de las
siguientes direcciones: 0x87 para el canal 0, 0x83 para el canal 1, 0x81 para el canal 2 y 0x82 para el canal
3.

2/7
Formato WAV:
Bytes Contenido usual Tipo de dato Propósito/Descripción
00 - 03 “RIFF” char [4] Identificador de trozo “RIFF”. El
formato WAVE está compuesto a su
vez por dos trozos: “fmt ” y “data”.
04 - 07 long Tamaño del resto del trozo RIFF
que sigue a este número = 36 +
tamaño de las muestras = tamaño
del archivo en bytes, incluyendo
cabecera, menos 8.
08 - 11 “WAVE” char [4] Identificador de formato del trozo.
12 - 15 “fmt ” char [4] Identificador del trozo “fmt ”.
16 - 19 16 long Tamaño del resto del trozo “fmt “
que sigue a este número.
20 - 21 1 unsigned short Formato de audio. PCM = 1. Valores
distintos de 1 indican algún modo
de compresión.
22 - 23 1 unsigned short Número de canales. 1 = mono, 2 =
estéreo.
24 - 27 long Frecuencia de muestreo
(muestras/segundo) = 8000, 11025,
22050, 44100.
28 - 31 long Número de bytes por segundo =
frecuencia de muestreo * nº de
canales * bits por muestra / 8
32 - 33 1 short Alineamiento de bloque = nº de
bytes para una muestra = nº de
canales * bits por muestra / 8.
34 - 35 8 short Número de bits por muestra (8, 16).
36 - 39 “data” char [4] Identificador del trozo “data”.
40 - 43 long Tamaño del trozo “data” a partir de
este número = nº de bytes
muestreados = nº de muestras * nº
de canales * bits por muestra / 8
44 - Muestras de sonido
Más información sobre el formato WAV en:
http://ccrma-www.stanford.edu/courses/422/projects/WaveFormat/

3/7
Programación de la SoundBlaster
#define BASE 0x220

(*) Lectura del DSP (función sin argumentos que devuelve el dato leído)

Es necesario seguir el siguiente procedimiento para leer de READ_DATA:


1) Leer el puerto READ_BUFFER_STATUS / DATA_AVAILABLE_STATUS (BASE + 0x0E) hasta que el
bit 7 = 1
2) Leer el dato del puerto READ_DATA (BASE + 0x0A)

(**) Escritura de un dato u orden en el DSP (función con un argumento, que no devuelve nada)

Es necesario seguir el siguiente procedimiento para escribir en WRITE_COMMAND_DATA:


1) Leer el puerto WRITE_BUFFER_STATUS (BASE + 0x0C) hasta que el bit 7 = 0
2) Escribir el valor deseado en el puerto WRITE_COMMAND_DATA (BASE + 0x0C)

Reset del DSP

Hay que reiniciar el DSP antes de programarlo. Esto se hace mediante los siguientes pasos:
1) Escribir un 1 en el puerto RESET (BASE + 6)
2) Esperar 3 microsegundos
3) Escribir un 0 en el puerto RESET (BASE + 6)
4) Leer de READ_DATA* hasta obtener el byte “listo” (0xAA)
El DSP tarda normalmente unos 100 µs en reiniciarse. Si tarda más de cierto tiempo razonable (unos
200 µs) es porque ha ocurrido un error (dirección BASE incorrecta o no hay SoundBlaster).

Control del mezclador


#define MixerAddr (BASE + 4)
#define MixerData (BASE + 5)
Puertos antiguos
VOCVolume 0x4
MICVolume 0xA
MasterVolume 0x22
FMVolume 0x26
CDVolume 0x28
LineVolume 0x2E
Puertos nuevos
MasterLeft 0x30 LineLeft 0x38 InputGainRight 0x40
MasterRight 0x31 LineRight 0x39 OutputGainLeft 0x41
VocLeft 0x32 MicVolume 0x3A OutputGainRight 0x42
VocRight 0x33 PCSpeaker 0x3B AGC 0x43
MidiLeft 0x34 OutPutSwitches 0x3C TrebleLeft 0x44
MidiRight 0x35 InputL 0x3D TrebleRight 0x45
CDLeft 0x36 InputR 0x3E BassLeft 0x46
CDRight 0x37 InputGainLeft 0x3F BassRight 0x47

Ejemplo:
unsigned char masterleft=16;
outportb(MixerAddr,MasterLeft);
outportb(MixerData,masterleft<<3);

4/7
Registros/Listado de puertos
Nº de bit
Índice 7 6 5 4 3 2 1 0
0x00 Reset Mixer
0x04 Voice Volume (L) Voice Volume (R)
0x0A . Mic Volume
0x22 Master Volume (L) Master Volume (R)
0x26 MIDI Volume (L) MIDI Volume (R)
0x28 CD Volume (L) CD Volume (R)
0x2E Line Volume (L) Line Volume (R)
0x30 Master Volume (L) .
0x31 Master Volume (R) .
0x32 Voice Volume (L) .
0x33 Voice Volume (R) .
0x34 MIDI Volume (L) .
0x35 MIDI Volume (R) .
0x36 CD Volume (L) .
0x37 CD Volume (R) .
0x38 Line Volume (L) .
0x39 Line Volume (R) .
0x3A Mic Volume .
PC Speaker
0x3B .
Volume
0x3C Output Mixer Switches
. . Line.L Line.R CD.L CD.R Mic
0x3D Input Mixer (L) Switches
. . MIDI.L MIDI.R Line.L Line.R CD.L CD.R Mic
0x3E Input Mixer (R) Switches
. . MIDI.L MIDI.R Line.L Line.R CD.L CD.R Mic
0x3F Input Gain (L) .
0x40 Input Gain (R) .
0x41 Output Gain (L) .
0x42 Output Gain (R) .
0x43 . AGC
0x44 Treble (L) .
0x45 Treble (R) .
0x46 Bass (L) .
0x47 Bass (R) .

Programa 1: E/S por programa

Lectura de una muestra de 8 bits por sondeo (dentro de la ISR)

1) Disparar conversión enviando la orden 0x20 (conversión A/D directa de 8 bits) al puerto
WRITE_COMMAND_DATA**
2) Leer dato digital del puerto READ_DATA*
5/7
Programa 2: E/S por DMA

Se utiliza la IRQ 5 [INT (5+8) = INT 0x0D] y el canal de DMA 1.

Programación de la constante de tiempo (TimeConstant)


En el modo DMA, la frecuencia de muestreo es controlada por el DSP. Éste usa una variable de un byte,
llamada TimeConstant fijada mediante la orden 0x40. Su valor se calcula mediante la expresión:
TimeConstant = 256 - 1000000 / FrecMuestreo
con lo cual la frecuencia de muestreo real será 1000000 / (256 - TimeConstant)

1) Enviar la orden 0x40 al puerto WRITE_COMMAND_DATA**


2) Enviar la TimeConstant al puerto WRITE_COMMAND_DATA**

Programación del DSP para que envíe a la memoria un bloque de muestras por DMA sin autoinicio

La orden 0x14 permite el envío de muestras desde memoria a la SoundBlaster y el 0x24 la lectura en
memoria desde la tarjeta, ambos usando DMA y 8 bits. El proceso para la captura de muestras es el
siguiente:
1) Programar el DMAC 8237 para la transferencia.
2) Enviar la orden 0x24 al puerto WRITE_COMMAND_DATA** (escritura en memoria por DMA sin
autoinicio)
3) Enviar el número de datos - 1 (2 bytes, el LSB primero) al puerto WRITE_COMMAND_DATA**
4) En la ISR: reprogramar el DMAC, activar una variable que indique que se ha llenado un buffer, y leer el
puerto DATA_AVAILABLE_STATUS (BASE + 0x0E) para reconocer la interrupción.

Programación del DSP para que envíe a la memoria un bloque de muestras por DMA con autoinicio

El proceso para la captura de muestras es el siguiente:


1) Programar el DMAC 8237 para la transferencia.
2) Fijar el tamaño de bloque tras el cual la SoundBlaster generará una interrupción. Para ello se enviar la
orden 0x48 al puerto WRITE_COMMAND_DATA**, y a continuación el número de datos - 1 (2 bytes, el
LSB primero) también al puerto WRITE_COMMAND_DATA**.
3) Enviar la orden 0x2C al puerto WRITE_COMMAND_DATA** (escritura en memoria por DMA con
autoinicio)
4) En la ISR: activar una variable que indique que se ha llenado un buffer, y leer el puerto
DATA_AVAILABLE_STATUS (BASE + 0x0E) para reconocer la interrupción.

Parada de la operación de DMA

Para detener las peticiones de DMA (por ejemplo, cuando se pulse una tecla para finalizar) se envía la
orden DMA_STOP (0xD0) al puerto WRITE_COMMAND_DATA**

Más información
http://faculty.petra.ac.id/irwankj/ap2/sb16doc.html
Buscar archivo sbdsp.txt en la web.
http://oxygen.it.net.au/mixing/index.html
http://the.earth.li/~tfm/oldpage/sb_dsp.html
http://www.geocities.com/SiliconValley/Park/8933/sound.html
http://www.inversereality.org/tutorials/sound%20programming/soundblaster16.html

6/7
Programación de la PCL-812PG
#define BASE 0x230

Programa 1: E/S por programa

Inicialización de la tarjeta

Inicialmente hay que programar tres puertos:

1) Escribir nº de canal (de 0 a 15) en BASE + 10


2) Escribir ganancia (de 0 a 4) en BASE + 9
3) Fijar Modo = 1 (disparo por software y transferencia por programa) en el puerto BASE + 11

Lectura de una muestra de 12 bits por sondeo (dentro de la ISR)

1) Disparar conversión escribiendo cualquier valor en el puerto BASE + 12


2) Leer de BASE + 5 hasta que el bit DRDY (bit 4) sea 0
3) Leer byte alto (4 bits más significativos) del puerto BASE + 5 (se puede hacer directamente dentro del
paso 2)
4) Leer byte bajo (8 bits menos significativos del puerto BASE + 4

Si se desea convertir la muestra de 12 a 8 bits:

MSB LSB

0 0 0 0 X X X X Y Y Y Y Y Y Y Y

X X X X Y Y Y Y
(MSB << 4) | (LSB >> 4)

Programa 2: E/S por interrupciones

Inicialización de la tarjeta

Inicialmente hay que programar cuatro puertos:

1) Escribir nº de canal (de 0 a 15) en BASE + 10


2) Escribir ganancia (de 0 a 4) en BASE + 9
3) Fijar Modo = 6 (disparo por temporizador y transferencia por interrupciones) en el puerto BASE + 11
4) Habilitar interrupciones escribiendo cualquier valor en el puerto BASE + 8

En las E/S por interrupciones y E/S por DMA es necesario programar el temporizador 8253 de la
tarjeta (distinto del de la placa madre del PC). Se debe programar los contadores 1 y 2 en modo 3:
"Generador de onda cuadrada". Se puede mandar una cuenta 2 al contador 2, con la que la entrada al
contador 1 es 1 MHz exacto y la cuenta a enviar al contador 1 sería 1 MHz / frecuencia_de_muestreo.
Se producirá la interrupción IRQ 7 [INT (7+8) = INT 0x0F] cada vez que esté lista una muestra. Al
final de cada interrupción hay que enviar cualquier dato al puerto BASE+8 (como se ha indicado más arriba,
esto también hay que hacerlo antes de que se haga la primera llamada a la interrupción).

Programa 3: E/S por DMA

En la E/S por DMA se produce la interrupción IRQ 7 [INT (7+8) = INT 0x0F] cuando termina la operación de
transferencia de un bloque completo (cuando el contador pasa de 0 a 0xFFFF). El canal de DMA es el 3.

7/7

También podría gustarte