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...
... 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 know.
[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 coil/inductor?
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).
Cheers!