IMPLEMENTED SO FAR

- Support for 4x20 LCD Display and large number display
- Brightness and contrast adjustment with remote
- (OPUS/Wolfson WM8741) DAC volume control: remote and rotary encoder
- (OPUS/Wolfson WM8741) DAC random filter selection 1 to 5 with remote
- (OPUS/Wolfson WM8741) DAC upsampling selection (L, M, H -this is the OSR setting)
- I2C level shifting (5V to 3.3V)
- Optimized power-up sequence

Thursday, December 3, 2009

Measuring I2S with Cheap Scope

I decided to to some audio measurement with the scope. Measuring I2S was the perfect exercise as the different clocks are sent in separate wire. Because of the limited bandwidth of the scope, choosing the slowest clock was necessary. A quick look at the I2S specification indicated that measuring the LRCK, the clock that tells you left channel data and right channel data was the line to measure.

Because in a single cycle LRCK indicates the transfer of data for a single stereo sample (left channel and right channel), LRCK always matches the sample rate. See Wikipedea for a better explanation.

Here is the measurement when iTunes plays at 44.1KHz sample rate



Here is the measurement when iTunes plays at 88.2KHz sample rate



Here is the measurement when iTunes plays at 96KHz sample rate

$49 Oscilloscope



A pretty good scope for audio applications. Maximum analog bandwidth is 1 MHz.

There is a Google group with discussions on this scope. Check out the "pages" section for more info on modding/upgrading the scope.

Thursday, November 19, 2009

OSR bits in WM8741


According to a Wolfson Engineer,
OSR, it's the DAC-to-input-rate-ratio. We want that to be high to have the DAC run fast, but not too fast to introduce timing related mayhem. You can't set this ratio directly but only indirectly through R7.

When you set low rate what you tell the DSP is high OSR. It means we use the maximum amount of upsampling since we know the input rate is low enough such that the resulting DAC frequency lies in the sweet spot of performance: high to run the sigma/delta with loads of headroom, not too high so as to introduce analogue problems.

For medium and high rates, the actual upsampling ratio reduces such that with the higher input rates we end up with the same actual DAC frequency.
Thus the OSR bits in the DAC controls the Internal upsampling of the DAC.
  • Low rate means "apply highest internal upsampling"
  • Medium rate means "apply medium internal upsampling"
  • High rate means "do not apply any internal upsampling"
You can test this out with the following:
  • If you input sample frequency to the DAC is 44.1 KHz, you can select any one of the 3 settings. With Low Rate, maximum internal upsampling is applied, with High Rate, no internal upsampling will be applied.
  • If your input sample frequency to the DAC is 192 KHz, then you can only select High Rate, meaning that no internal upsampling can be applied because the input data is at high rate or has been upsampled outside of the DAC

Wednesday, November 18, 2009

Testing WM8741 filter setting

Some people can hear differences between the digital filters in the WM8741 DAC. In my setup, I can't really hear clear differences between the different filter settings, and up to now I had no way to test whether the different filters were being selected by the software in Arduino.

The good people at AMB did an excellent job in characterizing filters 1, 2, and 3 with different upsampling, and found that without upsampling (i.e., with 44.1KHz material), filters 1 and 2 will roll off at 15Khz as compared with filter 3 as shown in this picture:



I downloaded a 15 KHz test tone (from mosquito ringtones) and played it in a loop in iTunes. The output was set at 44.1 KHz and I set the OSR bit in the WM8741 to "high" (meaning do not use internal upsampling). Then I selected and compared filters 1, 2, 3. Indeed, you can hear an attenuation with filters 1 and 2 as compared to filter 3. Filter 1 is filter A, 2 is B and 3 is C.

Therefore the software is working. (Keep in mind that if you are an old guy, you will need to ask a kid to help you listen to the 15KHz test tone)

Tuesday, November 3, 2009

Logic Level Converter



NKC Electronics has released this little board to allow converting voltage levels between Arduino and other devices.

Recall that Arduino is typically a 5V device and devices that you want to control (such as a DAC) are 3V devices. If you use the Arduino I2C interface (which is 5V logic) to control the 3V I2C interface of a device, you need this converter. More information here.

Thursday, October 15, 2009

LCDUINO-1



When I started my project, I posted in DIYAudio and got totally ignored. Fortunately other people recognized the potential of using Arduino for audio and have invested in making Arduino an "audio-friendly" device.

LCDUINO is an arduino-compatible board (I wouldn't call it a clone because it cannot use "arduino shields"). I believe the primary goal was to build a board of the same footprint as a 16x2 LCD so that it fits neatly behind the LCD, facilitating the construction of something like a headphone amplifier.

The device is the equivalent of an Arduino board (or clone) plus a serial LCD (which is what I used for my project). LCDUINO adds a real time clock, but lacks the USB chip for programming. I think a second goal for the project was to provide a lot of code so that for many purposes, no programming is necessary. If you want to program the board yourself, you will need to purchase a USB to serial converter and connect it to the LCDUINO

The real jewel in LCDUINO is the code that linuxworks is developing for the board which will be available to the user community.


You can find more at linuxworks web site and the AMB website.

Arduino+Buffalo

I think this is the first public project of Arduino controlling a Twistedpairaudio Buffalo DAC [link]

Thursday, October 8, 2009

Tuning iTunes

Haven't posted for a while... Spending time listening to music. I use iTunes running on Windows Vista

One anoying thing in iTunes is that in album view, it separates songs if they have multiple artists. The way to fix this is the following:

"You can mark these songs as a compilation in iTunes. Do do this, select all the songs that you want to be included in the compilation and select Get Info from the file menu and select Yes in the Compilation menu as shown below. After clicking OK iTunes group all the selected songs together." [
Link to Apple for complete article]



iTunes on PCs is also bit perfect if you match the sampling rate in the Quicktime control panel to the sampling rate of the source material. Ken Poon explains it well in his blog.

Tuesday, August 4, 2009

4 1/4 Digit DMM



Purchased this DMM in Shenzhen, China for RMB 200 (about 30 bucks) at the famous SEG Electronics Market. Yeap, everything you've heard about this place is true!.

Sunday, June 28, 2009

Friday, June 26, 2009

How Asynchronous Rate Conversion Works

Continuing with the discussion thread at DIYaudio, I will attempt to summarize how ASRC works.

Synchronous rate conversion

Let's say we are dealing with a SYNCHRONOUS rate conversion problem, from 44.1kHz to 48kHz, where both rates are derived from the SAME clock source. Meaning that, when measured with the same stopwatch (clock), the 44.1kHz rate is EXACLTY 44.1kHz, and the 48kHz rate is EXACTLY 48kHz.
In this environment, one could simply interpolate by 160 to 7.056MHz and decimate by 147 to 48kHz:

T
he first thing to do (at least conceptually) is to take the 44.1kHz data stream and stuff 160-1=159 zeros, evenly spaced in the time domain, between each sample. Then you apply the "zero-stuffed" sequence to a low-pass filter (cutoff at half the original sample rate or 22.05kHz), which will finalize the interpolation process by "filling in" the zeros with real data points. (hard to envision, but this is what happens with digital filters).

Now we simply grab every 147th sample, to generate our output sequence at 48kHz. That "grabbing every 147th sample" is precisely DECIMATION. Just digital re-sampling, or down-sampling. We didn't need a special filter for decimation in this case, because the interpolation filter did it's job for us.


Asynchronous rate conversion

In ASYNCHRONOUS sample rate conversion. The 44.1kHz clock and the 48kHz are NOT derived from the same time base, meaning they are not exactly the numbers they claim to be, when measured with the same stopwatch. So, in this asynchronous world, if have two time lines: one with ticks every 44.1kHz, the other one with ticks every 48kHz. Thus by definition, Asynchronous Rate Conversion is this:
There is NO interpolation by any FINITE integer you can do on the INPUT sample points ... meaning, no finite number of samples you can evenly space between the original samples ... that will give you perfect alignment with all the OUTPUT sample points.

Asynchronous Sample Rate Conversion: How does it work


Here we have a situation where we need to digitally CALCULATE output data samples at new points in time, different than the input data time points. And the time points are NOT synchronized. ... so there is no finite integer interpolation that we can perform on the input data that will align PERFECTLY with the output time points we need.

But we don’t have to be PERFECT. Conceptually, we will interpolate the input data by a pretty huge number, in fact, by a pretty huge INTEGER number, so that we effectively "fill in" very many samples in-between the original Fs_in samples. So instead of providing an interpolated input sample that corresponds to that exact point in time, we can provide the closest (in time) interpolated sample that is calculated. How BIG will the error be? The question is therefore is ... How far do I have to interpolate, by what integer, so that grabbing the most recent sample will give me acceptably LOW error ?

We can never achieve perfection here, but we can get ARBITRARILY CLOSE ... simply because the higher I interpolate, the lower the error. So the question is, how big should the interpolation number “N” be?


After a lot of math, it can be shown that input data at the Fs_in rate needs to be interpolated by N~2^20 (1,048,576 -over a million!), so that the error incurred by Asynchronous decimation to Fs_out will be acceptably small. But 2^20 is HUGE resulting in a frequency of 50 GHz and this is for an input sample frequency of 44.1 KHz.

Fortunately, because most of the samples are going to be ignored when decimating to the output sample rate (e.g. 48 KHz), we don’t have to calculate them in the first place. We only need the samples closest to the output sample rate. In order to do this we use FIR filters (Finite Impulse Response). And though clever implementation, and by knowing the output sample rate, the computational demands of implementing the FIR filter are manageable in a typical commercial implementation. (Meaning you don't have to do all the math or have heavy-duty computational engines).

My observations: Rate conversion from 44.1KHz to 192KHz is the same as 44.1 KHz to 176.4 KHz

From the above discussion, it can be seen that because the system is designed to select the interpolated sample that is closest to the output sampling rate, it does not matter whether the output sample rate is an integer multiple of the original sample rate or not.

This is important because in some audio circles it is believed that for CD material with its native sample frequency of 44.1KHz, it would "sounds better" if sample-rate converted to 88.2 KHz or 176.4KHz (integer multiple) than to 96KHz or 192KHz (not integer multiple). The argument presented here (by the expert at DIYaudio), at least from a theoretical point of view implies that the closest matching sample to clock-ticks in a 192 KHz clock, for example, should be no worse than the closest matching sample to clock-ticks in a 176.4 KHz clock.

Thursday, June 25, 2009

Asynchronous Re-clocker vs Asynchronous Rate Converter

The same discussion thread teaches the theory behind sample rate conversion.

We should first distinguish between two terms that are often used interchangeably in audio circles but are completely different technologies:

Asynchronous re-clocking

Asynchronous re-clocking or re-sampling: this term describes a pretty simple operation where a digital audio signal is simply re-clocked by a clock from a different time base. There is no interpolation or rate conversion performed on the signal.

Asynchronous Sample Rate Conversion:

This is categorically different, in the sense that SIGNIFICANT interpolation is performed on the Fs_in (input sample rate) signal to minimize error (both time & freq domain) when the ultimate decimation to Fs_out (output sample rate) occurs. Example chips that can perform this function are the CS8420, AD1896 (and their brethren)...

...and the SRC4192 which is the subject of the next project.

More on Pre/Post ringing

There is an excellent discussion thread on digital sampling at DIYAudio. In one of the posts, the following is explained:
"Pre/post ringing : most obvious in the classic step response of a steep, linear phase (usually FIR) filter. ... Let me just say now, for the record, that the pre/post ringing we often encounter in digital audio is nothing more than an artifact of the Gibbs phenomenon which simply states that abrupt transitions or discontinuities in one domain, cause ringing in the other.

Band-limited systems unfortunately fit in this category and there is no better example of a SHARPLY band-limited system than digital audio. Don't like the ringing? Sure we can eliminate it but the price you pay will be aliasing, pure & simple, no way around it. And that's a BAD tradeoff."

What is described above is the fact that with a linear phase filter, reducing the ringing will require the use of slow roll off filters allowing higher frequency images to reflect back into the audio band (this is called Aliasing).

More modern DACs such as the one we used in this project are addressing this problem with so called "minimum phase filters" and to completely eliminate any aliasing, the concept of "Apodizing filters" are used together with minimum phase filters.

We previously explained the digital filters of the WM8741 here.

Wednesday, June 24, 2009

Which I/O Expander?

My next project is to control the Texas Instruments SRC4192 chip. This device is an "asynchronous reclocker" and feeds the DAC. Theoretically it reduces jitter because it recreates the clock with a much better on-board oscillator. The device is implemented in a kit board from TwistedPearAudio.

The block diagram is as follows:



In order to interface to the control logic lines, I would need an I/O expander that would communicate with Arduino. Basically you want to swith these lines high or low to select the different configurations and features of the device.

Since there are up to 15 control lines and it needs to support the I2C protocol (to communicate with Arduino) and must by in DIP package (for easy soldering). I would need a 16-port I/O expander in DIP package. Looking over at Digikey, there is just one device in stock that meets the criteria: the PCA9555 by NXP Semiconductors.

It cost $2.13 Application note AN469 explains how these devices work in great detail.

More on Volume

In the latest code, I've fixed the volume values I used to program the WM8741. Previously I mistakenly used 0.25 dB as the smallest interval whereas it is .125 dB the smallest interval, so my volume readings were twice the actual value.

Also I did not see the need to use an interval of less than 1 dB because it is already not very discernible a difference of 1 dB.

Now, the typical listening level is above -50 dB, and mostly in the -30 dB to -15 dB. Therefore above the -48 dB at which point you will start experiencing (theoretically) some loss in information due to the nature of digital volume control.

I also got a response from Wolfson about how the volume control is implemented: Basically input less than 24 bit is padded to 24 bit, input that is 25 to 32 bit is reduced to to 24 bit with dither and the volume control is applied at the next stage.

Monday, June 22, 2009

LCD Settings in Arduino EEPROM

I've added adjusting the LCD Brightness and Contrast with the remote. I've assigned one button in the remote to select between "no adjustment", "brightness adjustment" and "contrast adjustment". This button is a toggle between these three modes.



When entering the brightness mode, the current value is read from the Arduino EEPROM. Two other buttons in the remote are used to increase the value and decrease the value, and adjust the LCD accordingly.



When entering the contrast mode, the current value for contrast is read from the Arduino EEPROM. Two other buttons in the remote are used to increase the value and decrease the value, and adjust the LCD accordingly.



When you exit the adjustment mode, the current settings for brightness and contrast are saved in the Arduino EEPROM. I've used addresses 0 and 1 in the EEPROM space to save the two values. The EEPROM of the Arduino ATmega 168 has 512 bytes of space and the ATmega328 has 1 K bytes of space.

The code for selecting the mode, read and write to EEPROM is as follows. Pressing a specified key in the remote will invoke the following code:

case KEYDISPLAY:
BC++;
if (BC%3==0){
lcd.
setCursor(0,4);
lcd.
print(" ");
EEPROM.write(BRIADDR,brightness); // Save value
EEPROM.write(CONADDR,contrast); // Save Value
}
if (BC%3==1){
lcd.
setCursor(0,4);
lcd.
print("BRI ");
brightness=
EEPROM.read(BRIADDR); // Read value
lcd.
print(brightness);
}
if (BC%3==2 ){
lcd.
setCursor(0,4);
lcd.
print("CON ");
contrast=
EEPROM.read(CONADDR); // Read value
lcd.
setCursor(8,0);
lcd.
print(contrast);
}
delay(100);
break;

To adjust the brightness and contrast, we send a value to a specific address in the LCD I2C interface/controller (This is a I2C LCD from web4robot). We use the Arduino wire library. The I2C address for the LCD is 0x4C, 0xFE is a prefix indicating that it is a command and not text to be displayed. 0x03 is the command for brightness and ox04 is the command for contrast. After sending the prefix and the command, the value is sent. Brightness value is 0-255 and contrast value is 0-100. The code is as follows:

// Routines for LCD Adjustment

// For LCD backlight adjustment
void BackLight(uint8_t bright)
{
Wire.beginTransmission(0x4C);
Wire.send(0xFE);
Wire.send(0x03);
Wire.send(bright);
Wire.endTransmission();
delay(25);
}

// For LCD contrast adjustment
void Contrast(uint8_t cont)
{
Wire.beginTransmission(0x4C);
Wire.send(0xFE);
Wire.send(0x04);
Wire.send(cont);
Wire.endTransmission();
delay(25);
}

Sunday, June 21, 2009

Latest Code v 0.7

Everything I've written is in this new code base. And everything is less than 9K. Link in the sidebar.

Saturday, June 20, 2009

New Fonts

Inspired by a new 4-line large font template at the Arduino forums (you can find the link in the sidebar), I decided to tweak my own 3-line Arduino large font.

Basically you create a number of shapes as custom characters and used them to form the large font. However, you are limited by the number of custom fonts you can specify in an LCD (typically 8). The 4-line large font in the Arduino forums is actually the same size as my 3-line large font. But by having 4 lines you have more flexibility in positioning the custom characters "to preety-up" the fonts but you give up some speed in displaying the large numbers (25% speed penalty: 3 lines vs 4 lines).
Here are the results



The left most number displays the selected digital filter in the DAC. Above, I've added an abbreviation to the name of the filter. In this case, LnS is "Linear Phase, Smooth Roll Off".



"LnA" means "Linear Phase, Apodizing". Also displayed is RATE, the input sample rate to the DAC. There is also filter #2: MnS: "Minimum Phase Smooth Roll-off"



"BrK" means "Brickwall" filter. Also displayed is INPT, the input format to the DAC. The WM8141 can receive both PCM (from CD players) and DSD (from SACD players). In the future i will be experimenting with extracting the DSD signal from inside a player and feeding this signal straight to the DAC.



"MnA" is "Minimum Phase, Apodizing" filter. Here RATE has been changed to 48K. Because the incoming signal is processed through a asynchronous reclocker chip to 192KHz, there is a sample rate mismatch and the DAC does not output any sound (In theory, this setting selects the appropriate filters to match the sample rate). In the future I will be using Arduino to control the asynchronous reclocker chip in order to change its output sample rate.

Saturday, June 13, 2009

I2C Address and R/W bit

I was reviewing my code and could not remember why the register addresses I defined in the code was different from the register addresses defined in the data sheet of the WM8741. After an hour reviewing the data sheet and the I2C protocol, I finaly realized that I2C address are 7 bit and the 8th bit is the Read/Write bit.

Since all the registers of the WM8741 are all write registers (R/W bit=0), they all end with zero. So the address value that you send in the I2C protocol is the 7 bit address plus the R/W bit, so the 8-bit values ends with zero.

Example:

7-bit Address plus R/W bit

00h=0000000 plus R/W bit = 00000000 = 00h or 0x00
01h=0000001
plus R/W bit = 00000010 = 02h or 0x02
02h=0000010 plus R/W bit = 00000100 = 04h or 0x04

Thursday, June 11, 2009

Why Pull-Up Resistor?

An often suggestion in Arduino debugging is "whether or not a pull-up resistor has been installed"

Why do we need a pull-up resistor? This article explains it well (and this one too), but in summary,

For an (digital) input pin, A pull-up resistor will set a default value when there is no signal at the input. In other words, when there is no input you don't want some random value but a definite value.
Also,
  • If when there is input you measure 0 (or low), and when there is no input you want it to measure 1 (or high), then you must use a pull-up resistor.
  • If when there is input and you measure 1 (or high), and when there is no input you want it to measure 0 (or low), then you must use a pull-down resistor.

But since Arduino has built-in pull-up resistors that can be enabled in software, you should think about a configuration that only requires pull-up resistor or you must implement the pull-down externally. However, if your external signal already has two definite states (high and low), then you don't need to enable the pull-up resistors inside the Atmel chip