See also post in Arduino Forum
This project continues the treatment of the DIY approach to soundcards - as an example of an overall approach to PC-based digital audio hardware development - started with ExtendingISASoundcard. AudioArduino is a project that demonstrates the use of an FTDI FT232R-based Arduino Duemilanove board as a 44.1 kHz, 8-bit, mono, full-duplex soundcard; by implementing corresponding, open-source
- microcontroller code for the Arduino's Atmel ATmega328 microcontroller (in .pde format, so it is buildable in Arduino IDE software); and a
- matching audio card driver for the Advanced Linux Sound Architecture (ALSA) (developed on Ubuntu 10.04 GNU/Linux operating system).
The above arrangement will cause the operating system to recognize an Arduino Duemilanove's analog input 0 pin as a mono audio input; and will generate audio output as a 62.5 kHz pulse-width modulated (PWM) signal on digital out 6 pin as a mono audio output. In this manner, high-level audio software such as Audacity can be used to directly interface with an Arduino.
Nothing more than a ~10μF electrolytic capacitor on the output is required, in order to attach a small loudspeaker (such as one from heaphones) for the ability to hear sound played on the PC audio software; the input can accept usual voltage signals in the range from 0-5V, and these - while captured as 8-bit data - will usually be rendered as values in the 'audio' range between -1 and 1 in audio software.
Please note that the reference version of the Arduino, Arduino - Arduino Uno released in 2010, does not have a FT232 USB interface chip - instead it has an ATmega8U2 chip, which has a completely different behavior; and hence AudioArduino as described here, cannot be applied to Arduino Unos.
As mentioned above, the AudioArduino (
audard) source can be browsed here, or checked out from svn through:
svn co https://sdaaubckp.svn.sourceforge.net/svnroot/sdaaubckp/audard/snd_ftdi_audard-an8m
It simply consists of a
- microcontroller code duplexAudard_an8m.pde;
- ftdi_sio-audard.c main driver file (which is a slightly modified version of the ftdi_sio.c Linux USB driver for FTDI) - and related header files (
- snd_ftdi_audard.h, which is based on Minivosc, and contains all ALSA soundcard related functionality.
Follow the instructions in 'Building and running' in order to work with it. The source code was developed and built on Ubuntu 10.04 (Lucid), spanning kernels from 2.6.32-23-generic to 2.6.32-27-generic.
- Note: see the comments in the latest ftdi_sio-audard.c for compiling the driver under kernel 2.6.38 (as on Ubuntu 11.04 Natty). Only a couple of lines need to be changed - and while compilation will generate a lot of warnings, the driver should still work.
Building and running
Build Arduino code
In order to use AudioArduino, it is advisable to first build the microcontroller code
.pde file in Arduino IDE, and 'burn'/'upload' the program on to the Arduino Duemillanove. When the Arduino is programmed (and at each power-up), the program starts automatically - and as soon as the program starts running, the LED13 on the Arduino should begin shining dimly (as it indicates the 44.1 kHz processing rate). (Note you may experience the need for a capacitor over RESET signal.)
Build PC driver code
The second step is the building of the PC soundcard driver. In essence, the instructions are the same as in Minivosc: only the kernel headers (not the entire source) is needed (along with compilation tools); and then the driver can be built as an 'out-of-tree' kernel module, by issuing the following in the driver source code directory (snd_ftdi_audard-an8m):
make clean && make
which should result with a kernel module file in the same folder,
snd_ftdi_audard.ko (which follows the ALSA naming convention, where related kernel modules are prefixed with '
snd-'; the '
ftdi' keeps the link to the original
ftdi-sio driver; and '
audard' is an initialism for AudioArduino).
Load PC driver - sequence
The third step is to establish a proper PC driver loading sequence. To begin with, the safest way is to start with a freshly booted system, to which the Arduino is not connected: note that attaching the Arduino before or while the system is booting, will result with the default
ftdi-sio driver being loaded, which would obviously conflict with the use of
Thereafter, the driver kernel module can be loaded in two ways:
- As out-of-tree module using
insmod. Note that this variant requires that the
usbserialis loaded manually first:
$ sudo modprobe usbserial # load usbserial module $ sudo insmod ./snd_ftdi_audard.ko # load snd_ftdi_audard driver
- As in-tree module using
modprobe. This variant requires that the driver is built first, then symlinked to the respective system module directory (in
$ make clean && make $ sudo ln -s /path/to/snd_ftdi_audard-an8m/snd_ftdi_audard.ko /lib/modules/$(uname -r)/kernel/drivers/usb/serial/With this in place, after each building of the driver, the command
$ sudo depmodshould be issued, which calculates module dependencies for system modules (those in
/lib/modules). With the dependencies calculated, we can then just directly call:
$ sudo modprobe snd_ftdi_audardto get both the AudioArduino driver - and the needed
usbserial- loaded in the Linux operating system. Note however, that with this option, having the Arduino attached to the PC at boot time will automatically load both the default
snd_ftdi_audard(which is no good, and would require manual unloading of
modprobe -r; which will still not be a guarantee that the remaining AudioArduino driver will work properly)
Connect Arduino to PC via USB
Once we are sure that the AudioArduino driver
snd_ftdi_audard is succesfully loaded in memory, we can proceed with the fourth step, which is attaching the Arduino to the computer through USB. If the Linux system log is observed (through
tail -f /var/log/syslog in a terminal) during the process of connecting the Arduino via USB, some log messages from the
snd_ftdi_audard should be visible. At this point, the Arduino should be visible as an 'AudArd' soundcard to the operating system - which we can check by calling the default ALSA command-line tools,
$ aplay -l **** List of PLAYBACK Hardware Devices **** card 0: Intel [HDA Intel], device 0: ALC662 rev1 Analog [ALC662 rev1 Analog] Subdevices: 1/1 Subdevice #0: subdevice #0 card 1: AUDARD [MySoundCard ftdi_sio_audard], device 0: AudArd PCM [AudArd PCM] Subdevices: 1/1 Subdevice #0: subdevice #0 $ arecord -l **** List of CAPTURE Hardware Devices **** card 0: Intel [HDA Intel], device 0: ALC662 rev1 Analog [ALC662 rev1 Analog] Subdevices: 1/1 Subdevice #0: subdevice #0 card 1: AUDARD [MySoundCard ftdi_sio_audard], device 0: AudArd PCM [AudArd PCM] Subdevices: 1/1 Subdevice #0: subdevice #0
mind the pulseaudio
Note that this means that the Arduino 'soundcard' should now be visible also to the system audio volume GUI, which in Ubuntu 10.04 is handled by
gnome-volume-control, which in turn needs
pulseaudio may interfere with the process of driver loading or removing, so it is advisable that pulseaudio is not running during this process; to ensure that is the case:
- first run
pulseaudio --kill(to stop
pulseaudio, which also kills
- Then do driver loading/unloading
- Finally, run
pulseaudio --startto get also
- Now, connecting/disconnecting the Arduino to/from a PC via USB should be safe.
set serial comm to 2 Mbps
With a loaded driver and Arduino attached to a PC - there is still one more, fifth step - which is setting the serial communication speed to 2Mbps. When the Arduino is attached and powered up, and its code starts running, it is set to automatically set the communication speed between the FT232 and the ATMega328 at 2 Mbps. However, on the PC side, the driver is still essentially a USB driver (the code portion from
ftdi-sio) with an ALSA audio card interface. Upon attachment of Arduino, the serial port node
/dev/ttyUSB0 which gets created in the PC that represents it also has a serial communication speed attribute; however, this one is by default set automatically by the system often at 9600 or 19200 bps. There are other problems related to serial ports (such as interpretation of XON/XOFF); and settings like these and the serial speed can be set by using the
$ stty 2000000 inpck -ixon -icanon -hupcl -isig -iexten -echok -echoctl -echoke min 0 -crtscts </dev/ttyUSB0
Once all these conditions are met (PC driver loaded; Arduino connected; corresponding serial port on PC set to 2 Mbps) - then we can start high-level audio software like Audacity, Ubuntu Manpage: arecord/aplay - or any audio software that should work with soundcards, like Pure Data - and then:
- sample from the analog in 0 pin on Arduino by recording the mono audio input on the 'AudArd' soundcard
- generate audio PWM on the digital out 6 pin on Arduino by playing back on the the mono audio output on the 'AudArd' soundcard
While the main discussion is in the paper, a few additional notes are included below.
Notes about videos
Here are a few notes regarding the videos:
- Sometimes a desktop capture of the PC desktop contents was performed along with actual recording of video. Some videos up there are overlays (composite) of video recording and desktop capture (
_compin filename); some are just (as of yet) uncomposited desktop captures (
- These desktop captures can be useful for easier visualising of the running procedure (i.e., driver loading)
MVI_4345_audard_pwm_out_sndOK shows the default behavior of AudioArduino; both a HF sawtooth and music test are performed; the Arduino plays back on a headphone loudspeaker, and at the end, the sound is played back through the PC speakers for comparison. The GOULD scope shows the PWM output, which has a frequency of 62.5 kHz; the DSO Nano shows the pulses on pin13 (LED), which should show a sustained rate of (close to) 44.1 kHz.
Note that since the GOULD scope is in analog mode, its screen persistence makes for a very smooth and rhythmically accurate video recording of the changes of the PWM signal.
MVI_4366_audard_saw_test_direct and MVI_4369_audard_music_test_direct show a more detailed test. The saw test is a test of reproduction of a signal, generated as file using the following python one-liner:
python -c "import sys; a1=(0, 64, 128, 192, 255); size=1000 ; [sys.stdout.write(str(a1[i%(len(a1))])+' ') for i in range(0,size-1,1)]"; and then loading it as an 'unsigned 8-bit' 44.1 kHz file in Audacity. That makes it a sawtooth signal with a period of 5 samples, or frequency of 44100/5 = 8820 Hz; notice that the (Audio)Arduino has a hard time reproducing that signal accurately. However, when music is used instead, the reproduction quality is subjectively not that far from the one obtained from netbook soundcard and speakers.
Note that since the Agilent scope is in digital mode, its screen refresh rate interferes with the capture rate of the video camera, hence video recording of the changes of the PWM signal on the scope is not rhythmically accurate
- MVI_4310_audard_first_pwm_hdphones is a document of a first test of audio capability on the Arduino, which reveals severe distortion of the sound. This distortion is due a bug in the Arduino code, which uses a plain array instead of a circular buffer - which in turn causes samples to be played in reverse; however, since samples arrive from PC in small chunks, it is these small chunks that are reversed - while as a whole, the whole signal is still rhythmically accurate.
- MVI_4346_audard_pwmsnd_cap_compare shows the difference between using no capacitor, a small capacitor and big capacitor on the Arduino output, when connecting it to a headphone speaker as load (note that the code on the Arduino is buggy in that recording, which is the cause of the heavy distortion).
- MVI_4292_pipe_loopback, MVI_4305_audacity_duplex_loopback show a digital loopback test: the Arduino is not set to sample and reproduce, but instead is simply copies each byte received from USB and sends it back via USB to the PC. The videos show how either command line tools - or high-level audio software - can be used to demonstrate the digital loopback. The main idea behind such demonstration being to play back/send data (file) from PC to Arduino, and capture the data from the Arduino at the same time on the PC - finally, the captured data can be compared to the original (to determine whether errors have occured in transfer), and these operations can be timed, so as to determine the actual throughput rate achieved in the PC-USB-Arduino-USB-PC loop.
- audardII-01-firstlight-waveform-comp and audardII-02-firstlight-analogin-comp represent documentation of early tests of audio driver and digital loopback functionality.
audard_log_animplot_01_full_badwrap and audard_log_animplot_01_usb_awbwrap are videos, obtained by piping the textual log output of the PC
snd_ftdi_audarddriver to a
pythonmatplotlib script; which visualise realtime buffer possitions of
dma_areaand USB buffers in the driver code - and as such reveal problems with buffer wrapping.
- hist-anread-NO, hist-anread-YES are histograms of time measurements on the Arduino, which represent how long a time does the code spend in individual sections, with and without data handling; done in relation to measuring Arduino's FT232 throughput rate. The timestamp data obtained on the Arduino is sent via USB, captured on the PC and then piped into a script utilizing gnuplot to generate the image frames for the video.
The approach taken in this project, is to perceive the soundcard as a device communicating to a PC through a specific bus interface, which further passes the data to analog-to-digital (A/D) and digital-to-analog (D/A) converters. While in ExtendingISASoundcard the bus is ISA, and both the bus interface and A/D/A converters are implemented as discrete parts - in this project, the bus is USB; and given that the Arduino can be abstracted as a connection between an FT232 and an ATMega328, the bus interface is represented by the FT232 (and partially by the code running on the ATMega328); and the ATMega328 contains both the hardware counters that generate the PWM output (as D/A converter), and the A/D converter.
The Arduino (or rather, its FT232) is by default handled by the ftdi_sio Linux driver, which presents the Arduino device as a serial port (usually
/dev/ttyUSB0). This project simply starts from
ftdi_sio, and slightly modifies it to include ALSA soundcard-specific functionality. Since the serial port interface is kept, it is possible to, say, write data to the serial port via the command line in one direction (say playback) - and simultaneously record the capture direction from high-level audio software (audacity).
Thus, soundcard operation can be demonstrated by using an off-the-shelf Arduino as a representation of a generic microcontroller-based device, and programming a specific microcontroller and PC audio driver code. In this, the actual workings of the USB protocol are completely abstracted (and thus considered unknown) - as simply the focus on the RS-232 serial signals (considered as known protocol) between the FT232 and ATMega328 is enough to determine the overall performance of the Arduino device in relation to a PC, and whether it can be employed as a soundcard. The main assumption is that, even if the Arduino is advertised as achieving max of 115200 bps serial data transfer speed, its individual parts claim greater speeds: 2.5 Mbps for the ATMega328, and 3 Mbps for the FT232. As
ftdi_sio already supports 2 Mbps rate - the assumption is that the PC can communicate through the FT232 with the ATmega328 at 2 Mbps; which would then be sufficient to transfer audio data close to (taken as reference) CD quality rates.
Note that since the FT232 and ATMega328 use TTL RS-232 8N1 communication, there are 8 data bits, one start and one stop bit - or 10 bits - in a serial packet; thus a bit rate of 2 Mbps (as in Megabit/sec, or Megabaud) equals an actual data transfer rate of (2000000/10=200000=) 200 KBps (as in KiloBytes/sec).
Sampling rate, resolution and number of channels
Since this project represents an introduction to practical implementation of soundcard hardware and software, the focus is on work with 8-bit sampling resolution, and mono audio channels (in both input and output directions). Only in this case, we have an equivalence between the 8-bit data payload of the serial packet, and the 8-bit sample representation of the audio data stream.
Increasing the sampling resolution, or number of channels, introduces the problem of interleaving and buffer wrapping, and the concept of frames within the ALSA architecture, where a frame is the size of a single analog sample in all channels for a given direction (playback or capture). Hence a stereo, 16-bit stream has a frame size of 4 bytes; and for mono 8-bit streams, the frame size is 1 byte.
Note that with a theoretical data rate throughput of 200 KBps, we can have 200000/44100 ~ 4.5, or rather 4 8-bit mono channels @ 44.1 kHz (or two 16-bit mono channels - or one stereo 16-bit channel - at the same rate). However, the capabilities of the ATMega328 will limit how much of that bandwidth can we use to demonstrate actual playback and capture channels.
The Arduino has 2 8-bit timers (Timer0 and Timer2) and one 16-bit timer (Timer1); each of these has two output compare (OC) units. Being clocked at 16 MHz, the Arduino can generate a rate close to 44.1kHz only by using the 16-bit timer (16000000/44100 ~ 362, which requires 9 bits); so the 16-bit timer is used to generate an interrupt close to 44.1 kHz. The OC unit A of Timer0 (OC0A) is used to generate the 8-bit audio output PWM signal at 62.5 kHz; while the OC0B, OC2A and OC2B are used to generate end-of-period signals (relevant only for AudioArduino-AnalogBoard).
The PC audio driver writes playback data to USB as chunks, that are transferred at 200 KBps; these received by Arduino, and are handled in an interrupt routine of the ATMega328 code, where they are stored in an intern circular/ring buffer. At each tick of the 44.1 kHz interrupt, the code:
- reads one byte (sample) from the circular buffer, and writes it to PWM
- reads the state of analog input 0, and writes that byte through USB to the PC
... and thus, while the playback data arrives in chunks to the Arduino - the capture data is sent through USB sample by sample; however, both of those rates are on average close to 44.1 kHz.
The duplex loopback test
The above discussion assumes that the theoretical 200 KBps will be achievable in full in reality as well (which, it turns out, is not really the case). Furthermore, one of the most important properties expected of a modern soundcard, is its capability to perform in "full-duplex" mode: the capability to both playback and record audio data simultaneously; however, without previous experience, it is not clear whether these theoretical 200 KBps refer to full- or, possibly, half- duplex mode (it turns out, they do describe full duplex operation, in the case of the Arduino Duemillanove).
The basic approach in developing the soundcard code (both microcontroller, and PC driver) was to first establish a "ground truth" about the actual throughput rates in full-duplex mode: the Arduino can be programmed to simply 'echo' (write back to USB) each byte it has received from USB, as soon as possible; then, by simultaneously writing to and reading from the Arduino we can determine the time it takes for these operations to execute, and thus the actual data throughput rate, as measured on the PC. Additionally, the delay between input and output serial signals for this mode of operation on the ATMega328 will represent the lower bound for expected latency in the system (as the actions of reading a byte from serial, storing it in memory, reading it from memory and writing it back to serial can be considered a minimum (quantum) of action relevant in this context) - and thus in a sense quantify full-duplex capability.
This 'duplex loopback' test can be performed first on a level of a serial port interface - e.g., by reading and writing simultaneously to the
/dev/ttyUSB0 using standard command line tools. With confirmed operation at 200 KBps in serial mode, the same 'loopback' Arduino code can be utilized with the AudioArduino PC driver,
snd_ftdi_audard; with this, one can use high-level audio software (Audacity) to simultaneously play back an audio file, and record from the Arduino - the expectation being, obviously, to capture the exact same file which is being played back. In both these cases, the same Arduino code copies a byte - a digital value - from its serial input to its serial output; thus this can be called a "digital duplex loopback" test.
With appropriate A/D and D/A interface, the ultimate test for a soundcard hardware would be the "analog duplex loopback" test: where the audio data played back from Audacity is converted to an analog voltage signal, which is subsequently sampled by an analog input of the Arduino (which otherwise uses the usual 'soundcard' microcontroller code) - where the success of the test is measured by the ammount of distortion of the captured loopback audio signal. Analog loopback is further discussed in AudioArduino-AnalogBoard, because it cannot be performed on just an Arduino - since the domains of input signal (voltage) and output signal (PWM voltage) are different.
Note that "16-bit is ... the minimum quality that Audacity uses internally" (Audacity Reference); and as such it is incapable of direct 8-bit playback (unlike, say,
snd_ftdi_audard also implements a playback interface, which can accept 16-bit stereo data from audacity, and convert it to 8-bit data, before sending it to the Arduino via USB.
Serial duplex loopback test - determining actual throughput rate
Complete details about this pursuit are documented on the thread "Arduino Forum - Measuring Arduino's FT232 throughput rate ?". Some of the more important points are:
- The Arduino microcontroller code that implements the 'digital duplex loopback' operation (writing back the received byte) is fiven in Reply #6.
- Both the ATMega328 and the FT232 are capable of full-duplex transfer (i.e., can simultaneously send are receive data over the TTL RS-232 serial interface).
- Arduino interrupts must be turned off to demonstrate error-free duplex transmission.
- For 2 Mbps setting, the actual achievable rate, for both sending and receiving, is about 98% of 200 KBps.
- Duplex cannot be tested using standard command-line writing (e.g.
cat somefile.txt > /dev/ttyUSB0) and reading (e.g.
cat /dev/ttyUSB0) methods for interface with a serial port; because there isn't a way to start both processes at the same time, and also
catsimply writes as soon as it can to the serial port, which usually crashes the serial throttling functions of the driver. Hence, this project supplied a program
writeread_bonus.c, which can demonstrate duplex operation of serial port using threads (see Analysis Tools).
- The latency of Arduino loopback code between received and echoed byte, on the serial line connecting the ATmega328 and the FT232, is around 6.940 μs (which is cca 30% of the 22.7 μs sample period for 44.1kHz).
- There is a significant jitter in the serial signal output by the ATMega328, compared to the one output by the FT232; the jitter can span some 0.26 μs (which is cca 52% of the 0.5 μs bit period for 2 Mbps)
- The rate in either direction on the TTL RS-232 serial line (betw. ATMega328 and the FT232) can be said to be sustained (i.e. the next byte immediately follows the previous one) - although sometimes there can be gaps (which seemingly have no influence on transmission errors).
- The inherent difference between clocks of FT232 and ATMega328, and the asynchronous nature of the RS-232 communication between the two, points that it will be more difficult to obtain similar performance at even higher possible communication rates (say 2.5 Mbps).
Audio duplex loopback test - Audacity
Once the hardware is demonstrated to be capable of error-free digital duplex transmission at rates of 98% of 200 KBps in a serial port, command-line context - the very same 'digital duplex loopback' code can be used to test the duplex performance of the PC audio driver, by using Audacity as high-level audio software to initiate simultaneous (full-duplex) playback and recording.
Due to the process of conversion between the Audacity internal 16-bit stereo format and mono 8-bit format otherwise present "on wire", it cannot be expected (due to rounding errors) that the capture of the loopback audio data will be the same as the original playback file; even if the original file was originally 8-bit - and this, in spite of the fact the entire loopback chain is digital, and indeed capable of error-free transmission (as demonstrated by serial loopback test)! Look in the videos for a demonstration of the audio software, digital duplex loopback test.
ALSA driver structs
Among the more difficult issues in driver programming, is determining the exact relationship between all the C structs involved, and finally determine the location of the
dma_area pointer of a given ALSA substream - which is needed to actually transfer data to and from the audio driver. For that purpose, a simplified structure map of this driver has been plotted, included below.
(Include structure map image here)
Analog Playback and Capture
As mentioned, for analog input in AudioArduino, the onboard A/D facility of the ATMega328 is used. Note that the Arduino features 6 analog input pins, which are first brought to a multiplexer on board the ATMega328; and the output of the multiplexer is sampled by the one and only A/D converter present on the ATMega328. Thus, implementing multi-channel input requires that the time needed to switch the multiplexer to a new input, and the time to perform the sampling, need to be taken into account; AudioArduino avoids dealing with the multiplexer switching, by setting it to route a mono (single) channel only. The A/D converter accepts voltage input in the range of 0V to 5V, which means typical devices used with analog input in Arduino (e.g., potentiometers) can be sampled at audio rate using high-level audio software - without any special handling of DC signals (which was otherwise the motivation behind ExtendingISASoundcard). However, this means that the usual 'line' voltage standard for analog audio, covering -2V to 2V needs to be 'preprocessed' ('scaled', or rather - 'shifted') before it can be captured by the Arduino's input in full.
In terms of analog output, as stated in "Sampling rate, resolution and number of channels", a timer/counter OC unit on board the Arduino is used to generate a 62.5 kHz PWM signal, which then reproduces the incoming 44.1 kHz audio stream (played back by PC audio software). While in basic terms, we could consider this to be an oversampling of the original 44.1 kHz signal (at 'PCM rate') with a 62.5 kHz signal (at 'PWM rate') (and thus not a cause for degradation of signal quality) - in reality, there are deficiencies, which become obvious when we try to reproduce a HF sawtooth signal with a period of 5 samples (and hence a frequency of 8820 Hz, for a sampling rate of 44.1 kHz) - shown on the image below.
The top trace represents the voltage of the PWM reproduction of this sawtooth signal; the 62.6 kHz period of the PWM signal is indicated (the spikes are due to the presence of headphone speaker as load at the PWM output pin). The bottom trace shows the pulses used to indicate the operation of the 44.1 kHz interrupt, that sets the 'PCM rate'. Obviously, the 44.1 kHz pulses do not coincide with the start of 62.5 kHz PWM periods - and yet, it is at those moments that the next value of the PWM duty cycle is set. Since the PWM signal cannot change its 'value' (carried by its duty cycle) instantly when the new value is set (otherwise, its period would change, and it would no longer be a PWM signal), it has to wait until the next PWM period to effectuate the value; in addition, sometimes there is no update of the analog value during a PWM period - in which case, the timer/counter simply repeats the last set value. Hence, the original 5-PCM-sample-long period sawtooth signal, is now reproduced as a signal with a longer period.
Note that in both input and output cases, the A/D converter and the timer/counter need to be set by specific ATMega commands to work at specific audio-rate frequencies; this is handled by the microcontroller
A slightly deeper examination of AudioArduino's possibilities for analog input/output, in respect to standard expectations from an off-the-shelf soundcard - as well as a closer look on the merits of PWM as output analog audio carrier - is taken up in AudioArduino-AnalogBoard.
Development and Analysis Tools
In a project spanning several domains, there is always the issue of which tools to use for development and analysis - especially in context of open source software. Besides the use of "third-party" tools, this project also developed and used "in-house" custom code - see the outline below.
Arduino - ATMega328
- Arduino IDE uses the avr-gcc to compile source code, and generate binary elf and hex files
- Use of simple emulators like emulino (which emulate .elf/.hex files) does not really help, since it is not easy to simulate the serial data input/output - and the behaviour of A/D and timer/counter circuits
- Worst-case execution time (WCET) analysis can be performed on the .elf by using the Bound-T software; which while not open source, has a limited freeware binary for Linux, which can be used to do a rough analysis on the .pde code output. Note that Bound-T has limited support for ATMega, and the ATMega328 is not among supported chips. The results of the analysis are a 'flow-graph' diagram, which includes clock tick usage (timing) of indivudal assembler commands.
avr-objdump -S file.cpp.elfcan be used to show a listing of C source code, mixed with the compiler assempler output
- avr-cycles can be used, to add clock timing information to output of
avr-objdump; this project provides a modified version of avr-cycles, which builds on Ubuntu Lucid (which can then be used for WCET analysis, and possibly for generation of flow-graphs)
- For measuring the actual Arduino throughput rate as seen on the PC, this project provides the writeread_bonus.c Linux program, that can start simultaneous reading and writing to a serial port in separate threads.
Digital sampling/storage oscilloscope (DSO)
- Oscilloscope is an essential tool for electronic troubleshooting
- However, for (additionally) decoding of digital signals - here only the TTL RS-232 between the ATMega328 and the FT232 is considered - a DSO is needed, which can capture voltage traces as data and send them to a PC for further analysis
- The bandwidth of the scope is important - a 2 Mbps RS-232 signal with a signal transition at every period is equivalent to a 1 MHz square wave; a square wave has infinite spectrum containing a fundamental and odd harmonics. If the bandwidth must include at least the second harmonic (5*fo) for accurate sampling of a square wave - that means the scope must have a bandwidth of at least 5 MHz to properly represent a 2 Mbps (1 MHz square) signal.
- Here Agilent 54621A is used, with analog bandwidth of 60 MHz; sampled oscilloscope traces can be downloaded as ASCII numeric data to a PC using the open-source agiload software for Linux.
Decoding of RS-232 oscilloscope captures
- This project has generated an example
pythonmatplotlib script, called mwfview-ser.py - which can:
- Additionally, examples of statistical analysis are also provided, which can be used to identify locations of 'gaps' between serially transmitted bytes.
ALSA PC driver
- All of the tools mentioned in Minivosc (under Debugging) are applicable to the AudioArduino ALSA driver as well.
Additionally, if a crash log is available, the
crashprogram can be used to inspect a backtrace:
$ apport-unpack /var/crash/linux-image-2.6.32-25-generic.0.crash /tmp/unpacked $ crash /path/to/vmlinux-2.6.32-25-generic /tmp/unpacked/VmCore crash> mod # list modules crash> mod -S # to reload all; for individual: mod -s snd_ftdi_audard snd_ftdi_audard.ko crash> mod crash> bt -a -l # print backtrace
- Also, instead of putting debug statements from the driver in the system log (risking the possibility to 'choke' it) - SystemTap can be used; useful for generating different kinds of profiling information (since the actual log statements are determined by SystemTap scripts) without the need to recompile the driver.
Note that in order to debug the driver in a virtual machine (with
gdb; see Debugging), the VM must support 'forwarding' of the actual USB packets on the physical machine to the VM. Under Ubuntu, the only possible option is to use the proprietary (although still freeware) version of Oracle VM VirtualBox, which supports the adding of "USB Filters".