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.

Nick Gammon
38.9k13 gold badges69 silver badges125 bronze badges
asked Apr 27, 2015 at 20:16
2
  • 79 clock cycles might no be enough to execute all the ISR code. Commented Apr 27, 2015 at 20:35
  • @Gerben, do you any idea how to solve it instead? Commented 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;
}
answered Apr 28, 2015 at 1:46
1
  • Glad to see you got it working. Commented Apr 28, 2015 at 12:56

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.