Interrupts and delay()

Hi, I recently started to to program the attiny85 using the following core from HLT:

As far as I know it does not support the tone() function so, in an attempt to make my own I created the following sketch:

void setup()
{
  pinMode(0, OUTPUT);
}

void loop()
{
  myTone(500);
  delay(1000);
  myNoTone();
  delay(1000);
}

ISR(TIMER1_COMPA_vect)
{
   PORTB ^= (1 << PORTB0); 
}


void myTone(int freq)
{
  float period = 1.00/(float)freq;
  float ticks = (125000.00*(float)period)/2.00;
  int over = ticks/255;
  TCCR1 = (1 << CTC1) | (1 << CS12); // divide by 8 prescaler
  
  
  OCR1A = ticks; //
  OCR1C = ticks; //
  TIMSK = (1 << OCIE1A) | (1<<TOIE1);
  
  sei();
}

void myNoTone()
{
 TCCR1 = 0;
 TCNT1 = 0;
}

Everything works fine, however, when running the sketch the delays between the tones aren,t 1000ms
If someone knows why this happens, please let me know. Thanks.

Peppel:
Everything works fine, however, when running the sketch the delays between the tones aren,t 1000ms
If someone knows why this happens, please let me know. Thanks.

So how long is the delay instead of the expected 1000ms?

And is it always the same length?

...R

The delays last the same, aprox. 1/2 of a second.

When I tried with the gcc-avr _delay_ms() It worked fine

What does this do

PORTB ^= (1 << PORTB0);

I can never get my head around that notation. Can you express the RHS as a binary value?

I'm wondering if bits are mangled in PORTB that should not be mangled.

...R

Robin2:
What does this do

PORTB ^= (1 << PORTB0);

I can never get my head around that notation. Can you express the RHS as a binary value?

I'm wondering if bits are mangled in PORTB that should not be mangled.

...R

Toggles bit zero in PORTB, i.e. PORTB = PORTB ^ 0x01;

Shouldn't mangle any other bits.

Common idiom, worth mastering.

PS: But it is not an atomic operation, so if not executed with interrupts inhibited (as it is here by virtue of being in an ISR), it could cause unintended results.

PORTB is the register that stores pin outputs.
The LSB of PORTB is PORTB0 (pin 5)

PORTB = 00000000
(1 << PORTB0) = 00000001
PORTB XOR (1 << PORTB0) = 00000001
It's just using a XOR mask to toggle pin 5, it has nothing to do with
timing or delays.

This is much easier to understand and PORTB = PORTB ^ 0b00000001; is even better.

And I guess the toggled bit is what is creating the tone.

So what is interfering with delay() ?

Can you add a little code to toggle the on board LED after every delay and ( A ) check the time against the flashing LED and ( B ) comment out the calls to myTone() and myNoTone() and see does that restore the delay() to its proper duration?

Might try it myself tomorrow.

...R

But there is a different way to toggle a pin.
You can write to the PINx register.

PINB = (1 << PORTB0);

That will Toggle the pin atomically using the PINxn h/w toggle functionality.

--- bill

Can you add a little code to toggle the on board LED after every delay and ( A ) check the time against the flashing LED and ( B ) comment out the calls to myTone() and myNoTone() and see does that restore the delay() to its proper duration?

I connected a LED to pin 6 of the attiny (PB1) and tried the following sketch:

#include <avr/delay.h>

void setup()
{
 DDRB = (1 << PORTB0) | (1 << PORTB1);
 PORTB = 0;

}

void loop()
{
  myTone(500);
  PORTB ^= (1 << PORTB1);
  delay(1000);
  myNoTone();
  PORTB ^= (1 << PORTB1);
  delay(1000);
}

ISR(TIMER1_COMPA_vect)
{
   PORTB ^= (1 << PORTB0); 
}


void myTone(int freq)
{
  float period = 1.00/(float)freq;
  float ticks = (125000.00*(float)period)/2.00;
  int over = ticks/255;
  TCCR1 = (1 << CTC1) | (1 << CS12); // divide by 8 prescaler
  
  
  OCR1A = ticks; //
  OCR1C = ticks; //
  TIMSK = (1 << OCIE1A) | (1<<TOIE1);
  
  sei();
}

void myNoTone()
{
 TCCR1 = 0;
 TCNT1 = 0;
}

the delays were still less than 1000ms, when I removed the tone functions the delays were normal.

Probably the interrupts are messing up with the delay()?

Peppel:
As far as I know it does not support the tone() function...

This core does...
http://code.google.com/p/arduino-tiny/

I finally solved my problem.

Because TIMSK is the only register in my sketch that affects timer1 and timer0 (delay timer) I replaced:

TIMSK = (1 << OCIE1A) | (1<<TOIE1);

with:

TIMSK |= (1 << OCIE1A) | (1<<TOIE1);

Note that OR operation.
Maybe when setting TIMSK I was also changing the timer0 settings??

Anyway, thanks to all. :slight_smile:

That's the sort of problem I had in mind when I said

I'm wondering if bits are mangled in PORTB that should not be mangled.

I just wasn't looking in the right place.

...R