Showing posts with label raspberry pi. Show all posts
Showing posts with label raspberry pi. Show all posts

Monday, March 31, 2014

Homebrew USB Sound Card

This project began out of necessity as I was working on a Raspberry Pi project a that required low latency audio output. However I was having major issues with latency from the the Pi's sound card, observing at least 20-30ms of latency. This would not do, I needed real time responsiveness, less than 5ms. With the help of CNLohr I began to try and build my own low latency USB sound card.

Here is the result...

CNLohr designed the PCB and I programmed the firmware. The sound card uses a MAX5556 digital to analog converter (DAC), a Mega8u2, and an Attiny44. I made a few modifications to the PCB to make it processing audio data more efficient and to fix a design flaw.

An attiny44 is used to drive the MAX5556 DAC using the 3 wire I²S interface. The attiny is running at 24.5Mhz which, with some clever use of the microprocessor, can feed the DAC with 48khz 16bit stereo data. I use the tiny's hardware timer to toggle the PA7 pin every 256 clock ticks, which drives the DAC's left/right clock. An assembly loop is used to toggle the DAC's serial clock and sdata pin. This loop is synchronized with the left/right clock (PA7). An assembly interrupt is used to copy data out of the attiny's SPI registers into memory. In an effort to minimize the time the SPI interrupt takes, I had to minimize the the amount of work done. Within the assembly, I carefully selected registers so that I could avoid having to push or pop registers in the event of an SPI interrupt.

The AT Mega8u2 is used to communicate with the USB host and the AT tiny. The Mega8u32 is clocked at 16Mhz, a limitation imposed by USB. Audio is streamed into a circular buffer from the USB host. The circular buffer is emptied over the SPI interface to the AT Tiny microprocessor. Assembly is used to send the data over SPI to make use of the avr's store and increment assembly instruction, saving many clock cycles. The Mega8u32 and the AT tiny are kept in sync by using an interrupt on the PC7 pin. This pin is, like the DAC's left/right clock, connected to the tiny's PA7 pin. A rising edge on the PC7 pin signals that it is time to begins ending new data to the at tiny.

A quickly hacked together topside program sends raw stereo data to the sound card. The internal buffer of the sound card is about 64 samples per channel, about 1.3ms. USB double buffering provides an additional ~.6ms of buffer. The sound card works pretty well from a PC. Occasionally the sound card will experience an inaudible buffer underflow. A red LED will flicker on the sound card when this is detected. Using this sound card on the Raspberry Pi is a completely different story. The Pi isn't capable of servicing the USB fast enough to to keep up. Buffer underflow occurs constantly, completely useless.

The source code is available at https://github.com/axlecrusher/AvrProjects/tree/master/soundCard

Slightly outdated schematics can be found here. https://svn.cnlohr.net/pubsvn/electrical/avr_soundcard/ It is lacking the modifications visible in my photos.

Edit:Added note about double buffered USB.

Friday, January 25, 2013

Install djbdns on Raspberry Pi

Install djbdns on Raspberry Pi

djbdns is a small, fast, and secure DNS server. Perfect for low resource systems. I also find it easier to configure than BIND (once you understand how).
I start with a raspbian image from http://www.raspberrypi.org/downloads

Install some packages that D. J. Bernstein says that we need.
apt-get install ucspi-tcp apt-get install daemontools

Don't install tinydns. It includes a pop3 server.
Install djbdns following http://cr.yp.to/djbdns/install.html

Create some users and groups that we will need for executing the dnscache and multilog.
useradd svclog useradd dnscache

Create the /etc/dnscache folder structure
dnscache-conf dnscache svclog /etc/dnscache

Setup /service directory, svscan looks at this directory to see which services to run.
mkdir /service ln -s /etc/dnscache /service/dnscache

Add the following to /etc/rc.local so that the supervised services start on boot.
/usr/bin/svscanboot &

svscanboot also needs the following link to function correctly.
ln -s /service/ /etc/service

Optional Things

Update /etc/dnscache/env/IP to contain the ip address to listen on. Also create a file entries in /etc/dnscache/root/ip to specify the networks that the dns server should reply to.

Edit /etc/dnscache/log/run adding s52428800 before ./main to set the log size to 50MB.
It should look something like
exec setuidgid svclog multilog t s52428800 ./main

You should update the root server list
wget http://www.internic.net/zones/named.root -O - | grep ' A ' | tr -s ' ' | cut -d ' ' -f4 > /etc/dnscache/root/servers/\@

Update /etc/resolv.conf to use your new dns server.

Change UDP packet size to accommodate big UDP packets. Many DNS servers require large UDP packets or djbdnscache will fail with drop # input / output errors. https://dev.openwrt.org/browser/packages/net/djbdns/patches/060-dnscache-big-udp-packets.patch

Resources

http://cr.yp.to/djbdns/dnscache.html
http://cr.yp.to/daemontools/multilog.html
http://cr.yp.to/daemontools/supervise.html
http://tinydns.org/