Hello!
Sorry for the long first post, but I’’m hoping for some advice on how to proceed…
I've been working with the Photon hardware as a hobbyist on and off for probably 10 years now. It started with a hardware hackathon at my old job, but my biggest project has been to create a charliecube and port the existing code over to the photon and then also create some cloud functions for a mobile app to run a game on it and to remotely change the animations and turn it on/off.
https://www.instructables.com/Charliecube-Charlieplexed-4x4x4-RGB-LED-cube/
Recently I finally took the step to actually create a design in KiCad so that I don't have to manually wire up the board and then also modified the footprint of the chip placement so that it would support various microcontrollers(I.E. primarily to allow for migrating from a photon to a photon 2).
After finally assembling a new cube I was able to set it up using a photon 2, but to my disappointment it didn’t work as expected. And after some research here I believe the lower GPIO speed on the photon 2 makes it not viable as a replacement.
There is a possibility that if I get a much deeper understanding of the hardware it can make it work, but after a couple days of troubleshooting I'm not certain what to do.
The charliecube works by quickly turning on and off pins so that specific leds on the cube light up correctly, and you are able to control all the leds using only 16 pins.
Every loop the program iterates all 192 LEDs(64 RGB LEDs) and briefly sets the pins and immediately turns them off again...
The main loop code is here:
void rgbMainLoop()
{
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 4; y++)
{
for (int z = 0; z < 4; z++)
{
for (int currentColor = 0; currentColor < 3; currentColor++)
{
drawLed(x, y, z, animationGrid[x][y][z][currentColor]);
delayMicroseconds(delay);
resetLed(x, y, z, animationGrid[x][y][z][currentColor]);
}
}
}
}
}
void drawLed(int x, int y, int z, int color)
{
int pin1 = 0;
int pin2 = 0;
switch (color)
{
case 0:
pin1 = red[x][y][z][0];
pin2 = red[x][y][z][1];
set_pins(pin1, pin2);
break;
case 1:
pin1 = green[x][y][z][0];
pin2 = green[x][y][z][1];
set_pins(pin1, pin2);
break;
case 2:
pin1 = blue[x][y][z][0];
pin2 = blue[x][y][z][1];
set_pins(pin1, pin2);
break;
default:
pin1 = red[x][y][z][0];
pin2 = red[x][y][z][1];
reset_pins(pin1, pin2);
pin1 = green[x][y][z][0];
pin2 = green[x][y][z][1];
reset_pins(pin1, pin2);
pin1 = blue[x][y][z][0];
pin2 = blue[x][y][z][1];
reset_pins(pin1, pin2);
}
}
void resetLed(int x, int y, int z, int color)
{
int pin1 = 0;
int pin2 = 0;
switch (color)
{
case 0:
pin1 = red[x][y][z][0];
pin2 = red[x][y][z][1];
reset_pins(pin1, pin2);
break;
case 1:
pin1 = green[x][y][z][0];
pin2 = green[x][y][z][1];
reset_pins(pin1, pin2);
break;
default:
pin1 = blue[x][y][z][0];
pin2 = blue[x][y][z][1];
reset_pins(pin1, pin2);
break;
}
}
void set_pins(int low_pin, int high_pin)
{
reset_pins(low_pin, high_pin);
pinMode(high_pin, OUTPUT);
pinMode(low_pin, OUTPUT);
digitalWrite(high_pin, HIGH);
digitalWrite(low_pin, LOW);
}
void reset_pins(int low_pin, int high_pin)
{
pinMode(low_pin, INPUT);
pinMode(high_pin, INPUT);
digitalWrite(low_pin, LOW);
digitalWrite(high_pin, LOW);
}
On the old photons this code works and all the LEDs light correctly(in fact I have a delay between turning the pins on and off so that the LEDs have more time on), but on the photon 2 it is much slower and so the LEDs don't continuously light up, instead they strobe. I tried removing the delay as well as using digitalWriteFast and was hopeful that would solve the problem, but there are some odd side effects I haven't been able to troubleshoot where the certain LEDs don't end up lighting up at all.
In the original code for the arduino I modified they actually didn't use the loop function at all but instead setup an interrupt timer and then directly set the registers on the ports for speed, but when I originally coded this I found I was successful with the simpler implementation.
Here is the relevant original arduino code I converted where it was iterating through a linked list of "frames" and setting the pins directly on the ports:
byte pinsB[] = {P1B,P2B,P3B,P4B,P5B,P6B,P7B,P8B,P9B,P10B,P11B,P12B,P13B,P14B,P15B,P16B};
byte pinsC[] = {P1C,P2C,P3C,P4C,P5C,P6C,P7C,P8C,P9C,P10C,P11C,P12C,P13C,P14C,P15C,P16C};
byte pinsD[] = {P1D,P2D,P3D,P4D,P5D,P6D,P7D,P8D,P9D,P10D,P11D,P12D,P13D,P14D,P15D,P16D};
#ifndef PWMMAX
#define PWMMMAX 8
#endif
#define FULL PWMMMAX
#define HALF PWMMMAX/2
// the interrupt function to display the leds
ISR(TIMER2_OVF_vect) {
int pin1 = _cube_current_frame->pin1;
int pin2 = _cube_current_frame->pin2;
int count = (pin1 & 0xF0) | ((pin2 & 0xF0)>>4);
pin1 = pin1&0x0F;
pin2 = pin2&0x0F;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
if (count > pwmm){
DDRB = pinsB[pin1] | pinsB[pin2];
DDRC = pinsC[pin1] | pinsC[pin2];
DDRD = pinsD[pin1] | pinsD[pin2];
PORTB = pinsB[pin1];
PORTC = pinsC[pin1];
PORTD = pinsD[pin1];
}
_cube_current_frame = _cube_current_frame->next;
if (_cube_current_frame == _cube__frame+1){
pwmm = (pwmm+1);
if (pwmm == PWMMMAX) pwmm = 0;
}
}
So at the moment I'm kind of at a loss on what path to pursue next. I was hoping to create these and give them out as gifts as well as harden the mobile app that controls them and I do have a few old Photons left to be able to make some more, but I was excited to migrate over to the Photon 2.
Here is an example video of the Photon and Photon 2 running the same code side by side:
https://youtu.be/1Wcpp11_k3Y?si=-m4yS7WClA7Jd-cs
Any help or ideas would be appreciated for a better approach to get the cube running correctly on the Photon 2.
Thanks!