RGBW pattern problem

I am up to make an RGBW controller that will power the RGBW LED strip. The MCU is GD32F330F8P6. It has a button which is intended to be used as a select button. You have to hold it pressed for a while to switch the case, and in a small window of time you need to press it to select the desired color (1 - 10). Every time you press the button, the LED strip should light the desired color just for you to know what you have selected, and not just count the presses of the button. The selected number is stored in EEPROM. After the last press, and a few seconds later, the MCU will restart itself and load the stored data, thus light the LED strip according to your selection.

I use this Arduino support:

Here is the code:

#include <Arduino.h>
#include <EEPROM.h>
#define led PA13
#define btn PA4
#define ledG PA5
#define ledR PA6
#define ledB PA7
#define ledW PB1
#define longTime 5000
int lastState = 0;
int currentState;
int caseSet = 0;
int countPress = 0;
unsigned long pressedTime = 0;
unsigned long releasedTime = 0;
unsigned long previousPressTime = 0;
int lastButtonState = 1;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
int buttonState;
int eepromValue;
int cnt = 15000;
void setup(){
  Serial.begin(9600);
  EEPROM.begin();
  eepromValue = EEPROM.read(0);
  Serial.println(eepromValue);
  delay(2000);
  pinMode(led, OUTPUT);
  pinMode(btn, INPUT);
}
void loop(){
  if(caseSet == 0){
  grbwOutputFunc();
  int currentState = digitalRead(btn);
  if(lastState == HIGH && currentState == LOW){
    pressedTime = millis();
    }else if(lastState == LOW && currentState == HIGH){
      releasedTime = millis();
      }
  long pressDuration = releasedTime - pressedTime;
  if(pressDuration > longTime){
    digitalWrite(led, HIGH);
    caseSet = 1;
    }else{
      digitalWrite(led, LOW);
      caseSet = 0;
      }
 lastState = currentState;
  }

 if(caseSet == 1){
  int reading = digitalRead(btn);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == LOW) {
        countPress++;
        if(countPress > 10){
          countPress = 1;
          }
        EEPROM.write(0, countPress);
        EEPROM.commit();
        Serial.println((String)"broj: "+countPress);
          switch (countPress){
            case 1:
            analogWriteColor1();
            break;
            case 2:
            analogWriteColor2();
            break;
            case 3:
            analogWriteColor3();
            break;
            case 4:
            analogWriteColor4();
            break;
            case 5:
            analogWriteColor5();
            break;
            case 6:
            analogWriteColor6();
            break;
            case 7:
            analogWriteColor7();
            break;
            case 8:
            analogWriteColor8();
            break;
            case 9:
            analogWriteColor9();
            break;
            case 10:
            analogWriteColor10();
            break;
            }
      }// if buttonState is low
    }// if reading is not buttonState
    if((millis() - lastDebounceTime) > cnt){
      NVIC_SystemReset();
      }
  }
  lastButtonState = reading;
  }//caseSet 1
}
void grbwOutputFunc(){
  switch (eepromValue){
    case 1:
    analogWriteColor1();
    break;
    case 2:
    analogWriteColor2();
    break;
    case 3:
    analogWriteColor3();
    break;
    case 4:
    analogWriteColor4();
    break;
    case 5:
    analogWriteColor5();
    break;
    case 6:
    analogWriteColor6();
    break;
    case 7:
    analogWriteColor7();
    break;
    case 8:
    analogWriteColor8();
    break;
    case 9:
    analogWriteColor9();
    break;
    case 10:
    analogWriteColor10();
    break;
    }
}
void analogWriteColor1(){
    analogWrite(ledG, 255);
    analogWrite(ledR, 0);
    analogWrite(ledB, 0);
    analogWrite(ledW, 0);
}
void analogWriteColor2(){
    analogWrite(ledG, 0);
    analogWrite(ledR, 255);
    analogWrite(ledB, 0);
    analogWrite(ledW, 0);
}
void analogWriteColor3(){
    analogWrite(ledG, 0);
    analogWrite(ledR, 0);
    analogWrite(ledB, 255);
    analogWrite(ledW, 0);
}
void analogWriteColor4(){
    analogWrite(ledG, 0);
    analogWrite(ledR, 0);
    analogWrite(ledB, 0);
    analogWrite(ledW, 255);
}
void analogWriteColor5(){
    analogWrite(ledG, 150);
    analogWrite(ledR, 150);
    analogWrite(ledB, 0);
    analogWrite(ledW, 0);
}
void analogWriteColor6(){
    analogWrite(ledG, 150);
    analogWrite(ledR, 0);
    analogWrite(ledB, 150);
    analogWrite(ledW, 0);
}
void analogWriteColor7(){
    analogWrite(ledG, 0);
    analogWrite(ledR, 150);
    analogWrite(ledB, 150);
    analogWrite(ledW, 0);
}
void analogWriteColor8(){
    analogWrite(ledG, 100);
    analogWrite(ledR, 255);
    analogWrite(ledB, 50);
    analogWrite(ledW, 0);
}
void analogWriteColor9(){
    analogWrite(ledG, 20);
    analogWrite(ledR, 120);
    analogWrite(ledB, 200);
    analogWrite(ledW, 0);
}
void analogWriteColor10(){
    analogWrite(ledG, 180);
    analogWrite(ledR, 60);
    analogWrite(ledB, 30);
    analogWrite(ledW, 0);
}

Now the problem.

When I hold the button pressed for 5 sec, it change the case and the small LED on the board is lit so I can know I entered the "programming" state. If I press the button three times, I can select the third color (blue), and I can see I have selected it. The board will reset and the blue will stay. Same goes for the 1, 2, 3, 4 cases. But, when I select, say case 9, it will show the selected color while I am in the "programming" mode, but when it restarts, I will get case 8. The bug is in cases 5, 8, 9.

So, it shows the correct color while the button is pressed, while in the "programming" mode. After reset, it shows the correct color only for some cases, not for all, and I don't see the pattern why is it happening. The same happen no matter if I let the board reset itself after a time set, or I reset it manually.

I had a similar problem with a GD32F130F8P6, so I switch to this one.

Now, I do know that in the datasheet there is not an E of EEPROM.

But, the package has its EEPROM example, so it ... "works".

Any suggestion? I am all ears.

Can you write a test to check if the Flash emulated EEPROM does work ?

If you put the colors in an array, then you don't need the switch-case, or all those functions.

The Wokwi simulation does not keep the contents of a EEPROM after the sketch is stopped, but you can test the buttons in Wokwi simulation on a Arduino Uno.

@dekip
+1 to test the EEPROM. Or at least to change an address.

I don't see anything in the code that could explain that the values sometimes stored and sometimes not.

The value is stored. In setup, the first thing I print the EEPROM value, and it is ok. But the LED color is not the one the EEPROM value should make it to be.

Say this 8 value. After reset, it says 8, but the color is not 8.

PS: I will change the address and let you know.

We can not test the combination of emulated EEPROM and the reset. Perhaps the emulated EEPROM is halfway being written when the reset occurs.
If we would have to fix your sketch, then we would probably make a new sketch without the need for a reset.

The variable 'caseSet' for either normal mode or setting the color is good.
Can you put the code for debouncing and to detect a long press in a function ?
The colors should be in an array. It will make the code smaller and easier.

Which problem are you trying to solve ?
Do you really need the emulated EEPROM ?
If the power is turned on, is it okay that it starts with 0 for the color ?

The board should be plugged and forget. And maybe once in a 6 months there might be a need to change the color. It will not be on all the time.

I need to finish a few things to try another address.

When you described the issue in first post, you wrote that the value read from EEPROM after reset is not the same as stored:

Where is the correct description? In the last case the problem is seems to be in EEPROM, but in the first - in your color output code.

And also, do you always get the same wrong values for cases 5 8 9? Or are they always different?

Huh?

Mate, I posted the code here. I get the right EEPROM value on the serial terminal, but this value does not represent the actual color on the LED strip.

Let's write it again. I can enter the "programming" mode by holding the button pressed. I can select the specific value (represented by the number), I can see the color which this number represent, and I can see it on the serial terminal. After the reset, I can see this same number on the serial terminal right from the EEPROM, but the color does not match.

Yes, I get the same wrong color for those few cases.

Just changed the EEPROM address. The same problem.

So your number stored and read correctly, the issue has nothing to do with EEPROM and we all wasting the time on 5 hours. Nice...

So do this test: Setup the one of problem color mode, say 8, in the constant variable. Change the program to use it as default color after reset.
Is the color will be same when you selected it by button and after restart?

(let's exclude eeprom from testing)

Everything was there. So, yeah, it is nice...

I will try and let you know.

Sorry dekip, but this is not going well. It is better to first put the code for debounce in a function and test it, so you are sure it works. Or use a library for debouncing. Then rewrite the rest of the sketch.

I tried it on a Arduino Uno in Wokwi simulation:

It shows yet another problem. When I force number 8, then it calls function analogWriteColor8(), as expected. However, it keeps on calling that function.
The continues call to analogWrite() might restart the PWM timer. The led could show something different, it can be different for each platform.

hmmm... why?
Isn't analogWrite() just to set a compare value, not affects the timer itself?

So, the idea could be to make a boolean so it fires analogWrite() once and stay there?

It works fine for other positions. I will try to change the color. It sounds silly, but...

Did you test the code with constant color mode = 9, as I asked you?

This is my first try:

// Forum: https://forum.arduino.cc/t/rgbw-pattern-problem/1247866
// This Wokwi project: https://wokwi.com/projects/395245481110779905
// Previous Wokwi project: https://wokwi.com/projects/395236442837506049
//
// Version 1: 15 April 2024
// Version 2: 15 April 2024
//   changed > to >= in millis timer.
//   table is now called: colorCombinationTable
//   colorMode -> colorIndex
//   added that the EEPROM is used when the red reset button is pressed.
//   
// Warning: It is now specifically for a Uno board.
//          The EEPROM does not keep its contents in Wokwi.

// -------------------------------------------
// Glue for the Uno
#define PA13 13
#define PA4  4
#define PA5  9
#define PA6  6
#define PA7  5
#define PB1  3
// -------------------------------------------

#include <EEPROM.h>
#include <Bounce2.h>

const int RGBWpin[4] = {PA6, PA5, PA7, PB1};
const int ledPin = PA13;
const int buttonPin = PA4;

unsigned long durationNewColor = 5000UL;

unsigned long previousMillisTimeout;
unsigned long durationBackToNormal = 15000UL;

bool setColorMode = false;
int colorIndex;
const int defaultColorIndex = 1;

Bounce button = Bounce();

// Eleven different led values, RGBW
const int colorCombinationTable[11][4] =
{
  {   0,   0,   0,   0},   // off, not used
  { 255,   0,   0,   0},   // color 1
  {   0, 255,   0,   0},   // color 2
  {   0,   0, 255,   0},   // color 3
  {   0,   0,   0, 255},   // color 4
  { 150, 150,   0,   0},   // color 5
  { 150,   0, 150,   0},   // color 6
  {   0, 150, 150,   0},   // color 7
  { 100, 255,  50,   0},   // color 8
  {  20, 120, 200,   0},   // color 9
  { 180,  60,  30,   0},   // color 10
};


void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println("---- RGBW pattern sketch ----");

  pinMode(ledPin, OUTPUT);

  colorIndex = EEPROM.read(0);
  Serial.print("colorIndex read = ");
  Serial.println(colorIndex);

  if(colorIndex < 1 or colorIndex > 10)
  {
    // It is not valid, fall back to default value.
    colorIndex = defaultColorIndex;
    Serial.print("colorIndex changed to ");
    Serial.println(colorIndex);
  }

  button.attach(buttonPin, INPUT_PULLUP);
  button.interval(20);   // debounce interval in ms

  // Set the values
  setRGBW(colorIndex);
}

void loop() 
{
  button.update();     // keep the Bounce2 library going

  if(!setColorMode)   
  {
    // Is the button pressed for a long time ?
    if(button.read() == LOW && button.currentDuration() >= durationNewColor) 
    {
      // Switch to the mode to set the color.
      digitalWrite(ledPin,HIGH);
      setColorMode = true;
      previousMillisTimeout = millis();
    }
  }
  else
  {
    // Set a new color mode
    if(button.fell())
    {
      // The button was pressed, next color
      colorIndex++;
      if(colorIndex > 10) 
        colorIndex = 1;

      EEPROM.write(0, colorIndex);
      Serial.print("(saved:");
      Serial.print(colorIndex);
      Serial.print("),");
   
      // Update the new value to the leds
      setRGBW(colorIndex);

      // Remember the time that a button was last pressed.
      previousMillisTimeout = millis();
    }
    else
    {
      // No button pressed for a very long time ?
      // Then go back to normal.
      if(millis() - previousMillisTimeout >= durationBackToNormal)
      {
        digitalWrite(ledPin,LOW);
        setColorMode = false;
      }
    }
  }
}

void setRGBW(int value)
{
  Serial.print(value);
  Serial.print(",");

  for(int i = 0; i < 4; i++)
  {
    analogWrite(RGBWpin[i], colorCombinationTable[value][i]);
  }
}

Test it in Wokwi:

1 Like

Hello @Koepel - After entering programming mode (5 seconds red button), selecting color combination (short press *red button), how is programming mode exited (storing the value)?

*red == green; // chromaticdysencephalia

Suppose that someone is in a hurry, selects a new color and turns it off.
Therefor the new color combination is saved at the same moment that is a new color combination is shown on the leds.

[UPDATE] @xfpd The button to select the color combination is green. But your question got me thinking: I didn't know that the EEPROM was still valid after pressing the red reset button on the Uno board in Wokwi. I have changed the sketch to make use of it :smiley:

2 Likes

I didn't know the red button on the Uno board in Wokwi was functional. Thanks.

I wasn't at home for a week. Sorry about that.

I tried few tests by setting the eepromValue to a constant code number. I noticed that the color code 8 is showing up on other color codes. So, if I set 8, the LED strip shows 8. If I set 9, it shows 8.

Haven't tried this yet: