Help with Nano TMR0 COMPARE interrupt example

All right, everything was moved to TMR2, saved, recompiled and reinstalled… it runs but otherwise no joy…

Changes to OCR2A cause no changes in the output signal… 41.2 KHz measured here.

Changes to prescaler ratio ( TCCR2B ) also have no effect, output signal = always 42.2 KHz

Datasheet I am using is straight from the Microchip website, I must assume it is current :

https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf

Thanks for your help, but this is ridiculous… I’m almost ready to walk away from this… for a few days anyway.

Here is the current code I am using… It compiles, it downloads, it runs and it wiggles the output pin at 41.2 KHz… PERIOD.

/*

Bob's Arduino AtMega 328P timer interrupt program

Timer_Interrupts_Bob.ino

BobStuff/Products/Si5351/Source

*/

// Definitions

#define OutputPin 12 // output pin for TMR0 signal

// TMR0 Interrupt Service Routine

ISR(TIMER2_COMPA_vect)

{

digitalWrite(OutputPin, digitalRead(OutputPin) ^ 1); // toggle the output pin

}

// Startup Code

void setup()

{

pinMode(OutputPin, OUTPUT); // digital pin 12 = output

noInterrupts(); // disable all interrupts ( temporary )

TCCR2A = 0; // clear TCCR2A

TCCR2B = 0; // clear TCCR2B

TCNT2 = 0; // clear TMR2 8 bit count register

OCR2A = 50; // count up to 50, then INTERRUPT

TCCR2A |= (1 << WGM21); // turn on TMR2 CTC mode

TCCR2B |= (1 << CS20); // set CS20, no prescaler ( = DIV BY 1 )

TIMSK2 |= (1 << OCIE2A); // enable TMR2 COMPARE interrupt

interrupts(); // enable all unmasked interrupts

}

// Main Program Loop

void loop()

{

}

no changes ?

There were frequency changes from the ORIGINAL post, but that occurred when I added earlier suggested changes… see my comments, in post 15…

Since that time, ( post 15 ) nothing I’ve done has changed the output frequency… including migrating everything to TMR2.

That's very weird. 41.2KHz ought to be impossible. (500Hz, OTOH, it what you'd expect from the default timer0 configuration.)

I don't see anything wrong with your code, although you're still not doing bytewise writes (it shouldn't matter since you clear the registers first.) (also, it's not "boolean", it's "bitwise.")

The code I’m now using is the code in post 3, which was provided by Kolaha and pointed out to me ( a second time ) in post 19…

Before I switched to that ( TMR2 ) code, I did try a byte wide register load, ( with my TRM0 code ) because I am not familiar with the bitwise syntax, and suspected I was screwing it up. ( which was true… )

40 KHz from 16 MHz is a division ratio of 400… with a prescaler ratio of 8, that would imply the counter was further dividing by 50. ( because 50 x 8 = 400 )

I was expecting a division by 50 ( it’s in my code : interrupt when count = 50 ) but the prescaler ratio should have been DIV 1, not DIV 8...

I also am at a loss to explain this. I‘m new to Atmel chips… and C coding… but certainly otherwise I have decades of experience in very similar technologies.

I didn’t expect to stump the crowds here on this forum… but so far, that seems to be the case…

I have no way to examine the register contents… that would reveal a lot… but apparently these NANOs don’t support debug utilities.

Well, THAT was rude... apparently the forum truncated my reply, there were a few more lines, shown below :

++++++++++

I was halfway hoping someone here would at least try the code on their own NANO and confirm they see the same problem I do.

I really didn’t expect it to be this tough…

I think it’s time to pause for maybe a day and chew on this… figure out my next move in this game.

Thanks for your help…

regards / Bob S.

A lot of programmers never get to programming any of the individual peripherals on a particular chip. After all, that would make their code less portable and less Aduino-like, and ... "there's this neat library that already does what I want."

40kHz would make sense. 41.2KHz is a bigger error from that than I'd expect.

I have no way to examine the register contents

Well, Serial.print(TCCR2A, HEX); and etc would work...

I was halfway hoping someone here would at least try the code on their own NANO and confirm they see the same problem I do.

My next step... (huh. Yep. 41.2KHz !)

You ARE looking at the pin on the nano labeled "D12", right? Substantial numbers of people with "prior experience" keep expecting "12" to be in the same place as
"Pin 12" on a DIP module... (although, there wouldn't be any reason to see 41.2KHz there, either. Nor 500Hz, previously.)

void loop() {
  delay(10000);
#define show(reg) Serial.print(#reg " = 0x"); Serial.println(reg, HEX)
  show(TCCR2A);
  show(TCCR2B);
  show(TCNT2);
  show(OCR2A);
  show(OCR2B);
  show(TIMSK2);
  show(TIFR2);
  show(ASSR);
  show(GTCCR);
  Serial.println();
}

Produces:

TCCR2A = 0x2
TCCR2B = 0x1
TCNT2 = 0x27
OCR2A = 0x32
OCR2B = 0x0
TIMSK2 = 0x2
TIFR2 = 0x7
ASSR = 0x0
GTCCR = 0x0

Hmm. Since your ISR is toggling the pin, the frequency will (should) be 1/(2*per) rather than 1/per. But that still doesn't match what we're seeing. :frowning:

I am looking at the pin with signal name D12… I already made that mistake with my first example program, and sorted it out.

Just returned from a nap I was up late last nite working this problem…

It occurred to me that maybe the counter register is not being reset to zero when an interrupt is triggered, despite what the docs say…

That would explain everything… the counter would simply “rollover” to zero at overflow, then generate another interrupt as it “passed by” the trigger count value.

I’ll add a line to zero the counter ( in the interrupt routine ) later and try that.

Yes, I considered that also… possibly the counter is also using a prescaled version of the 16 MHz clock… like an instruction clock ( with 4 counts per instruction )

Not sure I can trust the docs, I’m new to these Atmels, got no confidence in them yet.

I still need some sleep, back in an hour or two, you should call it a day… I’m retired, you probably are not.

The frequency counter I’m using is a secondary data display on a cheap Taiwan oscilloscope…

Only got 3 digits of freq readout, it doesn’t deserve the respect of a proper freq counter…

The freq error might very well be an artifact of the scope…. The whole thing was only ( about ) $ 200 I think.

Should be set to 49, not 50, if you want a count of 50.

On the atmega328, writing a 1 to the PINB register will toggle the corresponding output, so you could use

  PINB = 1 << 4;

Something else to consider, I'm not aware of how long it takes for the millis interrupt to execute, but with only 50 clock cycles to work with that may be interfering.

OK, that might explain the small freq error… except my mistake should make the freq lower, not greater, as I observed…

I suspect the instrument is wrong, it’s a very minor feature of a very cheap scope…

Anyway, I don’t need precise frequencies in my case… just “steady” frequencies… or really ANY “controllable” freq, at the moment…

This is all “sandbox’ work, at the moment… but thanks for the input.

PIN register is read only.

Ah. I've got it!

The clue was when I added the clear of the counter to the ISR, and the timing changed. That shouldn't happen - the counter should just keep going and call the interrupt periodically.

Except, with no prescaler, you're trying to interrupt every 50 clock cycles; about 320K interrupts per second.
digitalRead() and digitalWrite() are not "fast" functions. In fact, a simple loop containing digitalWrite() will only toggle the pin at about 100kHz. I'd guess that digitalRead() is of similar speed (they do similar "extra" processing.) So your ISR is taking about 20us to execute; when it finally returns, the next interrupt is there ready to go, but ... the output waveform is dominated by the speed of the ISR.

Change the ISR to manipulate the bare hardware (or use a digitalWriteFast() library), and you should see speeds closer to what you expect (I do!)

// TMR0 Interrupt Service Routine
ISR(TIMER2_COMPA_vect) {
  PINB |= 1<<PB4;   // writing to the input register causes a pin toggle.
}

GENERAL INFO : Section 8 of the datasheet for Atmel ATMega 328 describes a complex clock system that runs everything inside the chip…

In particular, the CPU clock is NOT THE SAME as the clock that runs the Timers…

Several other separate clocks ( and clock sources ) are also identified there…

Thanks, that solve the ( minor ) error problem.I will add your suggested code to mine, to speed it up... I got mine from a very slow example... but presently I wanted to see what was the maximum freq I could achieve... to learn the performance limits.

I thought I had selected CTC mode, which should ( I thought ) "clear" the TMR count value each time an interrupt is created. Now I have doubts, but still have not tested it yet. ( = add a TMR2 reset instruction in the ISR )

Is too, in this case. (CLKio == CLKcpu)
(this need not be the case on most ARM chips.) The main distinction on AVR seems to be that CLKio can continue running even with the CPU clock is stopped in sleep modes. (Yeah, this isn't clear in the datasheet. But there is nowhere to set CLKio separately, either.)

PIN register is read only.

Isn't. Writes to the pin register bits cause the output to toggle. (Yes, it's a bit of a kludge. See the datasheet:

13.2.2 Toggling the Pin
Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn. Note that the SBI instruction can be used to toggle one single bit in a port.

(Newer parts have a separate toggle register. Much ... cleaner.)

Getting late here, thanks for the help but this is enough for one day... g'nite