jenswilly.dk


KNX components with LPC11U68 MCU

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:

  1. Thorsten Gehrig's arduino-tpuart KNX-User-Forum
  2. 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:

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:

SIEMENS 5WG1117-2AB12
SIEMENS 5WG1117-2AB12

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

BTM2-PCB or 117/12 PCBA or TP-UART 2 Evaluation Board
BTM2-PCB or 117/12 PCBA or TP-UART 2 Evaluation Board

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:

5WG1117-2AB12 pinout
5WG1117-2AB12 pinout
BCU pinconnect to
GNDMCU GND
RXlevel shifter output → MCU TX
TXMCU RX
+5 VOptional: 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 and boolean and String so that was changed to uint8_t, bool and std::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 to uint16_t representations so I didn't have to mess with std::string::find() and std::string::substr() just to convert back to 16 bit addresses.
  • Timing functions. I needed an implementation of millis() and micros() so I made that using SysTick (the KnxTpUart repo doesn't need micros() 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 for begin(), end(), available(), peek(), read() and write(). I used the Ring Buffer-based methods in the chip library (I did have to implement RingBuffer_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:

  1. Port of Thorsten Gehrig's library KnxTpUartLPC on Bitbucket
  2. Port of Franck Marini's library KnxDevice on Github
  3. 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 of knx_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.

Leave a Reply