Mega 2560 timers, pins, problems

This code is for an LED/Sound layout using common-cathode RGB LEDs on a MEGA 2560 and 6 10k Potentiometers for adjustment.

When I use the code absent the volume library, it works perfectly, but when I incorporate the volume library, the results just become unpredictable and effed-up.

For example, Potentiometer 2 (potPins[1]), aka pin A6, corresponding to the Bval variable seems to slow down the execution of the code, i.e. has something to do with timer0 (I'm assuming), which is utilized by the volume library NO MATTER WHERE I PLUG IT (amongst the available analog pins, which are A8-A12, or A6).

This is really frustrating me beyond my ability to produce words to convey that emotion.

The obvious answer is "don't use the volume library, but it's pretty integral to the intended function of the project, and also, I need to know what this timer problem is". An answer for me could be as simple as "such and such pins shouldn't be used because they correspond to some interrupt or timer, but that answer doesn't seem available anywhere I've looked). And I obviously don't wholly grasp the idea of timers and interrupts.

Here is the problem code:

#include <Volume.h>
  
  Volume vol; // Plug your speaker into the default pin for your board type: //Note to self: this declares an instance of "Volume", is necessary.
            // https://github.com/connornishijima/arduino-volume#supported-pins 

int cathode[15] = {32, 34, 33, 35, 31, 49, 51, 52, 53, 50, A2, A1, A0, A3, 8};
int anode[9] = {2,3,5,6,9,10,7,11,12};

int period = 55;
int Rval = 50;
int Gval = 0;
int Bval = 50;

int potPins[6] = {A15, A14, A13, A5, A6, A7};
int potVals[6] = {0, 0, 0, 0, 0, 0};


void setPinModes();
void setColors();
void clearall();
void sequenceAdd();
void sequenceClear();
void getPotVals();

void setup() {



  vol.begin(); // After calling this, vol.delay() and vol.delayMicroseconds will no longer work
               // correctly! Instead, use vol.delay() and vol.delayMicroseconds() for
               // the correct timing

  vol.setMasterVolume(1.00); // Self-explanatory enough, right? Try lowering this value if the speaker is too loud! (0.00 - 1.00)
  vol.delay(500);

  vol.alternatePin(false);

Serial.begin(9600);
setPinModes();
setColors();




}

void loop() {

  clearall();
  setColors();
  getPotVals();
  //sequenceAdd();
  sequenceClear();
  

}

void setPinModes() {

  for (int i = 0; i < 15; i++) {
    pinMode(cathode[i], OUTPUT);
  }

  for (int i = 0; i < 8; i++) {
    pinMode(anode[i], OUTPUT);
  }

  for (int i = 0; i < 5; i++) {
    pinMode(potPins[i], INPUT);
}

}
void setColors() {

getPotVals(); //This is sort of sloppy coding, so clean this up now.

analogWrite(anode[0], Rval);
analogWrite(anode[3], Rval);
analogWrite(anode[6], Rval);

analogWrite(anode[1], Gval);
analogWrite(anode[4], Gval);
analogWrite(anode[7], Gval);

analogWrite(anode[2], Bval);
analogWrite(anode[5], Bval);
analogWrite(anode[8], Bval);
}

void clearall() {

for (int i = 0; i<15; i++) {
  digitalWrite(cathode[i], HIGH);
}

setColors();

}

void sequenceAdd(){
    for (int i = 0; i<15; i++) {
    digitalWrite(cathode[i], LOW);
    vol.delay(100);
    }
    clearall();
    for (int i = 14; i>0; i--) {
    digitalWrite(cathode[i], LOW);
    vol.delay(100);
    }
    clearall();
}

void sequenceClear() {

   
  for (int i = 0; i <12; i++) {
  digitalWrite(cathode[i], LOW);
  vol.delay(period);
  clearall();
  }

  vol.delay(period*0.20);
  digitalWrite(cathode[12], LOW);
  vol.delay(period*1.40);
  clearall();
  
  digitalWrite(cathode[13], LOW);
  vol.delay(period*1.70);
  clearall();
  
  digitalWrite(cathode[14], LOW);
  vol.delay(period*2.00);
  clearall();
  
  for (int i = 14; i > 2; i--) {
  digitalWrite(cathode[i], LOW);
  vol.delay(period);
  clearall();
  }

  vol.delay(period*0.20);
  digitalWrite(cathode[2], LOW);
  vol.delay(period*1.40);
  clearall();
  
  digitalWrite(cathode[1], LOW);
  vol.delay(period*1.70);
  clearall();
  
  digitalWrite(cathode[0], LOW);
  vol.delay(period*2.00);
  clearall();
}

void getPotVals() {

  for (int i = 0; i < 5 ; i++) {
    potVals[i] = analogRead(potPins[i]);
    Serial.print(potVals[i]);
    Serial.print("   ");
  }

  Serial.println();  // carriage return after potVals written serially.

  Rval = map(potVals[3], 0, 1023, 0, 255);
  Gval = map(potVals[4], 0, 1023, 0, 255);
  Bval = map(potVals[5], 0, 1023, 0, 255);
  

}

I'll be researching the issue and hoping someone will help me figure it out.

Thanks a lot.

Start by posting a schematic, not a frizzy drawing. Show all interconnections and power supplies. Include links to technical information on all hardware items.

This is clearly not a hardware problem. He reports that it works without using Volume.h library. And Volume.h sounds like the sort of library that would be great at causing whacko problems like this. Don't go sending people on fools errands when it's bloody obviously not going to provide any enlightenment.

The problem is that you are using PWM on pins 11 and 12 in combination with the Volume.h library, on a mega2560 that should take out pwm on pins 11, 12, and 13, and trying to use it anyway will break stuff.

analogWrite has no idea that the timer it would use to generate PWM on pins 11 and 12 has been completely reconfigured, and is now in an entirely different mode than it is expecting, and would set OCR1A or OCR1B to the duty cycle - if it were still in 8-bit pwm mode, like it was expecting, that would give you PWM of that duty cycle. But it's not. It's not in a PWM mode at all, it's in CTC mode (Clear Timer [and fire interrupt] on Compare match).

In vol.begin, it is set to F_CPU/20000 -1, that is, at 16 MHz it's set to 799 and the prescaler is dropped back to 1. Because see, it needs this to fire 20k times a second. if that doesn;'t ring alarm bells in your head right off the bat, it should. That means EVERY 800 CLOCK CYCLES IT FIRES THE INTERRUPT. Gee, I hope the author wrote it with careful attention to performance.... Of course, the fact that it is calling analogWrite on the speaker pin (analogWrite will be doing a surprisingly slow lookup of which timer is on that pin, then calling pinMode() which does another series of slowass lookups even though the pin was just set output 100 microseconds ago), when they could be doing a single write to the output compare register, since they only support pins on timer0 anyway for that, implies that they haven't given much attention to performance now does it?

Anyway, so analogWrite(11,duty) will write a number between 1 and 254 to OCR1A, instead of 799, making it this interrupt fire more frequently, with the observed effect of the sketch getting slowed down something horrible, because it's spending all it;'s time in that ISR. And of course, that's controlled by, if I'm not mistaken, the pot you have connected to A6, consistent with your observation.

The minimal effort solution is simple:
Don't use those pins for analogWrite(). Luckily, there are 3 more pins you can use, located in that block of pins on the end that nobody talks much about: 44, 45, and 46 can be used for PWM too, in place of the ones that the library makes non-usable with PWM. That should get things mostly sorted out I'd reckon.

Azzy (Doctor, that is),

I don't encounter too many people who impress me with their base of knowledge, but that one did it for me, man.

I was trying to sort out on my own what I'm sure was the same data you referenced, and just couldn't do it.

Long term, I'd eventually like to gain the level of intuition you seem to have developed about such technicalities.

Have you ever heard of the term "Mount Stupid"? It's the imaginary mountain in front of you when you take on a challenge so far beyond your expertise that you don't even know what to call stuff, and often, what questions to ask.

The base of mount stupid is where I've found myself stuck for some time in terms of a few things. BUT, occasionally I run into a problem challenging enough to prompt me to ask the right question, hopefully to the right forum, and eventually get the right answer, bumping me one step up the mountain, hence one step closer to enlightenment.

I knew timers were involved, but I didn't consider the internals involved in querying said timer(s), methods called in warped time due to clock speed irregularities, etc. I thought the issue must have been with the INPUT associated with that Pot, not the OUTPUTS it INDIRECTLY controlled, so I'd never have even considered looking into what it takes to analogWRITE when I thought my problems were analogREAD based.

Anyway... Awesome. Thanks.

Here is where I would say "I'll let you know how it works out" but you're right. I can feel it. So it will work.

Thanks, man.

Okay, that library is an absolute shitshow.

There is no reason it even needs to use timer0 and disrupt millis! It could use timer2!

Argh.... I got nerdsniped by this, forked it, and I think I've fixed it so it doesn't trash timekeeping... I had stuff to do! I have a party coming over tomorrow and my light strings don't work yet, and instead of working on that I fixed this stupid volume library, Not even compile tested - let me know if it appears to work and I will PR it and we'll see the guy's reaction. Since it's in library manager, I'd kind of like to get a fixed version out there, because people like yourself are running into it.

Tried to compile. Other than a few obvious typos, I am having the issue that the compiler is telling me that your recalculateVol() function (which was spelled differently in different places, but now isn't), is not declared in scope, despite my having added it to the header file.

I can't help but note that even once declared in the header file, the function does not appear in orange. What does that mean and how is it rectified?

It means that it's not defined as a keyword in keywords.txt. The Arduino IDE supports the dynamic addition of keywords to highlight in the editor by placing a keywords.txt file with the functions and objects listed in it. It doesn't make a difference apart from how it looks in the editor if keywords are defined in such a file, so it's mostly non-consequently, but it can be helpful in spotting typos.

Okay. So does that mean that any third-party library needs to have a keywords.txt file to utilize that IDE feature? If so, where does it need to be placed? (And I might be able to deduce that by looking at a library folder, but I'm presently afk).

I appreciate that new info and will play with it.

To address the "recalculateVol() not declared in this scope"...

Simply put, it's defined in the .cpp. It's declared in the .h. Where the hell else could it be declared?

Yes,that's correct. I did it for a few libraries I wrote for myself. It's pretty easy. Just use the proper syntax (described somewhere on this site, Google a bit) and put the text file in the library folder.

It doesn't influence the compiler though, so this doesn't explain your compilation issue. I haven't looked into that.

No dice.

Got it to compile, but no functionality, as in no lights, no beeps, etc...

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