Sound Blaster 16 Programming Document
Written by Ethan Brodsky
Version 3.5 - 6/26/97
Note: 97/6/11
I am experimenting with using transparency in the images
to allow irregularly-shaped diagrams without making assumptions about your
browser's background color. If the DSP command or mode diagrams are blue, please
contact me with information on your configuration so I can attempt to fix it.
Download
SB16DOC.ZIP (6,509 bytes)
Jump to section:
This information is
distributed AS IS. The author specifically disclaims responsibility for any loss
of profit or any consequential, incidental, or other damages resulting from the
use or misuse of this information. This information may be freely distributed in
any form as long as this disclaimer remains intact.
The Sound Blaster 16 is
capable of both FM and digitized sounds. Digitized sound capibilities range from
8-bit mono 5000 HZ sound all the way up to 16-bit stereo sound at 44khz. This
FAQ documents programming the SB16 DSP CT1341 chip for recording and playback of
digitized audio. Prior knowledge on programming earlier Sound Blaster sound
cards is necessary.
The
SB16's DSP chip is programming using several I/O ports at a base I/O address
determined by jumper settings. On the SB16, there are 16 I/O ports which are
used for FM synthesized music, mixer settings, DSP programming and CD-ROM
access. Five of these ports are used in programming the DSP. They are listed
below.
- 2x6h - DSP Reset
- 2xAh - DSP Read
- 2xCh - DSP Write (Command/Data), DSP write-buffer status (Bit 7)
- 2xEh - DSP Read-buffer status (Bit 7), DSP interrupt acknowledge
- 2xFh - DSP 16-bit interrupt acknowledge
You have to reset the
DSP before you can program it. The DSP can be reset using the following
procedure:
- Write a 1 to the reset port (2x6)
- Wait for 3 microseconds
- Write a 0 to the reset port (2x6)
- Poll the read-buffer status port (2xE) until bit 7 is set
- Poll the read data port (2xA) until you receive an AA
The DSP
usually takes about 100 microseconds to initialized itself. After this period of
time, if the return value is not AA or there is no data at all, then the SB card
may not be installed or an incorrect I/O address is being used.
To write a byte to the
SB16, the following procedure should be used:
- Read the write-buffer status port (2xC) until bit 7 is cleared
- Write the value to the write port (2xC)
To read a byte from
the SB16, the following procedure should be used:
- Read the read-buffer status port (2xE) until bit 7 is set
- Read the value from the read port (2xA)
The DMA
(Direct Memory Access) controller controls data transfers between I/O devices
and memory without using the CPU. An Intel 8237 DMAC integrated circut is used
to control this. An IBM compatible computer has two DMA controllers, one for
8-bit transfers and one for 16-bit transfers. The DMA controller, coupled with
an external page register, is capable of transfering blocks of up 64k to the
SB16. Here is information on I/O ports and register settings necessary for sound
card I/O:
I/O port addresses for the DMA Address and Count Registers
I/O port addresses for the control registers
I/O port addresses for lower page registers
Mode register bit assignments
Write single mask bit assignments
DMAC2 is used for 16-bit I/O and DMAC1 is used for 8-bit I/O. The procedure
for starting a transfer is complicated, so I'll list the steps for starting the
type of DMA transfers used for sound I/O:
- Calculate the absolute linear address of your buffer
LinearAddr := Seg(Ptr^)*16 + Ofs(Ptr^));
- Disable the sound card DMA channel by setting the appropriate mask bit
Port[MaskPort] := 4 + (Channel mod 4);
- Clear the byte pointer flip-flop
Port[ClrBytePtr] := AnyValue;
- Write the DMA mode for the transfer
The mode selection bits should be
set to 01 for single-mode. The address inc/dec bit should be set to 0 for
address increment. The auto-initialization bit should be set appropriately. I
will discuss auto-initialized DMA later. The transfer bits should be set to 10
for playback and 01 for recording. The channel select should be set to the
sound card DMA channel. Be aware that "read" means a read from memory (Write
to sound card) and that "write" means a write to system memory. Port[ModePort] := Mode + (Channel mod 4);
Some often used modes
are:
- 48h+Channel - Single-cycle playback
- 58h+Channel - Auto-initialized playback
- 44h+Channel - Single-cycle record
- 54h+Channel - Auto-initialized recording
- Write the offset of the buffer, low byte followed by high byte. For
sixteen bit data, the offset should be in words from the start of a 128kbyte
page. The easiest method for computing 16-bit parameters is to divide the
linear address by two before calculating offset.
if SixteenBit
then
begin
BufOffset := (LinearAddr div 2) mod 65536;
Port[BaseAddrPort] := Lo(BufOffset);
Port[BaseAddrPort] := Hi(BufOffset);
end
else
begin
BufOffset := LinearAddr mod 65536;
Port[BaseAddrPort] := Lo(BufOffset);
Port[BaseAddrPort] := Hi(BufOffset);
end;
- Write the transfer length, low byte followed by high byte. For an 8-bit
transfer, write the number of bytes-1. For a 16-bit transfer, write the number
of words-1.
Port[CountPort] := Lo(TransferLength-1);
Port[CountPort] := Hi(TransferLength-1);
- Write the buffer page to the DMA page register.
Port[PagePort] := LinearAddr div 65536;
- Enable the sound card DMA channel by clearing the appropriate mask bit
Port[MaskPort] := DMAChannel mod 4;
Unlike
earlier Sound Blasters, the SB16 is programmed with actual sampling rates
instead of time constants. On the SB16, the sampling rate is set using DSP
commands 41h and 42h. Command 41h is used for output and 42h is used for input.
I have heard that on the SB16, both these command currently do the same thing,
but I would recommend using the individual commands to guarantee compatibility
with future sound cards. The procedure for setting the sampling rate is:
- Write the command (41h for output rate, 42h for input rate)
- Write the high byte of the sampling rate (56h for 22050 hz)
- Write the low byte of the sampling rate (22h for 22050 hz)
To record or
play back sound, you should use the following sequence:
- Allocate a buffer that does not cross a 64k physical page boundary
- Install an interrupt service routine
- Program the DMA controller for background transfer
- Set the sampling rate
- Write the I/O command to the DSP
- Write the I/O transfer mode to the DSP
- Write the block size to the DSP (Low byte/high byte)
Upon interrupt when using single-cycle DMA:
- Program DMA controller for next block
- Program DSP for next block
- Copy next block if double-buffering
- Acknowledge the interrupt with the SB by reading from port 2xE for 8-bit
sound or port 2xF for 16-bit sound.
- Acknowledge the end of interrupt with the PIC by writing 20h to port 20h.
If the sound card is on IRQ8-15, you must also write 20h to A0h.
- D0
- Pause 8-bit DMA mode digitized sound I/O initiated by command Cxh.
Applicable to both single-cycle and auto-initialized DMA I/O.
- D4
- Continue 8-bit DMA mode digitized sound I/O paused using command D0.
Applicable to both single-cycle and auto-initialzied DMA I/O.
- D5
- Pause 16-bit DMA mode digitized sound I/O initiated by command Bxh.
Applicable to both single-cycle and auto-initialized DMA I/O.
- D6
- Continue 16-bit DMA mode digitized sound I/O paused using command D5.
Applicable to both single-cycle and auto-initialized DMA I/O.
- D9
- Exit 16-bit auto-initialized DMA mode digitized sound I/O after the end of
the current block.
- DA
- Exit 8-bit auto-initialized DMA mode digitized sound I/O after the end of
the current block.
- E1
- Get DSP version number. After sending this command, read back two bytes
form the DSP. The first byte is the major version number and the second byte
is the minor version number. A SB16 should have a DSP version of 4.00 or
greater. Check this before using an SB16 specific commands.
- Bx
- Program 16-bit DMA mode digitized sound I/O
Command sequence: Command,
Mode, Lo(Length-1), Hi(Length-1)
Command:
Common commands:
- B8 - 16-bit single-cycle input
- B0 - 16-bit single-cycle output
- BE - 16-bit auto-initialized input
- B6 - 16-bit auto-initialized output
Mode:
- Cx
- Program 8-bit DMA mode digitized sound I/O
Same procedure as 16-bit
sound I/O using command Bx
Common commands:
- C8 - 8-bit single-cycle input
- C0 - 8-bit single-cycle output
- CE - 8-bit auto-initialized input
- C6 - 8-bit auto-initialized output
The FIFO is used to eliminate inconsistencies in the sample period when the
sound card is not able to get DMA when it needs it. With FIFO disabled, the card
attempts DMA at precisely the instant that it needs a sample. If another device
with a higher priority is accessing DMA, the sound card waits for the sample and
the sampling rate may be decreased. The FIFO allows the DMA sample period to be
more erratic without affecting the audio quality. The FIFO is cleared whenever a
command is sent to the DSP. In Single-cycle mode, the DSP is constantly being
reprogrammed. The FIFO may still contain data which has not been output when it
cleared. To avoid this problem, the FIFO should be turned off for single-cycle
mode. When in auto-initialized mode, the DSP is never reprogrammed. The FIFO can
be left on and sound quality will be improved.
When single-cycle
DMA is used, sound output stops at the end of each block. The interrupt handler
can start another transfer, but there will be a break in output. This causes a
click between each block, reducing sound quality. When auto-initialized DMA is
used, sound output loops around at the end of the buffer. The DMA controller
keeps transfering the same block of memory that the DMA transfer was initiated
with. When the end of the buffer is reached, it will start sending the buffer
again by auto-initializing the current offset and count registers with the
values stored in the base offset and count registers. The usual method for
achieving click-less output is to allocate a buffer and divide it into two
blocks. Program the DMA controller with the length of the whole buffer, but
program the SB16 with the length of a block. (Half of the buffer) An interrupt
occurs for each sound card block, so two interrupts will occur each time the
buffer is played, once at the midpoint (Start of the second block) and once at
the end (In effect, the start of the first block) The interrupt handler should
copy data into the block that was just finished so that the data is ready when
it is needed for output. The programming procedure for an auto-initialized DMA
transfer is identical to the procedure for a single-cycle DMA transfer, except
that bit 4 of the DMA mode register and bit 3 of the DSP command are set.
Upon interrupt when using auto-initialized DMA:
- Copy next chunk into output buffer block that just finished
- Acknowledge the interrupt with the SB by reading from port 2xE for 8-bit
sound or port 2xF for 16-bit sound.
- Acknowledge the end of interrupt with the PIC by writing 20h to port 20h.
If the sound card is on IRQ8-15, you must also write 20h to A0h.
To stop sound immediately:
- 8-bit - Write DSP command D0h (Pause 8-bit DMA mode
digitized sound I/O)
- 16-bit - Write DSP command D5h (Pause 16-bit DMA mode
digitized sound I/O)
Both commands stop sound immediately, without an
interrupt.
To stop the sound at the end of the currently block:
- 8-bit - Write DSP command DAh (Stop 8-bit auto-init DMA
sound I/O)
- 16-bit - Write DSP command D9h (Stop 16-bit auto-init DMA
sound I/O)
These two commands will stop the sound at the end of the
current block. If your program is not prepared for an interrupt after output is
finished, it may cause problems.
You can also end auto-initialized mode by reprogramming the DSP for
single-cycle mode. The card then switches from A/I mode to S/C mode after the
next interrupt. It will then contiue to play or record for the length specified,
generate an interrupt and stop. This will allow you to stop output exactly at
the end of the data, without requiring the remainder of the DMA buffer to be
filled with silence. This technique may or may not be useful to you. I would
recommend using the pause commands documented in in the immediate stop section
unless another method is more suited to your purpose.
Thanks to Douglas Kaden at Creative Labs for information on 16-bit DMA,
FIFO mode, and other topics.
Back to Home
Page
View SMIX
information
View
SB16SND information
Ethan Brodsky
<ebrodsky@pobox.com>