Square pulse generator using internal register.

Hello,
Im trying to make pulse generator, frequency 250Hz, using internal register :

#define ledPin 13

void setup()
{
pinMode(ledPin, OUTPUT);

// initialize timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;

OCR1A = 32000; // compare match register 16MHz/1/292/2 set frequency 250Hz
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (0 << CS11)|(1<<CS10); // 1 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
}

ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine
{
digitalWrite(ledPin, digitalRead(ledPin) ^ 1); // toggle LED pin
}

void loop()
{
// your program here...
}

Basically is working, but after some periods register making false period, and again counting normal.
Maybe somebody has made the same? Maybe my code is wrong?

There are a couple of possible problems.

For one, there is no need to use interrupts. The timer can generate a continuous stream of pulses on an output pin, completely independent of what the processor is doing (e.g. PWM).

Since there are other interrupts (like Timer0) operating, one of those could delay your Timer1 ISR.

You are using just about the slowest possible way of toggling a pin. To toggle digital pin 13 on a Uno (PORTB, pin 5), use the single instruction

PINB ^= (1<<5);  //yes, use PINB to toggle *output* pin PB5

As always, see the processor data sheet for the details and explanation.

jremington:

PINB ^= (1<<5);  //yes, use PINB to toggle *output* pin PB5

Wrong.

use

PINB = (1<<5);  // yes, only write the bit you want to toggle

Or

 //         111100 
 //         321098
 PINB = 0b00100000; // toggle pin 13

Oops, thanks for catching that typo!

Thank you jremington.

I will change toggling. But how to avoid others registers interrupting? Can you pass code for code generation without interrupts?

The Timer1 section of the ATMega328 data sheet has the details. Carefully read the section on the control registers, in particular TCCR1A has bits that determine how the timer controls the OC1A and OC1B port pins.

In one setting, the timer will toggle the port pin when a compare match occurs. The pin must be set to output to see the result.

Just changed togling pin command to : PINB=(1<<5); but this not solve problem. Probably there is cause of interrupts. Interesting that pulse tremor is depended on prescaler. If prescaler is 1 tremor very big, more then one period, if prescaler is 64 ,tremor about 1/10 of period.

The same history with tone(), pulse width and frequency tremor.

Code:

void setup()
{

pinMode(5,OUTPUT);
}

void loop() { // put your main code here, to run repeatedly:
tone(5,20000);

}

To wach oscilloscope test on youtube:

Have you followed up on jremmington's comment and turn off timer0 or the timer0 interrupt?

Since there are other interrupts (like Timer0) operating, one of those could delay your Timer1 ISR.

Sigitask:
Thank you jremington.

I will change toggling. But how to avoid others registers interrupting? Can you pass code for code generation without interrupts?

TIMSK0 = 0;

will turn off timer0 which is the only interrupts that are on by default on the Uno or Mega (unless
you use Serial). However turning off timer0 stops millis(), delay() and micros() from working...

Use a relevant output compare pin for the timer you are using to output directly for jitter-free signal.

Thank you MarkT,
I will try TIMSK=0;

May you explain "Use a relevant output compare pin for the timer you are using to output directly" ?
Im beginner in Arduino and for me is difficult to understand.

void setup()
{
  pinMode(9, OUTPUT);//Timer1 OutputA D9
  
  // initialize Timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;
  OCR1A = 32000;            // compare match register 16MHz/1/292/2 set frequency 250Hz
  TCCR1B |= (1 << WGM12);   // CTC to OCR1A mode
  TCCR1B |= (1<<CS10);     // 1 prescaler 
  TCCR1A |= (1<<COM1A0);  //toggle outputA on compare match
  TIMSK0 = 0; //turn off Timer0 interrupts
  interrupts();            // enable all interrupts
}

void loop()
{}

Sigitask:
Thank you MarkT,
I will try TIMSK=0;

May you explain "Use a relevant output compare pin for the timer you are using to output directly" ?
Im beginner in Arduino and for me is difficult to understand.

Then you'll have to read the section in the datasheet about the timer in question under you understand,
because that's what I had to do when starting out on direct timer manipulation. But in short this
is how analogWrite() works. Each timer has several output-compare registers each attached to a given
pin which is compared with the timer count and determines if the pin should be high or low. This is all
configured by various fields in the timer registers.

Thanks for help!

Amazing! Problem partially solved. Have 2 frequency generator made on Timer 1, and Timer 2, without interrupts. No disturbing processor work.

Code :

void startGenerator()
{
TCCR2A = _BV(COM2A0) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS20)|_BV(CS21)|_BV(CS22);
OCR2A = 255; // 250, so timer2 counts from 0 to 250 (251 cycles at 16 MHz)

TCCR1A = _BV(COM1A0); //toggle OC1A on compare mach (connected to pin 9)
TCCR1B = _BV(WGM12) |_BV(CS12); //set prescaler to 256, and set timer 1 to CTC mode (clear timer on compare mach),
// Comparing with OCR1A
OCR1A = 62500;
}

void setup()
{
pinMode(11, OUTPUT);
pinMode(9, OUTPUT);

startGenerator();
}

void loop()
{
}