Monday, May 13, 2013

I²S Audio Support for Raspberry Pi

You might know, that the audio capabilities of the Raspberry Pi are not very sophisticated. There is no special audio hardware, because this would have risen the price of the Raspberry Pi. Therefore, there is only audio output via PWM and no audio input. Fortunately, the Revision 2 Raspberry Pi features I²S via an additional GPIO port.


After soldering a 2x4 pin header to P5, you have access to this digital audio interface. Some have proposed to solder it slanted. I prefer upright from top. This indeed produces problems with ribbon cables for the conventional GPIO header, but maintains the possibility for audio extension boards using both headers. Using a stacking header could be a solution for people who rely on ribbon cables.

In order to use the I²S interface you need additional hardware as well as software. In order to help with the software part, I wrote a kernel driver that I will explain in this post.

UPDATE 2: The driver is now included in the Raspberry Pi kernel. It includes support for the RPi-DAC and the HifiBerry DAC.
 
UPDATE 1: This post gives a short introduction for people how have already some experience in kernel compilation. If you want to have step-by-step instructions including how to set up your build environment, have a look at this comprehensive blog post.

Audio Hardware

There are lots of audio codecs with I²S interface that can be used for this purpose. Currently, there is no Plug and Play hardware for the Raspberry Pi, so you have two alternatives:
  • Use a ready build board. I have successfully tested a mbed audio codec board featuring a TLV320AIC23 and a PROTO audio codec board featuring a WM8731. The biggest challenge here is to connect them to the Raspberry Pi without crosstalk. Look into the datasheets for more information and ask if questions arise. Please note, that for the mbed board you have to connect the /CS pin to 3.3 V.
  • Build your own board. Some people have successfully connected a TDA1541/TDA1541A (having a DIL package) to the Raspberry Pi. Have a look at the Raspberry Pi I²S thread.

Kernel Compilation

The kernel driver I build is based on ALSA System on Chip (ASoC). You can use the I²S interface like any other ALSA device. ASoC provides a modular structure that is great for systems like the Raspberry Pi. Therefore, there is a wide range of supported codecs that can be used by the Raspberry Pi with minimal effort.

In order to get this driver up and running you have to compile a new kernel for the Raspberry Pi. This is extensively explained at elinux.org. In the section Get the kernel source use the following command to use the updated kernel:

mkdir linux
cd linux
git init
git fetch git://github.com/koalo/linux.git \
   rpi-3.8.y-asocdev:refs/remotes/origin/rpi-3.8.y-asocdev
git checkout rpi-3.8.y-asocdev
In the section Perform the compilation you have to activate the kernel driver in the configuration. The relevant section can be found at

Device Drivers > Sound card support > Advanced Linux Sound Architecture > ALSA for SoC audio support > SoC Audio support for the Broadcom BCM2708 I²S module

You should also enable the driver for the corresponding codec (Support for...). Continue the compilation and transfer the kernel and the modules to your Raspberry Pi.

Module Loading

First activate the I²C module. I²C (not I²S!) is used to control the codecs (e.g. volume, input selection). It is not supported by all drivers (e.g. TDA1543), but it doesn't harm to activate it anyway. Open

/etc/modprobe.d/raspi-blacklist.conf

and delete blacklist i2c-bcm2708

For loading the modules at boot, you have to add the following lines to /etc/modules
snd_soc_bcm2708
snd_soc_bcm2708_i2s
bcm2708_dmaengine
Furthermore, you have to load the codec specific modules:

PROTO board with WM8731
snd_soc_wm8731
snd_soc_rpi_proto
mbed board with TLV320AIC23
snd_soc_tlv320aic23
snd_soc_rpi_mbed
TDA1541/TDA1541A
snd_soc_tda1541a
snd_soc_rpi_tda1541a
Sabre ESS9018
snd_soc_ess9018
snd_soc_rpi_ess9018

Using it

Boot your Raspberry Pi. You should now have two sound cards accessible by ALSA. Check it with aplay -l. The result should look like

**** List of PLAYBACK Hardware Devices ****
card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
Subdevices: 8/8
Subdevice #0: subdevice #0
Subdevice #1: subdevice #1
Subdevice #2: subdevice #2
Subdevice #3: subdevice #3
Subdevice #4: subdevice #4
Subdevice #5: subdevice #5
Subdevice #6: subdevice #6
Subdevice #7: subdevice #7
card 1: sndrpitda1541a [snd_rpi_tda1541a], device 0: TDA1541A HiFi tda1541a-hifi-0 []
Subdevices: 1/1
Subdevice #0: subdevice #0

Use your second sound card for example like this:

mplayer -ao alsa:device=hw=1,0 great_music.wav

You should now hear your music. Otherwise, feel free to ask.

Recording is possible with

arecord -D hw:1,0 -f DAT my_record.wav

Thanks to all the contributors and testers! You are great!!

Thursday, April 4, 2013

PCM/PWM Clock Calculator

I was tired of calculating the same thing over and over again. Therefore, I build this little tool for calculating the Raspberry Pi PCM/PWM clock settings according to BCM2835 Audio & PWM clocks.
The tool is provided without warranty of any kind. Please check the settings manually before applying them to your hardware.

Hint: In most cases you want to set the external divider to 1, but it can be handy if you want for example adjust a derived clock, e.g. the I2S frame sync. You can get appropriate divider settings (i.e. all integer dividers of the divisor) by hovering the mouse over the (combined) divisor field.

Questions or suggestion are gladly welcome!

By the way: Can anyone explain why someone would prefer MASH-2 or MASH-3 over MASH-1? They have a higher variance, but I don't see any advantage.
Edit: I found a note in the datasheet, that this is because of noise-shaping. This means you increase the overall noise that is introduced by the jitter, but push it into higher frequencies. This has the advantage of reducing the perceived noise when using it for audio applications.





Oscillator PLLD
MASH 0
MASH 1
MASH 2
MASH 3

Tuesday, March 26, 2013

Murphy's Touchscreen

It was pretty straightforward to connect the touchscreen of my display to the Raspberry Pi. After plugging in the USB cable, the touchscreen reports itself as eGalax TouchScreen:

pi@raspberrypi ~ $ lsusb
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 0eef:0001 D-WAV Scientific Co., Ltd eGalax TouchScreen


Fortunately, there is a matching driver in the Linux kernel. It only wants to be activated. There are very detailed information about kernel compilation on the web, so I will skip that. In the configuration search for eGalax and activate the option for the corresponding USB driver (TOUCHSCREEN_USB_EGALAX).

After booting the new kernel, there should be a new device in /dev/input/by-id/ named usb-0eef_0001-event-if00. You can test it's functionality with

sudo evtest /dev/input/by-id/usb-0eef_0001-event-if00

Touching the touchscreen should produce some weird output (maybe you have to install evtest first). No further configuration is necessary at this point, everything will be detected automatically. It's time for startx:


I can touch the screen and the cursor moves - not to the position where my finger is, but this is only a matter of calibration. But, before I could start with that, the cursor stopped moving... I tried to reboot the Raspberry Pi, tested it at my PC, but the cursor does no longer react. I gave up and tested it again some time later. Surprise, surprise: It works again, but not for a long time. Furthermore, the evtest does no longer produce any output. Only sometimes it reports

Event: time 1364289593.457921, -------- SYN_REPORT --------
expected 16 bytes, got -1 

This is the same result as unplugging the USB cable. It looks very much as a hardware defect. I also recognized, that the case gets quite hot. Therefore, I opened the case:


There are three cable bundles coming out of the thick cable. It seemed very likely that two of them are for the TFT and one is for the touchscreen. Typically enough, the one for the touchscreen has four wires just like USB and the touchscreen still works when I unplug the two other connectors. We can focus on the little extra board sitting on top of the main board.


At the bottom you can see the USB cable, at the top the connector to the touchscreen. It seems to be a 4-wire resistive touchscreen. As the name implies, you only have to measure the resistance between the wires and calculate the touch position from that. There is a nice application note from Atmel about that topic. I measured the resistance between two of the pins marked in the picture above using a multimeter. The resistance changes when I touch the screen. There is also a small LED that lights up when I touch the screen (while the touchscreen is connected to the computer), but this only happens when the cursor also moves.


I don't think that I can fix the controller itself, but maybe I can connect another controller to the touchscreen some day, but until then I still own Murphy's touchscreen.

Friday, March 22, 2013

8" TFT for the Raspberry Pi

A small device calls for a small screen (or no screen at all). Luckily, I remembered that I bought a 8" TFT some years ago. I never used it for it's intended use case (I don't even remember what that was...), so I found it buried under some other electronic waste.


It is an Innovatek TM-868. It has VGA, audio connectors, an USB connector for touchscreen and a Composite Video connector. VGA is useless for the Raspberry Pi, but the Composite Video connector is of interest here, because there is a corresponding connector on the Raspberry Pi. This works out of the box, but only when you don't connect the HDMI cable at the same time, because the Pi can only drive one display at a time. If you want to leave the HDMI cable connected, you can also set an appropriate setting in the configuration file:
hdmi_ignore_hotplug=1
You can also set the video mode:
sdtv_mode=2 (PAL) or 0 (NTSC)
There are many other configuration options, but in most cases it should work directly as with my setup:


Next step is to connect the touchscreen.

Saturday, March 16, 2013

My Own Raspberry Pi

My own Raspberry Pi has finally arrived. Here it is, waiting for cool projects:


After setting up the SD card as usual, it boots up into a familiar Linux shell. Until now, there is nothing special about this device - apart from the size: It it really tiny. Without the connectors, it would fit well into your wallet. To be honest: Today's mobile phones are not bigger, but it wouldn't be much fun to connect low level peripherals to them.