[alsa-devel] AudioArduino - an ALSA soundcard driver for FTDI-based Arduinos

sdaau sd at imi.aau.dk
Fri Jun 3 20:22:37 CEST 2011

Hi all,

Missed a couple of replies, so I'll try to answer everything now... We 
may be going slightly off topic as far as both linux-usb and alsa-devel 
are concerned - I hope the respective communities won't mind :)

On 2011-05-30 23:15, Sid Boyce wrote:
>> Thanks, just wondered. With many SDR (Software Define Radio) project we
>> are constantly on the lookout for higher performance cards that are not
>> bandwidth restricted.
>> There are many interesting projects out there using arduino, good luck.
>> I've got a Teensy++ 2.0 on the way to have a play with.
>> Regards
>> Sid.

Hah - I noticed the signature, but I didn't really see the connection, 
until you clarified about SDR! :) Thanks for the note, and the reference 
to Teensy (have been hearing about that lately, but haven't had the time 
to look deeper)...

On 2011-06-03 07:37, Greg KH wrote:
> [snip]
>> I've just posted a diff on the SVN repository between the current
>> ftdi_sio-audard.c and the original ftdi_sio.c from kernel 2.6.32:
>> http://sdaaubckp.svn.sourceforge.net/viewvc/sdaaubckp/audard/snd_ftdi_audard-an8m/sio2.6.32-audard.diff?revision=211&view=markup
>> ... the link should show syntax coloring, so it maybe gets easier to
>> see what's going on there.
> Care to email it?  That way we can review it here and see how to
> structure it.

Of course! I am aware that people exchange patches on mailing lists, but 
unfortunately I don't have much experience with it. So I just attached 
the above-mentioned diff file here...

If needed, I will attach all other relevant files in plain text - let me 

>> [snip]
>> However, if there is some sort of a tutorial/guide (or even a
>> specific existing driver file example) that I could refer to, so as
>> to turn the current architecture into an option-based one, such that
>> I avoid messing with ftdi_sio.c directly -- I'd definitely love to
>> try and do that; so please let me know if there is some sort of a
>> recommended reading for this.
> I don't think there is a "tutorial" for something like this, but we
> would be glad to help you out here to do this.
> So, care to post the code here?

Sure - and just in case, I've attached the other relevant file, 
snd_ftdi_audard.h (which becomes included by the ftdi_sio == 
ftdi_sio-audard.c after its patched); let me know if I should attach the 
other files too (there is the code for the Arduino too, and also 
ftdi_sio.h and ftdi_sio_ids.h, but those are used verbatim - and a 
Makefile too).

On 2011-05-30 23:51, Caleb Crome wrote:
>> FYI, if you can raise the PWM rate on the arduino output, you can use
>> modulation tricks to increase the resolution.

On the Arduino Duemillanove , there is 16 MHz clock and ATmega328 - as 
far as I could gather, the highest possible PWM frequency there is 62.5 
kHz (in Fast PWM mode - achievable by setting the correct prescalers).

>> There are a lot of
>> limitations here, but there is probably some degree of improvement possible.
>>   Virtually all modern codecs do this to the extreme -- they sample really
>> fast, like 12 MHz, but only use 1 bit of resolution.  Modern 24-bit codecs
>> are really only 1 bit on the business end, but really fast.  Search for
>> delta-sigma or sigma-delta modulators if you're not familiar.

Thanks for the reference - I've studied delta-sigma waay back, and 
forgotten most of that; however, even then I haven't quite made the 
connection to what is referred to as 1-bit; so thanks for this, 
certainly something to read up on! As a side note, the ATmega328 on the 
sampling side, if I recall correctly, has a successive-approximation ADC 
built in (plus a multiplexer in front of it, to provide for multiple 
analog channels)...

>> If you can transmit, say, 10 bits and run your sample rate at ~4x your
>> intended rate, you can probably get about 10-bits of resolution on the
>> output.

Interesting - I'm not sure if I understand that statement correctly: in 
this case, an output compare (OC) unit of an 8-bit timer/counter of the 
Arduino's ATMega328 is used to produce PWM output; and since I by 
default can only write 8-bit values there in the microcontroller code, I 
have a hard time seeing how I could squeeze out 10 bits on output in 
that context; but maybe you had a different context in mind?

>> It requires a lowpass (antialiasing) filter though -- which gets
>> really nasty at sample rates below 40khz -- because then they need to be
>> sharp so you don't hear the aliasing.

Heh, this is where I got surprised :)

I too expected that at least I would hear some high-frequency "buzz" due 
to the 'hard edges' of the PWM signal - which would assume that I don't 
have a low pass filter which is sharp enough, as you state. But the 
surprising bit for me was that I could just stick this 62.5 kHz 
(carrying a 44.1 kHz data) PWM signal raw in a loudspeaker - and I can 
*not* hear a high-frequency "buzz" that I expected :) Obviously, the 
loudspeaker itself performs low pass filtering - I just thought 
originally it would not be sharp enough :)

>> Modern codecs manage this by shoving
>> all the aliasing noise up at a few MHz, so a simple RC filter is enough to
>> eliminate aliasing issues.  And not even necessary if driving
>> speakers/headphones directly.

Thanks for mentioning this too - I have often heard about the technique 
of "pushing aliasing noise up to MHz", however, still do not understand 
it practically yet. And interesting that you state it is "not necessary" 
for speakers/headphones - I'd agree with that (based on my above 
experience), but I wander if that is mainly due to the mechanical 
inertia of the loudspeaker membrane - or because of presence of 

>> Anyway, 9-bits is going to be much better than 8, so if you can run the
>> arduino at 88.2k, you could probably get roughly 9 bits of resolution.
>>   You'd probably do the upsampling on the linux side -- since the AVR is not
>> exactly bursting with MIPS.

I could send a data stream at 88.2 kHz, and there would be available 
data bandwidth too - however, since I have only an 8-bit timer/counter 
OC as a PWM generator, I still cannot see how I could get 9-bit 
resolution out of that. Maybe you imply some technique - like, I don't 
know - padding the 9-bit value to 16-bit, and then reproduce the MSB and 
LSB of this 16-bit value in rapid succession on the 8-bit PWM (though 
I'm just saying this off top of my head, this rapid succession thing 
would probably not work at all)?

>> Hmmm, or another idea:  what if you use 2 PWM channels and mix the outputs
>> together with an op-amp?
>> You could potentially get much improved resolution that way.  Basically, use
>> a summing node on your op-amp with one signal at unity, and the other signal
>> at 1/256*unity.

Heh, that's exactly what I was thinking too :) (I think its mentioned 
very briefly in the end of the paper) - basically, one 8-bit PWM 
reproduces the MSB of the 16-bit sample; and the other PWM reproduces 
the LSB of this 16-bit simple, and they are appropriately mixed in the 
analog domain. However, as you say:

>> I doubt that you'd ever get near 96 dB SNR (the ideal for
>> 16-bits), but you'd probably do better than 1 channel PWM at 8-bits could do
>> (theoretical best is 48 dB).

... yes, I too was asking myself whether the gains of reproducing 16-bit 
would not be offset by noise, added in the process of analog mixing of 
8-bit MSB and LSB analog values separately (which is, I believe, the 
same that you are saying; however, I have not yet the context to learn 
working with dB as measure of SNR properly).

>> Of course, if you're going through the trouble to add an op-amp, you might
>> as well skip the arduino all together and put a USB<->  audio chip in. :-)

Heh, indeed :) However, the point of this whole exercise was to have a 
complete overview of a sound card as system (including the PC).

For instance, before this, I've always had the misconception that when, 
say, Audacity plays a file, it sends the value for each sample (say, 
16-bit) one-by-one to the soundcard, and so the soundcard plays back the 
samples one-by-one. And that is not what happens: ALSA does its own 
chunking, then USB does its own chunking - which means that, at least 
for playback, as a code for the device (soundcard) you better be storing 
those incoming bursts of data in an array somewhere, and *then* 
reproduce sample-by-sample (from the stored data) at the requested 
reproduction rate.

Of course, in such a system, one needs to think about the analog domain 
as well - I tried to document a simple board, that would take the 
AudioArduino as is, and try to provide an analog line in/out interface 
to it with the simplest approaches (e.g. a discrete ramp-and-hold 
circuit, to convert the PWM signal to analog voltage levels); however, 
all I could conclude was that simple approaches actually produce 
slightly worse results (than just having the AudioArduino PWM out going 
directly into a speaker).


-------------- next part --------------
A non-text attachment was scrubbed...
Name: sio2.6.32-audard.diff
Type: text/x-patch
Size: 16641 bytes
Desc: not available
Url : http://mailman.alsa-project.org/pipermail/alsa-devel/attachments/20110603/974855d1/attachment-0001.diff 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: snd_ftdi_audard.h
Type: text/x-chdr
Size: 54670 bytes
Desc: not available
Url : http://mailman.alsa-project.org/pipermail/alsa-devel/attachments/20110603/974855d1/attachment-0001.h 

More information about the Alsa-devel mailing list