M-Bus Master on Raspberry Pi Pico
I have a working M-Bus Master implementation on the Raspberry Pi Pico, through a port of libmbus to the Pico C SDK.
The port itself was straightforward - the Pico’s hardware_uart API is easy to port to from libmbus’s current termios serial implementation.
To build pico-mbus:
- Install the Pico C SDK if you haven’t already got it - pico-build provides a simple way of doing this
- Clone and build pico-mbus
I’ve tested this, naturally, with the M-Bus Master Hat, although it should work with other M-Bus Master hardware serial implementations.
Wiring instructions are given in the README.
Here is the Pico output from scanning my M-Bus test rig, using mbus-scan, with slaves configured at addresses 1, 2 and 48.
------------
M-Bus: Start
M-Bus: Turn bus power on
M-Bus: Pause for 1000ms
M-Bus: Create serial context
M-Bus: Connect to serial
M-Bus: Using UART0
M-Bus: Set baudrate to 2400
M-Bus: TX Pin: 0
M-Bus: RX Pin: 1
M-Bus: Set flow control: CTS off RTS off
M-Bus: UART settings: Data 8 Stop 1 Parity 1
M-Bus: Set search retries value to 0
M-Bus: Scanning primary addresses:
Found an M-Bus device at address 1
Found an M-Bus device at address 2
Found an M-Bus device at address 48
M-Bus: Scan complete - results:
Slaves found: 3
Collisions: 0
Addresses found: 1 2 48
M-Bus: Disconnect
M-Bus: Free context
M-Bus: Turn bus power off
M-Bus: Pause for 10000ms before rescanning
Here is the Pico output from querying, using mbus-query, device at address 48.
------------
M-Bus: Turn bus power on
M-Bus: Pause for 1000ms
M-Bus: Create serial context
M-Bus: Connect to serial
M-Bus: Using UART0
M-Bus: Set baudrate to 2400
M-Bus: TX Pin: 0
M-Bus: RX Pin: 1
M-Bus: Set flow control: CTS off RTS off
M-Bus: UART settings: Data 8 Stop 1 Parity 1
M-Bus: Initialize slaves
M-Bus: Primary address: 48
M-Bus: Query complete - results:
<?xml version="1.0" encoding="ISO-8859-1"?>
<MBusData>
<SlaveInformation>
<Id>30137315</Id>
<Manufacturer>ATS</Manufacturer>
<Version>1</Version>
<ProductName></ProductName>
<Medium>Heat: Outlet</Medium>
<AccessNumber>207</AccessNumber>
<Status>00</Status>
<Signature>0000</Signature>
</SlaveInformation>
<DataRecord id="0">
<Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber>
<Unit>Energy (kWh)</Unit>
<Value>0</Value>
<Timestamp>1970-01-01T00:00:16Z</Timestamp>
</DataRecord>
<DataRecord id="1">
<Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber>
<Unit>Volume (1e-2 m^3)</Unit>
<Value>5</Value>
<Timestamp>1970-01-01T00:00:16Z</Timestamp>
</DataRecord>
<DataRecord id="2">
<Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber>
<Unit>On time (hours)</Unit>
<Value>70254</Value>
<Timestamp>1970-01-01T00:00:16Z</Timestamp>
</DataRecord>
<DataRecord id="3">
<Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber>
<Unit>Power (kW)</Unit>
<Value>1</Value>
<Timestamp>1970-01-01T00:00:16Z</Timestamp>
</DataRecord>
<DataRecord id="4">
<Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber>
<Unit>Volume flow (m m^3/h)</Unit>
<Value>0</Value>
<Timestamp>1970-01-01T00:00:16Z</Timestamp>
</DataRecord>
<DataRecord id="5">
<Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber>
<Unit>Flow temperature (1e-2 deg C)</Unit>
<Value>1</Value>
<Timestamp>1970-01-01T00:00:16Z</Timestamp>
</DataRecord>
<DataRecord id="6">
<Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber>
<Unit>Return temperature (1e-2 deg C)</Unit>
<Value>1</Value>
<Timestamp>1970-01-01T00:00:16Z</Timestamp>
</DataRecord>
<DataRecord id="7">
<Function>Instantaneous value</Function>
<StorageNumber>0</StorageNumber>
<Unit>Temperature Difference (1e-2 deg C)</Unit>
<Value>1</Value>
<Timestamp>1970-01-01T00:00:16Z</Timestamp>
</DataRecord>
<DataRecord id="8">
<Function>Instantaneous value</Function>
<StorageNumber>1</StorageNumber>
<Unit>Time Point (date)</Unit>
<Value>2023-09-02</Value>
<Timestamp>1970-01-01T00:00:16Z</Timestamp>
</DataRecord>
</MBusData>
M-Bus: Disconnect
M-Bus: Free context
M-Bus: Turn bus power off
M-Bus: Pause for 10000ms before requerying