* Add Raspberry Pi Pico port - Adds BACnet/IP with abstracted network layer - Adds BACnet MS/TP support using RS485/UART - Includes README with examples * Add Pico 2 MS/TP demo, CI, and docs
BACnet Stack Port for Raspberry Pi Pico
This directory contains the Raspberry Pi Pico port of the BACnet stack, supporting both BACnet/IP and BACnet MS/TP.
Overview
This port provides:
- BACnet/IP support with abstracted network layer (Developer must provide Ethernet implementation)
- BACnet MS/TP support using UART (RS485)
Hardware Used
The port is written against the Raspberry Pi Pico SDK. The same code is intended to build for boards that the Pico SDK exposes with compatible UART/GPIO support, such as:
picopico_wpico2pico2_w
The current make pico-cmake flow defaults to the Pico SDK board pico2 for this port unless -DPICO_BOARD=... is passed to CMake.
For the MS/TP side, the code currently assumes:
- UART1 on GPIO 8 (
TX) and GPIO 9 (RX) - GPIO 10 as the RS485 transceiver
DE/REcontrol pin - An external 3.3 V RS485 transceiver module, for example a MAX3485- or SN65HVD-based module
Typical wiring is:
- Pico/Pico 2 GPIO 8 -> transceiver
DI - Pico/Pico 2 GPIO 9 -> transceiver
RO - Pico/Pico 2 GPIO 10 -> transceiver
DEandRE - Pico/Pico 2
3V3-> transceiverVCC - Pico/Pico 2
GND-> transceiverGND - Transceiver
A/B-> BACnet MS/TP trunk
No external hardware is needed for the automated CI build because the CI job only verifies that the Pico MS/TP target compiles.
Software Dependencies
The external dependency required for this port is cloned by ports/pico/configure.sh into ports/pico/external/:
- Raspberry Pi Pico SDK 2.2.0 URL: https://github.com/raspberrypi/pico-sdk
The script checks out that SDK tag and initializes the SDK submodules needed by the build.
Build
From the repository root:
make pico-cmake
That target runs ports/pico/configure.sh, configures the CMake build in ports/pico/build, and builds the Pico port for pico2.
To select another supported board, configure manually and pass PICO_BOARD:
cd ports/pico
./configure.sh
cmake -S . -B build -DPICO_SDK_PATH="$PWD/external/pico-sdk" -DPICO_BOARD=pico2
cmake --build build -- -j"$(nproc)"
Using This Port
Implement Network Functions
Developer must implement the following functions declared in bip.h:
bool bip_socket_init(uint16_t port);
int bip_socket_send(
const uint8_t *dest_addr,
uint16_t dest_port,
const uint8_t *mtu,
uint16_t mtu_len);
int bip_socket_receive(
uint8_t *buf,
uint16_t buf_len,
uint8_t *src_addr,
uint16_t *src_port);
void bip_socket_cleanup(void);
bool bip_get_local_network_info(uint8_t *local_addr, uint8_t *netmask);
These BACnet/IP hooks are examples of the interface you need to provide. The repository does not yet include a complete in-tree Pico Ethernet or Wi-Fi transport implementation, so BACnet/IP still requires board-specific network code behind bip.h.
Example Usage
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/uart.h"
#include "mstimer_init.h"
#include "bip.h"
/* BACnet Stack Includes */
#include "bacnet/datalink/datalink.h"
#include "bacnet/basic/services.h"
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/tsm/tsm.h"
#include "bacnet/dcc.h"
static struct mstimer DCC_Timer;
int main() {
// Initialize Pico
stdio_init_all();
systimer_init();
// Initialize BIP datalink
Device_Set_Object_Instance_Number(12345);
Device_Init(NULL);
address_init();
// Initialize BACnet/IP on port 0xBAC0 (47808)
if (!bip_init(0xBAC0)) {
return -1;
}
/* set up confirmed service unrecognized service handler - required! */
Send_I_Am(&Handler_Transmit_Buffer[0]);
mstimer_set(&DCC_Timer, 1000); // 1 second timer
printf("BACnet BIP Initialized");
BACNET_ADDRESS src = {0};
uint8_t rx_buf[480];
const uint16_t max_pdu = sizeof(rx_buf);
while (1)
{
if (mstimer_expired(&DCC_Timer))
{
mstimer_reset(&DCC_Timer);
dcc_timer_seconds(1);
}
uint16_t pdu_len = bip_receive(&src, rx_buf, max_pdu, 0);
if (pdu_len > 0)
{
npdu_handler(&src, rx_buf, pdu_len);
printf("%u bytes received from MAC %u\r\n", pdu_len, src.mac[0]);
for (int i=0;i<pdu_len;i++) printf("%02X ", rx_buf[i]);
printf("\n");
}
}
return 0;
}
BACnet MS/TP (RS485)
For a minimal MS/TP example for this port, see main.c.
The RS485 driver is ready to use without modification. It uses the Pico SDK UART functions.