top of page

COLORCLOCK

What time is it?

Amber o'clock-ish (?)

IO Expander Analog Write Fails Me

Although the code for the IO expander compiles successfully, it doesn't produce the expected variable output voltage. The analogWrite function accepts values from 0 to 255 (0xFF) and normally setting it to 128 would result in half the output voltage compared to setting it to 255. However, I discovered that the output voltage remained the same whether the pin was set to 128 or 255.


In a previous test, I connected an LED and cycled through output values from 0 to 255, observing the LED brightening. But the differences in output voltage didn't scale as anticipated; there might be a variation up to a certain point, beyond which the voltage levels off.


// pin_num0 and pin_num1 produce the same output voltage
analogWrite(pin_num0, 128);
analogWrite(pin_num1, 255);

The digitalWrite function still works but I haven't the digitalRead yet. If digitalRead works, we might use this IO expander for the user control panel input buttons. But my confidence level in this piece of hardware is low, so we'll see if I actually end up using it.


Now I'm back to using ALL the Arduino PWM output pins to wire up the four LED strips. I'm a bit apprehensive about maxing out the available analog output pins, so I've ordered a new multiplexer, the CD74HC4067, as a backup solution for expanding analog outputs. The new parts have arrived, so I'll be soldering and testing them this weekend... 🤞


The new multiplexor. I'll need to solder on the headers prior to testing.


12V Level Shifter Works!

In this project, an Arduino output pin provides up to 3.3V, insufficient for the 12V needed by the RGB LED strips. So we're using a level shifter to boost the voltage to 12V.


In recent testing, I connected the Arduino's analog output to the level shifter input and the RGB strip to its output, and... it was a success! 🥳 The light cycled through colors as programmed, though transitions were slightly choppy, a topic I'll address later in this post.


The level shifter input pins are connected to the Arduino analog output pins and the level shifter output pins are connected to the RGB LED strips.


Lesson Learned: Don't Use a Member Variable to Define a Global

After successfully testing the level shifter, I quickly integrated the three additional ColorClock objects into the code, assigning analog output pins for each new strip. However, upon connecting more LED strips and running the code, the board appeared to freeze. Subsequent attempts to upload new code failed as the computer no longer detected the Arduino's serial port. Resetting the board and reseating the USB cable eventually restored the serial port connection. Despite this, re-uploading the program continued to cause the board to freeze again 😵‍💫


I barely touched the code! I was worried there was something on the board shorting so it took me about a day of swapping out hardware, doing incremental testing, and meticulously comparing Git commits before I identified the problem.


In the last commit where everything broke, I made one tiny optimization in an effort to reduce the use of 'magic numbers'... In the definition of the time periods for each color clock, I used a static member variable, TimeCalcs::SEC_IN_HR.


float cc0_period =  6.0 / TimeCalcs::SEC_IN_HR;
float cc1_period = 12.0 / TimeCalcs::SEC_IN_HR;
float cc2_period = 30.0 / TimeCalcs::SEC_IN_HR;
float cc3_period = 60.0 / TimeCalcs::SEC_IN_HR;

I should note that the three cc#_period variables used are globals in the main driver file. It seemed like the driver file was not aware of the value of TimeCalcs::SEC_IN_HR by the time it ran that part of the code. When I removed this reference to TimeCalcs::SEC_IN_HR it worked again 😅


float cc0_period =  6.0 / 3600.0;
float cc1_period = 12.0 / 3600.0;
float cc2_period = 30.0 / 3600.0;
float cc3_period = 60.0 / 3600.0;

I'll probably create some #defines at the top of the file to keep it looking a little cleaner.


Smooth Transitions

At first, I thought updating the color output every second would be enough since our original design had a 24-hour cycle time. But once we added a user-controlled light that allows participants to set cycle times as short as six seconds, I realized that smoother color transitions were essential for seamless aesthetics.


I am using a real-time clock module to output the current time, which the program uses to determine the color and the module's smallest granularity is one second. However, Arduino has a built-in function that outputs the current number of milliseconds since the program started, so I added a function to output the current millisecond within each second.


int FluxClock::get_milli(byte crnt_sec)
{
  static byte prev_sec = 0;
  static long int prev_millis = 0;
         long int crnt_millis = millis();

  // Resent millisecond count if its a new second
  if (crnt_sec != prev_sec)
  {
    prev_sec = crnt_sec;
    prev_millis = crnt_millis;
  }

  return static_cast<int>(crnt_millis - prev_millis);
}

The two videos included below demonstate the differences when updating the color output every second versus every millisecond. The three RGB LED strips in the videos cycle through all hues in the color wheel at different rates: 6 seconds, 12 seconds, and 30 seconds.


🌈



In this implementation, the program is updating the color output every second. Notice how abrupt the color transitions appear.



Here, the colors are updated every millisecond. The transitions in this implementation are much smoother than before.


OS Reinstallation is Always an Option

In the period of time that I started writing this post, I experienced an issue where the Ubuntu partition on my desktop decided not to connect to the internet. I struggled for a few days with all sorts of network settings before I realized it wasn't worth the trouble and just reinstalled Ubuntu in its entirety. As I was going through my whole new environment setup process, I documented most of what I did to streamline the next time I have to start over 😅


User Interface Software Design Begins!

The next step in the ColorClock saga is to design the software implementation for the participant-facing user control panel. I wired up a little prototype for testing. The final design will use arcade buttons embedded in an enclosure that will house the electronics.


In this small prototype I'm using breadboard-sized push buttons and LEDs. The final control panel will use light up triangular arcade buttons for red, green, blue, and frequency modification. I'm using one current-limiting resistor for all the LEDs and 10K pull-down resistors for each push-button.


The soldering work is not beautiful but it gets the job done.

A Beautiful Breadboard

Behold! The first design of the of the fully populated solderless breadboard!

This to-scale-ish design contains all of the modules that will be present on the final circuit board for ColorClock. The user interface controls are not present on this board.


🌈


To streamline the final phase of hardware testing and preempt the challenges of electronic troubleshooting, I found it important to meticulously design the layout of the prototyping breadboard. I started this layout by looking at the datasheets, obtaining the dimensions of each module, and drawing each component to scale. Then I decided it would be actually be more functional if I were using units of breadboard holes (approximately 0.1" between holes) instead of true dimensions. To determine the size represented on the diagram I placed each module on the breadboard and noted how many holes they covered and the positioning of all the pins. The next step is to actually wire this thing up and get to testing with the real LED light display 🙌


Clock Crafting

And on the topic of the light display, it's just about finished! My partner bought a plunge base and circle jig in order to cut the circle and route out pockets for the LED strips to rest in. I'm very pleased with the results 😀 We are using a reflective metallic finish to maximize the light output, and a sheet of translucent acrylic that will sit on top to diffuse the light.


The final routed wood piece features outer rings designed to house RGB LED strips. Each ring will display colors corresponding to the current time in days, hours, and minutes. The center of the piece will have a flower-like shape of LEDs that will be controllable by participant interaction via user control panel.


The LEDs are glued to the inside of the pockets, and the colored light will be reflected off the metallic finish.


IO Expander Integration Trials

In my last post, I was working on integrating the Arduino Nano ESP32 into the project. I successfully tested this board with the new RTC module and the new alphanumeric display 🤗 But then... I was in the process of testing the IO expander and ended up messing with my board configuration so much that I was no longer able to upload any code to the board 😦 Thankfully, ptillisch came to the rescue and resolved my issue 🥳


Though I was able to talk to the Nano board, I was unable to include the library to interface with the IO expander 😭 I chased my tail for a couple of weeks before I decided to move in a different direction (see notes at the end of this post).


The good news was that I could interface the IO expander with the MKR 1000 that I had been testing on before I got the Nano board. Sooooo I ordered two more Arduinos, the MKR 1010 (they no longer make the MKR 1000) and decided to move forward.


Can I Just Get Some Variable Voltage Control??

The plan:


  • Use the IO expander for analog output (required to create the RGB color mixing)

  • Use the Arduino on-board GPIO for digital input from user interface


When the new boards came in, I promptly began testing the IO expander. I was able to get the digitalWrite functions to work with ease, but I struggled with the analogWrite function. After days of banging my head against the wall 😖 my new contingency plan was to swap the IO functionality of the on-board Arduino GPIO and the IO expander, i.e. the IO expander for the digital IO and Arduino PWM for the RGB LED control.


ColorClock has four light strips and three variable voltage lines per strip (one for each red, green and blue) so I need exactly 12 PWM pins. According to the product page for the MKR 1010, there are supposed to be 13 PWM pins on the board BUT one of those listed pins would be unusable for variable voltage output on ColorClock because it needed to be used for the I2C SCL required for communication to the various modules.


This PWM output count would leave me NO wiggle room if one of the pins didn't work as expected. My concern grew when I noticed that the datasheet had conflicting information from the product website on which pins were capable of PWM output (see the notes at the end of this post for more information).


So, to get some clarity, I manually tested each individual pin. I wrote a tiny test program and hooked up a simple circuit with an LED where I varied the output voltage. I observed the LED to see if the light got brighter as the value of the output increased. I discovered more discrepancies between my empirical testing and the documentation (see notes).


We spent the afternoon at a brewery where I performed my variable output voltage test while my partner played his Steam Deck killing zombies or something.


Wiring Matters

The inconsistency between my findings and the documentation left me uneasy, so I went back to testing the IO expander with a minimal example. I knew my code was solid, so I double-checked the circuit wiring and sure enough, there was a mistake. After fixing it, I was able to see a variable output voltage on a multimeter using the analogWrite function using the IO expander 🎉 So now I'm back to the original plan of using the IO expander to control the lights, and the on-board GPIO for the digital inputs.


The input values set by my program didn’t correlate as expected with the measured voltage with the multimeter, so it looks like I’ll need to write some calibration functions so I can programmatically compensate for hardware characteristics.


Moving Forward

So, next steps will be:


  • Wire up the breadboard so beautifully depicted above.

  • Characterize the RGB LED strip, so I can programmatically adjust for the non-linear relationship between the IO expander's output voltage and the visible color from the lights.


We've got 2 1/2 months and counting... 😅



 

Notes

IO Expander Adafruit AW9523

There have been others that have had issues integrating the Adafruit_AW9523 library with the Arduino Nano ESP32. Though the GitHub issues page states that this issue was resolved, I'm not so sure it was...


Arduino MKR 1010 PWM Pins

According to the MKR 1010 product website, the following pins are available for PWM out:

0 .. 8, 10, 12, A3, A4

According to the MKR 1010 datasheet the following pins are available for PWM out:

0 .. 9

According to my empirical testing, the following pins are available for variable voltage output:

0 .. 8, 10, A3, A4, A0* **

* I learned that the A0 pin provides a true analog output, not a PWM signal which is why it was listed on neither the website nor the datasheet as a PWM pin. This page describes the difference between analog and PWM output.


** Pins 9 and 12, as listed on the datasheet and website, respectively, did not produce variable output voltages in my experiment.



The mystery of the missing package

A couple weeks ago I was tearing my house apart to find a package from Adafruit that I remember arriving a couple months prior. I'm not one to put something in a random place (except for my phone, an ongoing challenge I'm actively addressing!), so it turned into a whole week of organizing and repeatedly checking all the logical places it could be. I felt like I was going crazy.


I finally decided to find the email delivery confirmation but it was non existent in my inbox. And then I went to the Adafruit website and found a shopping cart containing all the items I was expecting in my package 😑 Looking at my shopping cart of unpurchased items, the real memory of what happened came flooding back... I was shopping for an encoder but couldn't commit and probably went to bed with intentions of finishing my shopping the next day but life got in the way. Studying my shopping cart, I discovered that one of the items I had planned to purchase was no longer in stock 😫


Lessons learned

  1. When having trouble finding a mailed package, first check if the items were ever ordered.

  2. Don't put off ordering a shopping cart full of items in hopes of finding that last perfect addition.


A new Arduino

One of the other items I had ordered that week was a new, smaller Arduino board. I have been using this old board I acquired from my brother years earlier that he was never able to connect to (it turns out he was using a power cable instead of a data cable to program 😅). For the final ColorClock installation, I want to make two identical circuit boards so I have a backup in case there are any problems during the week the project is being displayed.


I ordered an Arduino Nano ESP32 where nearly all of the pins are configurable to have PWM, a way to fake out an analog output with a digital signal. PWM output is what I need to have variable output voltage so I can send different outputs to the RGB LED pins creating different colors.


Nothing good is ever easy

So, I had this new Arduino and I just wanted to do a simple test so that I know I can talk to it. In my last post I shared my frustration with figuring out how to set build variables so I went back to developing on my beloved decade-old MacBook Pro. But after I figured out how to set build variables I migrated back to my new fancy Windows machine and applied the same changes to the boards.txt deep in the file system in the Arudino hardware folder. At that point I continued development on Windows.


Ok, back to the new Arduino board... I installed the drivers to talk to this board but I kept getting errors when trying to program it:

dfu-util: Cannot open DFU device 2341:0070 found on devnum 10 (LIBUSB_ERROR_ACCESS)
dfu-util: No DFU capable USB device available
Failed uploading: uploading error: exit status 74

I discovered that this was a known problem with this board and found in the Arduino forums that there is a post_install.sh script I need to run for the computer to see the Arduino. But this was a Bash script, and I was developing on Windows. I tried running the command in Git Bash, but I needed to use sudo and Git Bash didn't have sudo then I tried to run it in PowerShell just for fun.


A side note

Skipping ahead to the present, as I'm cleaning up this post and adding links, I have discovered that there is indeed a post_install.bat script that I probably could have run on Windows, but we're here now.


A solution to my development woes

The time had come to create a Linux partition. I was experiencing the same level of fear I had about arduino-cli, the command line tool for building and uploading Arduino code. Creating a Linux partition seemed scary because I had never done it before. But dammit I am a software engineer and I can do hard things!


My supportive partner assured me that setting up a Linux partition was not complicated. All I needed to do was download the Linux installer, put it on a USB drive, make it bootable, then boot into that USB drive. deep breath I can do this.


Creating a bootable USB was surprisingly painless. There are tons of instructions on the internet. The basic steps were:


  1. Download the Linux installer image.

  2. Make the USB stick bootable.

  3. Restart the computer and enter the BIOS.

  4. Select the USB from the boot menu.

  5. Follow on-screen instructions.


So I did it! I am actually writing this from my Ubuntu partition right now!


Like any new computer, there's the initial setup process, which, in my case, was missing even basic tools like Vim. But I'm no stranger to starting over.


Back to the new Arduino

The catalyst for the Linux partition was so that I could run a script that would allow my computer to see the Arudino Nano ESP32. I did all the things (installed arduino-cli, ran the post_install.sh script) and it's all working!


My next challenge is to test my new RTC module, test the I/O expander 🥺 (also scary) and start laying out the 'final' V1 version of the circuit board.


In other news... we're famous!

ColorClock is officially listed as 2024 Playa Art!! (go on, click the picture 😀)


bottom of page