Command and Control II

On to lighting control. Implementing a full stage lighting control system would have been a huge project, but thanks to open source software it is rarely necessary to start anything from scratch. This was very much the case for this project, thanks to the Open Lighting Architecture project (OLA). This provides an open source set of tools for generating control signals, recording and playing them back, and interfacing them out to vast array of lighting control hardware. One of the developers (Simon Newton) even has ready-built Raspberry Pi images with the software installed and ready to go. The only missing piece was getting the DMX-512 control signals out of the Pi and into the right electrical format, via the Pi's on-board UART.

A search on the associated open-lighting discussion group indicated that various people had talked about this, been told it wouldn't work, and not actually tried it. Given that quite a lot of similar adaptors using the FTDI USB-serial chip to send DMX exist (and are supported in OLA), this didn't seem a logical position. The fact that the Raspberry Pi UART is integrated at a much lower level than a USB converter (with hardware interrupts and DMA available) should give it much better performance. So I decided to carry on and build such a system so the actual results could be measured.

Why DMX-512 is Hard

There are a number of reasons why producing direct DMX-512 output from a computer is considered hard, and software developers want to hand the task off to an external microcontroller running bare metal code. The key ones seem to be:
  • DMX-512 runs a a non-standard (for PC) baud rate of 250kbaud. Many computer UARTs cannot run at this speed, which makes them a non-starter.
  • DMX-512 uses serial break signals (periods when the line is held continuously in the '1' (non-idle state) to demarcate successive frames of data. These cannot be sent by just writing characters out of the serial port.
  • DMX-512 has relative tight timing requirements for various elements of the signal – if your computer suddenly stops sending data for a while, then the lights you are controlling may go out or flicker randomly.

Hardware DMX Output

The hardware side of sending DMX-512 is relatively simple – it uses simplex RS-485 (I am ignoring optional extensions like RDM). Simplex means that data only goes one way – the controller sends data, and everything else in the system just listens to it, with no answering back! RS-485 is a common standard for industrial serial communications, using a screened, twisted, pair of wires. Because RS-485 is common industrially, there are lots of integrated circuits which can translate from the transmit pin coming out of the Raspberry Pi (at 3.3V TTL levels) to the standard (higher) RS-485 levels. I used a Maxim MAX3158 line driver, because it provides isolation between the DMX control line (which will be connected to lighting ground) and the Pi (which will be connected to audio ground). For a simple project like this, isolation isn't required, but it can be very useful in avoiding humming audio and flickering lights on larger projects. I also had got hold of some at a good price!
RS-485 output schematic (pdf | svg)
The schematic is mostly just taken from the data sheet. Power is supplied from the Pi's 5V power supply, which is converted into an isolated power rail within the chip, and used to feed the output stage. R1 “softens” the connection between the output cable ground and the line driver, as recommended in the data sheet. R2 and C4 link the Pi ground to the DMX ground at high frequencies (to minimise interference) and provide a backup ground path if no other ground exists.
R3 is the DMX line terminator, to minimise reflections on the DMX cable, and needs to be the ½ W part because it gets quite a lot of current through it when the full output voltage is being driven.
Part Value
C1, C2 100 nF 100 V
C31 µF
C410 nF
C5 100 nF
R1 100 Ω ¼ W
R2 47 kΩ ¼ W
R3 120 Ω ½ W

This all worked straightforwardly – each byte sent out of the Pi's serial port was translated through to RS-485 levels on the DMX output connector, with no sign of ringing or waveform distortion.

DMX Output Plug-in

So back to those things which make software developers avoid direct DMX output. Before we try to start, we need to stop the default Raspbian image from using the serial port as a text mode login screen, by following these instructions. With that done and rebooted, I no longer got random data coming out of the UART.
The first software challenge was to get the UART outputting data at 250kbaud. The maximum speed seemed to be limited to 115.2kbaud, until I found a post on how to run the Pi UART at 1Mbaud which explained how to increase the clock speed of the UART. So do as it says, and add the line
to /boot/config.txt and reboot your Pi (again). This raises the clock limit, but we can still only get the “standard” speeds of 230.4kbaud, 460.8k, 500k and 576k – no joy at 250k. The setserial utility seems to support custom rates, but they don't work in practice. There is a plaintive little message in
the system log
Feb 22 18:55:02 lightingpi kernel: [ 4519.973048] seterial sets custom speed on ttyAMA0. This is deprecated.
What it doesn't say is that setting the custom speed also doesn't work on the Pi UART! After much puzzling, I found a stack overflow post describing how to use the Linux-only termios2 interface to set arbitrary baud rates (this is what you are supposed to use in place of the depreciated setserial method, if you can find out about it). This works, although writing a C program to use the termios2 API has several more “surprises” in store for the unwary.

With the proof of concept in place, on to using it in OLA. OLA has pretty good developer documentation and a detailed log of creating another OLA output plug-in. Between these, it was fairly easy to work out that most of what I was doing could be copied from the existing plug-ins, mostly that FTDIchip output driver I found near the start.
After all messing to get the correct speed, integration into OLA was very smooth, once I did all the things listed in the instructions to register my new plug-in, there it was in the output of the ola_plugin_info command:
Id Plugin Name
1 Dummy
11 E1.31 (sACN)
15 SPI
10000 UART native DMX
(10000 is the dummy ID for testing, it will only get a “proper” ID when the code is accepted back into upstream OLA development). The source code to my forked copy of OLA with the Pi UART plug-in added can be found on Github here. commit a4959cc46d is the version which was used at the trail, although there has subsequently been a new version of OLA released upstream (which I need to update to).
Once OLA was compiled with the Pi output plug-in, it needed to be enabled (the plug-in is deliberately disabled by default), by creating the configuration file /var/lib/ola/conf/ola-uartdmx.conf
which contains just two lines:
device = /dev/ttyAMA0
enabled = true
(there are some other advanced options, but you probably don't need them).

Moment of Truth

You should now have the UART native DMX output device visible in the OLA web GUI, so you can connect it to Universe 0, and use the web DMX console to start sending some output. With any luck, you should be able to fade up your light(s)! The fade won't be very smooth, because the faders only update from the browser a few times per second, but it proves you have control. You can get more detailed control (and timed fades) with the ola_dmxconsole command line tool which is included with OLA.
Next time, I will look at the how I created audio and lighting files to play back through this system.


  1. Thanks for this great article! In my code, I have set UART clock rate to 4000000 (4MHz). See https://github.com/vanvught/OpenDMX/blob/master/pl011_dmx512_fiq/firmware/lib/bcm2835_pl011_dmx512.c
    So far, I have written a DMX Receiver (https://sites.google.com/site/rpidmx512/home) on the RPi baremetal. But I will take a look at your code.

  2. I am using your plug-in here https://sites.google.com/site/rpidmx512/raspberry-pi-ola-dmx512-sender

  3. Could I substitute the MAX3158 for a MAX1480? They are virtually identical except the 1480 has through-hole mounting, 5V Operating supply and 125mA operating current. I just have bad luck soldering SMD IC's.

    1. My MAX3158 is a through-hole part (I got the from here http://www.blue-room.org.uk/index.php?showtopic=27629) but I know that they don't make them in that package any more. Looking at the MAX1480 data sheet, it should work fine provided you get the MAX1480A part with fast slew rate drivers - the B suffix slew rate limited part for 250kbps max won't work with DMX at 512kbps. It has better isolation, so would actually qualify as an isolated DMX interface in terms of the DMX standard. R1 in figure 1 of the MAX1480 data sheet will need to be reduced to accept the 3V3 logic level from the Pi serial port. Note R7 included in the circuit there as protection for the chip, and that the data sheet doesn't show any connection between the isolated side common and logic side common (I found one was necessary with the MAX3158 to avoid lots of high frequency noise on the output, so is included in my schematic).

    2. Richard, How can we modify the code here with DMX TX, to add RX for RDM ? I need RDM on the PI4, and sincerely appreciate your help

    3. Receiving DMX is much harder than sending DMX, because it means detecting breaks, which ordinary serial doesn't. You are much better off talking to the active Open Lightning discussion group https://groups.google.com/g/open-lighting as in the introduction, than posting multiple comments on a blog post from 2014 ...

  4. Thanks, Found the right thread (https://groups.google.com/g/open-lighting/c/MXc3E2YN-u0/m/OK7RB9OPAAAJ), looks like native Serial is still lacking, hence need to use a USB-to-Serial Chip to drive RDM.