The Ultimate Integrate Part 7.

With the hardware done its time to tuneup the software driving the DSP. It is actually surprisingly easy to make a DSP like ADAU1701 sound bad if not understanding its design and limitations. The fist thing that has to be fully understod is found on page 29 in the ADAU1701 Data Sheet, it reads:

The serial port accepts up to 24 bits on the input and is sign-extended to the full 28 bits of the DSP core. This allows internal gains of up to 24 dB without internal clipping. A digital clipper circuit is used between the output of the DSP core and the DACs or serial port outputs (see Figure 29). This clips the top four bits of the signal to produce a 24-bit output with a range of 1.0 (minus 1 LSB) to −1.0. Figure 29 shows the maximum signal levels at each point in the data flow in both binary and decibel levels.

What does it tell us? That there is a 24 dB headroom in the DSP core but that this headroom will be clipped on the output if not attenuated down to 0 dB or below. I.e. if you got a 0 dB input signal and apply amplification to it (e.g. EQ, Room Correction, Linkwitz Transform etc., anything with a positive gain) then you got a 24 dB headroom for amplification BUT you have to attenuate it down below 0 dB again before it leves the DSP core or it will be clipped.

dB is a relative unit so its better to talk about dBFS in the digital domain and we also need to be able to relate it to something like dBV in the analog domain. We know the full scale rms input voltage because it is given by Table 13 on page 20 of the ADAU1701 Data Sheet


We also know that the DSP from 3e Audio is configured for an input sensitivity of 1.0 Vrms (i.e. 8k ADC0/ADC1 resistors). So 1.0 Vrms on the input represents 0 dBFS in the DSP core. Anything above 1.0 Vrms vill clip the input signal. So the first thing we should do is to make sure no signal source is hotter than 1.0 Vrms. I measured 0 dB (-3 dB rms) on the level detector in SigmaStudio feeding the DSP with a 1kHz signal at 1.0 Vrms. Playing music material from the same source with the same amplification resulted in approximately -8 dB level on the level detector with very few peaks hitting the 0.0 dB level.

The output level is easier to measure thanks to the built in signal generator. It is generating a 0 dBFS signal so set it to 1kHz and measure the voltage on the output. The specification for the output DACs can be found on page 21 in the ADAU1701 Data Sheet, it reads:

The ADAU1701 includes four Σ-Δ DACs. The SNR of the DAC is 104 dB, and the THD + N is −90 dB. A full-scale output on the DACs is 0.9 V rms (2.5 V p-p).

So 0 dBFS in the DSP core represents 0.9 Vrms output from the DAC. This is then amplified on the DSP from 3e Audio. I measured 1.533 (true) Vrms single ended and 3.075 (true) Vrms differential output. That represents +4.626 dB from 0.9 Vrms single ended and +10.672 dB for differential output. And from 1.0 Vrms input they are +3.710 dB single ended and +9.757 dB for differential output.

To sum it up for the DSP from 3e Audio, no more than 1.0 Vrms on the input, no more than 0 dBFS out of the DSP core and output max 1.533 Vrms if connected single ended to the power amp or 3.075 Vrms if connected with differential output (only if the amplifier supports it). With max input and output levels sorted its easy to prevent clipping and to match input sources and output power amplification.

Next up is the volume control. Programming Volume Controls (Notice to Programmers of Audio Software and Hardware) by Alexander Thomas is a really good read on how a volume control should work. It is really nice to be able to use the Single Slew External Volume Block in SigmaStudio to implement a four channel volume control without having to think about multi-gang pots and channel tracking. But how does it perform?

I will be driving the Single Slew External Volume Block from a potentiometer through one of the DSPs Aux ADCs. The position of the potentiometer will be represented by a value of 0.0 to 1.0 by the ADC. But what dB attenuation does each position represent? One way to find out is using the signal generator and a level detector in SigmaStudio. But the readout from the level detectors are quite corse. An alternative method is to use the undocumented Log LUT. I used both and compared the readout from each of them. I made a table based on the following values for the Lower Range (-90 to +6 dB) Log LUT: 

Table Row

Required Input

dB

1

0,0000305

-90,3

2

0,0000431

-87,3

3

0,000061

-84,3

4

0,0000864

-81,3

5

0,0001221

-78,3

6

0,000172

-75,3

7

0,0002441

-72,2

8

0,0003452

-69,2

9

0,0004883

-66,2

10

0,0006905

-63,2

11

0,0009766

-60,2

12

0,001381

-57,2

13

0,001953

-54,2

14

0,002762

-51,2

15

0,003906

-48,2

16

0,005523

-45,2

17

0,0078125

-42,1

18

0,011045

-39,1

19

0,015625

-36,1

20

0,0221

-33,1

21

0,03125

-30,1

22

0,04419

-27,1

23

0,0625

-24,1

24

0,08839

-21,1

25

0,125

-18,1

26

0,17678

-15,1

27

0,25

-12,0

28

0,3534

-9,0

29

0,5

-6,0

30

0,7071

-3,0

31

1

0,0

32

1,4142

3,0

33

1,9994

6,0


The table was populated with dB/10 values per row to get an intepolated decimal readout, e.g. Table row 1 was specified as -9.03 and so on. I then used a DC Input Entry instead of the Aux ADC to be able to set a precise static value used as the external input on the Single Slew External Volume Block. This is the readout from the level detector and the Log LUT for 0.0 as the external input. The level detector reads -96 dB and the Log LUT -9.03 (i.e. -90.3 dB).

And the readout with 1.0 as the external input. The level detector reads -3 dB and the Log LUT -0.0 (i.e. 0 dB). The difference is probably because I used a Peak Envelope for the Log LUT and I guess the level detector readout is rms.

A quick run trough 0.0 to 1.0 in increments of 0.1 gives the following results:

Static Level

dB Level Detector

dB Log LUT

0,0

-96

-90

0,1

-23

-20,2

0,2

-17

-14,2

0,3

-13

-10,7

0,4

-11

-8,2

0,5

-9

-6,0

0,6

-8

-4,7

0,7

-6

-3,1

0,8

-5

-2,2

0,9

-4

-1,2

1,0

-3

0


And as a graph:

I wonder what Alexander Thomas would think about this? The practical consequence is that the volume control vill be super sensitive at the low end and under utilised for the last 50%. Not a big deal if the DSP is only used as a crossover but pretty bad if it is supposed to act as a preamp. How to fix this? One way is to use a LUT and map the external input to the Single Slew External Volume Block into a better curve. Alexander Thomas writeup could serve as an inspiration. The Linear Interpolator Block has unfortunately been removed from the ADAU1701, it would otherwise have been really handy. But the functionality can luckily be replicated with two ordinary LUTs and some math

We can use Alexander Thomas approximations to populate the Slope and Step tables. Alexander Thomas seems to prefer the ^4 approximation for a 60 dB range but I also added ^3 and ^2 in the table below.

Aux ADC

Index

Gain (^2)

dB (^2)

Gain (^3)

dB (^3)

Gain (^4)

dB (^4)

0,0

1

0,0

-∞

0,0

-∞

0,0

-∞

0,1

2

0,01

-40

0,001

-60

0,0001

-80

0,2

3

0,04

-28

0,008

-41,9

0,0016

-55,9

0,3

4

0,09

-20,9

0,027

-31,4

0,0081

-41,8

0,4

5

0,16

-15,9

0,064

-23,9

0,0256

-31,8

0,5

6

0,25

-12

0,125

-18,1

0,0625

-24,1

0,6

7

0,36

-8,9

0,216

-13,3

0,1296

-17,7

0,7

8

0,49

-6,2

0,343

-9,3

0,2401

-12,4

0,8

9

0,64

-3,9

0,512

-5,8

0,4096

-7,8

0,9

10

0,81

-1,8

0,729

-2,7

0,6561

-3,7

1,0

11

1,0

0,0

1,0

0,0

1,0

0,0


And in graph form:


Now set up a spread sheet to do the math for you and its easy to make pretty much any curve of your liking. For example the Alexander Thomas ^3 approximation from above:

Aux ADC

Index

dB

Linear Gain

Slope Table

Step Table

0,0

1

-90

0,00003

0,0097

0,00003

0,1

2

-60

0,001

0,0704

-0,00604

0,2

3

-41,9

0,00804

0,1888

-0,02972

0,3

4

-31,4

0,02692

0,3691

-0,08381

0,4

5

-23,9

0,06383

0,6062

-0,17865

0,5

6

-18,1

0,12445

0,9182

-0,33465

0,6

7

-13,3

0,21627

1,265

-0,54273

0,7

8

-9,3

0,34277

1,7009

-0,84786

0,8

9

-5,8

0,51286

2,1996

-1,24682

0,9

10

-2,7

0,73282

2,6718

-1,6718

1,0

11

0

1

3,6458

-2,6458

1,1

12

2,7

1,36458




And this is what it looks like 0.0 to 1.0 in increments of 0.1 measured as before with the Log LUT:

Aux ADC

Index

^3 dB

0,0

1

-90

0,1

2

-60

0,2

3

-41,9

0,3

4

-31,4

0,4

5

-23,9

0,5

6

-18,1

0,6

7

-13,3

0,7

8

-9,3

0,8

9

-5,8

0,9

10

-2,7

1,0

11

0


And as a graph:

It actually measures as expected and its much better than before. Here is another example of how a simple spread sheet can be used. Its a pretty nice compromise for a more logarithmic curve (its the one Im using):

Aux ADC

Index

dB

Linear Gain

Slope Table

Step Table

0,0

1

-60

0,001

0,0401

0,001

0,1

2

-46

0,00501

0,0912

-0,00411

0,2

3

-37

0,01413

0,1749

-0,02085

0,3

4

-30

0,03162

0,2461

-0,04221

0,4

5

-25

0,05623

0,4377

-0,11885

0,5

6

-20

0,1

0,5849

-0,19245

0,6

7

-16

0,15849

0,927

-0,39771

0,7

8

-12

0,25119

1,4692

-0,77725

0,8

9

-8

0,39811

2,3285

-1,46469

0,9

10

-4

0,63096

3,6904

-2,6904

1,0

11

0

1

5,8489

-4,8489

1,1

12

4

1,58489




And as a graph:

This is now my updated "Volume Control" Hierarchy Board. Any EQ or internal amplification within the DSP core at 0 dBFS is kept < 10 dB. The speaker output got a compressor with a soft knee to manage anything > 0 dBFS. The headphone output is attenuated 12 dB (to protect hearing and match my AKG K550) so no compressor is needed.


DSP is now performing properly as a preamp and I am happy but almost out of MIPS...