I²C Support

This page details the I²C driver and client-code that makes use of it.

The current version is 1.3.0. Read the release notes.

The I²C driver is located in the repo’s /client/i2c directory. It depends on the Depot serial driver and utility libraries, which are found in the repo’s /client/common directory. Consult the header files for details of the public functions.

The driver enables the following client apps. You can find the source code for these apps in the /client directory.

cli2c

cli2c has the the following syntax:

cli2c {device_port} [command] ... [command]

Note

Arguments in braces { } are required; those in square brackets [ ] are optional.

  • device_port is the USB-connected I²C host’s Unix device path.
    On a Mac, this will be something like /dev/cu.usbmodem-101.
    On a Raspberry Pi or other Linux b, this will be /dev/ttyACM0.

  • [command] is an optional command block, comprising a single-character command and any required data as described in the following table.

Command

Args

Description

c

{bus} {sda_pin} {scl_pin}

Choose the host’s I²C bus (0 or 1) and the SDA and
SCL pins by their RP2040 GPIO number.
Defaults are board-specific and shown below.
You must select a bus before initialising it

f

{frequency}

The I²C bus frequency in multiples of 100kHz.
Supported values: 1 and 4

z

Initialise the target I²C bus. The bus is not initialised
at startup

w

{address} {data_bytes}

Write the supplied data to the I²C device at address.
data_bytes are comma-separated 8-bit hex values.
For example: 0x4A,0x5C,0xFF

r

{address} {count}

Read count bytes from the I²C device at address
and issue an I²C STOP

p

Issue an I²C STOP. Usually used after multiple writes

x

Reset the I²C bus

s

Display devices on the I²C bus.
Note This will initialise the bus if it is not
already initialised

i

Display I²C host device information

g

{pin} {hi\|lo\|r} {in\|out}

Set a GPIO pin

l

{on\|off}

Turn the I²C Host LED on or off

h

Display help information

Error and Data Output

All message output is routed via stderr. All data read back from a device is output to stdout so it can be captured to a file. Returned data is currently presented as hexadecimal strings. For example:

cli2c /dev/cu.usbmodem-101 r 0x18 16 > data.bin
cat data.bin
A0FF123B5C5FAA5F010304

Device Defaults

Board

I2C Bus

SDA Pin

SCL Pin

Pico

1

2

3

QTpy

1

22 (26)

23 (27)

Trinkey

0

16

17

ProMicro

1 (0)

2 (16) 3 (17)

Tiny

1

6

7

Nano

0

0

1

Note

The QTpy and ProMicro both have a STEMMA-QT port as well as pins. The values in brackets are the bus and pins used when the STEMMA-QT is set to be the default. This can be done uncommenting the set(USE_STEMMA 1) line in the board’s CMakeLists.txt file. But don’t forget that you can use the c command to choose an alternative I²C bus and pins.

GPIO

You can use cli2c to set a GPIO pin. Provide the GPIO number and its initial state (hi or lo) and its mode: whether it is an input or output (in or out).

Setting a pin to an output immediately sets its state to the provided value. To change the state, just pass in the opposite value. There’s no need to specify its mode again unless you wish to change it.

cli2c /dev/cu.usbmodem-101 10 hi out
cli2c /dev/cu.usbmodem-101 10 lo

Setting a pin to an input does nothing immediately, and the supplied state value is ignored unless it is r, for read. To read an input pin, pass r in place of a state: cli2c will output the pin’s current value as a two-digit hex number:

cli2c /dev/cu.usbmodem-101 10 lo in
cli2c /dev/cu.usbmodem-101 10 r 1

Again, you don’t need to restate the pin’s mode unless you’re changing it.

matrix

matrix is a specific driver for HT16K33-based 8x8 LED matrices. Use it with this command-line call:

matrix {device} [I2C address] [commands]

Note

Arguments in braces { } are required; those in square brackets [ ] are optional.

  • {device} is the path to the multi-bus adaptor, eg. /dev/cu.usbserial-DO029IEZ.

  • [I2C address] is an optional I²C address. By default, the HT16K33 uses the address 0x70.

  • [commands] are a sequence of command blocks as described below.

Command

Arguments

Description

a

[on\|off]

Activate or deactivate the display.
Once activated, the matrix will remain
so for as long as it is powered.
Pass on (or 1) to activate, off (or 0) to deactivate.
Calling without an argument is a de facto activation

b

{0-15}

Set the brightness to a value between
0 (low but not off) and 15 (high)

c

{ascii_code} [true\|false]

Plot the specified character, by code, on the display.
If the second argument is included
and is true (or 1), the character
will be centred on the display

g

{hex_values}

Plot a user-generated glyph on the display. The glyph
is supplied as eight comma-separated 8-bit hex values,
eg. 0x3C,0x42,0xA9,0x85,0x85,0xA9,0x42,0x3C

p

{x} {y} [1\|0]

Plot a point as the co-ordinates {x,y}.
If the third argument is 1 (or missing), the pixel will
be set; if it is 0, the pixel will be cleared

t

{string} [delay]

Scroll the specified string.
The second argument is an optional delay between
column shifts in milliseconds. Default: 250ms

w

Clear the screen

r

{angle}

Rotate the display by the specified multiple of 90 degrees

h

Display help information

Multiple commands can be issued by sequencing them at the command line. For example:

matrix /dev/cu.usbserial-DO029IEZ 0x71 w r 3 p 0 0 p 1 1 p 2 2 p 3 3 p 4 4 p 5 5 p 6 6 p 7 7

Note

The client-side display buffer is not persisted across calls to matrix, so building up an image across calls will not work. While the display retains its own image data, the local buffer is implicitly cleared with each new call. This may be mitigated in a future release.

Examples

Draw a dot at 1,1

matrix /dev/cu.usbserial-DO029IEZ p 1 1

Draw T, centred

matrix /dev/cu.usbserial-DO029IEZ c 123 true

Draw a smiley

matrix /dev/cu.usbserial-DO029IEZ g 0x3C,0x42,0xA9,0x85,0x85,0xA9,0x42,0x3C

Scroll “Hello, World!” across the display

matrix /dev/cu.usbserial-DO029IEZ t "Hello, World!    "

Note

The four spaces (two matrix columns each) ensure the text disappears of the screen at the end of the scroll.

segment

segment is a specific driver for HT16K33-based 4-digit, 7-segment LEDs. Use it with this command-line call:

segment {device} [I2C address] [commands]

Note

Arguments in braces {} are required; those in square brackets \[\] are optional.

  • {device} is the path to the multi-bus adaptor’s device file, eg. /dev/cu.usbserial-DO029IEZ.

  • [I2C address] is an optional I²C address. By default, the HT16K33 uses the address 0x70.

  • [commands] are a sequence of command blocks as described below.

Command

Arguments

Description

a

[on\|off]

Activate or deactivate the display.
Once activated, the matrix will
remain so for as long as it is powered.
Pass on (or 1) to activate, off (or 0)
argument is a de facto activation

b

{0-15}

Set the brightness to a value between
0 (low but not off) and 15 (high)

f

Flip the display vertically.
Handy if your LED is mounted upside down

g

{definition} {digit} [true\|false]

Write a user-generated glyph on the display
at the specified digit.
The glyph is supplied as an 8-bit
value comprising bits set for the
segments to be lit. Optionally
specify if its decimal point
should be lit

v

{value} {digit} [true\|false]

Write a single-digit number (0-9, 0x0-0xF)
on the display at the specified digit.
Optionally specify if its decimal point
should be lit

c

{char} {digit} [true\|false]

Write the character on the display at
the specified digit. Only the
following characters can be used:
0-9, a-f, -, space (use ' ') and
the degree symbol (used '*')
Optionally specify if its decimal point
should be lit

n

{number}

Write a number between -999 and 9999
across the display

k

Light the segment’s central colon symbol

w

Clear the screen

z

Write the buffer to the screen immediately

h

Display help information

Multiple commands can be issued by sequencing them at the command line. For example:

segment /dev/cu.usbserial-DO029IEZ 0x71 w f n 7777

Note

The display buffer is not persisted across calls to segment, so building up an image across calls will not work. While the display retains its own image data, the local buffer is implicitly cleared with each new call. This may be mitigated in a future release.

Examples

Draw 42.4 degrees

segment /dev/cu.usbserial-DO029IEZ n 4240 d 1 c '*' 3