1

I'm writing a simple program that is using Timer 1 comparator B to generate a square wave on DEBUG_PIN.

So my code at first turns on timer 1 with prescaler 8192 so that one tick is approximately 1ms. Then , when timer reaches up to 100 I turn off all timers, than enable timer1 compB and drive DEBUG_PIN high. When timer1B interrupt occurs, then it drives DEBUG_PIN low and disables TIMER1B interrupts.

The problem is that whenever I run the code, DEBUG_PIN state is always high. Here is the strange thing: when I change comparator from B to A on the same timer, everything works fine! Here is the code:

#include "avr/interrupt.h"

#define DEBUG_PIN 4

volatile bool flag = false;
volatile int counter = 0;

ISR (TIMER1_COMPB_vect){
  digitalWrite( DEBUG_PIN, LOW );
  bitClear(TIMSK, OCIE1B);
}

void setup() {
  cli();

  pinMode( DEBUG_PIN, OUTPUT );

  digitalWrite( DEBUG_PIN, HIGH );
  //stop TIMER1
  TCCR1 = 0;
  //prescaler is 8192 sot that 1 tick is 1ms, enable timer1
  TCCR1 |= (1<<CS13)|(1<<CS12)|(1<<CS11)|(0<<CS10);
  sei();
}

void loop() {

    if( TCNT1 >=100 ){
      cli();
      counter = 0;
      //disable compB
      bitClear(TIMSK, OCIE1B);

      digitalWrite( DEBUG_PIN, HIGH );

      /* enable compB */
      //set comparatorB value
      OCR1B = 70;
      //enable compA interrupts
      bitSet(TIMSK, OCIE1B);

      TCCR1 = 0 ;

      TCCR1 |= (1<<CS13)|(1<<CS12)|(1<<CS11)|(0<<CS10);

      TCNT1 = 0;

      //reset OCF1A interrupt flag, just in case
      bitSet(TIFR,OCF1B);
      sei();
    }
}

Does anybody has any idea where this comes from?!?!

  • I tested your program and it works as expected: roughly 70 ms up every 100 ms. What core are yo using? – Edgar Bonet May 9 '17 at 9:28
0

Alright, I fixed the problem. There is some kind of issue witm pwm hardware generation with timers on ATTINY85. Although I am not using it, I tried resetting whole GTTCR register before enabling COMPB interrupt and it worked! Here is the working code:

#include "avr/interrupt.h"

#define DEBUG_PIN 4

volatile bool flag = false;
volatile int counter = 0;

ISR (TIMER1_COMPB_vect){
  digitalWrite( DEBUG_PIN, LOW );
//  flag = false;
//  TCNT1 = 0;
  bitClear(TIMSK, OCIE1B);
}

void setup() {
  cli();

  // put your setup code here, to run once:


  pinMode( DEBUG_PIN, OUTPUT );

  digitalWrite( DEBUG_PIN, HIGH );
  TCCR1 = 0;
  TCCR1 |= (1<<CS13)|(1<<CS12)|(1<<CS11)|(0<<CS10);
  sei();
}

void loop() {

    if( TCNT1 >=100 ){
      cli();
      counter = 0;
      //disable compB
      bitClear(TIMSK, OCIE1B);

      digitalWrite( DEBUG_PIN, HIGH );

      /* enable compB */
      //set comparatorB value
      OCR1B = 70;
      //enable compA interrupts
      bitSet(TIMSK, OCIE1B);

      TCCR1 = 0 ;

      GTCCR = 0;

      TCCR1 |= (1<<CS13)|(1<<CS12)|(1<<CS11)|(0<<CS10);

      TCNT1 = 0;

      //reset OCF1A interrupt flag, just in case
      bitSet(TIFR,OCF1B);
      sei();
    }
}

Funny thing isthat you don't have to do this if you're using COMPA. Dunno why though...

EDIT: I tried clearing GTCCR bits one by one and it turns out that the bit that was causing problems was PWM1B bit. So instead of GTCCR = 0 I use bitClear(GTCCR, PWM1B); and everything works fine:)

Seems like PWM1B is enabled by default, dunno why...

  • Which core are you using? – Edgar Bonet May 9 '17 at 12:00
-1

Here is the code:

that code can be greatly improved:

1) break down your task into logical blocks;

2) code each block as per the datasheet, with comments;

3) tell your readers what you intended your code to do and what your code did.

4) read the datasheet.

edit: your code, following the steps above, set to flip PB4 at OCR1B = 70, on an attiny85 @ 8MIPS, produced the following.enter image description here

you are close so keep working at it.

edit 2: once setup, the code is fairly simple.

ISR (TIMER1_COMPB_vect){
  //bitClear(TIMSK, OCIE1B);
    //update the next match point for timer1, ch b
    OCR1B +=(IO_GET(DEBUG_PORT, 1<<DEBUG_PIN))?(DEBUG_PR - DEBUG_DC):DEBUG_DC;
    IO_FLP(DEBUG_PORT, 1<<DEBUG_PIN);   //flip the output pin
}

void loop() {

}

the above code generates a pulse train with a duty cycle of DEBUG_DC / DEBUG_PR. Nothing in the loop() so it is fully transparent to the user. enter image description here

  • 1) I think this program is quite straight-forward, thus it does not need to be broken down more – Em Ka May 9 '17 at 0:50
  • 3) So my code at first turns on timer 1 with prescaler 8192 so that one tick is approximately 1ms. Then , when timer reaches up to 100 I turn off all timers, than enable timer1 compB and drive DEBUG_PIN high. When timer1B interrupt occurs, then it drives DEBUG_PIN low and disables TIMER1B interrupts. – Em Ka May 9 '17 at 0:54
  • 4) I have read datasheet very carefully – Em Ka May 9 '17 at 0:54
  • Did you try to run the program on physical attiny, not in simulation? – Em Ka May 9 '17 at 11:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.