Raspberry Pi Espresso CPU… from scratch

Having corrupted my SD card again (deep sigh), it’s time for a complete rebuild again. I thought this would be an opportunity to update these notes.

The first task is to download an image and write to an SD card. Previously I downloaded Raspbian (Kernel 3.12, Release 2014-12-24) from raspberrypi.org. I used Win32DiskImager to write this to an 8GB SD card. This time I used the Noobs image and selected Raspian OS (although, having done this, I would not recommend Noobs because the two stage boot makes things rather more difficult to set up. If you are starting from scratch, I would recommend using the vanilla Raspbian image as I did originally).

I’m using a Raspberry Pi Model A, 2nd revision board. After hooking it up to a TV with HDMI, I connected a USB keyboard and wireless USB dongle to the single USB port on the Pi, and powered on.

First time I did this, the Pi booted up with a configuration menu. I expanded the file-system to fill the SD card, over-clocked to 900Mhz, changed the root password and host-name. More recently, using Noobs, I was able to do this same configuration under X windows.

The Pi was set to boot to CLI, without automatic log on, both SPI and I2C were enabled in the configuration.

The next step is to configure wireless networking. I’m using an Edimax USB adapter (EW-7811Un) apparently based on Realtek RTL8188CUS chipset.

The contents of /etc/network/interfaces were left with the Raspbian defaults. However, the settings in /etc/wpa_supplicant/wpa_supplicant.conf needed to be changed to suit my own network, as shown below:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    scan_ssid=1
    ssid="yourssid"
    psk=2a1f2e3c8d7f5e4a35c6f4e3d...
    proto=WPA
    key_mgmt=WPA-PSK
    pairwise=CCMP
    auth_alg=OPEN
}

The PSK above is generated by using wpa_passphrase as follows:

wpa_passphrase <ssid> <password>

Since my SSID is hidden, I had to add the scan_ssid setting to make it find the network. Without this, it gives loads of errors about DHCP discover failing.

Another problem I have had a few times is that if you make small typo in the wpa_supplicant file, it will fail to start with error 1.

Having changed the settings, I restarted the wireless network as follows:

sudo ifdown wlan0
sudo ifup wlan0

This got it up and running on the network, and then I was able to SSH into the Pi.

Next I decided to try an update as follows:

sudo apt-get update
sudo apt-get upgrade

As a quick check at this stage:

uname -r
4.1.13+

Configuring FBTFT for the HY28.

Next, I decided to install the FBTFT drivers for the LCD display. These are apparently now included in the Raspberry Pi Foundation kernel, so let’s try updating that:

sudo rpi-update
sudo reboot

Check the version:

uname -r
4.1.15+

Having connected the HY28A TFT LCD to the Pi via the SPI bus, I tried loading the drivers (using the same settings I had backed up from my previous working installation):

# load the driver: the panel goes black
sudo modprobe fbtft_device name=hy28a rotate=270 gpios=reset:25 fps=20
# map console to LCD for testing
con2fbmap 1 1

Having done this, the console appeared on the LCD, confirming that it works. I then made it permanent by loading the module from /etc/modules-load.d/fbtft.conf

spi-bcm2835
fbtft_device

The options are set in /etc/modprobe.d/fbtft.conf

options fbtft_device name=hy28a rotate=270 gpios=reset:25 txbuflen=32768 fps=20

For reference only, the touchpanel driver settings used to be the following in /etc/modules (and haven’t yet been corrected for systemd as I don’t use them currently):

# Touchpanel driver
ads7846_device pressure_max=255 y_min=190 y_max=3850 gpio_pendown=17 x_max=3850 x_min=230 x_plate_ohms=60 ads7846

To make the console appear during boot, I added the following to the end of /boot/cmdline.txt. This font seemed the best of the few that I tried.

fbcon=map:10 fbcon=font:Acorn8x8

After about 30 minutes, the LCD screen goes blank. To disable this, I changed the BLANK_TIME to zero in /etc/kbd/config:

# prevent screen blanking
BLANK_TIME=0

Installing the ADS1015 ADC board

For Raspbian, we first have to enable I2C by adding the following lines to /etc/modules:

# I2C drivers for ADC board
i2c-bcm2708
i2c-dev

After a reboot, I installed i2c-tools for convenience:

sudo apt-get install python-smbus
sudo apt-get install i2c-tools

Having done this, the following can be used to detect I2C devices:

sudo i2cdetect -y 1
# for older Raspberry Pi boards:
# sudo i2cdetect -y 0

For my Pi, the ADS1015 appears as address 0x48 on /dev/i2c-1. Having confirmed this, I wrote a small command-line test program to check that the ADC was working and returning voltage readings.

With my buttons wired to the ADC via a resistor ladder, this was an opportunity to check that they worked as planned. With various button combinations, I obtained the following readings:

  • No buttons = 3.30V
  • Lower button = 2.18V
  • Upper button = 1.65V
  • Both buttons = 1.31V

Problem 1 (solved?): Wireless disconnects

After using this for a while, I started having problems with the wireless going down, usually half-way through editing a file over SSH. I seem to remember having this issue before and fixing it with some changes to disable power management in the boot command-line… but couldn’t remember the details.

Based on something I read here, I decided to try adding this to /etc/network/interfaces:

wireless-power off

After some time, it became evident that this hadn’t solved the problem. I’m pretty sure it’s not the power supply, as it worked fine on this PSU for about a year until the re-install.

Anyway, in desperation I added a 100uF low ESR electrolytic between 5V and GND (can’t hurt!), and also tried re-positioning the wifi adapter to have a clear line of sight to the router.

This didn’t solve the problem either, although it did stop the Pi from rebooting when the wifi dongle is inserted (the network doesn’t come back up if you do this though..)

For my next attempt, I tried setting the USB speed down to V1 to see if that helped (better to have a slow connection than an unreliable one…)

dwc_otg.speed=1

This seemed to improve matters at first, but after extended use it still seems unreliable. The next thing I tried was this suggestion to create a configuration file at /etc/modprobe.d/8192cu.conf to disable power management:

options 8192cu rtw_power_mgnt=0 rtw_enusbss=0

For good measure, I’ve also added this to /boot/cmdline.txt (which actually seems familiar, and might be what solved this problem before):

smsc95xx.turbo_mode=N

Finally, I’ve increased the minimum reserve virtual memory in /etc/sysctl.conf as I seem to remember doing that last time:

vm.min_free_kbytes = 16384

This is really starting to become annoying now. I’ve spent more time rebooting and messing with the wireless than working on the project.

Update: this seems more stable now. I think one of the last two steps must have been the real solution!

Installing LIBSDL

I’m using the SDL 1.2 library for graphics on the TFT display, as well as the SDL TTF library for font rendering, and SDL image library. These are installed as follows:

sudo apt-get update
sudo apt-get install libsdl1.2-dev libsdl-ttf2.0-dev libsdl-image1.2-dev

Installing pigpio

Es(pi)resso used to use kernel mode drivers for the TSIC 306 Temperature Sensor and the HCSR-04 Ultrasonic Range Finder. The problem is that these needed to be rebuilt when the kernel was updated, and this isn’t easy to do on the Pi (I only managed to build these via cross-compilation from Ubuntu on a PC).

Having recently discovered the PIGPIO library, I decided to move to user mode drivers implemented with pigpio. This is obviously more convenient as it avoids the need to rebuild kernel modules and makes a self contained project.

The first step is to install pigpio as follows:

wget abyz.co.uk/rpi/pigpio/pigpio.zip
unzip pigpio.zip
cd PIGPIO
make
make install

Having done this, I rewrote the code to use PIGPIO. In the first instance, I tried using the functions directly from pigpio.h. However, I ran into all sorts of mysterious crashes at start up. After some debugging, my theory was that this might be due to the use of static variables in both pigpio and in my own code, potentially resulting in undefined order of initialisation at start up. Consequently, I rewrote the code to use the PIGPIOD daemon instead (via the pigpiod_if functions), and this works fine.

Almost all the GPIO is now moved to PIGPIOD, with the exception of the hardware PWM which has been retained for the boiler power regulation (primarily because of the very low PWM frequency used).

Check out and configure the Es(pi)resso software

Now we have the dependencies, the software needs to be checked out from Subversion:

sudo apt-get update
sudo apt-get install subversion
mkdir sandbox
cd sandbox
svn checkout https://github.com/jam3sward/espiresso.git/trunk gaggia

There is no configuration, so the software should just build like this:

make

It can be installed to /usr/local/bin as follows:

sudo make install

Every time it runs, the controller software creates log files at /var/log/gaggia. This folder must be created manually as follows:

sudo mkdir /var/log/gaggia

There is also a configuration file with the PID controller parameters and other settings. From the project directory, this is copied to /etc/gaggia.conf as follows:

sudo cp gaggia.conf /etc

There are some PNG images (used to display icons on the LCD) which need to be installed in /etc/gaggia as follows:

sudo mkdir /etc/gaggia
sudo cp images/*.png /etc/gaggia
ls /etc/gaggia

At this point, the software can be started in interactive mode by adding the -i parameter. This displays output in the console and allows the software to be stopped by pressing a key.

sudo ./gaggia start -i

Assuming this works, the LCD display should show the current temperature, water level etc.

 Problem 2 (solved): GPIO initialisation at boot time

The Raspberry Pi was initialising GPIO15 (RXD) as pull-up at power on. In early testing, this resulted in the pump being switched on when the system was powered up!

To fix this, I used the device tree pin configuration to change the GPIO pin initial state to an input with pull-down at power on. The pin is later changed to an output by the control software.

First, we check that the Raspberry Pi firmware is later than July 15th 2014:

vcgencmd version

Then we install the device tree compiler:

sudo apt-get update
sudo apt-get install device-tree-compiler

Then the device tree source file is needed. This is located in the source code tree here: gaggia/dt-blob/dt-blob.dts

Finally, the device tree source file is compiled to a binary blob, and copied to the /boot partition:

sudo dtc -I dts -O dtb -o /boot/dt-blob.bin dt-blob.dts

Note: on NOOBS this file apparently has to be on the recovery partition.

When the system is rebooted, the GPIO pin comes up as a pull-down, and the pump sits idle until the controller is ready to power it on.

Faster boot times

In an attempt to make it boot up faster and reduce writes to the SD card, I made the following changes to /boot/cmdline.txt:

  1. Removed console=tty1
  2. Added noatime nodiratime
  3. Added quiet

The current /boot/cmdline.txt looks like this:

dwc_otg.lpm_enable=0 root=/dev/mmcblk0p7 rootfstype=ext4 elevator=deadline noatime nodiratime fsck.repair=yes rootwait quiet smsc95xx.turbo_mode=N fbcon=map:10 fbcon=font:Acorn8x8

Running the controller automatically at start up

To make the software run automatically at start up, I created two scripts under /etc/init.d. One, called pigpiod is used to start the pigpio daemon. The other, called gaggia, is used to start the controller.

These are installed as follows:

# copy the executable to /usr/local/bin
sudo cp gaggia /usr/local/bin

# copy the scripts into /etc/init.d
sudo cp scripts/gaggia /etc/init.d/gaggia
sudo cp scripts/pigpiod /etc/init.d/pigpiod
sudo chmod +x /etc/init.d/gaggia
sudo chmod +x /etc/init.d/pigpiod

# install the scripts
sudo update-rc.d gaggia defaults
sudo update-rc.d pigpiod defaults

When the machine starts, the pigpiod daemon is initialised first, followed by the gaggia controller. This enables the machine to automatically start when powered on.

Button 2 on the front panel can later be used to safely shut down the Pi (by pressing for more than 2 seconds).

Another way to shut down the controller is to log in remotely, and type:

sudo /etc/init.d/gaggia stop

Furthermore, holding Button 2 as the system boots will prevent the controller from starting up. This is useful when the machine is being powered on for maintenance or development.

 Installing Samba

Installing Samba makes it possible to access the log files over the local network, and is also generally useful for transferring files. The first step is to install Samba itself:

sudo apt-get update
sudo apt-get install samba samba-common-bin

Make a backup of the original smb.conf configuration file, and edit the file:

sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.$(date +%F)
sudo nano /etc/samba/smb.conf

In my case, I commented out the [printers] section and the [print$] section, and added the following section to make the log files visible:

[logs]
comment = Logs
path = /var/log/gaggia
browseable = yes
only guest = yes
read only = yes
public = yes

Finally, the configuration can be tested, and the Samba service restarted as follows:

testparm
sudo service smbd restart
sudo service nmbd restart

Installing Samba has the added bonus of making it possible to SSH to the Pi using the host name, rather than having to use the IP address.

Problem 3 (solved?): SD card corruption

Having got everything working really well… it just stopped booting. Connecting the Pi to my TV with HDMI, I found that it was failing early in the boot process with a kernel panic, complaining over a missing file-system. Turns out the SD card was corrupted. No idea how that happened.

After some initial panic, I managed to repair the SD card from a PC running Ubuntu using fsck.ext4 something like this:

NOTE: mmcblk0p2 will probably need to be changed on your PC
sudo fsck.ext4 -v /dev/mmcblk0p2

After rebooting the Pi, fsck ran again. It actually seemed to crash fsck itself and streamed out pages and pages of junk on-screen. I just left it to see what happened and it eventually came up and started working again.

I’m now thinking of making the SD card read only and moving the file system to USB to improve reliability.

Problem 4 (solved?): Display reliability

Although the display has been running fine for several months, I recently found it started behaving erratically. The first issue was that it would sometimes randomly shift the display vertically (i.e. as if it was scrolled, with wrap around). Eventually, I found that I just got a white screen at boot.

Having eliminated the obvious things like checking the settings in /etc/modules and the wiring, I decided to try reducing the speed from 32MHz to 16MHz, which seemed to cure the white screen:

fbtft_device name=hy28a rotate=270 gpios=reset:25 speed=16000000 fps=20

Since the display was working fine at 32MHz for a long time, I can only conclude that this might be due to poor contact in the connectors or wiring (I’ve removed and reconnected the headers many times), or it could be related to FBTFT competing with PIGPIO, which is running a lot of DMA and using 9% CPU. Either way, I’ll see how well the display performs at 16MHz, in the absence of a better solution.

Disable swapfile

How to disable the swap file:

sudo swapoff --all
sudo apt-get remove dphys-swapfile

Installing Busybox syslogd

I decided to install Busybox syslogd (which logs to a circular buffer), hopefully reducing SD card activity:

sudo apt-get install busybox-syslogd
sudo dpkg --purge rsyslog
logread

5 thoughts on “Raspberry Pi Espresso CPU… from scratch”

  1. Hi!
    I have a raspberry pi application requiring determinate state of the GPIO at boot. I saw your dt-blob.dts, but I´m not sure if I need all the code, because I only need to change behavior of 2 pins. Could you maybe help me customize a .dts?
    PS: Sorry that I write this here, but I didn´t know how to contact you.

  2. There are some 1.2mpa flow sensors on amazon uk. If correct that’s 12bar so could be put after the pump. Some are on prime. 0.15L/min and others.

    I have a Sage machine where the meter is on the feed from the water tank. The opv output messes it up if it opens. Could try adding the T. Assume that goes between the meter and the pump but scratch my head a little on how well that will work.

    Thanks for the ideas.

Leave a Reply

Your email address will not be published. Required fields are marked *