RP2040 Multi-Bus Adaptor Firmware

This page details the firmware which runs on RP2040-based multi-bus adaptor boards. When running, the firmware listens to the UART hosted by the RP2040’s USB connection for the following commands and for read/write indicators.

'A matrix display client and the CPU activity display example running on a Raspberry Pi 400'

The current version is 1.2.1. Read the release notes.

The buses currently supported:

Caution

Build the firmware with Pico SDK 1.5.0 or above.

Processing Incoming Data

The first received byte is checked by the firmware. If the value is less than 0x80, the code checks for a command, otherwise it processes the bytes as a read or write operation.

Generic Commands

Command

Arguments

Description

#

Set the bus-host’s current mode

?

Get bus-host device info

*

{1|0}

Set the bus-host’s LED state1

!

Respond to connection request

$

Get last device error. Returns an error code byte

1 If SHOW_HEARTBEAT is not defined in CmakeLists.txt, this call will respond with an ERR signal.

I²C Commands

Command

Arguments

Description

c

{bus_index}
{SDA_pin}
{SCL_pin}

Configure the I²C bus. This must be performed before the bus is
initialised. The first argument is 0 or 1; only bit 0 is checked.
The other args are 8-bit values

1

Set I²C bus frequency to 100kHz

4

Set I²C bus frequency to 400kHz

i

Initialise the I²C bus for use

x

Reset the I²C bus

p

Manually issue an I²C STOP signal

s

{bitfield}2

Start an I²C read or write operation targeting a specific device

d

Scan the I²C bus for devices. If the bus is not initialised when this
command is issued, it will be initialised automatically with default
values

2 Bits 7 through 1 are the target device’s I²C address. Bit 0 is the operation required: 1 for read, 0 for write.

1-Wire Commands

Command

Arguments

Description

c

{data_pin}

Configure the 1-Wire bus’ data pint. This must be performed before the bus is
initialised

i

Initialise the 1-Wire bus for use and discover devices

x

Reset the 1-Wire bus

d

Scan the 1-Wire bus for devices. If the bus is not initialised when this
command is issued, it will be initialised automatically with default
values

GPIO Commands

Command

Arguments

Description

g

{bitfield}

Set or get a GPIO pin. The pins can’t be those already used for buses

Command Responses

Commands are acknowledged with an ACK (0x0F) or an ERR (0xF0). Note that these values may change.

Commands that return arbitrary amounts of data append the data with \r\n as an end-of-sequence marker.

Modes

The multi-bus adaptor starts up in I²C mode, ie. ready for I²C operations. To switch to 1-Wire mode, send the # command followed by a character byte indicating the required mode.

Mode

Code

LED Colour

I²C

'i'

Cyan

1-Wire

'o'

Yellow

None

N/A

Red

Selecting a mode affects a number of operations, including device scans, info requests, reads, writes and bus initialisations.

The Adaptor’s Initial Response

Client code should first issue the connect request command, !.

In versions prior to 1.2.0, the response to this command would be four bytes: OK\r\n, or 4F4B0D0A in hex integers. From version 1.2.0, the adaptor continues to return four bytes, but now the final two bytes are, respectively, the adaptor’s firmware major and minor version numbers: 4F4B0102. Only four bytes are issued, so your code need not check for \r\n.

This data can be used to ensure the adaptor firmware is up to date and to determine what features are supported. For example, if an adaptor responds with OK\r\n, the client knows the firmware is less than 1.2.0 so it should not attempt to access 1-Wire functionality.

Read and Write Operations

The outcome depends on the value of the first byte in the sequence.

If the value is in the range 0x80 to 0xBF, it is a read operation and the number of bytes to read is given by: value - 0x80 + 1.

If the value is in the range 0xC0 to 0xFF, it is a write operation and the number of bytes to write is given by: value - 0xC0 + 1. These bytes follow the state byte.

Only 64 bytes can be requested/written at a time. This is usually sufficient, but for larger amounts, issue subsequent requests for 64 bytes or less.

GPIO

You configure a GPIO pin, or read its value, by issuing the g command followed by up to two bytes of data to indicate the target pin and the desired operation. The first byte is formatted as follows:

Bit

Role

0-4

The GPIO pin number, 0-31

5

Is the operation a read (1)?

6

Is the pin an output (1) or input (0)?

7

The pin’s state: high (1) or low (0)

For example, to configure pin 11 to a digital output initially set to logic High, you would pass 0xCB, ie. 11001011.

To configure pin 24 as an input, send 0x58, or 01011000. To subsequently read the pin’s value, send 0x38, or 00111000.

The adaptor will respond with ACK or ERR on all configuration, or output state setting operations.

Read operations will return the value read as an 8-bit integer.

Device Scan Format

Requesting a peripheral device scan by issuing the d command in I²C mode returns is a string of I²C addresses separated by full-stops. Each address is a 7-bit value encoded as two-digit hex numbers.

If the adaptor is in 1-Wire mode, the returned string comprises 16 hex pairs for each included 1-Wire device. This is the 1-Wire device’s unique 64-bit ID.

Both strings are terminated by \r\n.

If no peripherals are present, Z\r\n is returned whatever mode is selected.

Adaptor Information Format

Requesting adaptor information by issuing the ? command returns a sequence of integers and strings separated by full stops and followed by \r\n. The sequence of fields is bus dependent.

For I²C mode:

Field

Size

Notes

Is I²C ready?

2

Binary value: 1 == true, 0 == false

Is I²C being used?

2

Binary value: 1 == true, 0 == false

I²C bus ID

2

1 or 0

I²C SDA pin

2-3

0-31 in decimal form

I²C SCL pin

2-3

0-31 in decimal form

I²C bus frequency

2

1 (100kHz) or 4 (400kHz)

I²C address

2-4

8-127 in decimal form

Firmware version

6-12

Major, minor and patch values as separate fields

Firmware build

2-4

1-999

Unique RP20240 ID

17

16-byte value as two-digit hex values

Board type

2-17

Per board ID string, eg. RP-PI-PICO

For 1-Wire mode:

Field

Size

Notes

Is 1-Wire ready?

2

Binary value: 1 == true, 0 == false

1-Wire data pin

2-3

0-31 in decimal form

Firmware version

6-12

Major, minor and patch values as separate fields

Firmware build

2-4

1-999

Unique RP20240 ID

17

16-byte value as two-digit hex values

Board type

2-17

Per board ID string, eg. RP-PI-PICO

Note Size includes the post-value separator.

Error Codes

The following errors are defined in the file errors.h:

Error

Code

GEN_NO_ERROR

0x00

GEN_UNKNOWN_MODE

0x01

GEN_UNKNOWN_COMMAND

0x02

GEN_LED_NOT_ENABLED

0x03

GEN_CANT_CONFIG_BUS

0x04

GEN_CANT_GET_BUS_INFO

0x05

I2C_NOT_READY

0x20

I2C_NOT_STARTED

0x21

I2C_COULD_NOT_WRITE

0x22

I2C_COULD_NOT_READ

0x23

I2C_ALREADY_STOPPED

0x24

The format is as follows:

  • Bits 6-8 — The mode.

  • Bits 1-5 — A mode-specific error code.

Mode

Mode Bits

General

000

I²C

001

SPI

010

UART

011

1-Wire

100

GPIO

101

Reserved

111

Source code

The multi-bus adaptor firmware source code can be found in this GitHub repo.

Build and Deploy the Adaptor Firmware

Note

The following assumes you have the Pico SDK installed on your build machine and that the PICO_SDK_PATH environment variable is set.

  1. Clone the repo.

  2. Navigate to the repo directory.

  3. Run cmake -S . -B firmwarebuild.

  4. Run cmake --build firmwarebuild.

  5. Write the firmware depending on which board you are using:

    • ./deploy.sh /path/to/device firmwarebuild/firmware/pico/firmware_pico_rp2040.uf2

    • ./deploy.sh /path/to/device firmwarebuild/firmware/qtpy/firmware_qtpy_rp2040.uf2

    • ./deploy.sh /path/to/device firmwarebuild/firmware/promicro/firmware_promicro.uf2

    • ./deploy.sh /path/to/device firmwarebuild/firmware/tiny/firmware_tiny2040.uf2

    • ./deploy.sh /path/to/device firmwarebuild/firmware/trinkey/firmware_trinkey2040.uf2

The deploy script tricks the RP2040-based board into booting into disk mode, then copies over the newly build firmware. When the copy completes, the RP2040 automatically reboots. This saves of a lot of tedious power-cycling with the BOOT button held down.

Supported Boards