Use your M5StickCPlus2 to create a USB to I2C Bridge to connect to your I2C Peripherals. The UXB-300 is a browser-based GUI builder that lets you wire up register-level controls of an IC without touching any code. The example below uses the LTR-329 as the peripheral.
Hardware Used:
USB Bridge: ESP32S3 - M5StickC Plus2 : https://www.adafruit.com/product/4290
Peripheral : Light Sensor - LTR-329: https://www.adafruit.com/product/5591
Schematic/Datasheet: https://learn.adafruit.com/adafruit-ltr-329-ltr-303/downloads
Cables: USB-C Cable between PC and M5Stick https://www.adafruit.com/product/4474
Grove to Qwiic cable between M5Stick and LTR-329 https://www.adafruit.com/product/4528
The Arduino IDE 2.3.10 was used to create and load a sketch onto the M5Stick. The UXB-300 was used to create a GUI to control the peripheral and display the results in real time.
Links to Sketch and GUI:
Arduino Sketch: m5stickC_esp32s3_i2c_oled.ino : https://github.com/labs16/ESP32S3-I2C-Bridge
UXB-300 LTR-329 GUI: https://apps.labs16.com/poverholt/esp32-s3_ltr-329
Just want to jump in? Connect your M5Stick with LTR-329 Hardware, click the UXB-300 LTR-329 GUI link above, and skip to the Connect Hardware and Control with GUI step below.
Want to build it yourself? Continue to follow along…
Detailed Steps to do on your own: ( Define | Create | Connect )
The ESP32-S3 has USB OTG capability and is configured in the sketch to use serial protocol to send and fetch I2C commands. The UXB-300 GUI can be easily configured to communicate with the ESP32-S3 and interactively communicate via I2C with the peripherals.
Since the ESP32-S3 is used as a USB bridge, we need to define the serial data being sent and received between the ESP32-S3 and the UXB-300 GUI over USB. The packet payload definition will, at a minimum, need to support the peripheral being used - in this case an LTR-329.
Packet Payload Definition: (byte count varies with data length)
< Byte0 > < Byte1 > < Byte3 >< Byte4 >.....< Byte8 >
< Byte0 > = Mode/Size Byte and it contains information on whether it is a Block Transfer and the Size(Bytes) of the Data. The High Nibble determines if it is Block and the Lower Nibble is the size of the Data Transfer. A High Nibble of 0xB indicates a block transfer.
Example: 0xB2 means Block of length two bytes, 0x04 means non-block of length four bytes.
< Byte1 > = R/W Byte: Read = 0x72 and Write = 0x77
< Byte2 > = dev-id = 7-bit Device Address for the peripheral
< Byte3 > = ADDR = register address in Hex
< Byte4:N Bytes > = DATA sent / received
< Byte N+1 > ERROR Byte
The Packet Payload Definition above was used for this project. This definition is flexible — both the sketch and GUI packet builder are easy to adjust per your application.
The peripheral datasheet and peripheral schematic allow us to confirm the settings and that the definition above is sufficient. The peripheral is non-block with a data size of one byte.
Byte0 = 0x01
dev-id (7-bit) Device Address is 0x29 per the Datasheet.
Byte 2 = dev-id (7-bit) = 0101001b = 0x29
Page 14 from the datasheet provides the supported Register Addresses, which are one byte in size, together with the datalength which is shown to be one byte in size as well.
The ERROR Byte will be returned by the M5Stick (0x00 if no error, 0xFF if error)
This translates to the following for writing and reading from the peripheral using the M5Stick as a USB bridge.
Send: 0x01 0x77 0x29<ADDR><DATA><ERROR>
Fetch : 0x01 0x72 0x29<ADDR><DATA><ERROR>
- Bold indicates bytes returned from the M5Stick versus sent from the host.
The Arduino Sketch uses M5's M5StickCPlus2 board, which is available via Board Manager on the Arduino IDE under esp32 version 3.3.10. The M5StickCPlus2(v 1.0.1), M5Unified(v 0.2.17) and M5GFX(v 0.2.22) Libraries were installed.
Normally you'd write something custom on the host side to read these registers — UXB-300 handles that, letting you skip straight to the hardware. The tool is available at
Click Create to start a new project. Choose the sign-in path or create the device from scratch. If you are already signed in, you can select the LTR-329 from the list of devices available, Otherwise, name your project, type in the Device ID (as noted above, the Device ID for this board is 0x29) and select custom. Click on Create.
Click on Pkt Builder from the Page Nav. Here you will create your custom packet protocol based on the Packet Payload Definition steps. Page 14 of the datasheet shows the device using a One Byte interface.
Click on the Edit pencil for the One Byte protocol to edit the Send and Fetch fields to match the Defined Packet Payload. Click the ‘+’ sign under each section to add Send and Fetch steps.