The Sweeney Brewery v3 has lots of electrical controls. I have six 2-way electric ball valves – three for tun control and three for gas control, and two 3-way valves for various fluid routing processes. I also have a new Omega CN7500 (more on that later), and the system pump.
Controlling everything, I have an RPi v2. The first problem was how to control all of the devices. the RPi offers support for multiple communication protocols including one-wire, RS232, RS485, and lots of others. After flirting with one-wire, I settled on RS485 for several reasons. First, the Omega could communicate with either RS232 or RS485. I had to design the controllers for the electric ball valves from scratch, so that wasn’t a limiting factor. RS485 can also support up to 32 devices per communications port. Also, RS485 can communicate over long distances. These all added up to a design decision to use RS485.
There’s lots of information on using RS485 with RPi – most of it poorly written, erroneous, or just plain wrong. I went down the road of trying to get the RPi to control RS485 directly but soon gave that up because of voltage conversions. Then I found a neat little RPi shield that takes care of the voltage shifting for you. This was the solution that would allow me to control both the Omega PID and an array of relays that could control the mechanical controls.
And so I set out to configure the RPi to communicate to the serial devices. This was NOT easy. I installed a minimal Raspbian image (September 2016, Kernel 4.4) and updated all packages. I setup SSH and a USB wireless dongle to communicate with my house network so I could work on the RPi headless. I then added the following additional packages using apt-get:
This package should be installed with pip:
- minimalmodbus (has a custom driver for the Omega CN7500!!)
The setup instructions for the LinkSprite shield are old (2013) and inaccurate. They detail the following tasks which have to be modified on the new systemd enabled Raspbian image.
- Install library dependencies (detailed above)
- Disable use of the serial port as a TTY. Use raspi-config to do this. Run
sudo raspi-configand check if it has the option
serial. If it has, set it to disabled and you’re done.
- Set the serial GPIO flags to ALT0:
gpio readall gpio mode 15 ALT0; gpio mode 16 ALT0 gpio readall
You should now see pins 15 and 16 set to ALT0.
- Disable the login messages on the serial port. This is tricky because the instructions assume an old version of unix that uses SystemV (i.e., edit /etc/inittab). The newest version of Raspbian uses systemd, which doesn’t have /etc/inittab. The correct way to do this under systemd is to run:
sudo systemctl mask serial-getty@ttyAMA0.service
After I took these steps, I was able to communicate to the Omega controller via a simple python script that extended the custom Omega CN7500 driver for python. Here’s the simple script which returns the current process temp from the controller:
#!/usr/bin/env python import omegacn7500 instrument = omegacn7500.OmegaCN7500('/dev/ttyAMA0', 2) # port name, slave address print instrument.get_pv() # print temperature
And so, I made my first successful RS485 communication. More to follow.
Well, it turns out that the steps to enable the RS485 on the RPi3 are different. I found an article that deals with much of the subtlety of this. Because of the addition of bluetooth on the RPi3, /dev/ttyAMA0 is reserved for that, and so the procedure is slightly different. In the following steps, we will move bluetooth from the high-performance /dev/ttyAMA0 interface to the lower performing /dev/ttyS0.
Raspberry Pi 3’s and 4’s are great little beasts, and add Bluetooth, yay! However, in order to use the Bluetooth correctly the /dev/ttyAMA0 has been “stolen” from the GPIO header and an inferior second one has been substituted in it’s place. No-one will ever know! Unfortunately /dev/ttyAMA0 was a hardware serial port (uart) and high performance (hence it was nabbed for the Bluetooth) and the second port is partly software and a bit flaky. Many people’s applications got broken.
The second serial port you will see referred to as the “mini uart” and lives at /dev/ttyS0. It also calculates it’s bit timing’s from the CPU cores frequency and if the CPU is under heavy load it can corrupt the serial communications. Not good.
In order to work around this, many people “fix” the CPU core frequency so that the serial port is stable. This comes at a slight loss in performance (though normally not noticeable). I’ll describe how you do this in the next section.
To summarize, the default ports on a Raspberry Pi 3 / 4 and be crystal clear:
/dev/ttyAMA0 -> Bluetooth
/dev/ttyS0 -> GPIO serial port.
If you stick with these as is, your Bluetooth will work as nature intended AND you can use a serial port over the GPIO (there is a way of swapping the serial ports around if you don’t want to use the Bluetooth and I’ll cover that at the end of this post).
There is yet another wrinkle in that in the latest Jessie / Stretch / Buster releases (as of August 2019) the GPIO serial port is disabled by default. In order to enable it, edit config.txt:
$ sudo nano /boot/config.txt
and add the line (at the bottom):
As of May 2016 this will also lock the cpu core frequency for you so there’s nothing else you need to do (If you aren’t convinced and you really like to belt and braces it the command is: core_freq=250 which you add to the same file as well).
Reboot for the changes to take effect.
This should get you good serial communications for most uses.
On the Raspberry Pi 3 the second serial port is called /dev/ttyS0 and is by default mapped to the GPIO pins 14 and 15. So immediately, if you have code that references /dev/ttyAMA0 you’re going to have problems and things aren’t going to work.
You could go through your code and replace ttyAMA0 with ttyS0 and that should work. However, if you find yourself use the same SD card on a Raspberry Pi other than a rpi3 your code won’t work again.
In order to try and get around this the Foundation have introduced a serial port alias (as of May 2016 – 2016-05-10). Thus you have serial ports: serial0 and serial1 (rpi3). The Raspberry Pi kernel sorts out where these point to depending on which Raspberry Pi you are on. Thus on a Raspberry Pi 3 / 4 serial0 will point to GPIO pins 14 and 15 and use the “mini-uart” aka /dev/ttyS0. On other Raspberry Pi’s it will point to the hardware UART and /dev/ttyAMA0.
To find out where it is pointing you can use the command:
$ ls -l /dev | grep serial
So where possible refer to the serial port via it’s alias of “serial0” and your code should work on both Raspberry Pi 3 / 4’s and other Raspberry Pi’s.
Disabling the Console
If you are using the serial port for anything other than the console you need to disable it. This will be slightly different depending on whether you are running a Raspberry Pi 3 / 4 or not.
For non Raspberry Pi 3 / 4 machines, remember it’s /dev/ttyAMA0 that is linked to the getty (console) service. So you need to perform this command from a terminal window:
$ sudo systemctl stop serial-getty@ttyAMA0.service $ sudo systemctl disable serial-getty@ttyAMA0.service
The “disable” will stop it loading in the future.
For Raspberry Pi 3’s the command is similar but referencing /dev/ttyS0:
$ sudo systemctl stop serial-getty@ttyS0.service $ sudo systemctl disable serial-getty@ttyS0.service
You also need to remove the console from the cmdline.txt. If you edit this with:
$ sudo nano /boot/cmdline.txt
you will see something like:
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes root wait
remove the line: console=serial0,115200 and save and reboot for changes to take effect.
Swapping the Serial Ports on Raspberry Pi 3 / 4
What if you don’t want to use the Bluetooth and you want that high performance /dev/ttyAMA0 back on the GPIO? Well you can do this and the way you do this is via a device overlay called “pi3-miniuart-bt” i.e. use the mini-uart (/dev/ttyS0) for Bluetooth (you may get some loss of performance on your Bluetooth though).
You can also just disable the Bluetooth all together by using another overlay “pi3-disable-bt”. In both cases if you can find out more of what they do here: /boot/overlays/README
To use add the following line to the /boot/config.txt
$ sudo nano /boot/config.txt
Save and reboot for changes to take effect.
You can check that it has worked by:
$ ls -l /dev
and you’ll see something like this: