Skip to content

Repository files navigation

OpenKNX Common

OpenKNX Common is a library meant to be used once in every OpenKNX Device firmware.

The main functions are:

  • setup and calling the knx stack
  • setup and calling of the OpenKNX Modules
  • flash handling for persistent data of the OpenKNX Modules

Includes ETS configuration and own group objects, see application description (German only).

Usage

It is designed for usage with the headerfile generated by OpenKNXproducer, which provides the necessary defines in knxprod.h:

MAIN_OpenKnxId
MAIN_ApplicationNumber
MAIN_ApplicationVersion

BASE_StartupDelayBase
ParamBASE_StartupDelayTimeMS
BASE_HeartbeatDelayBase
KoBASE_Heartbeat
ParamBASE_HeartbeatDelayTimeMS

Hardware

ARCH info
RP2040 the reference platform with full support (including dual core support)
SAMD21 obsolete but still supported. no hw should be developed on this anymore
ESP32 experimental

Configuration

To configure the Hardware-Setup use the following defines in hardware.h

General HW settings

define default unit function mandatory/optional
SAVE_INTERRUPT_PIN if defined >= 0, falling edge on this pin will trigger power save actions optional
KNX_UART_RX_PIN UART receive Pin to connect to BCU mandatory for TP devices
KNX_UART_TX_PIN UART transmit Pin to connect to BCU mandatory for TP devices
KNX_UART_NUM HW UART number mandatory for TP devices
SAVE_POWER_PIN if defined >= 0 this pin will be used to shut off non crucial power optional
SAVE_POWER_PIN_POWER_OFF value of SAVE_POWER_PIN to shut the power off (e.g. LOW or HIGH) mandatory if SAVE_POWER_PIN defined
SAVE_POWER_PIN_POWER_ON value of SAVE_POWER_PIN to shut the power on (e.g. LOW or HIGH) mandatory if SAVE_POWER_PIN defined

General FW settings

define default unit function
OPENKNX_RECOVERY_TIME 6000 ms hold prog button to erase knx and openknx data (not firmware or filesystem). Turn off with 0
OPENKNX_DUALCORE build with dualcore support (only on RP2040)
OPENKNX_WATCHDOG compile with watchdog (use only for releases. debugger not working with active watchdog)
OPENKNX_WATCHDOG_MAX_PERIOD 16 s the timeout period of watchdog
OPENKNX_WATCHDOG_AUTOERASE_RESETS 5 s erase knx flash after X fast watchdog restarts
OPENKNX_WATCHDOG_AUTOERASE_TIMEOUT 16 s timeout after the fast restart counter is to be reset
OPENKNX_MAX_MODULES 9
OPENKNX_WAIT_FOR_SERIAL 2000 ms wait at startup until SERIAL_DEBUG is connected.
(optional with timeout - in devmode use high values like 20000 - 0 will disable waiting)
Not supported on ESP32
OPENKNX_MAX_LOOPTIME 4000 µs how much time is the loop allowed to consume. (soft limit)
OPENKNX_LOOPTIME_WARNING 7 ms issue a warning if the loop has lasted X ms or longer longer.
OPENKNX_LOOPTIME_WARNING_INTERVAL 1000 ms how often the warning may be issued in the console
OPENKNX_RUNTIME_STAT Integrate Collection of Runtime-Statistics.
OPENKNX_RUNTIME_STAT_BUCKETN 16 the number of histogram buckets for Runtime-Statistics
OPENKNX_RUNTIME_STAT_BUCKETS default set µs The upper (included) limits of histogram bucket, without last bucket as this will be limited by data-type only. Must be a comma-separated list with OPENKNX_RUNTIME_STAT_BUCKETN-1 entries
OPENKNX_DEBUG Enable debug mode
OPENKNX_TRACE Enable debug mode + tracing. To see trace logs, the log prefix (format PREFIX<SUB>, e.g. Channel<4>) must match a filter. Filter syntax: prefix exact or * suffix wildcard (Channel, Channel*); optional <sub> with exact value, numeric range 1-19, comma list 4,5,7 (combinable: 1-5,9), or * suffix wildcard (Test*). A filter without <sub> ignores the sub part (matches all). Combine several filters with ;, e.g. OPENKNX_TRACE=Test1<1-4>;Test2<8> (commas stay reserved for the sub list).
OPENKNX_DEBUGGER Must be defined if you want to use a debugger (SWD). (e.g., switches off watchdog)
OPENKNX_TIME_DIGAGNOSTIC Enable time diagnostic console commands. Will be automatically defined if OPENKNX_DEBUG is defined.
OPENKNX_TIME_TESTCOMMAND Enable time text command to check the behavior of the posix time calculation functions
OPENKNX_TIME_CLOCK arch depen. Specifies the used time class. The default for SAMD21 is OpenKNX::Time::TimeClockMillis, for all other architectures OpenKNX::Time::TimeClockSystem
OPENKNX_LITTLE_FS arch depen. If true, LittleFS will be enabled. Default true for RP2040 and ESP32.
OPENKNX_OVERRIDE_MASK_VERSION defines a mask version which will be returned regardless of the MASK_VERSION used for the build. Set this define if the used mask version does not match the media type.
OPENKNX_RTT Enable RTT Mode (Disable USB Serial output) + Increase BUFFER_SIZE_UP to 10240!
BUFFER_SIZE_UP 1024 Bytes Using by Segger RTT

Memory Management

PSRAM Helper Macros

On ESP32 and RP2350, you can utilize PSRAM for both static data and dynamic memory allocation. The following macros are provided in helper.h:

Macro Function With OPENKNX_PSRAM Without OPENKNX_PSRAM
PSRAM_MALLOC(size) Allocate dynamic memory ESP32 ps_malloc, RP2350 pmalloc malloc(size)
PSRAM_CALLOC(count, size) Allocate and zero memory ESP32 ps_calloc, RP2350 pcalloc calloc(count, size)
PSRAM_REALLOC(ptr, size) Reallocate memory ESP32 ps_realloc, RP2350 realloc realloc(ptr, size)
psram_new(Type) Placement-new in PSRAM PSRAM allocation Normal allocation
psram_delete(p) Destruct + free PSRAM object ~T() + free() delete p
PsramAllocator<T> STL allocator using PSRAM PSRAM_MALLOC-backed std::allocator<T>
PSRAM_DATA Place variable/array in PSRAM RP2350 section .psram, ESP32 EXT_RAM_BSS_ATTR No-op
PSRAM_CODE Place function in PSRAM RP2350 section .psram_code No-op (ESP32 cannot execute from PSRAM)

The section names are not free-form: arduino-pico's linker script collects *(.psram*) into the PSRAM region (lib/rp2350/memmap_default.ld), ESP-IDF uses .ext_ram.bss. A section name outside those patterns links without error and silently ends up in normal RAM — verify placement in the .map file (RP2350 PSRAM window starts at 0x11000000).

ESP32 caveat verified by build: PSRAM_DATA only places data in PSRAM if the underlying sdkconfig has CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=yEXT_RAM_BSS_ATTR degrades itself to a no-op otherwise (checked in esp_attr.h), and the sdkconfig shipped with this project's pinned pioarduino release does not set it. PSRAM_MALLOC/PsramAllocator are unaffected — confirmed via nm that PsramAllocator<T>::allocate() calls the real ps_malloc, not a stub. RP2350 has no equivalent gate: PSRAM_DATA there is proven placed at 0x11000000 with just RP2350_PSRAM_CS set.

PSRAM_DATA variables live in a NOLOAD section: they cannot be statically initialized and are not zeroed at startup. Initialize them explicitly at runtime.

Control defines:

  • OPENKNX_PSRAM — automatically defined when ESP32 BOARD_HAS_PSRAM or RP2350 RP2350_PSRAM_CS is detected. Only these two are checked, because they are what the cores themselves use to bring the PSRAM heap up — defining any other name would enable the macros without an initialized heap. On PlatformIO the board must also declare upload.psram_length, otherwise the PSRAM region has zero length
  • OPENKNX_DISABLE_PSRAM — define in hardware.h to disable PSRAM and force fallback to normal RAM/Flash (useful for debugging with Segger, etc.)

Example usage:

// Dynamic allocation
uint8_t *buf = (uint8_t*)PSRAM_MALLOC(8192);  // PSRAM if available
free(buf);                                    // always free with free()

MyClass *obj = psram_new(MyClass)();          // Placement-new in PSRAM
psram_delete(obj);                            // destructs + frees correctly

// STL container in PSRAM
std::vector<uint8_t, PsramAllocator<uint8_t>> vec;
vec.resize(8192);

// Static allocation
PSRAM_DATA uint8_t largeBuf[8192];            // Array in PSRAM
PSRAM_CODE void heavyComputation() { }        // Function in PSRAM (frees Flash)

LEDs

see README_LED.md

Buttons

define default unit function
PROG_BUTTON_PIN undef GPIO to drive the OpenKNX programming button. Button supports short press (<1000ms), long press, and double press (500ms intervals).
PROG_BUTTON_PIN_MODE INPUT_PULLUP values: INPUT_PULLUP, INPUT_PULLDOWN, INPUT. Specifies the mode for the programming button pin.
OPENKNX_BUTTON_DEBOUNCE 50 ms Software debounce time for buttons to avoid false triggers. Setting to 0 disables it (i.e. to use Hardware debounce).

OpenKNX GPIO Abstraction Layer

OpenKNX Common includes an abstraction layer for GPIOs to seamlessly access GPIOs from the OpenKNX modules, if the GPIOs are integrated into the MCU or provided by port expanders.

Configuration hardware.h

#define OPENKNX_GPIO_NUM 1
#define OPENKNX_GPIO_TYPES OPENKNX_GPIO_T_TCA9555
#define OPENKNX_GPIO_ADDRS 0x20
#define OPENKNX_GPIO_INTS 0xFF  

#define OPENKNX_GPIO_WIRE Wire
#define OPENKNX_GPIO_CLOCK 400000
#define OPENKNX_GPIO_SDA 28
#define OPENKNX_GPIO_SCL 29

#define OPENKNX_xxx_PINS 0x010D, 0x010B, 0x0102, 0x0104

Note:

If you use one or more GPIO expanders (OPENKNX_GPIO_NUM ≥ 1), the lists >OPENKNX_GPIO_TYPES, OPENKNX_GPIO_ADDRS, and OPENKNX_GPIO_INTS must contain exactly as >many entries as specified. The order of entries determines the assignment of expander >addresses and types in the system.

GPIO Numbering:
For expander 1, the IOs are addressed as 0x0100 to 0x01FF, for expander 2 as 0x0200 to 0x02FF, and so on, where XX stands for the IO number on the respective expander (usually 0–7 or 0–15, depending on the expander type).
For MCU-internal GPIOs, use the plain pin number (e.g., 24).

Example:

  • 0x0105 means IO 5 on expander 1
  • 0x0202 means IO 2 on expander 2

Sample code

openknx.gpio.pinMode(24, OUTPUT);        // Set MCU-GPIO 24 to OUTPUT
openknx.gpio.digitalWrite(24, HIGH);     // Write MCU-GPIO 24 to HIGH

openknx.gpio.pinMode(0x0105, OUTPUT);    // Set IO 5 on expander 1 (addressed as 0x01) to OUTPUT
openknx.gpio.digitalWrite(0x0105, HIGH); // Write HIGH to IO 5 on expander 1

openknx.gpio.digitalRead(0x0105);        // Read IO 5 on expander 1

openknx.gpio.pinMode(0x0202, INPUT_PULLUP); // Set IO 2 on expander 2 (addressed as 0x02) to INPUT_PULLUP

Supported Hardware

  • TCA6408: 8-bit I2C port expander
  • TCA9555: 16-bit I2C port expander
  • PCA9554: 8-bit I2C-bus expander (I2C slave address range 0x20 to 0x27)
  • PCA9557: 8-bit I2C-bus expander (I2C slave address range 0x18 to 0x1F)

Features

Current

pinMode, digitalRead, digitalWrite, attachInterrupt

Planned Features

  • Interrupt handling on expanders
  • analogRead/Write
  • bulk setting of pins

Further improvements

  • Multicore
  • expanders on different I2C units (e.g. 0x01 on Wire, 0x02 on Wire1)

About

Used by OpenKNX firmware packages and contains support methods for various functionality. It is not a standalone package

Topics

Resources

Stars

8 stars

Watchers

8 watching

Forks

Releases

Packages

Contributors

Languages