Unit Chain Bus

BusChainUnit is the helper class for Bus devices on the Chain bus. It provides methods to configure GPIO pins (input, output, external interrupt), read ADC values, and communicate with I2C devices. The class supports multiple work modes including GPIO output, GPIO input, external interrupt, ADC, and I2C.

Support the following products:

Unit Chain Bus

UiFlow2 Example

GPIO control

Open the m5basic_unit_chain_bus_gpio_example.m5f2 project in UiFlow2.

This example demonstrates how to configure and use GPIO pins with the Unit Chain Bus module. The example configures GPIO1 as input mode with pull-up, and GPIO2 as output mode with push-pull configuration. It continuously reads GPIO1 input value every 200ms and displays the state (HIGH/LOW) on screen. GPIO2 output level toggles every 1 second (every 5 cycles) between HIGH and LOW, demonstrating output control functionality.

UiFlow2 Code Block:

m5basic_unit_chain_bus_gpio_example.png

Example output:

None

ADC reading

Open the m5basic_unit_chain_bus_adc_example.m5f2 project in UiFlow2.

This example demonstrates how to read ADC values from the Unit Chain Bus module and use them to control RGB brightness.

UiFlow2 Code Block:

m5basic_unit_chain_bus_adc_example.png

Example output:

None

I2C device communication

Open the m5basic_unit_chain_bus_i2c_dlight_example.m5f2 project in UiFlow2.

This example demonstrates how to use the Unit Chain Bus module to communicate with I2C devices. The example shows how to configure the bus for I2C mode and use it with I2C devices like the DLight sensor.

UiFlow2 Code Block:

m5basic_unit_chain_bus_i2c_example.png

Example output:

None

MicroPython Example

GPIO control

This example demonstrates how to configure and use GPIO pins with the Unit Chain Bus module. The example configures GPIO1 as input mode with pull-up, and GPIO2 as output mode with push-pull configuration. It continuously reads GPIO1 input value every 200ms and displays the state (HIGH/LOW) on screen. GPIO2 output level toggles every 1 second (every 5 cycles) between HIGH and LOW, demonstrating output control functionality.

MicroPython Code Block:

  1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
  2#
  3# SPDX-License-Identifier: MIT
  4
  5import os, sys, io
  6import M5
  7from M5 import *
  8from chain import ChainBus
  9from chain import BusChainUnit
 10import time
 11
 12
 13title = None
 14label_gpio1 = None
 15label_tip1 = None
 16label_tip2 = None
 17label_gpio2 = None
 18bus2 = None
 19unit_chain_bus_0 = None
 20last_time = None
 21gpio1_value = None
 22cnt = None
 23gpio2_value = None
 24
 25
 26def setup():
 27    global \
 28        title, \
 29        label_gpio1, \
 30        label_tip1, \
 31        label_tip2, \
 32        label_gpio2, \
 33        bus2, \
 34        unit_chain_bus_0, \
 35        last_time, \
 36        gpio1_value, \
 37        cnt, \
 38        gpio2_value
 39
 40    M5.begin()
 41    Widgets.setRotation(1)
 42    Widgets.fillScreen(0x222222)
 43    title = Widgets.Title(
 44        "Unit Chain Bus Example: GPIO", 3, 0xFFFFFF, 0x0000FF, Widgets.FONTS.DejaVu18
 45    )
 46    label_gpio1 = Widgets.Label(
 47        "GPIO1 Value: --", 10, 85, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18
 48    )
 49    label_tip1 = Widgets.Label(
 50        "Unit Chain Bus GPIO1: Input", 10, 55, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18
 51    )
 52    label_tip2 = Widgets.Label(
 53        "Unit Chain Bus GPIO2: Output", 10, 136, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18
 54    )
 55    label_gpio2 = Widgets.Label(
 56        "GPIO2 Value: --", 10, 165, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18
 57    )
 58
 59    bus2 = ChainBus(2, tx=21, rx=22)
 60    unit_chain_bus_0 = BusChainUnit(bus2, 1)
 61    unit_chain_bus_0.set_gpio_input(1, BusChainUnit.GPIO_PULL_UP)
 62    unit_chain_bus_0.set_gpio_output(2, BusChainUnit.GPIO_MODE_PUSHPULL, BusChainUnit.GPIO_PULL_UP)
 63    if (unit_chain_bus_0.get_work_mode(1)) == (BusChainUnit.WORK_MODE_GPIO_INPUT):
 64        print("set gpio1 as gpio input success")
 65    else:
 66        print("set gpio1 as gpio input failed")
 67    if (unit_chain_bus_0.get_work_mode(2)) == (BusChainUnit.WORK_MODE_GPIO_OUTPUT):
 68        print("set gpio2 as gpio output success")
 69    else:
 70        print("set gpio2 as gpio output failed")
 71    unit_chain_bus_0.set_rgb_color(0x000099)
 72
 73
 74def loop():
 75    global \
 76        title, \
 77        label_gpio1, \
 78        label_tip1, \
 79        label_tip2, \
 80        label_gpio2, \
 81        bus2, \
 82        unit_chain_bus_0, \
 83        last_time, \
 84        gpio1_value, \
 85        cnt, \
 86        gpio2_value
 87    M5.update()
 88    if (time.ticks_diff((time.ticks_ms()), last_time)) >= 200:
 89        last_time = time.ticks_ms()
 90        gpio1_value = unit_chain_bus_0.get_gpio_input_value(1)
 91        if gpio1_value:
 92            label_gpio1.setText(str("GPIO1 Value:  HIGH"))
 93        else:
 94            label_gpio1.setText(str("GPIO1 Value:  LOW"))
 95        cnt = (cnt if isinstance(cnt, (int, float)) else 0) + 1
 96        if cnt >= 5:
 97            cnt = 0
 98            gpio2_value = not gpio2_value
 99            if gpio2_value:
100                unit_chain_bus_0.set_gpio_output_value(2, 1)
101                label_gpio2.setText(str("GPIO2 Value:  HIGH"))
102            else:
103                unit_chain_bus_0.set_gpio_output_value(2, 0)
104                label_gpio2.setText(str("GPIO2 Value:  LOW"))
105
106
107if __name__ == "__main__":
108    try:
109        setup()
110        while True:
111            loop()
112    except (Exception, KeyboardInterrupt) as e:
113        try:
114            bus2.deinit()
115            from utility import print_error_msg
116
117            print_error_msg(e)
118        except ImportError:
119            print("please update to latest firmware")

Example output:

None

ADC reading

This example demonstrates how to read ADC values from the Unit Chain Bus module and use them to control RGB brightness.

MicroPython Code Block:

 1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
 2#
 3# SPDX-License-Identifier: MIT
 4
 5import os, sys, io
 6import M5
 7from M5 import *
 8from chain import ChainBus
 9from chain import BusChainUnit
10import time
11import m5utils
12
13
14title = None
15label_adc = None
16label_tip = None
17bus2 = None
18unit_chain_bus_0 = None
19last_time = None
20adc_value = None
21
22
23def setup():
24    global title, label_adc, label_tip, bus2, unit_chain_bus_0, last_time, adc_value
25
26    M5.begin()
27    Widgets.setRotation(1)
28    Widgets.fillScreen(0x222222)
29    title = Widgets.Title(
30        "Unit Chain Bus Example: ADC", 3, 0xFFFFFF, 0x0000FF, Widgets.FONTS.DejaVu18
31    )
32    label_adc = Widgets.Label(
33        "ADC Value: --", 10, 85, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18
34    )
35    label_tip = Widgets.Label(
36        "Unit Chain Bus GPIO1: ADC", 10, 55, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18
37    )
38
39    bus2 = ChainBus(2, tx=21, rx=22)
40    unit_chain_bus_0 = BusChainUnit(bus2, 1)
41    unit_chain_bus_0.set_adc(1)
42    if (unit_chain_bus_0.get_work_mode(1)) == (BusChainUnit.WORK_MODE_ADC):
43        print("set gpio1 as adc input success")
44    else:
45        print("set gpio1 as adc input failed")
46    unit_chain_bus_0.set_rgb_color(0x000099)
47
48
49def loop():
50    global title, label_adc, label_tip, bus2, unit_chain_bus_0, last_time, adc_value
51    M5.update()
52    if (time.ticks_diff((time.ticks_ms()), last_time)) >= 200:
53        last_time = time.ticks_ms()
54        adc_value = unit_chain_bus_0.get_adc_input(1)
55        label_adc.setText(str((str("ADC Value: ") + str(adc_value))))
56        print((str("ADC Value: ") + str(adc_value)))
57        unit_chain_bus_0.set_rgb_brightness(
58            int(m5utils.remap(adc_value, 0, 4096, 0, 100)), save=False
59        )
60
61
62if __name__ == "__main__":
63    try:
64        setup()
65        while True:
66            loop()
67    except (Exception, KeyboardInterrupt) as e:
68        try:
69            bus2.deinit()
70            from utility import print_error_msg
71
72            print_error_msg(e)
73        except ImportError:
74            print("please update to latest firmware")

Example output:

None

I2C device communication

This example demonstrates how to use the Unit Chain Bus module to communicate with I2C devices. The example shows how to configure the bus for I2C mode and use it with I2C devices like the DLight sensor.

MicroPython Code Block:

 1# SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
 2#
 3# SPDX-License-Identifier: MIT
 4
 5import os, sys, io
 6import M5
 7from M5 import *
 8from hardware import Pin
 9from hardware import I2C
10from chain import ChainBus
11from chain import BusChainUnit
12import time
13from unit import DLightUnit
14
15
16title = None
17label_brightness = None
18label_mode = None
19i2c0 = None
20bus2 = None
21dlight_0 = None
22unit_chain_bus_0 = None
23last_time = None
24brightness = None
25
26
27def setup():
28    global \
29        title, \
30        label_brightness, \
31        label_mode, \
32        i2c0, \
33        bus2, \
34        dlight_0, \
35        unit_chain_bus_0, \
36        last_time, \
37        brightness
38
39    M5.begin()
40    Widgets.setRotation(1)
41    Widgets.fillScreen(0x222222)
42    title = Widgets.Title(
43        "Unit Chain Bus Example: I2C", 3, 0xFFFFFF, 0x0000FF, Widgets.FONTS.DejaVu18
44    )
45    label_brightness = Widgets.Label(
46        "Brightness: -- lux", 10, 85, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18
47    )
48    label_mode = Widgets.Label(
49        "Unit Chain Bus GPIO1&2: I2C", 10, 54, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18
50    )
51
52    i2c0 = I2C(0, scl=Pin(22), sda=Pin(21), freq=100000)
53    bus2 = ChainBus(2, tx=21, rx=22)
54    unit_chain_bus_0 = BusChainUnit(bus2, 1)
55    unit_chain_bus_0.set_i2c(BusChainUnit.I2C_SPEED_100K)
56    dlight_0 = DLightUnit(unit_chain_bus_0)
57
58
59def loop():
60    global \
61        title, \
62        label_brightness, \
63        label_mode, \
64        i2c0, \
65        bus2, \
66        dlight_0, \
67        unit_chain_bus_0, \
68        last_time, \
69        brightness
70    M5.update()
71    if (time.ticks_diff((time.ticks_ms()), last_time)) >= 500:
72        last_time = time.ticks_ms()
73        brightness = int(dlight_0.get_lux())
74        label_brightness.setText(str((str("Brightness: ") + str((str(brightness) + str(" lux"))))))
75        print((str("Brightness: ") + str((str(brightness) + str(" lux")))))
76
77
78if __name__ == "__main__":
79    try:
80        setup()
81        while True:
82            loop()
83    except (Exception, KeyboardInterrupt) as e:
84        try:
85            bus2.deinit()
86            from utility import print_error_msg
87
88            print_error_msg(e)
89        except ImportError:
90            print("please update to latest firmware")

Example output:

None

API

BusChainUnit

class chain.unit_bus.BusChainUnit(bus, device_id)

Bases: KeyChain

Bus Chain Unit class for interacting with Bus devices over Chain bus.

Parameters:
  • bus (ChainBus) – The Chain bus instance.

  • device_id (int) – The device ID of the Bus device on the Chain bus.

UiFlow2 Code Block:

init.png

MicroPython Code Block:

from chain import ChainBus
from chain import BusChainUnit

chainbus_0 = ChainBus(2, 32, 33, verbose=True)
bus_chain_unit_0 = BusChainUnit(chainbus_0, 1)
get_work_mode(gpio)

Get the Unit ChainBus work mode.

Returns the work mode of the specified GPIO pin.

Work mode values:
  • BusChainUnit.WORK_MODE_UNCONFIGURED

  • BusChainUnit.WORK_MODE_GPIO_OUTPUT

  • BusChainUnit.WORK_MODE_GPIO_INPUT

  • BusChainUnit.WORK_MODE_EXIT

  • BusChainUnit.WORK_MODE_ADC

  • BusChainUnit.WORK_MODE_I2C

Parameters:

gpio (int) – GPIO number (1 or 2).

Returns:

Work mode value, or None if failed.

Return type:

int | None

UiFlow2 Code Block:

get_work_mode.png

MicroPython Code Block:

mode = unit_chain_bus.get_work_mode(1)
if mode == BusChainUnit.WORK_MODE_GPIO_OUTPUT:
    print("GPIO1 is configured as output")
set_gpio_output(gpio, mode, pull=2)

Set pin as output.

Parameters:
  • gpio (int) – GPIO number (1 or 2).

  • mode (int) – Output mode. Use BusChainUnit.GPIO_MODE_PUSHPULL (0) or BusChainUnit.GPIO_MODE_OPENDRAIN (1).

  • pull (int) – Pull-up/down configuration. Use BusChainUnit.GPIO_PULL_UP (0), BusChainUnit.GPIO_PULL_DOWN (1), or BusChainUnit.GPIO_PULL_NONE (2). Default is BusChainUnit.GPIO_PULL_NONE (2).

Returns:

True if the operation was successful, False otherwise.

Return type:

bool

UiFlow2 Code Block:

set_gpio_output.png

MicroPython Code Block:

success = unit_chain_bus.set_gpio_output(1, BusChainUnit.GPIO_MODE_PUSHPULL, BusChainUnit.GPIO_PULL_UP)
set_gpio_output_value(gpio, value)

Set GPIO output value.

Parameters:
  • gpio (int) – GPIO number (1 or 2).

  • value (int) – Output value. 0 for low level, 1 for high level.

Returns:

True if the operation was successful, False otherwise.

Return type:

bool

UiFlow2 Code Block:

set_gpio_output_value.png

MicroPython Code Block:

success = unit_chain_bus.set_gpio_output_value(1, 1)  # Set GPIO1 to high level
set_gpio_input(gpio, pull)

Set GPIO input mode configuration.

Parameters:
  • gpio (int) – GPIO number (1 or 2).

  • pull (int) – Pull-up/down configuration. Use BusChainUnit.GPIO_PULL_UP (0), BusChainUnit.GPIO_PULL_DOWN (1), or BusChainUnit.GPIO_PULL_NONE (2).

Returns:

True if the operation was successful, False otherwise.

Return type:

bool

UiFlow2 Code Block:

set_gpio_input.png

MicroPython Code Block:

success = unit_chain_bus.set_gpio_input(1, BusChainUnit.GPIO_PULL_UP)
get_gpio_input_value(gpio)

Get GPIO input value.

Parameters:

gpio (int) – GPIO number (1 or 2).

Returns:

GPIO value. 0 for low level, 1 for high level. Returns None if failed.

Return type:

int | None

UiFlow2 Code Block:

get_gpio_input_value.png

MicroPython Code Block:

value = unit_chain_bus.get_gpio_input_value(1)
if value == 1:
    print("GPIO1 is high")
set_gpio_exit(gpio, pull, trigger_mode)

Set pin as external interrupt input mode.

Parameters:
  • gpio (int) – GPIO number (1 or 2).

  • pull (int) – Pull-up/down configuration. Use BusChainUnit.GPIO_PULL_UP (0), BusChainUnit.GPIO_PULL_DOWN (1), or BusChainUnit.GPIO_PULL_NONE (2).

  • trigger_mode (int) – Trigger mode. Use BusChainUnit.GPIO_INTR_RISING (0), BusChainUnit.GPIO_INTR_FALLING (1), or BusChainUnit.GPIO_INTR_ANYEDGE (2).

Returns:

True if the operation was successful, False otherwise.

Return type:

bool

UiFlow2 Code Block:

set_gpio_exit.png

MicroPython Code Block:

success = unit_chain_bus.set_gpio_exit(1, BusChainUnit.GPIO_PULL_UP, BusChainUnit.GPIO_INTR_RISING)
set_gpio_exit_callback(gpio_num, trigger_mode, callback)

Set GPIO external interrupt callback.

Parameters:
  • gpio_num (int) – GPIO number (1 or 2).

  • trigger_mode (int) – Trigger mode. Use BusChainUnit.GPIO_INTR_RISING (0) for rising edge or BusChainUnit.GPIO_INTR_FALLING (1) for falling edge.

  • callback – Callback function.

Return type:

None

UiFlow2 Code Block:

set_gpio_exit_callback.png

MicroPython Code Block:

def gpio_exit_callback(args):
    print("GPIO external interrupt")

unit_chain_bus.set_gpio_exit_callback(1, BusChainUnit.GPIO_INTR_RISING, gpio_exit_callback)
set_adc(channel)

Set ADC channel.

Parameters:

channel (int) – ADC channel number (1 or 2), corresponding to GPIO1 or GPIO2.

Returns:

True if the operation was successful, False otherwise.

Return type:

bool

UiFlow2 Code Block:

set_adc.png

MicroPython Code Block:

success = unit_chain_bus.set_adc(1)
get_adc_input(channel)

Read ADC value.

Parameters:

channel (int) – ADC channel number (1 or 2).

Returns:

ADC value (0-4095), or None if failed.

Return type:

int | None

UiFlow2 Code Block:

get_adc_input.png

MicroPython Code Block:

value = unit_chain_bus.get_adc_input(1)
set_i2c(speed=0)

Set I2C mode.

Parameters:

speed (int) – I2C speed. Use BusChainUnit.I2C_SPEED_100K (0) or BusChainUnit.I2C_SPEED_400K (1). Default: 0.

Returns:

True if the operation was successful, False otherwise.

Return type:

bool

UiFlow2 Code Block:

set_i2c.png

MicroPython Code Block:

success = unit_chain_bus.set_i2c(BusChainUnit.I2C_SPEED_400K)
readfrom(addr, nbytes, *args, **kwargs)

Read data from an I2C device.

Parameters:
  • addr (int) – I2C device address (7-bit).

  • nbytes (int) – Number of bytes to read (max 64).

  • stop (bool) – Generate stop condition (ignored, kept for compatibility).

Returns:

Read data as bytes.

Return type:

bytes

UiFlow2 Code Block:

readfrom.png

MicroPython Code Block:

data = unit_chain_bus.readfrom(0x48, 4)
readfrom_into(addr, buf, *args, **kwargs)

Read data from an I2C device into a buffer.

Parameters:
  • addr (int) – I2C device address (7-bit).

  • buf (bytearray) – Buffer to read into.

  • stop (bool) – Generate stop condition (ignored, kept for compatibility).

Return type:

None

UiFlow2 Code Block:

readfrom_into.png

MicroPython Code Block:

buf = bytearray(4)
unit_chain_bus.readfrom_into(0x48, buf)
writeto(addr, buf, *args, **kwargs)

Write data to an I2C device.

Parameters:
  • addr (int) – I2C device address (7-bit).

  • buf (bytes|bytearray) – Data to write.

  • stop (bool) – Generate stop condition (ignored, kept for compatibility).

Returns:

Number of bytes written.

Return type:

int

UiFlow2 Code Block:

writeto.png

MicroPython Code Block:

n = unit_chain_bus.writeto(0x48, b"")
readfrom_mem(addr, memaddr, nbytes, *args, **kwargs)

Read data from an I2C device memory (register).

Parameters:
  • addr (int) – I2C device address (7-bit).

  • memaddr (int) – Memory/register address.

  • nbytes (int) – Number of bytes to read.

  • addrsize (int) – Register address size in bits (8 or 16). Default: 8.

Returns:

Read data as bytes.

Return type:

bytes

UiFlow2 Code Block:

readfrom_mem.png

MicroPython Code Block:

data = unit_chain_bus.readfrom_mem(0x48, 0x00, 4)
readfrom_mem_into(addr, memaddr, buf, addrsize=8, *args, **kwargs)

Read data from an I2C device memory (register) into a buffer.

Parameters:
  • addr (int) – I2C device address (7-bit).

  • memaddr (int) – Memory/register address.

  • buf (bytearray) – Buffer to read into.

  • addrsize (int) – Register address size in bits (8 or 16). Default: 8.

Return type:

None

UiFlow2 Code Block:

readfrom_mem_into.png

MicroPython Code Block:

buf = bytearray(4)
unit_chain_bus.readfrom_mem_into(0x48, 0x00, buf)
writeto_mem(addr, memaddr, buf, *args, **kwargs)

Write data to an I2C device memory (register).

Parameters:
  • addr (int) – I2C device address (7-bit).

  • memaddr (int) – Memory/register address.

  • buf (bytes|bytearray) – Data to write.

  • addrsize (int) – Register address size in bits (8 or 16). Default: 8.

Return type:

None

UiFlow2 Code Block:

writeto_mem.png

MicroPython Code Block:

unit_chain_bus.writeto_mem(0x48, 0x00, b"")
scan(*args, **kwargs)

Scan for I2C devices.

Returns:

List of I2C device addresses found, or empty list if failed.

Return type:

list

UiFlow2 Code Block:

scan.png

MicroPython Code Block:

devices = unit_chain_bus.scan()
for addr in devices:
    print("Found device at 0x{:02X}".format(addr))