Possible Timer issue?

Hey.

I am writing some basic code (a set of functions) for a STEM club.

I re-wrote the code following some issues to now use a “software PWM” like set up.

So far, I can happily get single Red, Green, Blue LEDs on an ATTiny85 (pins PB0, PB1,PB4) to “set as a certain colour” using my custom function:
setColor(hexcode,time).

The issue is that the delay() seems to not work. It is far too quick?

#include <avr/sleep.h>
#include <avr/interrupt.h>
/*
   ATtiny85 3 LEDs R, G and B.


  Software PWM:
  overflows @ 8MHz on 8 bit clock
  = 31.25KHz

  256 overflows = 122Hz (plenty!)

  On the overflow of a 8 bit timer...increment a global value.
  Initially all RGB are off.
  If say we want half on (128) on Red...
  Off for 256-128, then on till the "256 overflow".
  If we wnated blue on 200, Off for 56 then on after...

*/
#define R 0
#define G 1
#define B 4
#define sensor 3

// The global counters...

volatile unsigned int overflows = 0 ;
volatile byte brightness = 0;

volatile byte redVal = 0;
volatile byte blueVal = 0;
volatile byte greenVal = 0;

volatile boolean state = false;

#define pink 0xFF00FF
#define yellow 0xFFFF00
#define cyan 0x00FFFF
#define purple 0x9900FF
#define white 0xFFFFFF
#define orange 0xFF9900
#define green  0x00FF00
#define red 0xFF0000
#define blue 0x0000FF
#define black 0x000000

volatile byte blips = 0;

void setup() {
  ACSR = 0;
  ACSR |= (1 << ACD) | (0 << ACIE); // Dont need the Analog Digital Converter...
  WDTCR = 0;                  //Turn off Watchdog

  DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB4) | (0 << DDB3); // LEDs are outputs...sensor is INPUT.
  PORTB = 0;  // Sink / OUTPUT LOW

  PWMCounterPrepare();

}

void loop() {
  setColor(pink, 1);
  setColor(cyan, 3);
}

void setColor(unsigned long hex, float seconds) {

  redVal = hex >> 16;
  greenVal = hex >> 8;
  blueVal = hex;
  delay(seconds * 1000);
}

// Set up an 8 bit counter as a PWM counter...
// The counter on OVF triggers the ISR (ISR_OVF)
// ISR OVF will increment the "overflow count"
// The ISR also does the compares to turn on the RGB leds.

void PWMCounterPrepare() {
  // Using Timer1...8MHz / 256 = overflows at 31.25KHz
  // 8 bit resolution = 256 overflows...=~130Hz.

  TCCR1 = 0;
  TCCR1 = (1 << CS10); // Full speed (8MHz)
  GTCCR = 0;
  TIMSK = (1 << TOIE1); // Interrupt enable

}

ISR(TIMER1_OVF_vect) {

  // PWM Set the red LED on ...
  if (overflows > (255 - redVal)) {
    PORTB = PORTB ^ 0x01;
  }
  // PWM set the green LED on
  if (overflows > (255 - greenVal)) {
    PORTB = PORTB ^ 0x02;
  }
  // Set the Blue LED on...
  if (overflows > (255 - blueVal)) {
    PORTB = PORTB ^ 0b00010000;
  }

  //increment the number of overflows...
  overflows++;

  // After 255 cycles...set the overflows back to 0
  // and turn off the LEDs.
  if (overflows >= 255) {
    overflows = 0;
    PORTB = 0;
  }

}

I was expecting the Red+Blue on for 1 second…
Then Blue + Green on for 3 seconds…
Loop.

But basically I am getting that…but the delay is very fast!

I guess it may be a timer issue…but when I try use Timer0…there is a conflict with delayMicroseconds().

Thanks for any help!

I guess that ISR(TIMER1_OVF_vect) {} will carry on regardless of the delay() statement called indirectly from the main loop(). One way of stopping that behaviour is to set a global variable which the timer checks and prevents it from incrementing its 'overflow' counter.

6v6gt:
I guess that ISR(TIMER1_OVF_vect) {} will carry on regardless of the delay() statement called indirectly from the main loop(). One way of stopping that behaviour is to set a global variable which the timer checks and prevents it from incrementing its 'overflow' counter.

Ah yes!

So basically the "natural" overflow of the timer causes the overflow count increment...
So having a boolean global flag that say goes false before delay() may help!

I will be back if it doesn't work but thanks for the quick reply!

You are trashing TIMSK and timer 0 is used for delay(), so I’m surprised it works at all

Set TIMSK like this:

void PWMCounterPrepare() {
  // Using Timer1...8MHz / 256 = overflows at 31.25KHz
  // 8 bit resolution = 256 overflows...=~130Hz.

  TCCR1 = 0;
  TCCR1 = (1 << CS10); // Full speed (8MHz)
  GTCCR = 0;
  TIMSK |= (1 << TOIE1); // ADD IN TIMER 1 Interrupt enable
}

So basically the “natural” overflow of the timer causes the overflow count increment…
So having a boolean global flag that say goes false before delay() may help!

That makes no sense to me at all.
Your ISR continually counts 0…255 to PWM the LEDs, that’s got nothing to do with delay() timing.

Yours,
TonyWilk

Right....
I think the issue is I want 2 clocks...
I can not differentiate between OVF triggered by delay or by my PWM function.
I need to use Timer0.

Timer0 always comes back with this error:
"wiring.c.o (symbol from plugin): In function delayMicroseconds': (.text+0x0): multiple definition of __vector_5'"

I.e. the delayMicroseconds() already uses it.

Can I somehow @Override the delayMicroseconds() so the method isn't even compiles...as I will not be using it?

TonyWilk:
You are trashing TIMSK and timer 0 is used for delay(), so I’m surprised it works at all

Set TIMSK like this:

void PWMCounterPrepare() {

// Using Timer1…8MHz / 256 = overflows at 31.25KHz
  // 8 bit resolution = 256 overflows…=~130Hz.

TCCR1 = 0;
  TCCR1 = (1 << CS10); // Full speed (8MHz)
  GTCCR = 0;
  TIMSK |= (1 << TOIE1); // ADD IN TIMER 1 Interrupt enable
}

Didn’t notice I missed the OR on the TIMSK register…my bad.
Will make changes…

Hi,

void setColor(unsigned long hex, float seconds)

and

delay(seconds * 1000);

The delay parameter is an int not a float,
It may help, I don't know just an observation., try.

void loop() {
  setColor(pink, 1.0);
  setColor(cyan, 3.0);
}
int delaymSeconds = seconds * 1000.0
delay(delaymSeconds);

Tom.. :slight_smile:

Why is is necessary to use a Hardware Timer in a program that uses delay()? Why not just use millis() or micros() for timing as illustrated in Several Things at a Time

...R

  WDTCR = 0;                  //Turn off Watchdog

Unless you turn it on, which you don't, there is no reason to turn it off.

That line of code does not turn off the watchdog.

TomGeorge:
Hi,

void setColor(unsigned long hex, float seconds)

and

delay(seconds * 1000);

The delay parameter is an int not a float,
It may help, I don’t know just an observation., try.

Fixed the issue! Thank you for spotting my oversight.

Robin2:
Why is is necessary to use a Hardware Timer in a program that uses delay()? Why not just use millis() or micros() for timing as illustrated in Several Things at a Time

…R

The timer is for the software based PWM.
At 8MHz, 8bit timer = about 31KHz of overflow.
Wanting 8 bit resolution…
So 31KHz / 256 =~120Hz (so fast enough for LEDs to not seem to be “flickering”).