A Big I²C Project
This project started in a small way when I purchased a PLASMA 2350 kit with skull bottle. The kit worked very well, was easy to program but needed some sort of input device to make the blinkies flash. For a start I added 3 pots to the ADC pins for basic colour control but needed an extra pot to control position. I connected an IO Expansion board so that I could connect the 4th potentiometer. I thought a display would be useful so added a SSD1306 128x64 mono I2C device to the same bus. I quickly got these talking to each other and the fun had started.
Normally, I would have swapped input devices to try out a new one. I remembered that in theory the I2C bus can support up to 127 devices in its addresses but only about 10 or 11 in practice because of capacitance problems on the bus. I looked around and collected all the I2C devices from my collection and started adding them one by one. Each one was added, tested for basic operation before adding another. The list grew longer and it still worked. I included I2C sensors and it all kept working.
I really like a big, bright and colourful display such as Display 2.0" and wanted to add it the mix, but the PLASM board did not have sufficient pins for an SPI device. I changed project focus and switched processor board to a Pico Lipo 2XL W. Loads of pins and plenty of memory. I dug out an old LCD2040 with an I2C backpack – slow and looking from a different era - but it worked. It needed 5V so I put that on the other I2C bus.
I exchanged the long RGBLED string in the skull for a shorter one (15 Neopixels and less power load) and added a 16 Neopixel ring to another pin. At this point Pimoroni brought out the Infra-Red Aye Arr remote with IR receiver stick. It only needs 1 pin and is ideal for controlling Neopixels so I connected it up.
In the end I finished up with the following circuit.
Scanning I2C bus. (GPIO Pins 4 & 5 = QW/ST connector)
10 devices found.
Dec addr: 10 , Hex addr: 0xa Track Ball Has RGBLED in ball
Dec addr: 15 , Hex addr: 0xf Rotary encoder Has RGBLED in knob
Dec addr: 24 , Hex addr: 0x18 IO Expander Analog and Digital I/O
Dec addr: 33 , Hex addr: 0x21 Qw/ST Pad 10 buttons and 4 white LEDs
Dec addr: 35 , Hex addr: 0x23 LTR-559ALS-01 Light sensor
Dec addr: 56 , Hex addr: 0x38 AHT20 Temperature & Humidity
Dec addr: 60 , Hex addr: 0x3c SSD1306 OLED Display 128x64
Dec addr: 100 , Hex addr: 0x64 DF2301QG Offline Voice Recognition Sensor
Dec addr: 106 , Hex addr: 0x6a LSM6DS3TR-C Accelerometer & gyroscope
Dec addr: 118 , Hex addr: 0x76 BME280 Temperature, pressure, humidity
GPIO 0 has 15 NeoPixel RGB string in the skull bottle
GPIO 38 has 16 NeoPixel RGBW ring
IR Receiver stick on Rx, GPIO 1. Aye Arr IR Remote sends the signals for input.
3 x 10K potentiometers on ADC pins (GPIO 26,27,28)
Hanging from the IO Expander: RGB LED, Single RED LED, button and 10K pot
0x27 is LCD2004 on the other I2C bus (GPIO Pins 2 and 3) – 4 rows of 20 characters
Display 2.0" SPI 320x240 pixel colour screen
All connected to Pico Lipo 2XL W, on a Pico Decker
Coding
This was a pretty big project. I wanted a single program, menu driven, which would use all the connected components and devices including the WiFi chip on the Pico board. I decided that the menu would be driven with the buttons on the QW/ST Pad and displayed on the little SSD1306 screen. The rather slow LCD2004 was used mainly for instructions for each menu item.
SSD1306 Menu screen
All run from the Menu
There would be distinct sections to the code – hints of COBOL! The first part would import all the necessary libraries and carry out the setup for each in turn, with a simple LED flash or screen message to prove they were working. A scan of the I2C bus would be useful to check all 10 devices had connected. The second section would allow the user to pick input devices from the menu and output changes to as many devices as possible. I thought I could use the WiFi connection to report on recent earthquakes as I already had code which could be easily repurposed.
Each menu item/input device was coded and the resulting visual output tested as a separate program. Then the active part converted to a single procedure, added and tested in the main program via the menu. Once this was finished, I collected many of the similar visual output sequences together into a couple of procedures [lights() - switch things on] and [tidy_up() – turn them off]) to make the whole thing neater.
Each time I was ready to add a new menu item to the growing program I saved it with a new version number. You do not want to damage the existing working code while adding a complicated new feature. Increasing versions numbers allow you to easily take a step back to a working version if you get lost/confused in an upgrade.
After thoughts
The simple SSD1306 display is very useful. The improved graphical instructions now available in MicroPython for the Pico are excellent and upgrade the display from just small text output. I’ve included a simple routine to allow double sized text characters in the code. Which others might find useful.
The Aye Arr remote library taught me a great deal. (I’d not encountered binding instructions before nor realised that you can use tuples without brackets!) It might take bit of time to understand how the library works but it is much more versatile and reliable than less sophisticated IR remote libraries that I’ve used in the past.
I was delighted with the Track Ball - very responsive and easy to code. I prefer it upside-down with the wires pointing away. It would make a good menu controller in place of the QW/ST Pad. I kept it and the other small components steady on the desktop with small blobs of BluTack.
I’ve been unhappy with the output from Pico ADC pins for ages. You do not get a reliable zero when using a 10K potentiometer. (Arduino UNOs gave much more reliable 0 to 1023 readings years ago. Who needs 16-bit values from a pot? Most of the time we only need a range of 0-255. [I know, consistent 16-bits with PWM]) The IO Expansion board is the answer. It has more ADC pins, no jitter on the zero, versatile with PWM and digital IO. It is really easy to code and you can use several together by changing the addr.)
I feel I must thank all the programmers who supply the libraries which make the lives of we ‘hobby coders’ so much easier by doing all the really difficult stuff and neatly package it for our use in MicroPython. Their efforts are built on the work and ideas of Ad P.M.M. Moelands and Herman Schutte, who developed I²C (Inter-Integrated Circuit) in 1980 at Philips’ laboratories in Eindhoven, Netherlands.
Code is below.
Comments welcome
Regards
Tony Goodhew






