We're building a new house at the moment so I'm looking into various flavors of home automation right now. And even though many people seem to go with Philips HUE-based solutions, I've decided on using KNX instead. There are both advantages and disadvantages but that's an entirely different post.
Obviously I want to be able to add my own components to the setup – both as actuators (i.e. things that are controlled by automation/switches, like lights, relays, motors) and as sensors (i.e. inputs that can trigger stuff, like switches, light sensors, motion sensors, …).
Since my weapon of choice at the moment is NXP's 32 bit ARM LPC11U00 series, the job at hand is as follows:
Connect an LPC11U68 to a KNX bus and observe and send data objects.
Current implementations
What better place to start than to steal be inspired by what other people have already made. A quick search yielded a couple of interesting articles and two promising repositories:
- Thorsten Gehrig's arduino-tpuart KNX-User-Forum
- Franck Marini's KnxDevice
Note that both of the above repos use a Siemens TP-UART2 device as interface to the KNX bus. There are several other ways of implementing a custom KNX device. Among them are:
- KNiXuino (Tapko SIM-KNX-based)
- Weinzierl BAOS (A much more professional and comprehensive solution)
But these are more expensive and can be hard to find suppliers for. On the other hand they provide more "real KNX device" implementations with provisioning through ETS5 and suchlike. But for now, I will use the two Arduino- and TP-UART2-based solutions.
Hardware
The KNX bus runs on a 24 V twisted-pair cable so we need a way of connecting the MCU to the KNX bus without frying the MCU. Enter the Bus Coupling Unit (BCU). This devices handles the physical, data link and network layers of the communication and simply passes all bus data on to the MCU by way of a standard 5 V serial connection.
The MCU will then handle the rest of the communication stack and the application layer.
Excerpt from KNX Basics:
Components of bus devices
All standard bus devices are made up of two parts – the bus coupling unit (BCU) and the application module (Fig. 27).
If these two components are separable, they are connected via a standardised, 10 or 12-pin physical external interface (PEI).
I'm using a SIEMENS 5WG1117-2AB12 which contains a TP-UART2:

It's fairly cheap and can be purchased from many places (from voltus.de for example).

Oh, and once you disassemble it a little bit, it is 100% identical to the "TP-UART 2 Evaluation Board" (also known as "117/12 PCBA" or "BTM2-PCB") which is mentioned in many KNX DIY articles:
Level shifting
Since the BCU runs on 5 V, we need level shifting on the USART TX from the 3.3 V LPC MCU since the TPUART2 datasheet lists the "minimum voltage range for input high level" as 3.5 V which is higher than the MCU's high output level (which is 3.3 V).
We don't need to level shift for the MCU's RX pin if we are using pins that are 5 V tolerant (so check the datasheet for the RX pin you're using).
The exact method of level shifting is not important. We're only running 19.2 kbaud so we don't need any high-speed stuff. (For my test project, I just ran the signal through two NOT gates of a 74LS04 IC with a 5 V supply because that's what I had handy. For the "production" version, I'll probably use something else.)
Pinout
The pinout from the BCU is easy. From the datasheet:

BCU pin | connect to |
---|---|
GND | MCU GND |
RX | level shifter output → MCU TX |
TX | MCU RX |
+5 V | Optional: 3.3 V voltage regulator and then to MCU VCC supply |
Firmware
I converted both of the above Arduino-based repos to work with MCUXpresso for LPC. The vast majority of the code has been left untouched – so many, many thanks to Franck and Thorsten 🙇♂️ for their work.
These are the changes I needed to make:
- Converted data types. Arduino uses
byte
andboolean
andString
so that was changed touint8_t
,bool
andstd::string
. Sure, I could just have#define
'd my way out of it but I prefer to use the "proper" types.
Also, the KnxTpUart repo used strings to represent KNX addresses which I changed touint16_t
representations so I didn't have to mess withstd::string::find()
andstd::string::substr()
just to convert back to 16 bit addresses. - Timing functions. I needed an implementation of
millis()
andmicros()
so I made that using SysTick (the KnxTpUart repo doesn't needmicros()
so SysTick counting milliseconds is good enough and easy to implement) or using a 32 bit timer counting a 1 MHz for microseconds. - Serial driver. This turned out to be way more gnarly than it should have been. Basically I created an abstract class for the
HardwareSerial
interface to match the Arduino class. Then I created derived classes for USART0 and USART1 respectively and implemented methods forbegin()
,end()
,available()
,peek()
,read()
andwrite()
. I used the Ring Buffer-based methods in the chip library (I did have to implementRingBuffer_Peek()
in the chip library as well).
Then came the problems. The data I received was not what I expected and I spent a lot of time poring over the bytes and bits with both scope and logic analyzer (if you don't already have one, get yourself a Saleae Logic Analyzer – it's awesome) and manually parsing the KNX packages. Long story short: for the UASRT0, I forgot the UART0_LCR_PARITY_EN
bit in configuration required to enable even parity. For the USART1 implementation (which, frustratingly, uses completely different registers and methods from the USART0), I first left out Chip_Clock_SetUSARTNBaseClockRate()
required for configuring the USARTn clock and then I forgot UARTN_CFG_PARITY_EVEN
for the pesky even parity. Sigh…
Anyway, everything is now working.
Make with the code, already
Sure, here you go:
- Port of Thorsten Gehrig's library KnxTpUartLPC on Bitbucket
- Port of Franck Marini's library KnxDevice on Github
- Complete (albeit slightly messy) example: KNX LPC on Bitbucket
Add the two KNX repos as subdirectories under the main project directory and refresh. Use the#define KNX_LIBRARY
at the top ofknx_test.cpp
to choose which implementation to use.
You need to check "Exclude resource from build" on the directory you are not using. And you should exclude the "examples", "drivers", "serial" subfolders as well for the project to compile.
Hey! Det er sgu da dig der har jydskatomkraft.dk