btaudio.c module modification to get 896000 Samples per second with the Bt878A ADC

 

conexant-fusion-878a-board

spectrogram-full-adsl-boot

 


Update! 08-2005 ALSA support for the Bt878a and Fedora Core 4
Application:
My First Software Defined Radio (SDR) Receiver

 

Versión en Castellano

Basis: In my last article Analog to Digital Converter with 16 bits and 448000 Samples per second based in the Bt878A you can read the steps to follow to digitalize analog signals using the Analog to Digital Converter (ADC) built-in the Bt878A chip with speeds up to 448000 Samples per seconds (Sps). Now, I describe a simple modification to the btaudio.c module to obtain higher digitalization speeds.

Objective: Find out how the sampling speed selection works in the Bt878's audio stage and get higher sampling speeds, above 448000 Sps, which is the standard one.

Method: We recompile the module, fixing the DA_SDR register with values below 4, which is the minimum allowed value, as we can read in the datasheet.

 

1 - Preparation:

- Follow the steps explained in the previous article (click here)
- We need the Linux Kernel sources installed because we will to compile the btaudio.c. We will need a Linux Mandrake 9.1 also.
 

2 - Reading the Bt878A datasheet:

The Fusion 878A datasheet from Conexant is ambiguous to answer the question: Which is the maximum speed what the Bt878A's audio ADC can digitalize?. After reading it we can obtain this information:

In the section 2.18.7 Audio Data Formats we can see this figure:

conexant-fusion-878a-audio-data-path

The digitalized audio stream goes thru a Decimation Low Pass Filter. A decimator is just a digital stage that divides the total number of samples by some value to obtain a smaller quantity of them. For instance, with a 1000 samples per second (Sps) stream and a decimation of 2, we obtain a 500 Sps output stream, in other words, we discard one sample out of every two. If the decimation is equal to 4, we divide by 4 and obtain a 250 Sps stream and so on. The digitalized signal is still the same but with a lower amount of Sps, because of this the signal bandwidth is also reduced. This acts as a low pass filter. For instance, our original 1000 Sps signal can carry a 500 Hz bandwidth approximately, but reducing the stream speed to 500 Sps makes this frequency to be reduced to 250 Hz as well.

In the section 6.3 Local Registers (Memory Mapped), are described the sound stage registers "0x10C-Audio Control Register (GPIO_DMA_CTL)" and we find:

Bits

Type Default Name

Description

[13] RW 0 DA_ES2

 Enables Digital Decimation Filter (DDF).
 0 = Disables DDF
 1 = Enable DDF stage 2 and associated decimation factor of 2

[11:8] RW 0000 DA_SDR

 Specifies the DDF first stage and decimation rate. Range: 4 to 15.

Right now, I don't know the exact function of the DA_ES2 register but is clear the function of the DA_SDR one. Its mission is to tell the Bt878a the value to divide the digital stream, that is, the decimation value. In the range from 4 to 15.

We find also:

"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."

Here, Conexant relates the PCI bus latency with the 224 KHz frequency. If we multiply this by 2 we get: 224000 * 2 = 448000. Keep this result in mind.

 

3 - Reading the btaudio.c README

In the btaudio.c README, we read:

"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.
"

The module creator tell us that the maximum digitalization speed is 448 KHz, that is 448000 Sps.

 

4 - Studying the btaudio output in the /var/log/syslog log

When we load the module into memory with the Debug option activated (#insmod btaudio debug=1), we tell the module to inform us about some internal parameters. Let's see some examples:

We activate the audio capture with 448000 Sps:

# sox -w -r 448000 -t ossdsp /dev/dsp1 -t .wav test.wav

(note: the /dev/dsp1 parameter is hardware dependent).

And the messages in the syslog are:

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
 

Please note that the dec parameter is equal to 4.

We activate the capture now with a lower speed:

# sox -w -r 440000 -t ossdsp /dev/dsp1 -t .wav test.wav

In this case the SOX command says that the module can not give us the 440000 speed "sox: Unable to set audio speed to 440000 (set to 448000)" and it selects 448000 again. The syslog shows dec equal to 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
 

Now we capture with a 358400 Sps speed:

# sox -w -r 358400 -t ossdsp /dev/dsp1 -t .wav test.wav

SOX do not show any error message and the syslog output is:

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
 

Notice that now the dec value is 5. You can repeat this test with the following speed and see how the decimation register changes. For hwrate = 298666, dec = 6. For hwrate = 256000, dec = 7.  For hwrate = 224000, dec = 8, etc.

Now, is easy to guess how the module adjust the DA_SDR register to obtain the closest speed to the user request, starting with DA_SDR = 4 for the 448000 Sps speed. This give us and interesting information: If when we digitalize with 448000 we are decimating by 4, then, the real ADC speed is 4 * 448000 = 1792000 sps (1,792 MHz).

Quite impressing speed but the datasheet says that the decimation register minimum value is 4. What happens if we load this register with a lower value?

 

5 - btaudio.c module experimental modification

Is not possible to force the DA_SDR value externally and we need to do a small modification in the btaudio.c module.

First, modify the line 1109 in the module source:

printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n",

And just add a little comment in the text. For instance:

printk(KERN_INFO "btaudio: driver version 0.7 (test) loaded [%s%s%s]\n",

The objective is to be sure that our module version loads into memory after the executions of the #insmod ./btaudio.o debug=1 command, instead the default Kernel one.

Second, between the line 650 and the line 651 we insert one line with the text: i = 3; where 3 is the value to load the DA_SDR register first. We will change this value later. The modification shows as follows:

--------------------------------cut---
bta->sampleshift = s;
i = 3;
bta->decimation = i;
--------------------------------cut---

Save the file, unload from memory, compile and load the module again:

# 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

Pay attention that now we specify the exact location of the compiled binary file. This way, the insmod command will load our version instead the binary stored en the Kernel directory. We check that the module has load successfully reading the /var/log/syslog output :

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


Remember to adjust the volume control every time the module loads in memory.

 

6 - Testing the new speeds

I've done some digitalization tests (recompiling the module every time) with dec equal to 3, 2 and 1. I've tried dec = 0 also but the module crashes with a Divide by Zero error. In the three valid cases, the SOX command works perfectly and a .wav file is created without any perceptible problem.

I get the test signal just taking a cable, approaching one side to a television (like an antenna) and connecting the other side to the ADC. This way we capture the 15625 Hz and its harmonics.

 

dec=3  hwrate=597333

# sox -w -r 597333 -t ossdsp /dev/dsp1 -t .wav test.wav

spectrum-597333-test-signal-bt878a-adc-tv

The digitalization works fine and we get the spectrum of the test signal up to 295276 Hz.

 

dec=2  hwrate=896000

# sox -w -r 896000 -t ossdsp /dev/dsp1 -t .wav test.wav

spectrum-896000-test-signal-bt878a-adc-tv

The digitalization works fine and we get spectrum of the test signal up to 442915 Hz.

 

dec=1  hwrate=1792000

# sox -w -r 1792000 -t ossdsp /dev/dsp1 -t .wav test.wav

spectrum-1792000-test-signal-bt878-adc-tv

In this case something different happened. The signal has been successfully digitalized, up to 885830 Hz, but the spectrum give only noise. Is a very regular noise but I can't give any explanation for it.

 

7 - Test at 896000 Sps

By now, I leave the 1792000 speed as invalid and I'll use the next one: 896000 Sps.

Let's unplug any cable and leave the ADC connector "open in the air". We realize a new capture and analyze it using SpectraPLUS (Average = 10).

spectrum-896000-open-wire-bt878a-floor

Surprise!. Now we don't get the typical spectrum with just noise in low frequencies and some carriers caused by the PC electronics. We get a lot of carriers uniformly distributed thru all the spectrum and an interesting noise in the higher zone.

spectrogram-896000-open-wire-bt878a-adc-largo

Those frequencies are separated around 12620 Hz and I don't have a clue where do they come from. I also have no idea about the origin of the noise curve present in the spectrum which is similar to the noise distribution in a delta-sigma ADC. Could be our case?. Unfortunately, I don't have enough knowledge about ADCs to answer this question now. But, as I said before, if the incoming signal is strong enough these interferences almost disappear.

Now, let's put into the ADC the signal that comes from the TV tuner in the PCI card (explained in the previous article) without any channel tuned and analyze the spectrum again. This give us and idea of which the ADC response can be at this speed.

spectrum-896000-noise-bt878-adc

The red line is the spectrum of the previous signal (connector open) and I think it can be considered the "noise floor". The yellow line is the spectrum of the TV noise signal.

 

8 - Conclusion

I think is clear that the Bt878a has surpassed its original 448000 Sps limitation. It can digitalize up to 896000 Sps and give us 442 KHz usable bandwidth. Not bad, isn't?. Soon, we will do more tests to get deeper into the real possibilities of this chip (some one says it is just 10 bits ;)


Update! 08-2005 ALSA support for the Bt878a and Fedora Core 4
 

- Credits:

Eduardo Alonso
Luis Padilla
Gerd Knorr


- Author:

Juan Domenech Fernandez

http://www.domenech.org

Versión en Castellano

v1.4 01-may-2006
v0 17-may-2004