PoLabs PoCANbridge2-15 Device API Reference

Overview
The PoCANbridge2-15 provides two independent control interfaces: a CAN bus using the PoCAN v2 protocol and an RS485 port using Modbus RTU. Both interfaces operate on shared underlying hardware state (two H-bridges, analog inputs, driver fault state, and non-volatile configuration), so values written over one bus are immediately visible on the other.
Key Specifications
| Motor channels / drivers | 2 independent integrated H-bridge driver |
|---|---|
| Supply voltage | 5–48 V DC (single supply for the whole board) |
| Output current | Up to 7.5 A per bridge channel (set by on-board current-sense range) |
| PWM frequency | 20 Hz to 100 kHz (shared by both bridges) |
| Current sensing | Per-bridge average and peak current |
| Analog inputs | 4 analog inputs (IO1–IO4) |
| Digital output | OUT1 (revision 1.1 only) |
| CAN / PoCAN v2 device identity addressing | Factory 32-bit device ID and assignable 16-bit PoCAN v2 ID |
| RS485 hardware revision | RS485 transceiver fitted on hardware revision 1.1 only |
| RS485 default settings | 19200 baud, 8 data bits, even parity, 1 stop bit (8E1); default slave address 1 |
| Modbus register width | All holding registers are 16-bit |
| Modbus CRC | CRC-16 with polynomial 0xA001 (reflected 0x8005), initial value 0xFFFF, low byte first (little-endian) |
Quick Setup
- Choose the control interface: use CAN with the PoCAN v2 protocol, or use RS485 with Modbus RTU (revision 1.1 only).
- For CAN: address the device using either its 32-bit factory device ID or a 16-bit assignable PoCAN v2 ID, and use directed commands / heartbeat frames as defined in the API reference.
- For RS485 (hardware rev 1.1): wire a two-wire half-duplex bus and connect signals as A-to-A and B-to-B, sharing grounds.
- If the RS485 device does not respond, swap the two data leads (a reversed A/B pair is called out as the most common wiring fault).
- For RS485/Modbus: communicate to the slave address (default 1). Writes to broadcast address 0 are executed by all devices and produce no response.
Device overview

1.1 Purpose This document is the complete interface reference for the PoCANbridge2-15. The device provides two independent control interfaces — a CAN bus running the PoCAN v2 protocol, and an RS485 port running Modbus RTU — and this document covers both. Sections 2 to 8 define the CAN / PoCAN v2 protocol: its wire format, addressing, device lifecycle, heartbeat behaviour, and every command an external host (master) can send, defined byte-by-byte with request and response payloads, range constraints and error returns. Section 9 defines the RS485 / Modbus RTU interface: its physical layer, framing, the register, coil and discrete-input map, and worked examples. The appendices give quick-reference tables for both buses. The CAN protocol is referred to as PoCAN v2. Over CAN the firmware implements the device (slave) role and can optionally also act as a host (master) on the same bus. Over RS485 the device is always a Modbus RTU slave. Both interfaces operate on the same underlying hardware — the same two H-bridges, analog inputs, fault state and nonvolatile configuration — so a value written over one bus is immediately visible on the other. 1.2 Device overview The PoCANbridge2-15 is a motor-bridge node with two independent integrated H-bridge drivers, four analog inputs (IO1–IO4), an RGB status LED, and two control interfaces. Over CAN it is addressable by either its 32-bit factory device ID or a 16-bit assignable PoCAN v2 ID; it responds to a defined set of directed commands, broadcasts heartbeat frames, and supports a host-loss failsafe. Over RS485 — fitted on hardware revision 1.1 — it is a Modbus RTU slave with a flat 16-bit register map plus coil and discrete-input spaces, reached at a configurable slave address (1–247, default 1). The two interfaces share the same bridges, inputs, fault state and configuration store; the RS485 / Modbus interface is documented in full in Section 9. 1.3 Physical layer The annotated view below identifies every external connector and on-board indicator. Numbered callouts correspond to the legend that follows. Specification Value Motor channels 2 × independent integrated H-bridge driver Supply voltage 5 – 48 V DC (single supply for the whole board) Output current Up to 7.5 A per bridge channel, set by the on-board current-sense range PWM frequency 20 Hz – 100 kHz, shared by both bridges Current sensing Per-bridge average and peak current Analog inputs 4 × 0–5 V (IO1–IO4) Digital output 1 × OUT1 Communication CAN 2.0 / PoCAN v2 + RS-485 / Modbus RTU Both motor channels are fully independent: each can be set to Coast, Forward, Reverse or Brake with its own PWM duty cycle, and each reports its own average and peak current and driver fault state. The board runs from a single 5–48 V DC supply, and each bridge can drive up to 7.5 A. The same node can act as a CAN master that discovers and coordinates other PoCAN v2 devices on the bus, or as a slave under an external host. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 8 PoCANbridge2-15 — connectors and indicators (numbered callouts) # Feature Description 1 Power input DC supply terminals (VCC −/+) for the motor rail 2 Bridge 1 output H-bridge 1 motor terminals 3 Bridge 2 output H-bridge 2 motor terminals 4 H-bridge drivers Two integrated H-bridge drivers 5 FAULT 1 LED Bridge 1 driver fault indicator 6 FAULT 2 LED Bridge 2 driver fault indicator 7 PWR LED Power-good indicator 8 Main MCU 32-bit microcontroller running the firmware 9 SWD header Programming / debug header 10 485TERM jumper RS-485 bus termination select 11 CANTERM jumper CAN bus termination select PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 9 # Feature Description 12 Analog inputs Four 0–5 V inputs IO1–IO4 (with +5 V and GND) 13 RS-485 port Modbus RTU interface (B, A, GND) 14 CAN bus port PoCAN v2 interface (H, L, GND) 15 Status LED RGB device-status indicator (STAT) 16 USB port Configuration and firmware updates Termination jumpers (10, 11) let the board sit at either end of a CAN or RS-485 bus without external resistors, and the two FAULT LEDs (5, 6) give an immediate visual indication of a driver fault on either channel, mirroring the status shown in software. CAN bus Parameter Value Bus CAN 2.0B / CAN controller (classic CAN frames) Identifier type 29-bit extended identifier Frame format Classic CAN (no bit-rate switch, no FD payload) Payload size 0–8 bytes (DLC 0–8) Default nominal bit rate 500 kbit/s Selectable nominal bit rates 125, 250, 500, 1000 kbit/s FD data rates (reserved) Off / 2 Mbit/s / 5 Mbit/s — not used by classic frames Termination 120 Ω at each end of bus (external) All PoCAN v2 traffic uses the 29-bit extended identifier format. Standard (11-bit) frames and remote frames are rejected by the device’s CAN filter configuration. Termination is mandatory: install one 120 Ω resistor across CAN_H / CAN_L at each end of the bus. An un-terminated bus may appear to work at 125 kbit/s (the long bit time lets reflections settle before the sample point) and silently fail at 250 / 500 / 1000 kbit/s with bit-readback errors during transmission. RS485 / Modbus RTU (hardware revision 1.1)
Parameter Value Bus / protocol RS485 (EIA-485), 2-wire half-duplex; Modbus RTU slave Peripheral UART3 (hardware revision 1.1 only) Direction control Automatic, hardware-driven driver-enable (DE), active HIGH Default settings 19200 baud, 8 data bits, even parity, 1 stop bit (8E1) Selectable baud rates 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 bit/s Selectable frame formats 8E1, 8O1, 8N2, 8N1 Slave address 1–247 (default 1); address 0 = broadcast Termination 120 Ω at each end of bus (external) The RS485 / Modbus RTU interface is documented in full in Section 9 (framing, the register, coil and discrete-input map, and worked examples); see Section 9.2 for wiring.
1.4 Roles Two logical roles exist on a PoCAN v2 bus: PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 10 • Host (master) — performs network discovery, sends directed commands, and broadcasts host-heartbeat frames. There is normally exactly one active host on the bus. •
Device (slave) — responds to discovery, executes directed commands addressed to it, and broadcasts its own heartbeat frames. Several devices can coexist on the same bus. A device may also be configured to act as a host (PoCANbridge2 can do both). If the host disappears, any device with the temporary-host feature enabled will, after a deterministic delay, begin broadcasting a host heartbeat itself so other devices remain operational. These roles apply to the CAN bus; on RS485 the device is always a Modbus RTU slave and never initiates bus traffic. 1.5 Conventions used in this document • All multi-byte integer fields are little-endian unless explicitly stated otherwise. • Hexadecimal values are written with a 0x prefix (e.g. 0x40). • Bit numbering is LSB = bit 0. • “Byte 0” of a payload is the first byte transmitted (CAN data byte 0). • “DLC” is the CAN Data Length Code, equal to the number of payload bytes (0–8). •
Examples shown as “03 A8 61 00 00” are space-separated byte values transmitted in order. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 11 2. CAN Identifier Format 2.1 29-bit identifier layout Every PoCAN v2 frame uses a 29-bit extended identifier split into three fields: Bits Field Width Description [28:18] Scope 11 bits Message category — discovery, heartbeat, or directed [17:16] Flags 2 bits Scope-specific sub-type / direction [15:0] LSB / PoCAN v2 ID 16 bits Target or source 16-bit address (or device-ID MSB/LSB during discovery) 2.2 Scope values
Scope Symbol Meaning 0x105 PC2_SCOPE_DISCOVERY Network discovery (MSB/LSB enumeration, ID assignment) 0x106 PC2_SCOPE_HEARTBEAT Periodic heartbeat traffic (device + host) 0x107 PC2_SCOPE_DIRECTED Application-level directed commands (host↔device) 0x108 PC2_SCOPE_LEGACY Reserved — backward compatibility with original PoCAN. Not used by this device. Frames with any other scope value are rejected by the device’s CAN filter and never reach application code. 2.3 Reserved 16-bit addresses Address Symbol Meaning 0x0000 PC2_ID_UNASSIGNED No PoCAN v2 ID has been assigned to the device 0xFFFF PC2_ID_BROADCAST Broadcast address — every device accepts the frame, no response is sent 0x0001 … 0xFFFE — Normal assignable range for device PoCAN v2 IDs On power-on the device adopts its 16-bit device-ID LSB as a provisional PoCAN v2 ID. If that value happens to be 0x0000 or 0xFFFF, the firmware substitutes 0x0001. The host can later assign a permanent ID with the ID_ASSIGN discovery command (Section 4.5). 2.4 Device identity Every device exposes two identifiers: • 32-bit device ID — derived deterministically from the MCU’s 96-bit unique-ID using a Jenkins one-at-a-time hash. This value is permanent and globally unique per chip. It is split into a 16-bit MSB and 16-bit LSB for the discovery protocol. • 16-bit LSB PoCAN v2 ID — the working address used on the bus for heartbeats and directed messages. After discovery the host can assign any value in 0x0001…0xFFFE. Note: PoCAN v2 IDs assigned over the wire are currently held in RAM only — re-running discovery after a power cycle is recommended. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 12 3. Device State Machine & Heartbeat 3.1 State codes A device passes through the following states from power-on. The current state is reported in every heartbeat frame (byte 2). Hex Dec Symbol Description 0x00 0 RESET Power-on reset, internal initialisation 0x01 1 HWBOOT_CHECK Hardware bootloader-switch check (no switch on this device) 0x02 2 MEMORY_CHECK Flash integrity check 0x03 3 WAITLOAD_CHECK Decide whether to wait for firmware update 0x0A 10 APP_START Application running — waiting for host activation. Heartbeats are emitted from this state onward. 0x0B 11 OPERATIONAL Fully operational. Directed commands are accepted only in this state. 0x63 99 BOOTLOADER_WAIT Waiting up to 10 s for a host bootloader request 0x64 100 BOOTLOADER Device is in firmware-update mode 3.2 Boot sequence On power-on the device runs the following sequence: 1. RESET → HWBOOT_CHECK → MEMORY_CHECK → WAITLOAD_CHECK. 2. If the device was configured with waitload_support=true, it enters BOOTLOADER_WAIT for up to 10 seconds (waiting for a host bootloader command). Otherwise, or after the timeout, it advances. 3. If the device is in standalone mode it goes directly APP_START → OPERATIONAL. 4. Otherwise it stops at APP_START and waits for the host to send a host-heartbeat carrying the OPERATIONAL command (0xF0). Each state change is broadcast immediately on the CAN bus as a state-transition heartbeat (Section 3.4). 3.3 System flags Byte 1 of every device heartbeat is a bitfield reporting fault conditions: Bit Mask Symbol Description 0 0x01 PC2_SYSFLAG_HW_ERROR Hardware error (any driver fault, including thermal) 1 0x02 PC2_SYSFLAG_POWER_ERROR Power-domain error (under/over voltage on motor supply) 2 0x04 PC2_SYSFLAG_SW_ERROR Software/internal error 3 0x08 PC2_SYSFLAG_COMM_ERROR Communication / host-loss error (set when failsafe triggers) 4–7 — — Reserved, transmitted as 0 3.4 Heartbeat frame types Heartbeats use scope 0x106.
The 2-bit flags field selects the heartbeat type, and the 16-bit LSB carries the sender’s PoCAN v2 ID (or the broadcast address 0xFFFF for the host heartbeat). Flags Symbol Sender LSB field Purpose 0 PC2_HB_GENERIC Device Device PoCAN v2 ID Periodic device heartbeat (every hb_interval) 1 PC2_HB_STATE_TRANSITIO N Device Device PoCAN v2 ID Emitted immediately on any state change PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 13 2 PC2_HB_ASYNC_UPDATE Device Device PoCAN v2 ID Rotating analog data update (sent alongside heartbeat in OPERATIONAL) 3 PC2_HB_HOST Host (or temphost) 0xFFFF (broadcast) Keeps devices operational; carries optional host command 3.4.1
Device heartbeat (generic, state, async) Generic and state-transition heartbeats use the same 3-byte payload: Byte Field Description 0 hb_interval_idx (high nibble) | counter (low nibble) High nibble = heartbeat-interval LUT index (0–15). Low nibble = 4-bit rolling counter that increments on every transmission. 1 sys_flags System-flags byte (Section 3.3) 2 state Current state code (Section 3.1) The async update heartbeat (flags=2) carries application-defined payload. For PoCANbridge2-15 it rotates through three slots, identified by byte 0: Byte 0 Slot Bytes 1..N 0x00 APP_ASYNC_IO_12 IO1_lo, IO1_hi, IO2_lo, IO2_hi (millivolts, little-endian uint16) 0x01 APP_ASYNC_IO_34 IO3_lo, IO3_hi, IO4_lo, IO4_hi (millivolts, little-endian uint16) 0x02 APP_ASYNC_CURRENTS Bridge1_ma_lo, Bridge1_ma_hi, Bridge2_ma_lo, Bridge2_ma_hi, drv_fault_byte The slot rotates 0 → 1 → 2 → 0 … on every heartbeat cycle, so the host receives a full analog snapshot every three heartbeat periods. 3.4.2 Host heartbeat The host (or a temporarily-elected host) broadcasts a host heartbeat with scope 0x106, flags=3, LSB=0xFFFF. Devices use it for two purposes: as a presence indicator that the host is still alive, and as a command channel for high-level lifecycle control. Host-heartbeat payload — DLC 0 means “host is alive, no command”. DLC ≥ 1 carries a command byte: Byte 0 Symbol Effect on device 0x00 PC2_HCMD_NOP Presence only — refreshes host-last-seen timestamp 0x01 PC2_HCMD_TIME_SYNC Time-synchronisation request (accepted, no action in current firmware) 0xF0 PC2_HCMD_OPERATIONAL If device is in APP_START or BOOTLOADER_WAIT, transition to OPERATIONAL 0xFF PC2_HCMD_BOOTLOADER If device is in BOOTLOADER_WAIT, transition to BOOTLOADER 3.5 Heartbeat interval table
The high nibble of heartbeat byte 0 advertises the device’s current heartbeat interval as an index into the following LUT. The host can change it by sending command 0x40 (Set Heartbeat Interval) — see Section 6.7.1. Index Interval Index Interval 0 1000 ms (default) 8 100 ms 1 1 ms 9 250 ms 2 2 ms 10 500 ms 3 5 ms 11 1000 ms 4 10 ms 12 2000 ms 5 20 ms 13 5000 ms 6 25 ms 14 reserved (treated as 1000 ms) 7 50 ms 15 reserved (treated as 1000 ms) PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 14 3.6 Host-absence detection & temporary host Each device maintains a host_last_seen timestamp, refreshed on every received host heartbeat.
If host_timeout_ms elapses without a host frame, the device flags the host as absent. The default host_timeout_ms is 5000 ms. If host absence persists and the device is in OPERATIONAL state, the device may itself elect to broadcast a host heartbeat (containing PC2_HCMD_OPERATIONAL) after a deterministic delay equal to host_timeout_ms + (device_id_lsb & 0xFF) × 10 ms. This deterministic offset prevents multiple devices from colliding when they elect simultaneously. When the real host returns, the temporary host relinquishes its role on the very next received host heartbeat. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 15 4. Discovery Protocol (scope 0x105) 4.
1 Overview Discovery is used by a host to enumerate every device on the bus by its permanent 32-bit device ID. It is also used to read and assign the 16-bit PoCAN v2 ID. Three forms of discovery frame exist, distinguished by the 2-bit flags field and the DLC of the frame. 4.2 Discovery flag values Flags Symbol Direction Meaning 0 PC2_DISC_F_MSB_REQ Host → all Broadcast MSB request (DLC=0) or addressed command (DLC=8) 1 PC2_DISC_F_LSB_REQ Host → device Request the LSB of the device whose MSB matches the LSB field 2 PC2_DISC_F_MSB_RESP Device → host MSB response — LSB field carries the device-ID MSB 3 PC2_DISC_F_LSB_RESP Device → host LSB response — LSB field carries the device-ID LSB 4.3 Two-phase enumeration sequence A complete enumeration consists of two phases: Phase 1 — MSB collection The host broadcasts an MSB request. Every device on the bus replies with its 16-bit device-ID MSB. Direction Scope Flags LSB field DLC Payload Host → bus 0x105 0 0xFFFF 0 (empty) Device → host 0x105 2 device_id_msb 0 (empty) Phase 2 — LSB collection For each unique MSB returned in phase 1, the host sends an LSB request targeting that MSB. The matching device replies with its LSB. Direction Scope Flags LSB field DLC Payload Host → bus 0x105 1 0 (empty) Device → host 0x105 3 device_id_lsb 0 (empty) After both phases the host knows the full 32-bit device ID = (MSB << 16) | LSB for each device on the bus. 4.4 Addressed discovery commands (32-bit ID lookup) Once the host knows a device’s 32-bit ID it can address that device individually before assigning it a 16-bit PoCAN v2 ID. This uses the same scope (0x105) with flags=0 (PC2_DISC_F_MSB_REQ) and DLC=8. Bytes 0–3 carry the target 32-bit device ID (little-endian); byte 4 carries the command code; bytes 5–7 carry command-specific parameters. Request frame format Byte Field Description 0–3 device_id (LE) Target 32-bit device ID, little-endian 4 cmd Discovery command code (see below) 5–7 parameters Command-specific (zero-filled if unused) Response frame format All addressed discovery responses are emitted as a single broadcast frame with scope=0x105, flags=2 (PC2_DISC_F_MSB_RESP), LSB=0xFFFF, DLC=8: Byte Field Description PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 16 0–3 device_id (LE) Echo of the device’s 32-bit ID 4 cmd Echo of the command code 5–7 data Command-specific 4.5 Discovery commands 0x00 — IDENTIFY — Device identification Returns device type code and short firmware version. Request payload Byte Field Value Description 0–3 device_id 0x???????? Target 32-bit device ID 4 cmd 0x00 PC2_DCMD_IDENTIFY 5–7 padding 0x00 Zero Response payload Byte Field Value Description 0–3 device_id echo 32-bit device ID, little-endian 4 cmd 0x00 IDENTIFY echo 5 device_type 0x15 PoCANbridge2-15 type code (PC2_DEVTYPE_POCANBRIDGE2) 6 fw_major 1 Firmware major version 7 fw_minor 0 Firmware minor version Notes •
The response carries only major.minor. For the full major.minor.patch.build use directed command 0x30 (Firmware Info) — Section 6.6.1. 0x10 — ID_READ — Read current 16-bit PoCAN v2 ID Returns the device’s currently assigned PoCAN v2 ID (the 16-bit address used for heartbeats and directed messages). Request payload Byte Field Value Description 0–3 device_id 0x???????? Target 32-bit device ID 4 cmd 0x10 PC2_DCMD_ID_READ 5–7 padding 0x00 Zero Response payload Byte Field Value Description 0–3 device_id echo 32-bit device ID, little-endian 4 cmd 0x10 ID_READ echo 5 pocan2_id_lo value Low byte of current PoCAN v2 ID 6 pocan2_id_hi value High byte of current PoCAN v2 ID 7 reserved 0x00 Zero PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 17 0x11 — ID_ASSIGN — Assign a 16-bit PoCAN v2 ID Writes a new 16-bit PoCAN v2 ID into the device. Subsequent heartbeats and directed messages will use this address.
Request payload Byte Field Value Description 0–3 device_id 0x???????? Target 32-bit device ID 4 cmd 0x11 PC2_DCMD_ID_ASSIGN 5 new_id_lo value Low byte of new PoCAN v2 ID 6 new_id_hi value High byte of new PoCAN v2 ID 7 reserved 0x00 Zero Response payload Byte Field Value Description 0–3 device_id echo 32-bit device ID, little-endian 4 cmd 0x11 ID_ASSIGN echo 5 pocan2_id_lo value Low byte of accepted PoCAN v2 ID 6 pocan2_id_hi value High byte of accepted PoCAN v2 ID 7 reserved 0x00 Zero Notes • The new ID must not be 0x0000 (PC2_ID_UNASSIGNED) or 0xFFFF (PC2_ID_BROADCAST). • The assignment is held in RAM and does not currently survive a power cycle. Re-run discovery and re-assign on each boot if a fixed mapping is required. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 18 5. Host Heartbeat Commands (scope 0x106 / flags=3) Host heartbeats are broadcast with scope=0x106, flags=3 (PC2_HB_HOST), LSB=0xFFFF. They serve two roles: they keep the host_present flag alive on every device, and — when DLC ≥ 1 — they carry a single command byte that the device acts on. No response is sent to a host heartbeat command. The host should send host heartbeats at the same nominal cadence as device heartbeats (see Section 3.5). The default host-absence timeout is 5000 ms. 5.1 Command byte values Code Symbol DLC Effect on device 0x00 PC2_HCMD_NOP 0 or 1 Presence only. Refreshes host_last_seen, no state change. 0x01 PC2_HCMD_TIME_SYNC 1+ Reserved for time synchronisation. Currently accepted but takes no action. 0xF0 PC2_HCMD_OPERATIONAL 1 If device is in APP_START or BOOTLOADER_WAIT → transition to OPERATIONAL. Has no effect in other states. 0xFF PC2_HCMD_BOOTLOADER 1 If device is in BOOTLOADER_WAIT → transition to BOOTLOADER. Has no effect in other states. 5.2 Typical use A host that wishes to take control of an idle device after discovery sends a host heartbeat with byte 0 = 0xF0. The device, on receiving it from APP_START, transitions to OPERATIONAL and begins accepting directed commands. After that, the host typically reverts to sending host heartbeats with DLC=0 (presence only) at its chosen cadence. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 19 6. Directed Commands (scope 0x107) 6.1 Directed frame format Directed commands target a single device by its 16-bit PoCAN v2 ID, or broadcast to every device using 0xFFFF. Direction is encoded in the flags field: Flags Symbol Direction 0 PC2_DIR_F_HOST_TO_DEV Host → Device (request) 2 PC2_DIR_F_DEV_TO_HOST Device → Host (response) Direction flags 1 and 3 are reserved and not used in this protocol version. 6.1.1 Request frame Field Value Scope 0x107 Flags 0 (PC2_DIR_F_HOST_TO_DEV) LSB or 0xFFFF for broadcast DLC 1–8 (depends on command) Byte 0 Application command code (Sections 6.3–6.8) Bytes 1+ Command-specific parameters 6.1.2 Response frame Devices respond only when: • they are in OPERATIONAL state, • the target address matches their own PoCAN v2 ID (no response to broadcast commands), and • the registered application command handler returns a non-zero response length. Field Value Scope 0x107 Flags 2 (PC2_DIR_F_DEV_TO_HOST) LSB DLC 1–8 (all responses fit in a classic CAN frame) Byte 0 Echo of the original command code Bytes 1+ Response data — see each command When the device receives a directed command its handler cannot recognise, it responds with a two-byte NACK: byte 0 echoes the command code, byte 1 = 0xFF. 6.2 Command summary All directed commands implemented in firmware v1.0.0 (build 176) are grouped below. Section numbers in the rightmost column point to the per-command detail in this document. Code Name Min req DLC Section 0x01 Set Bridge (mode + duty %) 4 6.3.1 0x02 Set Bridge Fine (mode + 16-bit duty) 5 6.3.2 0x03 Set PWM Frequency 5 6.3.3 0x04 Coast All Bridges 1 6.3.4 0x05 Emergency Stop (brake all) 1 6.3.5 0x06 Read PWM Frequency 1 6.3.6 PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 20 0x10 Read IO1 & IO2 1 6.4.1 0x11 Read IO3 & IO4 1 6.4.2 0x12 Read Bridge Currents 1 6.4.3 0x13 Read All Analog Summary 1 6.4.4 0x14 Read Peak Bridge Currents 1 6.4.5 0x20 Read Driver Fault Status 1 6.5.1 0x21 Clear Driver Faults 1 6.5.2 0x22 Read Driver Register 3 6.5.3 0x30 Firmware Info 1 6.6.1 0x31 Capabilities 1 6.6.2 0x40 Set Heartbeat Interval 2 6.7.1 0x41 Set Standalone Mode 2 6.7.2 0x42 Set Failsafe Config 3 6.7.3 0x43 Read Failsafe Config 1 6.7.4 0x44 Save Config to Flash 1 6.7.5 0x45 Factory Reset 1 6.7.6 0x46 Clear Failsafe 1 6.7.7 0x47 CAN Role (read / write) 1-2 6.7.8 0x48 CAN Baud (read / write) 1-2 6.7.9 0x49 Soft Reboot 1 6.7.10 0x50 Visual Identify (LED effect) 1 6.8.1 0x60 Blocks: Deploy Start (PoLogic) 6 6.9.1 0x61 Blocks: Clear (PoLogic) 1 6.9.2 0x65 Blocks: Virtual Input (PoLogic) 4 6.9.3 0x66 Blocks: Clear Errors (PoLogic) 1 6.9.4 0x67 Blocks: Runtime Control (PoLogic) 2 6.9.5 0x6A Blocks: Deploy Data (PoLogic) 2-8 6.9.6 0x6B Blocks: Deploy End (PoLogic) 1 6.9.7 0x6C Blocks: Get Block State (PoLogic) 3 6.9.8 6.3 Motor / Bridge control 0x01 — Set Bridge (mode + duty %) Sets the operating mode and duty cycle of one H-bridge. The duty is given in whole percent (0–100). For higher resolution, use 0x02. Request payload Byte Field Value Description 0 cmd 0x01 APP_CMD_SET_BRIDGE 1 bridge 0 or 1 0 = Bridge 1, 1 = Bridge 2 2 mode 0–3 0=COAST, 1=FORWARD, 2=REVERSE, 3=BRAKE 3 duty % 0–100 Duty cycle in whole percent Response payload Byte Field Value Description 0 cmd 0x01 Echo 1 bridge echo Echo of bridge index 2 mode echo Echo of mode 3 duty % echo Echo of duty % PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 21 4 status 0x00 = OK Always 0x00 if the request validates Notes • Out-of-range parameters (bridge > 1, mode > 3, duty > 100) cause the device to ignore the command and emit no response. • Internally the duty is converted to basis points: duty_bp = duty × 100. So 50 % becomes 5000 bp. 0x02 — Set Bridge Fine (mode + 16-bit duty 0–10000 = 0.00–100.00 %) High-resolution form of Set Bridge. The duty is given as a 16-bit value in basis points (1/100 %): 10000 = 100.00 %. Request payload Byte Field Value Description 0 cmd 0x02 APP_CMD_SET_BRIDGE_FINE 1 bridge 0 or 1 0 = Bridge 1, 1 = Bridge 2 2 mode 0–3 0=COAST, 1=FORWARD, 2=REVERSE, 3=BRAKE 3 duty_lo LE byte 0 Low byte of duty (basis points) 4 duty_hi LE byte 1 High byte of duty (basis points) Response payload Byte Field Value Description 0 cmd 0x02 Echo 1 bridge echo Echo of bridge index 2 mode echo Echo of mode 3 duty_lo echo Echo low byte 4 duty_hi echo Echo high byte 5 status 0x00 = OK Always 0x00 if the request validates Notes • Duty values above 10000 are rejected (no response). • This is the command used internally by the firmware-side bridge-test harness because it avoids the lossy %-conversion in 0x01. 0x03 — Set PWM Frequency Sets the PWM carrier frequency used by both H-bridges. The frequency is given as a 32-bit little-endian value in Hz. Request payload Byte Field Value Description 0 cmd 0x03 APP_CMD_SET_PWM_FREQ 1–4 freq_hz uint32 LE Frequency in Hz (range 1000 – 100000) Response payload Byte Field Value Description 0 cmd 0x03 Echo 1 status 0x00 = OK 0x01 = out of range 0x01 if frequency is outside 1000–100000 Hz PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 22 Notes • The new value is also stored in the in-RAM NV config copy. Use 0x44 (Save Config) to persist it across power cycles. 0x04 — Coast All Bridges Immediately sets both bridges to COAST (high-impedance) at 0 % duty. Request payload Byte Field Value Description 0 cmd 0x04 APP_CMD_COAST_ALL Response payload Byte Field Value Description 0 cmd 0x04 Echo 1 status 0x00 = OK Always 0x00 0x05 — Emergency Stop (brake all) Immediately sets both bridges to BRAKE at 100 % duty (low-side short across the load). Request payload Byte Field Value Description 0 cmd 0x05 APP_CMD_ESTOP Response payload Byte Field Value Description 0 cmd 0x05 Echo 1 status 0x00 = OK Always 0x00 Notes • BRAKE applies a low-side short across both legs of the H-bridge. The motor decelerates as fast as the load and backEMF allow. • Use 0x04 (COAST) if the motor should be allowed to free-wheel instead. 0x06 — Read PWM Frequency Reads back the currently configured PWM frequency. Request payload Byte Field Value Description 0 cmd 0x06 APP_CMD_READ_PWM_FREQ Response payload Byte Field Value Description PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 23 0 cmd 0x06 Echo 1–4 freq_hz uint32 LE Current PWM frequency in Hz 6.4 Analog input The four IO inputs (IO1–IO4) are read through a 5.1 kΩ / 10 kΩ voltage divider into the on-board ADC. The firmware compensates for the divider so that returned values represent the actual connector voltage in millivolts (rounded to the nearest mV). Bridge currents are derived from the current-sense output, with windowed peak detection scaled by the current duty cycle. Input characteristics and behavior • Measurement range — 0 to approximately 4.98 V at the connector. The 5.1 kΩ / 10 kΩ divider presents about twothirds of the connector voltage to the 3.3 V ADC, so full scale (ADC count 4095) is about 4982 mV. A connector voltage above that saturates the reading at roughly 4982 mV and cannot be distinguished from any higher voltage. • Resolution — the ADC is 12-bit, giving about 1.22 mV per count at the connector after divider compensation. Values are reported in 1 mV units, but the real step is about 1.22 mV; the least-significant millivolts are quantization, not extra accuracy. • Divider and reference — a fixed 5.1 kΩ series / 10 kΩ to-ground divider (nominal ratio ×1.51); the firmware multiplies the ADC reading back up to connector millivolts. Absolute accuracy therefore tracks the resistor tolerance and the 3.3 V analog reference. • Signal type — single-ended, DC-coupled and referenced to device ground. The inputs are meant for a steady or slowlyvarying DC level; they are not differential and are not intended for AC or audio-band signals. • No filtering — every read (CAN 0x10 / 0x11 / 0x13, the async heartbeat, and the Modbus IO registers) returns the most recent single ADC sample from the continuously scanned DMA buffer. There is no hardware oversampling and no firmware averaging, so a noisy input gives a noisy reading; average successive reads on the host if a settled value is needed. • Update behavior — the ADC scans all six channels (the four IO inputs and the two bridge-current senses) continuously by DMA, so a read always reflects the latest completed scan. Over CAN the async heartbeat sends the analog data in a three-slot rotation — IO1/IO2, then IO3/IO4, then the bridge currents, one slot per heartbeat — so polling 0x10 / 0x11 directly gives lower latency than waiting for the rotation. • Over-voltage — the divider does not protect against large over-voltage. For a source that can exceed about 5 V, scale or clamp it externally so the divider output stays within the MCU’s analog input limits. 0x10 — Read IO1 & IO2 Returns IO1 and IO2 connector voltages in millivolts (16-bit little-endian). Request payload Byte Field Value Description 0 cmd 0x10 APP_CMD_READ_IO12 Response payload Byte Field Value Description 0 cmd 0x10 Echo 1–2 IO1_mv uint16 LE IO1 voltage in millivolts 3–4 IO2_mv uint16 LE IO2 voltage in millivolts PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 24 0x11 — Read IO3 & IO4 Returns IO3 and IO4 connector voltages in millivolts (16-bit little-endian). Request payload Byte Field Value Description 0 cmd 0x11 APP_CMD_READ_IO34 Response payload Byte Field Value Description 0 cmd 0x11 Echo 1–2 IO3_mv uint16 LE IO3 voltage in millivolts 3–4 IO4_mv uint16 LE IO4 voltage in millivolts 0x12 — Read Bridge Currents Returns the duty-corrected average current of each H-bridge in milliamps (16-bit little-endian). Request payload Byte Field Value Description 0 cmd 0x12 APP_CMD_READ_CURRENTS Response payload Byte Field Value Description 0 cmd 0x12 Echo 1–2 bridge1_ma uint16 LE Bridge 1 current in mA (average over PWM period) 3–4 bridge2_ma uint16 LE Bridge 2 current in mA (average over PWM period) Notes • When the bridge is in COAST (mode 0) or faulted, the returned current is 0. • Internal computation: bridge_ma = peak_ma × duty_bp / 10000. peak_ma is obtained from windowed maxima over 50 ms windows. 0x13 — Read All Analog Summary Returns a compressed summary of all four IO channels, both bridge currents, and the fault summary byte — useful for a low-overhead poll cycle that fits in a single CAN frame. Request payload Byte Field Value Description 0 cmd 0x13 APP_CMD_READ_ALL_ANALOG Response payload Byte Field Value Description 0 cmd 0x13 Echo PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 25 1 IO1_hi8 (IO1_mv >> 4) & 0xFF IO1 voltage scaled by 1/16 (resolution ≈ 16 mV) 2 IO2_hi8 (IO2_mv >> 4) & 0xFF IO2 voltage scaled by 1/16 (resolution ≈ 16 mV) 3 IO3_hi8 (IO3_mv >> 4) & 0xFF IO3 voltage scaled by 1/16 (resolution ≈ 16 mV) 4 IO4_hi8 (IO4_mv >> 4) & 0xFF IO4 voltage scaled by 1/16 (resolution ≈ 16 mV) 5 I_B1_hi8 (bridge1_ma >> 4) & 0xFF Bridge 1 current scaled by 1/16 (resolution ≈ 16 mA) 6 I_B2_hi8 (bridge2_ma >> 4) & 0xFF Bridge 2 current scaled by 1/16 (resolution ≈ 16 mA) 7 drv_fault bitfield Combined driver fault byte — see Appendix B Notes • Reconstruct the approximate millivolt / milliamp value as (byteValue << 4). The 4 LSBs of resolution are lost — for full resolution use 0x10, 0x11 or 0x12. • Use this command for fast cyclic polling where bandwidth matters; use 0x10/0x11/0x12 when you need the full 1 mV / 1 mA resolution. 0x14 — Read Peak Bridge Currents Returns the most recent ON-state (peak) current per bridge in mA, as measured at the current-sense output before the duty-cycle correction performed for 0x12. For a resistive load this should be near V_supply / R and roughly constant across duty cycles; for an inductive load it depends on PWM frequency and motor inductance. Request payload Byte Field Value Description 0 cmd 0x14 APP_CMD_READ_PEAK_CURRENTS Response payload Byte Field Value Description 0 cmd 0x14 Echo 1 B1_peak_lo uint8 Bridge 1 peak current low byte (mA) 2 B1_peak_hi uint8 Bridge 1 peak current high byte 3 B2_peak_lo uint8 Bridge 2 peak current low byte (mA) 4 B2_peak_hi uint8 Bridge 2 peak current high byte Notes • Reconstruct each value as (high << 8) | low — 16-bit little-endian unsigned milliamps. • Relationship to 0x12: at steady state, bridge_ma ≈ peak_ma · duty_bp / 10000. Reading both 0x12 and 0x14 lets a host verify the device’s internal averaging math, calibrate the current sense against a known resistive load, or distinguish resistive from inductive loads by watching whether peak stays flat as duty ramps. • When a bridge is in COAST or faulted, the peak value reports the most recent measurement (it is not zeroed); use 0x12 if you need a coast-aware reading. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 26 6.5 Driver diagnostics Each H-bridge is implemented with a integrated H-bridge driver. The chip exposes fault and status registers over SPI; these commands relay them over CAN. See Appendix B for the meaning of every bit returned by 0x20. 0x20 — Read Driver Fault Status Reads the FAULT, STATUS1 and STATUS2 registers of both driver chips after re-sampling them over SPI. Request payload Byte Field Value Description 0 cmd 0x20 APP_CMD_READ_DRV_FAULT Response payload Byte Field Value Description 0 cmd 0x20 Echo 1 DRV1.FAULT reg 0x01 DRV1 FAULT register 2 DRV1.STATUS1 reg 0x02 DRV1 STATUS1 register 3 DRV1.STATUS2 reg 0x03 DRV1 STATUS2 register 4 DRV2.FAULT reg 0x01 DRV2 FAULT register 5 DRV2.STATUS1 reg 0x02 DRV2 STATUS1 register 6 DRV2.STATUS2 reg 0x03 DRV2 STATUS2 register Notes • FAULT register bits (each chip): bit 6=FAULT, bit 5=OLA2, bit 4=OLA1, bit 3=OCP_LS2, bit 2=OCP_HS2, bit 1=OCP_LS1, bit 0=OCP_HS1. • STATUS1 register bits: bit 7=OTW, bit 6=TSD, bit 5=OCP, bit 4=VMUV, bit 3=VMOV, bit 2=ITRIP_CMP, bit 1=OLA, bit 0=FRM_ERR. • STATUS2 register bits: bit 7=OLP_CMP, bit 5=IN2_ST, bit 4=IN1_ST, bit 3=DRVOFF_ST, bit 1=OTW_ST. 0x21 — Clear Driver Faults Issues a CLR_FLT write to both driver chips, waits ~1 ms, then re-reads the FAULT register and returns the result. Request payload Byte Field Value Description 0 cmd 0x21 APP_CMD_CLEAR_DRV_FAULT Response payload Byte Field Value Description 0 cmd 0x21 Echo 1 DRV1.FAULT reg 0x01 after clear DRV1 FAULT register after the clear (should be 0 if condition is gone) 2 DRV2.FAULT reg 0x01 after clear DRV2 FAULT register after the clear Notes • Faults that are still physically present (e.g. ongoing overcurrent) will reassert immediately and remain visible in the response. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 27 0x22 — Read Driver Register Reads a single 8-bit register of a specific driver device over SPI. Request payload Byte Field Value Description 0 cmd 0x22 APP_CMD_READ_DRV_REG 1 device 0 or 1 0 = DRV1 (Bridge 1), 1 = DRV2 (Bridge 2) 2 reg_addr 0x00–0x10 driver register address — see datasheet Response payload Byte Field Value Description 0 cmd 0x22 Echo 1 device echo Echo 2 reg_addr echo Echo 3 reg_val value Register contents Notes • Addresses 0x04–0x07 are reserved in the driver and should not be read. • Common addresses: 0x00=DEVICE_ID (=0x25 for the driver), 0x01=FAULT, 0x02=STATUS1, 0x03=STATUS2, 0x08=COMMAND, 0x09=SPI_IN, 0x0A=CONFIG1, 0x0B=CONFIG2, 0x0C=CONFIG3, 0x0D=CONFIG4, 0x10=CONFIG6. • Out-of-range device indices are silently ignored (no response). 6.6 Device information 0x30 — Firmware Info Returns the firmware version of the currently running component (bootloader or application), including major.minor.patch, 16-bit build number, and the validity flag for the application image. Request payload Byte Field Value Description 0 cmd 0x30 APP_CMD_FW_INFO Response payload Byte Field Value Description 0 cmd 0x30 Echo 1 component 0=bootloader 1=application Component reporting the version 2 major uint8 Major version of running component 3 minor uint8 Minor version 4 patch uint8 Patch version 5 build_lo uint8 Build number low byte 6 build_hi uint8 Build number high byte 7 app_valid 0 or 1 1 if a valid application image is present Notes PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 28 • Response is a single classic CAN frame with DLC = 8 (1 command echo + 7 data bytes). • When component = 1 (running from the application) the returned version IS the application image version; there is no separate “application image” version field in this response. Internally the firmware also tracks the application image version separately, but it is not transmitted on the wire because classic CAN frames are limited to 8 bytes. • For a short major.minor without going through directed traffic, use the discovery IDENTIFY command (0x00) — see Section 4.5. 0x31 — Capabilities Returns a bitfield describing the optional features supported by this device, plus its bridge / IO counts. Request payload Byte Field Value Description 0 cmd 0x31 APP_CMD_CAPABILITIES Response payload Byte Field Value Description 0 cmd 0x31 Echo 1–2 caps uint16 LE bitfield Capability bitfield (see Appendix C) 3 n_bridges uint8 Number of bridges (always 2 on PoCANbridge2-15) 4 n_io uint8 Number of analog inputs (always 4) 5 adc_bits uint8 ADC resolution (always 12) Notes • On firmware 1.0.0, the device reports caps = 0x01FF — every capability bit defined in Appendix C is set. 6.7 Configuration Configuration commands modify the device’s in-RAM working settings. Use 0x44 (Save Config) to persist them to flash. The non-volatile config block stores: PWM frequency, driver register defaults, heartbeat interval index, standalone flag, failsafe configuration (both bridges + global enable + timeout + failsafe PWM and DRV register override), CAN role/baud/FD index, and blocks-runtime flags. 0x40 — Set Heartbeat Interval Selects the device heartbeat interval from the lookup table (Section 3.5). Request payload Byte Field Value Description 0 cmd 0x40 APP_CMD_SET_HB_INTERVAL 1 idx 0–15 Interval index (see Section 3.5). Out-of-range values fall back to index 0. Response payload Byte Field Value Description 0 cmd 0x40 Echo 1 idx accepted index Index actually applied (may have been clamped) 2–3 interval_ms uint16 LE Resolved interval in milliseconds PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 29 0x41 — Set Standalone Mode Enables or disables standalone mode. In standalone mode the device transitions directly to OPERATIONAL on boot without waiting for a host heartbeat. Request payload Byte Field Value Description 0 cmd 0x41 APP_CMD_SET_STANDALONE 1 enable 0 or 1 0 = wait for host, 1 = standalone Response payload Byte Field Value Description 0 cmd 0x41 Echo 1 enable 0 or 1 Standalone flag actually applied 0x42 — Set Failsafe Config (per-bridge or global) Configures the action taken by each bridge when the host is declared absent, and globally enables / disables the failsafe with an extra timeout. The first parameter byte selects between per-bridge and global modes: Request payload Byte Field Value Description 0 cmd 0x42 APP_CMD_SET_FAILSAFE 1 target 0, 1 or 0xFF 0=Bridge 1, 1=Bridge 2, 0xFF=global enable + timeout 2 param2 see below Per-bridge: action; Global: enable flag 3 param3 see below Per-bridge: DRV mode for FORWARD/REVERSE; Global: timeout_lo 4 param4 see below Per-bridge: duty_lo (basis points); Global: timeout_hi 5 param5 see below Per-bridge: duty_hi (basis points); Global: not used Response payload Byte Field Value Description 0 cmd 0x42 Echo 1 target echo Echo of bridge index or 0xFF 2 status 0x00 = OK Always 0x00 if the request validates Notes • Per-bridge action values (param2): 0=COAST, 1=BRAKE, 2=HOLD (keep current mode/duty), 3=FORWARD at the supplied duty, 4=REVERSE at the supplied duty. • Per-bridge duty is in basis points: 0–10000 = 0.00–100.00 %. Duty values above 10000 are rejected. • Global enable: param2 = 0 disables, param2 = 1 enables. Timeout (param3/param4) is the additional delay in milliseconds beyond host_timeout_ms before the failsafe action is executed. A timeout of 0 means: fire immediately when host_present transitions to false. • In a HOLD action, the duty bytes are still required by the parser but their values are ignored. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 30 0x43 — Read Failsafe Config Returns the global failsafe enable, timeout, and per-bridge action/duty. The response packs into 8 bytes; the duty of Bridge 2 is not included due to the 8-byte limit. Request payload Byte Field Value Description 0 cmd 0x43 APP_CMD_READ_FAILSAFE Response payload Byte Field Value Description 0 cmd 0x43 Echo 1 enabled 0 or 1 Global failsafe enable 2–3 timeout_ms uint16 LE Additional timeout in milliseconds 4 b1_mode 0–4 Bridge 1 action (see 0x42 notes) 5–6 b1_duty_bp uint16 LE Bridge 1 failsafe duty in basis points 7 b2_mode 0–4 Bridge 2 action (duty not included; see 0x42) 0x44 — Save Config to Flash Captures the current in-RAM settings and writes the entire non-volatile config block to flash. Settings persist across power cycles. Request payload Byte Field Value Description 0 cmd 0x44 APP_CMD_SAVE_CONFIG Response payload Byte Field Value Description 0 cmd 0x44 Echo 1 status 0x00 = OK 0x01 = flash error Save result Notes • Before writing, the device snapshots heartbeat-interval index and standalone flag from RAM into the NV config struct. PWM frequency and failsafe values are already kept in the RAM copy by their own commands. 0x45 — Factory Reset Erases the device’s NV config sector and reloads default values into RAM. Existing settings are lost. Request payload Byte Field Value Description 0 cmd 0x45 APP_CMD_FACTORY_RESET Response payload Byte Field Value Description PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 31 0 cmd 0x45 Echo 1 status 0x00 = OK 0x01 = flash error Erase result Notes • Defaults are applied to the hardware immediately. The CAN role, baud rate, and FD index are reset along with all other parameters. 0x46 — Clear Failsafe Exits a triggered failsafe state. Clears the COMM_ERROR system flag, stops the failsafe LED indication, coasts both bridges, and restores the pre-failsafe PWM / DRV register configuration. The host must then resume bridge control with normal commands. Request payload Byte Field Value Description 0 cmd 0x46 APP_CMD_CLEAR_FAILSAFE Response payload Byte Field Value Description 0 cmd 0x46 Echo 1 status 0x00 = OK Always 0x00 Notes • A device that has triggered its failsafe stays in failsafe until this command is sent — even if the host returns. The host must explicitly clear the state before resuming normal control. See Section 7. 0x47 — CAN Role (read / write) Read or change the device’s CAN role (DISABLED / MASTER / SLAVE) at runtime. Changes are applied live via the internal app_set_can_role() path — no flash save, no reboot. Use 0x44 SAVE_CONFIG afterwards if the change should persist. Request payload Byte Field Value Description 0 cmd 0x47 APP_CMD_CAN_ROLE 1 new_can_mode uint8 (opt) If present: write the new can_mode. Omit for readonly. Response payload Byte Field Value Description 0 cmd 0x47 Echo 1 current_mode uint8 0 = DISABLED, 1 = MASTER, 2 = SLAVE (after write, if any) Notes • Out-of-range new_can_mode (> 2) is silently rejected — no response. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 32 • Useful for bench tools that need to switch a device out of master mode temporarily to verify slave-side behaviour (e.g. failsafe-on-host-loss). See Section 7.4 for the master/failsafe interaction. 0x48 — CAN Baud (read / write) Read or change the nominal CAN baud rate at runtime. Writes invoke pc2_apply_can_baud() which briefly stops, reinits, and restarts the CAN controller; bit-timing segments stay constant, only the prescaler changes. Request payload Byte Field Value Description 0 cmd 0x48 APP_CMD_CAN_BAUD 1 new_baud_idx uint8 (opt) If present: write the new can_baud_idx. Response payload Byte Field Value Description 0 cmd 0x48 Echo 1 current_idx uint8 0 = 125 k, 1 = 250 k, 2 = 500 k, 3 = 1 M (after write, if any) Notes • The response is sent at the OLD baud (it leaves the TX FIFO before the reconfigure). Subsequent traffic uses the new baud. Hosts must retune their own adapter before continuing. • Out-of-range new_baud_idx (> 3) is silently rejected — no response. • No flash save — use 0x44 SAVE_CONFIG to persist. 0x49 — Soft Reboot Triggers a soft reset on the device. The firmware ACKs the request, then schedules an NVIC_SystemReset() ~100 ms later via the same pending-reboot machinery used by the web UI. Used by hosts and bench tools that need to verify boottime behaviour (e.g. confirming that a flash-saved PoLogic program is restored on boot) without power-cycling the device. Request payload Byte Field Value Description 0 cmd 0x49 APP_CMD_REBOOT Response payload Byte Field Value Description 0 cmd 0x49 Echo 1 status 0x00 ACK; the actual reset fires ~100 ms after this response leaves the bus. Notes • The device is unresponsive for approximately 2–3 seconds while it reboots; hosts should poll APP_CMD_FW_INFO (0x30) to detect when the device is back. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 33 • On reboot, any PoLogic program that was saved to flash with BLOCKS_DEPLOY_FLAG_FLASH set is restored by blocks_runtime_load() before normal operation resumes. • CAN baud and CAN role are not affected — they are read from the same NV store at boot. 6.8 Visual identification 0x50 — Visual Identify (LED effect) Triggers a ~3-second colour-cycling effect on the device’s RGB status LED. Used by host UIs to help the operator physically locate one specific device on the bus. Request payload Byte Field Value Description 0 cmd 0x50 APP_CMD_IDENTIFY Response payload Byte Field Value Description 0 cmd 0x50 Echo 1 status 0x00 = ACK 0xFF = NACK Acknowledgement 6.9 PoLogic block engine (commands 0x60 – 0x6C) PoLogic is the on-device ladder-logic / block-graph runtime — a small evaluator that walks a directed graph of blocks (gates, latches, timers, counters, math, comparators, virtual switches, I/O blocks) once per tick. A program is deployed as a compact binary blob (see Appendix F) and persists in RAM, optionally in flash. The commands in this group expose the runtime over the CAN bus; the same set is also reachable via WebSocket on the device’s web UI. Commands fall into three phases: (1) single-frame control — clear, set virtual input, clear errors, pause / resume / step; (2) multi-frame deploy — start with length + CRC, stream 6-byte chunks, commit with size + CRC validation, optionally save to flash; (3) single-frame state read — fetch one block’s flags and integer output by ID. All commands return a status byte in resp[1]; the full status enumeration is in Appendix H. Two error responses are extended beyond the standard 2-byte tail to carry diagnostic detail (received header on DEPLOY_REJECTED, runtime snapshot on NOT_FOUND for GET_BLOCK_STATE). Old masters reading only the first two bytes see the same status; new masters reading the full 8 bytes can disambiguate the failure cause without a UART probe. 0x60 — Blocks: Deploy Start Opens a multi-frame deploy session. The host announces the total payload length and a CRC-16/CCITT-FALSE over the program bytes (see Appendix G), then streams the payload via 0x6A frames and commits with 0x6B. Request payload Byte Field Value Description 0 cmd 0x60 APP_CMD_BLOCKS_DEPLOY_START 1 flags uint8 Bit 0 = BLOCKS_DEPLOY_FLAG_FLASH. When set, the loaded program is also written to NV after a successful commit and will be reloaded at the next boot. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 34 2-3 total_len uint16 LE Total length of the program in bytes (sum of all DEPLOY_DATA payload bytes that follow). Must not exceed BLOCKS_PROGRAM_MAX = 4096. 4-5 crc16 uint16 LE CRC-16/CCITT-FALSE over the entire program payload (header + blocks + wires). Response payload Byte Field Value Description 0 cmd 0x60 Echo 1 status uint8 0 = OK; 10 = DEPLOY_BUSY (another session in progress); 12 = DEPLOY_TOO_LARGE (total_len > 4096); 2 = BAD_REQUEST (DLC < 6). Notes • After OK the device holds the deploy session for up to 5 s of inactivity; missing DATA / END frames cause subsequent traffic to be treated as starting fresh and the eventual END returns DEPLOY_NO_START. • The CRC is validated at END, not on each DATA frame — this protocol assumes the CAN frame CRC catches single-bit transport errors and uses CRC-16 only to detect assembly bugs in the host. 0x61 — Blocks: Clear Clears the active runtime program and, if a program was previously saved to flash, also erases the NV slot. Idempotent — calling on an already-empty runtime returns OK. Request payload Byte Field Value Description 0 cmd 0x61 APP_CMD_BLOCKS_CLEAR Response payload Byte Field Value Description 0 cmd 0x61 Echo 1 status 0x00 Always OK. 0x65 — Blocks: Virtual Input Sets the boolean output of a POCAN_VIRT_SW block in the running program. Useful for driving inputs from a host without wiring a physical switch. Request payload Byte Field Value Description 0 cmd 0x65 APP_CMD_BLOCKS_VIRT_INPUT 1-2 id uint16 LE Editor-assigned block ID of the target POCAN_VIRT_SW. 3 state 0 / 1 0 = drive output low, 1 = drive output high. Persists across ticks until cleared or overwritten. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 35 Response payload Byte Field Value Description 0 cmd 0x65 Echo 1 status uint8 0 = OK; 1 = NOT_ACTIVE (no program loaded); 3 = NOT_FOUND (id not in program); 4 = WRONG_TYPE (block exists but is not a virtual switch); 2 = BAD_REQUEST (DLC < 4 or state not 0/1). 0x66 — Blocks: Clear Errors Clears the internal runtime error list (s_errors[], up to BLOCKS_MAX_ERRORS = 8 entries). Has no effect on the program itself. Request payload Byte Field Value Description 0 cmd 0x66 APP_CMD_BLOCKS_CLR_ERRORS Response payload Byte Field Value Description 0 cmd 0x66 Echo 1 status 0x00 Always OK (regardless of whether the list was empty). 0x67 — Blocks: Runtime Control Pause, resume, or single-step the runtime evaluator. State persists across calls until changed. Request payload Byte Field Value Description 0 cmd 0x67 APP_CMD_BLOCKS_RT_CTRL 1 subcmd 0 / 1 / 2 0 = pause; 1 = resume; 2 = single-step (executes one full tick of BLOCKS_EVAL_PASSES passes, then repauses). Response payload Byte Field Value Description 0 cmd 0x67 Echo 1 status uint8 0 = OK; 1 = NOT_ACTIVE; 2 = BAD_REQUEST (DLC < 2 or subcmd > 2). 0x6A — Blocks: Deploy Data (no response) Streams one chunk of program payload during an open deploy session. Fire-and-forget — the device does not respond per frame; sequence and length errors are reported at DEPLOY_END. Request payload PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 36 Byte Field Value Description 0 cmd 0x6A APP_CMD_BLOCKS_DEPLOY_DATA 1 seq uint8 Sequence number, starts at 0, increments by 1 per frame, wraps at 256. 2-7 payload 1–6 bytes Up to 6 program bytes. The final frame may carry fewer; the device truncates to (total_len − received_len) and ignores trailing bytes. Response payload No response. (Broadcast destinations or commands the firmware does not acknowledge.) Notes • Send frames back-to-back; the device is tested at 500 kbit/s with no inter-frame pause. If your USB-CAN adapter cannot keep up, insert a short delay between frames (see the bench’s chunk_pause_ms option). • A sequence-number mismatch silently aborts the in-progress flag; the eventual DEPLOY_END returns DEPLOY_SEQ regardless of how many frames followed. 0x6B — Blocks: Deploy End Commits the assembled program. Validates total length, CRC, and (via blocks_runtime_deploy()) the binary itself. If BLOCKS_DEPLOY_FLAG_FLASH was set at START, also writes the program to NV after a successful load. Request payload Byte Field Value Description 0 cmd 0x6B APP_CMD_BLOCKS_DEPLOY_END Response payload Byte Field Value Description 0 cmd 0x6B Echo 1 status uint8 0 = OK; 11 = DEPLOY_NO_START; 14 = DEPLOY_SIZE; 13 = DEPLOY_SEQ; 15 = DEPLOY_CRC; 16 = DEPLOY_REJECTED. See Appendix H for the full enumeration. 2 n_blocks uint8 On OK: number of blocks loaded. On REJECTED: received magic LSB (diagnostic). 3-4 n_wires uint16 LE On OK: number of wires loaded. On REJECTED: byte 3 = received magic MSB, byte 4 = received version (diagnostic). 5 flash_ok 0 / 1 On OK: 1 if flash save succeeded (or save was not requested). On REJECTED: received header num_blocks LSB (diagnostic). 6 (diag) uint8 On REJECTED only: received header num_wires LSB. Not present on OK (response is 6 bytes long). 7 (diag) uint8 On REJECTED only: received total length LSB. Notes • Response length is 6 bytes on OK and most failures, 8 bytes on DEPLOY_REJECTED — the extended tail lets a host distinguish version mismatch / bad magic / truncated stream / malformed structure without UART access. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 37 • The most common cause of DEPLOY_REJECTED is a binary version mismatch (host emitting v3 to a v4 firmware, or vice versa). The diagnostic fields will show received version != 4. 0x6C — Blocks: Get Block State Reads the primary observables of one block from the running program: its packed flags byte and the int32 at ival[0]. Polling at 50–200 ms is the recommended cadence for live inspection. Request payload Byte Field Value Description 0 cmd 0x6C APP_CMD_BLOCKS_GET_BLOCK_STATE 1-2 id uint16 LE Editor-assigned block ID. Response payload Byte Field Value Description 0 cmd 0x6C Echo 1 status uint8 0 = OK; 1 = NOT_ACTIVE; 3 = NOT_FOUND (with diagnostic tail — see Notes); 2 = BAD_REQUEST. 2 flags uint8 On OK: packed flags byte. Bits [0..3] = out[0..3] (booleans). Bits [4..6] = prev_in[0..2] (edge-detect history). Bit [7] = timer_running. On NOT_FOUND: num_blocks in the loaded program. 3-6 ival0 int32 LE On OK: b->ival[0] (primary integer output). On NOT_FOUND: byte 3-4 = blocks[0].id LE, byte 5-6 = blocks[1].id LE (or 0 if num_blocks < 2). 7 type uint8 On OK: blocks_type_t value of the block (for host-side sanity check). On NOT_FOUND: blocks[0].type. Notes • Response is 8 bytes on OK and on NOT_FOUND; 2 bytes on other errors. • For boolean-only blocks, ival[0] is 0 — the master watches bit 0 of flags. For counters and math blocks, watch ival[0] for the integer value. • The runtime updates state once per tick (~10 ms). Polling faster than that yields duplicate reads; slower than ~200 ms loses fast pulses visible to the human eye. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 38 6.10 Digital output (OUT1) OUT1 is a general-purpose digital output (hardware revision 1.1). It is controllable over CAN with the command below and identically over RS485 via holding register 0x0110 / coil 0x0000 (Section 9) — both buses drive the same pin. Output characteristics and behaviour • Pin and type — OUT1 is MCU pin PA10, configured as a push-pull CMOS output: it actively drives both states and needs no external pull-up (it is not open-drain). Logic levels are 0 V for low and 3.3 V for high. • Drive capability — this is a logic-level signal pin, not a relay or load driver. It cannot directly switch a lamp, solenoid, relay coil or motor; the current it sources or sinks must stay within the microcontroller GPIO limits given in the MCU datasheet. To switch a real load, drive an external MOSFET, transistor or relay driver from OUT1. The pin uses a low output speed (slow slew), suited to status or enable signalling rather than fast switching. • Boot / default state — OUT1 is driven LOW at power-on and after every reset, before any host command runs, and stays LOW until a host sets it. • Persistence — the live OUT1 level is volatile: it is held only on the pin and is not written to flash by Save Config (0x44). After a reboot or power cycle OUT1 returns to LOW regardless of its previous level. Only the failsafe default (Section 7.5) is stored in non-volatile configuration. • Autonomous behaviour — outside the host-loss failsafe, the firmware never changes OUT1 by itself; the pin simply reflects the last value written. The same pin is reachable three ways — CAN command 0x07, Modbus holding register 0x0110 and Modbus coil 0x0000 — and a value set on any one is immediately visible on the others. • Hardware revision — OUT1 exists only on hardware revision 1.1. On revision 1.0 the pin is not fitted: CAN command 0x07 returns no response, and Modbus register 0x0110 and coil 0x0000 return an exception. 0x07 — OUT1 Digital Output Reads or sets the OUT1 digital output. Send with no data byte to read; send one data byte to set the level. The response always reports the live pin level and the configured failsafe default. Request payload Byte Field Value Description 0 cmd 0x07 APP_CMD_OUT1 1 state 0x00 / 0x01 Optional. Omit (DLC 1) to read. 0 = low, 1 = high. Response payload Byte Field Value Description 0 cmd 0x07 Echo 1 live_state 0x00 / 0x01 Actual OUT1 pin level 2 failsafe_default 0x00 / 0x01 / 0x02 OUT1 state on failsafe: 0 = hold, 1 = low, 2 = high (Section 7.5) Notes • Hardware revision 1.1 only. On revision 1.0 the OUT1 pin is not present and the command returns no response. • Mirrors RS485 holding register 0x0110 and coil 0x0000; a value set on one bus is visible on the other. • The failsafe default is set with command 0x42 (Set Failsafe) using selector byte 0xFE — see Section 7.5. Set OUT1 high (directed payload): 07 01 -> Rsp 07 01 00 Set OUT1 low : 07 00 -> Rsp 07 00 00 Read OUT1 : 07 -> Rsp 07 PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 39 7. Host-loss Failsafe 7.1 Concept The failsafe protects connected loads when the host disappears from the bus. If failsafe is enabled (command 0x42 with target = 0xFF), the device monitors host_present and, when the host stays absent for host_timeout_ms + failsafe_timeout_ms, it executes the configured failsafe action. 7.2 Triggering Each bridge may be programmed with one of five failsafe actions, set per bridge with command 0x42: Value Symbol Action 0 NV_FS_COAST Set the bridge to COAST (high-impedance) at 0 % duty 1 NV_FS_BRAKE Set the bridge to BRAKE at 100 % duty 2 NV_FS_HOLD Keep the current mode and duty unchanged 3 NV_FS_FORWARD Drive the bridge in FORWARD direction at the configured duty (basis points) 4 NV_FS_REVERSE Drive the bridge in REVERSE direction at the configured duty (basis points) When the failsafe fires, the device additionally: • Sets the COMM_ERROR bit in the system-flags byte (visible in every heartbeat — see Section 3.3). • Activates the failsafe LED indication (alternating red/amber at 2 Hz). • Applies the configured failsafe PWM frequency (failsafe_freq_hz) if it lies in the valid 20 Hz – 100 kHz range. • Applies the configured failsafe DRV CONFIG3 / CONFIG4 register overrides (sets OCP and slew-rate to the failsafe values). 7.3 Clearing A device that has fired its failsafe stays in the failsafe state until the host explicitly clears it, even if the host returns and resumes heartbeating. The clearing sequence is: 1. Host sends command 0x46 (Clear Failsafe). The device clears the COMM_ERROR flag, stops the failsafe LED, coasts both bridges, and restores the pre-failsafe PWM / DRV register configuration. 2. The host optionally reads fault status (command 0x20). 3. The host resumes normal bridge control with commands 0x01, 0x02, etc. 7.4 Interaction with CAN role (master vs. slave) Failsafe is fundamentally a slave-side concept: it watches for the absence of host heartbeats from some other node on the bus. A device configured as CAN master (nv_cfg.can_mode = NV_CAN_MASTER) IS the host on the bus and broadcasts the host heartbeats itself — it cannot lose a host that it is. As a result, failsafe-on-host-loss can never trigger while the device is in master mode. The two settings are independent in the configuration store (the firmware accepts any combination), but only some combinations are meaningful: CAN role Failsaf e Behaviour on host loss Slave / disabled Disabl ed No automatic action; bridges continue under host control or whatever last command was received. Slave / disabled Enable d Device executes the configured per-bridge failsafe action after host_timeout_ms + failsafe_timeout_ms. Normal use case. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 40 Master Disabl ed Master continues operating; auto-takeover does not apply because the device is already the host. Master Enable d Configuration is accepted but failsafe can never fire (master is its own host). The device logs a warning at boot and on any runtime change to either field; the web UI displays a banner on the Failsafe tab. If the deployment needs both host failover and failsafe semantics, that requires a separate architecture (e.g. an external supervisor or two redundant hosts on the bus); a single device cannot fulfil both roles at once. PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 41 7.5 OUT1 digital output on failsafe When the failsafe triggers, OUT1 can be driven to a configured default state alongside the bridge failsafe actions. The default is Hold, so OUT1 is left unchanged unless configured otherwise (this preserves the prior behaviour). It is set with command 0x42 (Set Failsafe) using the OUT1 selector byte 0xFE. Value OUT1 on failsafe 0x00 Hold — leave OUT1 unchanged (default) 0x01 Drive LOW 0x02 Drive HIGH Set OUT1 failsafe default = HIGH: 42 FE 02 -> Rsp 42 FE 00 Read it back (cmd 0x07, response byte 2): 07 -> Rsp 07 02 • Like the bridges, OUT1 is not automatically restored when the failsafe clears; the host re-asserts it. • Hardware revision 1.1 only; the setting is stored in NV and persists with Save Config (0x44). 8. Worked Examples All examples below show CAN frame contents from the host’s point of view. Each frame is described by its 29-bit extended identifier (in hex), the DLC, and the payload bytes. Responses from the device are shown where relevant. 8.1 Example A — Discovery, identification, ID assignment The host wants to enumerate every device on the bus and give a specific one a known address. Step 1 — Broadcast MSB request TX ID = 0x1 4140 FFFF DLC=0 (scope=0x105, flags=0, lsb=0xFFFF) Every device on the bus replies one frame each, e.g.: RX ID = 0x1 4148 1234 DLC=0 (scope=0x105, flags=2, lsb=0x1234 = MSB) RX ID = 0x1 4148 ABCD DLC=0 (scope=0x105, flags=2, lsb=0xABCD = MSB) The host has collected MSB list = { 0x1234, 0xABCD }. Step 2 — Per-MSB LSB request TX ID = 0x1 4144 1234 DLC=0 (scope=0x105, flags=1, lsb=0x1234) RX ID = 0x1 414C 5678 DLC=0 (scope=0x105, flags=3, lsb=0x5678 = LSB) TX ID = 0x1 4144 ABCD DLC=0 RX ID = 0x1 414C 9ABC DLC=0 The host now knows two devices: 0x12345678 and 0xABCD9ABC. Step 3 — IDENTIFY each device by 32-bit ID TX ID = 0x1 4140 FFFF DLC=8 payload = 78 56 34 12 00 00 00 00 (32-bit device ID + cmd 0x00 + 3 pad bytes) RX ID = 0x1 4148 FFFF DLC=8 payload = 78 56 34 12 00 15 01 00 (echo of ID + cmd 0x00 + dev_type=0x15 + fw_major=1 + fw_minor=0) PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 42 Step 4 — Assign PoCAN v2 ID 0x0042 to that device TX ID = 0x1 4140 FFFF DLC=8 payload = 78 56 34 12 11 42 00 00 (32-bit device ID + cmd 0x11 + new_id LE = 0x0042 + pad) RX ID = 0x1 4148 FFFF DLC=8 payload = 78 56 34 12 11 42 00 00 (echo with accepted ID = 0x0042) 8.2 Example B — Drive Bridge 1 forward at 75 % Device 0x0042 has been discovered and is in OPERATIONAL state. TX ID = 0x1 41C0 0042 DLC=5 payload = 02 00 01 EC 1C (scope=0x107, flags=0, lsb=0x0042; cmd=0x02 SET_BRIDGE_FINE, bridge=0, mode=1 FORWARD, duty_bp=0x1CEC=7500 = 75.00 %) RX ID = 0x1 41C2 0042 DLC=6 payload = 02 00 01 EC 1C 00 (scope=0x107, flags=2, lsb=0x0042; echo + status=0x00 OK) 8.3 Example C — Configure failsafe and save to flash // 1. PWM frequency → 25 kHz (25000 = 0x000061A8) TX ID = 0x1 41C0 0042 DLC=5 payload = 03 A8 61 00 00 // 2. Heartbeat interval → 100 ms (index 8) TX ID = 0x1 41C0 0042 DLC=2 payload = 40 08 // 3. Disable standalone mode TX ID = 0x1 41C0 0042 DLC=2 payload = 41 00 // 4. Bridge 1 → BRAKE on host loss TX ID = 0x1 41C0 0042 DLC=6 payload = 42 00 01 03 10 27 (cmd=0x42, bridge=0, action=BRAKE, DRV_MODE_BRAKE=3, duty=10000=0x2710) // 5. Bridge 2 → REVERSE at 20 % on host loss TX ID = 0x1 41C0 0042 DLC=6 payload = 42 01 04 02 D0 07 (cmd=0x42, bridge=1, action=REVERSE, DRV_MODE_REVERSE=2, duty=2000=0x07D0) // 6. Globally enable failsafe with 0 ms extra timeout TX ID = 0x1 41C0 0042 DLC=5 payload = 42 FF 01 00 00 // 7. Save to flash TX ID = 0x1 41C0 0042 DLC=1 payload = 44 RX ID = 0x1 41C2 0042 DLC=2 payload = 44 00 // OK 8.4 Example D — Failsafe recovery after host returns The host has reconnected after a network drop. Device 0x0042 is still in failsafe state (COMM_ERROR set in heartbeats, bridges in their failsafe positions). // 1. Clear failsafe TX ID = 0x1 41C0 0042 DLC=1 payload = 46 RX ID = 0x1 41C2 0042 DLC=2 payload = 46 00 // OK PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 43 // 2. Read DRV faults to make sure hardware is healthy TX ID = 0x1 41C0 0042 DLC=1 payload = 20 RX ID = 0x1 41C2 0042 DLC=7 payload = 20 00 00 00 00 00 00 // 3. Resume — Bridge 1 forward at 50 % TX ID = 0x1 41C0 0042 DLC=5 payload = 02 00 01 88 13 (duty=5000=0x1388 → 50.00 %) 8.5 Example E — Deploy a PoLogic program and observe it The host deploys a minimal two-block program (a virtual switch wired to a NOT gate), saves it to flash, drives the switch, and reads back the inverted output. The 90-byte binary payload below is the wire format described in Appendix F: a 12- byte header with version=4, magic=0x5042 (“PB”), num_blocks=2, num_wires=1, followed by two 36-byte block records and one 6-byte wire record. // 1. DEPLOY_START — flags=0x01 (save to flash), // total_len=90 (0x5A 00 LE), // crc16=0xD755 (precomputed from the 90 program bytes) TX ID = 0x1 41C0 0042 DLC=6 payload = 60 01 5A 00 55 D7 RX ID = 0x1 41C2 0042 DLC=2 payload = 60 00 // OK, session open // 2. DEPLOY_DATA — 15 frames of 6 bytes each (90 / 6 = 15) TX ID = 0x1 41C0 0042 DLC=8 payload = 6A 00 42 50 04 00 02 00 TX ID = 0x1 41C0 0042 DLC=8 payload = 6A 01 01 00 00 00 00 00 TX ID = 0x1 41C0 0042 DLC=8 payload = 6A 02 00 00 00 00 01 00 … (12 more frames carrying the rest of the payload) … TX ID = 0x1 41C0 0042 DLC=8 payload = 6A 0E 00 00 00 00 01 00 (no per-frame response) // 3. DEPLOY_END — commit, validate, save to flash TX ID = 0x1 41C0 0042 DLC=1 payload = 6B RX ID = 0x1 41C2 0042 DLC=6 payload = 6B 00 02 01 00 01 (status=OK, n_blocks=2, n_wires=1, flash_ok=1) // 4. Drive the virtual switch (block id=1) HIGH TX ID = 0x1 41C0 0042 DLC=4 payload = 65 01 00 01 RX ID = 0x1 41C2 0042 DLC=2 payload = 65 00 // OK // 5. Read state of the NOT gate (block id=2) — Q should be LOW TX ID = 0x1 41C0 0042 DLC=3 payload = 6C 02 00 RX ID = 0x1 41C2 0042 DLC=8 payload = 6C 00 00 00 00 00 00 07 (status=OK, flags=0x00 → out0=0, ival0=0, type=7=NOT) // 6. Drive the virtual switch LOW TX ID = 0x1 41C0 0042 DLC=4 payload = 65 01 00 00 RX ID = 0x1 41C2 0042 DLC=2 payload = 65 00 // OK // 7. Re-read NOT gate — Q should now be HIGH TX ID = 0x1 41C0 0042 DLC=3 payload = 6C 02 00 RX ID = 0x1 41C2 0042 DLC=8 payload = 6C 00 01 00 00 00 00 07 (status=OK, flags=0x01 → out0=1, ival0=0, type=7=NOT) // 8. (Optional) Soft-reboot — flash-saved program should restore TX ID = 0x1 41C0 0042 DLC=1 payload = 49 RX ID = 0x1 41C2 0042 DLC=2 payload = 49 00 // ACK; reset in ~100 ms (device unresponsive for 2–3 s; poll 0x30 FW_INFO to detect return) PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 44 PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 45 PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 46 9. RS485 / Modbus RTU Interface 9.1 Overview In addition to the PoCAN v2 CAN protocol described in Sections 1–8, the PoCANbridge2-15 exposes a second, independent control interface: a Modbus RTU slave on its RS485 port. The two interfaces act on the same underlying application state — the same two H-bridges, the same four analog inputs, the same driver fault summary, and the same non-volatile configuration store — so a value written over one bus is immediately visible on the other. The RS485 transceiver is fitted on hardware revision 1.1. On revision 1.0 the RS485 path is not functional and this interface is unavailable; the CAN capability bitfield (command 0x31, Appendix C) advertises RS485 presence via APP_CAP_RS485 (bit 3). RS485 configuration (address, baud, frame format) is performed over the RS485/Modbus interface itself using the configuration registers in Section 9.7.4; there is no CAN command for it. The slave implements a deliberately compact subset of Modbus RTU — no library, one flat 16-bit register space plus small coil and discrete-input spaces — sufficient for full motor, IO, diagnostics and configuration control. Function codes 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0F, 0x10 and 0x11 are supported. 9.2 Physical layer and wiring Parameter Value Standard Modbus RTU over RS485 (EIA-485), 2-wire half-duplex Peripheral UART (hardware revision 1.1 only) Signals TX = PB10, RX = PB1, driver-enable DE = PB14 (hardware-controlled) Direction control Automatic via UART DE output, active HIGH; no host action required Default settings 19200 baud, 8 data bits, even parity, 1 stop bit (8E1), slave address 1 Selectable baud rates 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 bit/s Selectable frame formats 8E1, 8O1, 8N2, 8N1 Termination 120 Ω across A/B at each end of the bus (external) Bias Fail-safe bias resistors recommended on long or multi-drop runs RS485 lines are conventionally labelled A (non-inverting, D+) and B (inverting, D−) plus a common ground. Connect the device A to bus A, device B to bus B, and share grounds. When using a typical USB-RS485 adapter (for example an FT232RL / “HW-157”), set its mode jumper to RS485 and wire adapter A → device A, adapter B → device B, GND → GND. If the device does not respond, swap the two data leads — a reversed A/B pair is the most common wiring fault and causes complete silence rather than corrupted data. 9.3 Frame format, CRC and timing Every Modbus RTU frame is: slave address (1 byte) + PDU (function code + data) + CRC-16 (2 bytes). The device replies to a request addressed to its own slave address; a request to address 0 is a broadcast (see Section 9.4). CRC-16 parameters Parameter Value Polynomial 0xA001 (reflected 0x8005) Initial value 0xFFFF Reflection Input and output reflected Final XOR none Byte order on the wire low byte first, then high byte (little-endian) End-of-frame detection (t3.5) The slave detects the end of a frame from an idle gap on the line, per the Modbus specification: 3.5 character times at baud rates up to and including 19200, and a fixed 1.75 ms above 19200 (the specification’s high-baud rule, so frames are PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 47 neither split nor merged). No master-side action is required, but be aware the required inter-frame quiet time is roughly 1.75 ms at 38400 and above, and proportionally longer at lower baud rates. A master should leave at least this much idle time between transactions. Limit Value Max registers per FC03/FC04/FC16 transaction 32 Max coils / discrete inputs per FC01/FC02/FC0F transaction 64 Frame integrity Frames failing CRC are silently ignored (no reply) 9.4 Addressing and defaults Item Value Slave address range 1 – 247 Default slave address 1 Broadcast address 0 — every device applies the write; no reply is sent Default baud / format 19200 / 8E1 A write addressed to slave 0 (broadcast) is executed by the device but produces no response, exactly as the Modbus standard requires. Read function codes sent to the broadcast address are ignored. Device-type code The CAN IDENTIFY command (Section 4.5) reports a single-byte device-type 0x15. The Modbus interface reports a 16-bit device type 0x0215, both in the device-type register (0x0010) and in the Report Slave ID response (Section 9.10). The 16- bit form encodes the product family in the high byte and the variant in the low byte: 0x02 = PoCANbridge2 family, 0x15 = the “-15” variant. The two values are consistent — the low byte of the Modbus code equals the CAN code. 9.5 Supported function codes Code Function Request Response 0x01 Read Coils start, quantity byte count + packed bits 0x02 Read Discrete Inputs start, quantity byte count + packed bits 0x03 Read Holding Registers start, quantity byte count + register values 0x04 Read Input Registers (alias of 0x03) start, quantity byte count + register values 0x05 Write Single Coil address, 0xFF00 / 0x0000 echo of request 0x06 Write Single Register address, value echo of request 0x0F Write Multiple Coils start, quantity, bytes start, quantity 0x10 Write Multiple Registers start, quantity, bytes start, quantity 0x11 Report Slave ID (none) identity payload (Section 9.10) Function codes 0x03 and 0x04 address the same flat register space; either may be used to read any holding register. Any other function code returns exception 0x01 (Section 9.6). 9.6 Exception responses When the device cannot fulfil a request it returns a Modbus exception: the response function code is the request code with the high bit set (code | 0x80), followed by a one-byte exception code. Frames that fail CRC, or that are addressed to another slave, produce no reply at all rather than an exception. Code Name Meaning in this device 0x01 Illegal Function Unsupported function code. 0x02 Illegal Data Address Unmapped register/coil address, or a write to a read-only register (inputs, device info, commit status). PoCANbridge2-15 | API reference 23. 06. 2026, Volavlje 30, 1000 Ljubljana 48 0x03 Illegal Data Value Value out of range (e.g. duty > 10000, mode > 3, address not 1–247, baud index > 7, format > 3), a quantity of 0 or above the per-transaction limit, a non-coast motion command while the drive interlock is disabled, or a confirm register written with the wrong magic. 0x04 Device Failure Reserved for an internal failure; not normally returned. 9.7 Holding-register map All holding registers are 16-bit. Read with FC03 or FC04; write with FC06 (single) or FC16 (multiple). Writes to read-only registers return exception 0x02. The map is grouped into four blocks: read-only inputs, read-only device information, read/write control, and read/write configuration.
Documents / Resources
![]() | PoCANbridge2-15 Device API Reference |
References
- pologic.pypologic.py
- User Manualmanual.tools

