3 pwm pins ticking up or down, 3 working fine

Hi Everyone,
I am at a total loss as to what I must be missing in my code. I am using a nano and have 8 pots for inputs on A0-A7 and 6 mA gauges on D3, D5, D6, D9, D10, D11. Neopixel strip data on D2.
Everything works great other than D3, D5, D6 are ticking up and down. D3 and D6 slowly decrease hit the max and return to 0 and track back up again. D5 rises slowly hits the max goes back to zero.
I have tested the outputs and inputs and everything looks as expected even after the mapping. I have added an external power supply no change. The issue hits at the analogwrite step. When I check the outputs via the serial monitor after this step they are ticking up and down and the gauges match this behavior. If I move the pot mapped to D3 and D6 to zero and the output stays at zero, pot on D5 full and it stays close to 255. The pot seems to define the start point of the drifting. The drift is in increments of 1 and takes about 24-25 seconds from 0 or 255 to the opposite side, when it hits 0 or 255 it will then immediately kick back over to its starting position. If I move D3 to a different gauge the problem moves to the new gauge so it does look like the pin is the issue. Again D9-11 are working perfectly fine.
3 hours in and just can not figure this one out, any help would be appreciated.

//Guage Puzzle June 4

//  INCLUDES
#include <FastLED.h>

// CONSTANTS
#define NUM_LEDS 6
#define DATA_PIN 2
int numOutputs = 8;
int numInputs = 8;
int brightness = 255;
CRGB leds[NUM_LEDS];
const byte meterPins[] = {3, 5, 6, 9, 10, 11};
const byte sliderPins[] = {A0, A1, A2, A3, A4, A5, A6, A7};
// Win condition const byte relayPin = 2;
const int targetValues[] = {128, 128, 128, 128, 128, 128, 128, 128};
const int tolerance = 4;
int y = 0;
const byte smoothInterval = 40;
struct Timer {
  CRGB targetColor;
  uint32_t previousMillis;
  byte counter = 0;
  bool isBlending = false;
}
timer[NUM_LEDS];

// GLOBALS
// 10-bit input values from the ADC have values in the range (0-1023)
int inputValues[8] = {};
// 8-bit output values to pass to AnalogWrite PWM output have values in the range (0-255)
int outputValues[8] = {};
bool isSolved = false;


//Sequence for LED blend
void update(byte currentLed){
  uint32_t currentMillis = millis();
  if (millis() - timer[currentLed].previousMillis > smoothInterval)
  {
    timer[currentLed].previousMillis = currentMillis;
    if (timer[currentLed].counter < 255 && timer[currentLed].isBlending == true)
    {
      timer[currentLed].counter++;
      CRGB tempColor = blend( leds[currentLed], timer[currentLed].targetColor, timer[currentLed].counter );
      //Serial.print(timer[currentLed].counter);
      //Serial.print("\ttempColor:"); Serial.print(tempColor.r); Serial.print(" "); Serial.print(tempColor.g); Serial.print(" "); Serial.println(tempColor.b);
      leds[currentLed] = tempColor;
      FastLED.show(); // needed removed from loop
      if (leds[currentLed] == timer[currentLed].targetColor)
      {
        //Serial.print("target reached LED "); Serial.println(currentLed);
        timer[currentLed].counter = 0;
        timer[currentLed].isBlending = false;
      }
    }
  }
}


void setup() {
  Serial.begin(9600);
  //Set up LEDs to start colors
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  for(int i=0; i<NUM_LEDS; i++){
    leds[NUM_LEDS] = CRGB::Red;
    FastLED.show();
 }
// Initialise the output pins
  for(int i=0; i<6; i++) {
    pinMode(meterPins[i], OUTPUT); 
  }
}



void loop() {
  for(int i=0; i<numInputs; i++){
    // Clear ADC
    for(int x=0; x<2; x++) {
      analogRead(sliderPins[i]);
      delay(5);
    }
    inputValues[i] = analogRead(sliderPins[i]);
  }
  // Quick set for outputs
  for(int i=0; i<numOutputs; i++){
    outputValues[i] = inputValues[i];
    //Testing Inputs, note floating pin produces variable results START
    //Output and input values correct
    //Serial.print(i);
    //Serial.print("-");
    //Serial.print(outputValues[i]);
    //Serial.print(",");
    //if(i>(numOutputs-2)){
    //Serial.println("");
    //}
    //END
  }
  
  //Setting up custom paramters/relationships
  //outputValues[0] = (inputValues[0] + inputValues[1]/ 5.5);
  //outputValues[1] = (inputValues[1] - inputValues[2]);
  //outputValues[2] = (inputValues[2]);
	//outputValues[3] = (inputValues[3]);
  //outputValues[4] = (inputValues[4]);
  //outputValues[5] = (inputValues[5]);
  
	// Check outputs vs targets
  bool allMetersCorrect = true;
  // Loop over each output
	for(int i=0; i<numOutputs; i++){
    outputValues[i] = map(outputValues[i], 0, 1000, 0, 255);
    outputValues[i] = constrain(outputValues[i], 0, 255);
    //output values correct
    if(abs(outputValues[i] - targetValues[i]) > tolerance) {
      allMetersCorrect = false;
      // Turn incorrect matches to red
      timer[i].targetColor = CRGB::Red;
      timer[i].isBlending = true;
    }
    else {
      // Turn LED Green when input is correct
      timer[i].targetColor = CRGB::Green;
      timer[i].isBlending = true;
    }
    update(i);
	}
  //Write to the meters
  for (int i=0; i<6; i++){
    //Failure on output 1-3
    analogWrite(meterPins[i], outputValues[i]);
    //Output values wrong
    Serial.print(i);
    Serial.print("-");
    Serial.print(outputValues[i]);
    Serial.print(",");
    if(i>(4)){
    Serial.println("");
    }
    //END   
  }
	if(allMetersCorrect && !isSolved) {
    //Serial.println("Solved!");
    isSolved = true;
    //Wipe gauges on solve need to add delay on return to stop gauge bounce
    //y = y+20;
    //if(y >= 850){
      //y=0;
      //}
    //for(int i=0; i<6; i++){
      //outputValues[i] = y;
     }
 // If the puzzle had been solved, but now the meters are no longer correct
  else if(isSolved && !allMetersCorrect) {
    //Serial.println("Unsolved!");
    isSolved = false;
  }
  //Display Inputs
  //for(int i=0; i<8; i++) {
   // Serial.print(inputValues[i]);
   // Serial.print(",");
   // if(i>6) { Serial.println(""); }
  //}
  //Display Outputs
   //Serial.print("OUTPUT  ");
   //for(int i=0; i<numInputs; i++) {
   //Serial.print(i);
   //Serial.print("-");
   //Serial.print(outputValues[i]);
   //Serial.print(",");
   //if(i>6) {
   //Serial.println("");
   //}
  //}
}

So you are saying that it is not a programming error. Then i suspect that FastLED is fiddling with the PWM timer to compensate for the time it spend with interrupts turned 'off'
In regards to the mapping, a simple

outputValues[i] = inputValues[i] >> 2;

actually reduces the 10 bit to an 8-bit value more accurately and efficiently than what you do with map() and constrain() , but you say that is not the issue, so FastLED is probably to blame.
Comment out FastLED.show() to confirm that. If that is so, you can switch to adafruit_neopixel.h which does not have the compensation. I think that the compensation should be optional, but the developers of FastLED do not agree.

Thank you I will test this shortly. And I am NO expert at this. So what I am saying is I have checked the inputs and outputs at every stage and it’s good. The problem is introduced with the analog write function. And it’s with the first 3 pwm pins and not the last 3.

So I removed the fast.led show and it did not make a difference. But you got me thinking. I removed the call to the update function next and that fixed the issue.
If I remove the line defining CRGB tempcolor and the associated leds[currentled] = tempcolor this also solves the issue even when leaving the fastled.show line active.
So do I need to figure out how to switch libraries and a blend or is something wrong with the code that I am using? This is a really strange artifact. Spent about an hour inspecting the wiring and all the simple stuff.

Thanks for the tip with the mapping.

Your suggestion on removing the mapping and constrain works beautifully btw. Like this is kinda a big deal. Much smoother response and it removed a bounce out of the gages. Before I was seeing a +_ of around 2-3 and there was constant movement. This is rock solid without a single digit change. The physical affect of this is very substantial. I have no idea how this forum figures all this stuff out.

So you are saying that the issue is here ?

CRGB tempColor = blend( leds[currentLed], timer[currentLed].targetColor, timer[currentLed].counter );

But now it shows me that there is code missing... Where is blend() defined ?
I see now that you are using a type of 'fade-function' personally i don't do it the way you do.

Anyway i think i've found it.

#define NUM_LEDS 6
#define DATA_PIN 2
int numOutputs = 8;
int numInputs = 8;
(....)
for(int i=0; i<numOutputs; i++){
    outputValues[i] = map(outputValues[i], 0, 1000, 0, 255);
    outputValues[i] = constrain(outputValues[i], 0, 255);
    //output values correct
    if(abs(outputValues[i] - targetValues[i]) > tolerance) {
      allMetersCorrect = false;
      // Turn incorrect matches to red
      timer[i].targetColor = CRGB::Red;
      timer[i].isBlending = true;
    }
    else {
      // Turn LED Green when input is correct
      timer[i].targetColor = CRGB::Green;
      timer[i].isBlending = true;
    }
    update(i);  // so that is a maximum of 7
}

but within update()

void update(byte currentLed){
  uint32_t currentMillis = millis();
  if (millis() - timer[currentLed].previousMillis > smoothInterval)
  {
    timer[currentLed].previousMillis = currentMillis;
    if (timer[currentLed].counter < 255 && timer[currentLed].isBlending == true)
    {
      timer[currentLed].counter++;
      CRGB tempColor = blend( leds[currentLed], timer[currentLed].targetColor, timer[currentLed].counter );
      //Serial.print(timer[currentLed].counter);
      //Serial.print("\ttempColor:"); Serial.print(tempColor.r); Serial.print(" "); Serial.print(tempColor.g); Serial.print(" "); Serial.println(tempColor.b);
      leds[currentLed] = tempColor;  

So if currentled is 6 or 7 you are writing beyond the size of the array, and the results of that are unpredictable.

I think that question has been answered, though i would like to note the mistake in your code is a result of the way the FastLED library has been set up. You are not the first to write beyond the size of the array, and you will not be the last and the FastLED developers have no intention of doing anything about it. To be clear, with adafruit_neopixel, you can not write beyond the size of the led buffer.

As long as you understand what the shifting of the bits of the 10-bit value to the right 2 bits results in an 8 bit value, and how you can make use of that, there is no need to figure out how the forum does it. Glad to be of help.

Ahhhhh I see what you are saying. I have 8 inputs and 6 gauges with 6 LEDs. Need to separate that out from the win conditions.

Nice catch.

1/2 way through switching to the neopixels library so may as well finish that off.

Thank you!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.