2

I have defined my code to generate an interrupt over each 5μs on CTC mode using timer1 but the output shows a time of ~15μs.

Following the equation to set the counting number to achieve the desired time

(# timer counts + 1) = (target time) / (timer resolution)

I've got OCR1A = 79 for a desired time of 5μs using no prescaler and a source clock of 16MHz on Arduino Uno.

My code is as follows:

// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>

#define LEDPIN 9

void setup()
{
    pinMode(LEDPIN, OUTPUT);
    digitalWrite(LEDPIN, HIGH);

    // initialize Timer1

    cli();          // disable global interrupts

    TCCR1A = 0;     // set entire TCCR1A register to 0
    TCCR1B = 0;     // same for TCCR1B

    // set compare match register to desired timer count:
    OCR1A = 79;

    // turn on CTC mode:
    TCCR1B |= (1 << WGM12);

    // Set CS10 bit for no prescaler:
    TCCR1B |= _BV(CS10);

    // enable timer compare interrupt:
    TIMSK1 |= (1 << OCIE1A);

    sei();          // enable global interrupts

}

void loop () {}

ISR(TIMER1_COMPA_vect)
{
  digitalWrite(LEDPIN, !digitalRead(LEDPIN));  
}

This is the output from my logic analyzer:

Output From Logic Analyzer

Is it a limitation of the Arduino or am I missing something?

My idea is to generate a PWM manually to control a servo motor using timer1 and precisely increase the period by 10μs during "on" time and get the desired angle.

After some experiments, I have discovered that my motor (MG996R) has a range from 0.6ms to 2.1ms during "on" time to move from 0 to 180 degrees.

I have tried the Arduino's Servo library but it goes far than 180 degrees (I don't know why). That's why I am building my own code for that purpose.

2
  • 79 clock cycles might no be enough to execute all the ISR code.
    – Gerben
    Apr 27, 2015 at 20:35
  • @Gerben, do you any idea how to solve it instead? Apr 27, 2015 at 20:52

1 Answer 1

3

I got it working just analyzing time consumption of digitalWrite and digitalRead functions. They took around 13us to execute (each one), so this added up a few extra undesired microseconds to the final period.

Instead, I set up digital output using DDRD for configuring and PORTD for setting the desired output, which results in approximately 1us to set the output value (HIGH or LOW).

I changed the prescaler to 8 and the code below shows how to get a 100kHz wave output with 5us duration of "on" time using timer1 CTC mode.

void setup()
{
    DDRD = B00001000; // pin 3 as output
    PORTD &= ~_BV(PORTD3);   // set 3 as LOW

    // initialize Timer1

    cli();          // disable global interrupts

    TCCR1A = 0;     // set entire TCCR1A register to 0
    TCCR1B = 0;     // same for TCCR1B

    // set compare match register to desired timer count:
    OCR1A = 9;

    // turn on CTC (Clear Timer on Compare Match) mode:
    TCCR1B |= (1 << WGM12);

    // Set CS10 bit for clk/8 prescaler:
    TCCR1B |= _BV(CS11);

    // Output Compare A Match Interrupt Enable
    TIMSK1 |= (1 << OCIE1A);

    sei();          // enable global interrupts

}

ISR(TIMER1_COMPA_vect)
{
  PORTD = ~PORTD;
}
1
  • Glad to see you got it working.
    – Gerben
    Apr 28, 2015 at 12:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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