Pages: [1]   Go Down
Author Topic: Reseting ATTiny85 timer so millis and delay will work properly  (Read 897 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am currently using an ATTiny85 using the core found at:

http://hlt.media.mit.edu/?p=1695

I'm using the 1MHz clock option

I have a PWM and timer setup to control an RGB LED and it's working fine. Here is my setup:

Code:
TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
TCCR0B = 0<<WGM02 | 1<<CS00;
TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
GTCCR = 1<<PWM1B | 2<<COM1B0;

From here I assign my Red/Green/Blue with the following method:

Code:
void showColor(byte red, byte green, byte blue) {
 
    OCR0A = ~red;
    OCR0B = ~green;
    OCR1B = ~blue;
}

It works great. But now whenever I use delay or millis the values are not correct. My project has different modes. One mode allows the RGB color to be set, but I also want to reset my timer(s) in another mode that will give proper values for delay/millis.

Can this be done at runtime?

I looked at the datasheet and it says that TCCR0A, TCCR0B, TCCR1, GTCCR are 0x00 by default, but when I set these registers to 0x00 my program stops. I assume because I have turned off the timers.

My questions are these:

1. Does someone have the default values for the timer registers that the Arduino ISP uses?

2. Can someone tell me where to find this information?

3. Is there a problem with setting the timers at runtime after setup?


Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 112
Posts: 5288
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
2. Can someone tell me where to find this information?

it's in hardware/arduino/cores/arduino/wiring.c

The Timer0 interrupt has to be called once every 1024 µs. So set the prescaler and overrun value appropriately.


Quote
3. Is there a problem with setting the timers at runtime after setup?

No, except that the millis() won't be the milliseconds after startup in this case.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok.. I just went through the process to reset the timer to default values and I wanted to get an opinion on my thought process. Bare with me please...

timing section in wiring.c:

Code:
// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
// the overflow handler is called every 256 ticks.
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))

// the whole number of milliseconds per timer0 overflow
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)

// the fractional number of milliseconds per timer0 overflow. we shift right
// by three to fit these numbers into a byte. (for the clock speeds we care
// about - 8 and 16 MHz - this doesn't lose precision.)
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)

volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;

#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
SIGNAL(TIM0_OVF_vect)
#else
SIGNAL(TIMER0_OVF_vect)
#endif
{
// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = timer0_millis;
unsigned char f = timer0_fract;

m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}

timer0_fract = f;
timer0_millis = m;
timer0_overflow_count++;
}

unsigned long millis()
{
unsigned long m;
uint8_t oldSREG = SREG;

// disable interrupts while we read timer0_millis or we might get an
// inconsistent value (e.g. in the middle of a write to timer0_millis)
cli();
m = timer0_millis;
SREG = oldSREG;

return m;
}


I'm not seeing how this gets me a default prescale and overrun value, but I do see this in the init section:

Code:
// on the ATmega168, timer 0 is also used for fast hardware pwm
// (using phase-correct PWM would mean that timer 0 overflowed half as often
// resulting in different millis() behavior on the ATmega8 and ATmega168)
#if defined(TCCR0A) && defined(WGM01)
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
#endif 

// set timer 0 prescale factor to 64
#if defined(__AVR_ATmega128__)
// CPU specific: different values for the ATmega128
sbi(TCCR0, CS02);
#elif defined(TCCR0) && defined(CS01) && defined(CS00)
// this combination is for the standard atmega8
sbi(TCCR0, CS01);
sbi(TCCR0, CS00);
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
// this combination is for the standard 168/328/1280/2560
sbi(TCCR0B, CS01);
sbi(TCCR0B, CS00);
#elif defined(TCCR0A) && defined(CS01) && defined(CS00)
// this combination is for the __AVR_ATmega645__ series
sbi(TCCR0A, CS01);
sbi(TCCR0A, CS00);
#else
#error Timer 0 prescale factor 64 not set correctly
#endif

// enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
sbi(TIMSK0, TOIE0);
#else
#error Timer 0 overflow interrupt not set correctly
#endif

If I'm tracing the code properly it seems like I should execute the following because TCCR0B and TIMSK are present:

Code:
sbi(TCCR0B, CS01);
sbi(TCCR0B, CS00);
sbi(TIMSK, TOIE0);

The datasheet says that setting CS00 and CS01 is the clkio/64 (from prescaler)

Then it looks like I need to set the overrun value back to 0xFF. The datasheet says that WGM0[2:0] = 0 should do the trick.

This is what I end up with.. Does this make sense?

RGB Control Mode:
Code:
TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
TCCR0B = 0<<WGM02 | 1<<CS00;
TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
GTCCR = 1<<PWM1B | 2<<COM1B0;

Timer Mode:
Code:
TCCR0A = 0<<COM0A0 | 0<<COM0B0 | 0<<WGM00;
TCCR0B = 0<<WGM02 | 3<<CS00;
TIMSK |= 1<<TOIE0;

I'm not at home so I can't compile this until later tonight, so I wanted to see if this makes sense.

Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 112
Posts: 5288
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Add

Code:
TIMSK &= ~(1<<TOIE0);

to your PWM setup to disable the timer interrupt during the PWM phase.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Excellent. It's working. Thanks for your help!
Logged

Pages: [1]   Go Up
Jump to: