ATtiny45 timer issue

Hello,
I am generating PWM signals on the ATtiny 45, also a couple of masking signals for a H-bridge.
I have the ATtiny core from David A Mellis (MIT Media Labs, HighLowTech.org).
The duty cycle varies sinusoidally so I’m using the millis() function for the argument of sin() function.
I have set the internal 16MHz clock (I burnt the bootloader, but not sure if it is really running 16Megs).
I am not sure what timer is used by millis() on this core, right now I am generating the PWM on Timer0.
The prescaler for timer0 is set to 1/64. I think this produces a PWM of 976Hz.
Works well with 976Hz, code:

void setup()
{
  DDRB = 0b00011001;     // PB0, PB3, PB4 as output
  PORTB = 0b00010000;    // initialize PB3 and PB4 as high and low
  TCCR0A = 0b10100011;   // connect timer0 to output compare register (OCR0A), mode = clear OC0A on compare match.
  TCCR0B = 0b00000011;   // Prescaler = 1/64. f(pwm) = F_CPU/(256*prescaler). F_CPU = 16MHz, f(pwm) = 976.5625Hz in this case.
}

void loop()
{
  t = millis();   // Hey, what's the time?
  
  D = 255*abs(sin(2*PI*f*(t*0.001)));  // calculate duty

  if( D<Dt )
  {
    flag = 0;
  }
  else if( (D>=Dt)&&(!flag) )   // check for threshold crossing
  {
    PORTB ^= 0b00011000;      // complement PB3 and PB4 (mask signals)
    flag = 1;                 // flag prevents multiple threshold crossings
  }
  
  OCR0A = D;       //controls duty on PB0
  
  if(t>=10000) ((void (*)())0x0000)();     // soft reset every 10s
}

Okay, now I need a still higher PWM frequency of above 3kHz so when I changed the prescaler to 1/8, seems like it’s messing up the millis(), which I think is messy because the frequency of the sine and mask signals is also varying. (Probably, prescaler 64 was right for millis)?
Then I decided to use Timer1 for PWM, which did not produce any output (maybe I did not program it correctly. Timers on the Tiny are horrendous).

Now I am afraid I have screwed the control bits of both timers, I don’t know how to set them back for successful millis() operation (or do I have to?), nor do I have an oscilloscope to measure waveform frequencies.

So I basically need to know what timer to work on, before tackling other problems.

Any help appreciated.
Thanks.

Depends on the core. On my core ( https://github.com/SpenceKonde/ATTinyCore/ ), it’s Timer0 - I think the D. A. Mellis core does the same too - so that the fantastically feature-laden high speed Timer1 is available for user code without breaking millis.

Note that Timer1 on the tiny x5 series is WEIRD - but also very powerful. It is NOT your garden variety 16-bit timer like almost every other AVR - it’s an 8 bit high speed (ie, it can be set to be clocked off the 64mhz output of the PLL - the one that’s divided down to 16mhz to get the “16mhz internal” clock) timer with a built-in dead-time generator and a prescaler with all the powers of 2 available up to like, 1k or something. I think it’s designed for driving a dual h-bridge in motor control applications - but ofc you can do all sorts of stuff with that.

Thanks a lot.
I'll then try Timer1 correctly now. But should I reconfigure Timer0 so that millis works correctly? Or will the core correct it when I re-upload?

I have a few doubts regarding using timer1. Should I enable the PWM1A bit ? Should I program the PLL control register? What will be the input clock frequency to its prescaler?

Thanks.

Okay so I referred the datasheet and did some work:

void setup(){
  DDRB = 0b00011010;     // PB1, PB3, PB4 as output
  PORTB = 0b00001000;    // initialize PB3 and PB4 as high and low.
  TCCR1 = 0b11100101;    // Prescaler = 1/16 from PLL. PWM mode. Clear timer on compare match with OCR1C (top).
  GTCCR = 0x00;          // disconnect OCR1B
  OCR1C = 199;           // f(PWM)=f(PCK)/(OCR1C+1). f(PCK)=f(PLL)/prescaler. f(PLL)=64MHz gives f(PWM)=20kHz.
  OCR1A = 0;             // init.
  PLLCSR = 0b00000010;   // enable 64MHz high speed mode. enable PLL.
  _delay_us(100);        // wait for PLL to lock (100us usually)
  while(PLLCSR&(0x01) != 0x01);  // wait till PLL has locked
  PLLCSR |= 0b00000110;   // Connect PLL to timer1 as clock. 
}

The code gets stuck in the while loop. Never enters the void loop().
However, if I comment out the while loop, I am getting a PWM output (on an LED), but I can't verify its frequency.

[note: The tiny was heating up, so I reduced the clock to 8MHz internal, I don't think this will affect the PLL in anyway]

The code that configures timer0 for millis is part of your sketch (it's in the Arduino libraries) - it's part of the arduino init() function (defined I think in wiring.c), which is called before setup(). If you upload a sketch that doesn't break millis, millis will not be broken. Registers on AVR microcontrollers are volatile and are restored to startup condition upon reset.

Well, when using the 16mhz internal (PLL) clock, the PLL is always on and locked to the system clock (since they divide it by 4 to get the 16mhz), while when it's being used as the clock source for timer1 but not the system clock you do have to turn it on

Thanks, drAzzy. I changed to 8 MHz internal, then reuploaded the PLL part, now its working. The other timings relying on millis are fine while I change the prescaler. I just need an oscilloscope for tuning now! :slight_smile:

Do the control registers get erased when I upload a new program, without touching them?

The registers are reset to default state every time the chip is reset (which is done during the upload process) and every time power is applied.

wornoutflipflops:
Do the control registers get erased when I upload a new program, without touching them?

DrAzzy:
Registers on AVR microcontrollers are volatile and are restored to startup condition upon reset.

They get erased every time the board resets; they are not preserved, no register is. I'm not sure I understand the source of your confusion here...

Very well. That solves my confusion.
I asked because in case I dumped some other code without changing registers, I wanted to know if its operation would be affected by previously set control bits. Seems now it won't.

My program does a "soft reset" every 10 seconds, that is, jumps to 0x0000 in the code space. I wonder if that resets the control registers, and setup() is executed again to load the control registers, then it wastes a lot of time right? I do that in order to avoid millis() returning huge values in the long run and slowing down operations. Correct me if I am doing anything foolish.