Sunday, January 19, 2014

Remote 7" Touchscreen for the Raspberry Pi

There is already a large number of touchscreen solutions for the Raspberry Pi. I present yet another one. The special feature of this solution is that you just need a single HDMI cable to connect the touchscreen to the Raspberry Pi. There is no need for an additional USB cable or any proprietary solution for transmitting the touch information. Therefore, with a long HDMI cable it is easy to place the touchscreen and the Raspberry Pi at different places (e.g. at the wall and inside a cupboard).


The touchscreen itself is the popular 7" AT070TN9X (AT070TN90 or AT070TN92). You can purchase it at your preferred china auctioneer or you invest a litte more money and buy it as A13-LCD7-TS at popular electronic distributors. The second option provides you the advantage of an adapter board by Olimex with convenient pin headers (instead of a flexible flat cable (FFC)) and some voltage regulators for providing the various voltages needed for driving a TFT.

The second thing you need is a PCB that converts from the HDMI signal to the parallel interface of the TFT and provides the circuitry for the touch functionality. It is not available for purchase, but feel free to do whatever you want with the material provided below under the terms of the Creative Commons Attribution 4.0 International License.


The above picture presents the components on the PCB. A LM2675M switching regulator on the right side provides 3.3 V for driving the display as well as the components on the board.


The touchscreen is connected via a large pin header that matches the one on the Olimex board. As already mentioned, the TFT display is driven by a digital parallel interface. It consists of 8 bit per color channel (red, green and blue). Furthermore, it contains a clock signal, a HSYNC and VSYNC (for indicating line and frame starts) and a DE line for indicating blank times. The remaining signals on the header are for power supply, enable display (EN), backlight (BKL), orientation (LR, UD) and touchscreen (TP*).


For converting the HDMI signal to the parallel digital interface, a TFP401A by Texas Instruments is used. A predecessor (the TFP101A) was previously used by Till Harbaum to connect a TFT to the BeagleBoard. The TFP401A is available in a TQFP100 package. Hand soldering is therefore doable with some practice.


Most of the pins are connected to the pin header, while the other major part is connected to the HDMI connector that is shown below. Besides the video signal itself, the HDMI standard provides a I2C interface that is of interest for the remaining parts. As explained in a previous blog post, this is mainly used for transmitting information about the display. For this purpose, one can connect a EEPROM to this interface as shown in the picture below. For the Raspberry Pi, this is not needed and might even cause troubles (as I have experienced...).


Apart from that, other I2C devices can be connected to the Raspberry Pi via this interface, too. It has 5 V signal levels. In order to connect 3.3 V devices, a level shifting logic as explained some time ago is needed.


Two devices are connected to the left side. The first one is a MCP4726 DAC for providing the reference voltage for the backlight. With this device it is possible to set the backlight intensity of the TFT with a simple command by the Raspberry Pi.


The second device is a AD7879-1W touchscreen controller by Analog Devices. Since it is a resistive touchscreen, the controller is responsible for measuring the resistance between the screen layers. This measurement is subject to noise resulting in imprecise measurements. The advantage of the AD7879-1W (compared to a previously tested TSC2003) is the integrated combined median- and mean-filtering to reduce this noise. Furthermore, it is one of the few remaining touchscreen controllers than can be soldered by hand. Most of the modern ICs are provided in QFN packages. This trend has advantages for the compactness of end-user devices, but induces problems for prototyping and hobby projects (unless until someone explains to me how to solder them by hand).


The following pictures show the final PCB as drawing and in real (unpopulated).


Last but not least it is possible to use prototyping boards instead of a dedicated PCB, but I would not suggest that ;-)


Saturday, November 9, 2013

I²C over HDMI

The Raspberry Pi contains several I²C interfaces for accessing peripherals such as sensors, DA-converters or EEPROMs. Two interfaces are accessible via P1 and P5. A third interface is integrated in the HDMI interface. It is disguised as Display Data Channel (DDC), but is nothing than a conventional I²C interface. The integration into the HDMI interface provides the possibility to transmit video, audio and control information via a single cable. Possible applications are reading out the capabilities of your monitor via EDID or controlling brightness and contrast.

In particular, it is interesting if you are planning to build a display for the Raspberry Pi. In this case it is very helpful to have an additional data channel for example to control a backlight circuit. Yet, it is more difficult to use than the other I²C interfaces of the Raspberry Pi and some precautions must be taken:

WARNING
  • It might break your monitor irreparably: Via DDC it might be possible to set a monitor in an invalid state with no hope of recovery.
  • It might interfere with the GPU: The GPU of the Raspberry Pi claims full control over the DDC interface. Accessing it from the CPU might cause problems.
  • In contrast to the other I²C interfaces, it has a 5 V high level. You might want to use level shifting.

Physical Access

Since this interface is accessible via the HDMI connector, you can not just use jumper wires to access it. If the device you want to connect to, has an HDMI connector (e.g. if you want to control a monitor via DDC) you can skip this section. The same applies if it has a DVI connector, because a DVI-HDMI adapter forwards the according lines.

Building an own device is more complicated, because most HDMI connectors have 0.5 mm pitch SMD pins. For testing purposes it is more convenient to build an adapter from a HDMI cable. Get a short, cheap HDMI cable, cut it through and remove jacket and shield.


Now you have to solve a little riddle to match the pins to the correct wires. Apparently you can not rely on the colors. At least for my assignment I could not find any matching color scheme on the Internet. Therefore, I used a multimeter to identify which pin is connected to which wire. Have a look at Wikipedia to get the pin out. It helps to know, that the TMDS channels (Data 1-3, Clock) are seperately shielded. I soldered the wires to a pin header and can now access the HDMI interface via jumper cables. Luckily, there is also a 5 V line available that can be used to drive your circuit. Although, it must not consume much current (below 50 mA).



Kernel Patching

Because of these mentioned drawbacks, the current kernel does not support this I²C interface. You have to apply this patch to the rpi-3.10.y branch:

mkdir linux
cd linux
git init
git fetch git://github.com/raspberrypi/linux.git \
   rpi-3.10.y:refs/remotes/origin/rpi-3.10.y
git checkout rpi-3.10.y
wget https://s3.amazonaws.com/de.koalo.stuff/\
0001-Add-support-for-BSC2.patch

patch -p1 < 0001-Add-support-for-BSC2.patch

Then compile and copy it to the Raspberry Pi as described at elinux.org. You can now access this I²C interface as bus 2. The following should give you an overview about the I²C modules connected via HDMI.

sudo modprobe i2c-dev
sudo i2cdetect 2

Monday, November 4, 2013

I²C Level Shifting


A common problem with I²C is level shifting. For example the Raspberry Pi has a 3.3 V I²C interface. Connecting a 5 V I²C interface will break the Raspberry Pi. There are many possibilities, including explicit level shifting ICs. In this post I will describe a very elegant way that works quite nice and only uses two N-channel MOSFET transistors. Those should be part of every electronics toolbox. I use 2N7002 transistors, but many others should do the job, too. The source of this is an application note of NXP.

Easy I²C level shifting

The connection is the same for SDA and SCL line as depicted above. All SDA and SCL pins of 3.3 V devices should be connected to the source of the respective MOSFET while the pins of 5 V devices are connected to the drain. The gates should be connected to 3.3 V. The resistors are the I²C pull-up resistors that should be used anyway. You might want to experiment with other values to get more speed or better reliability. For me those values work quite good and enable a reliable connection of I²C devices at different voltages.

Theoretical Background

I²C is based on open collector outputs. Pull-up resistors to the positive supply make the default state high. Each IC connected to the bus can pull down the line to low. When no device accesses the I²C bus, the voltage is pulled up to the respective high voltage. This is 3.3 V on the left side and 5 V on the right side. Therefore, gate and source are on the same voltage level. No current can flow between drain and source, because the MOSFET channel is not conducting. Therefore, no damage will happen.

This changes when a 3.3 V device pulls down the line. The voltage between gate and source (Vgs) rises to 3.3 V. Now current flows from drain to source until the drain is pulled down, too. Both sides are now at low level as intended by the 3.3 V device. When a 5 V device wants to pull down the line, the process is slightly different. Since a MOSFET contains an implicit body diode, current starts flowing as soon as the source voltage is higher than the drain voltage. Vgs rises and the voltage is further pulled down until both sides are at low level.


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.