I wrote a simple program to generate PWM wave with 50% duty cycle. Then I went for debugging in AtmelStudio. All registers except OCR0 were assigned there respective values. Why OCR0 not assigned any value.
ATmega32, Fast PWM.
#include <avr/io.h>
int main(void)
{
DDRB = (1 << PB3);
TCCR0 |= (1 << WGM01) | (1 << WGM00) | (1 << COM01);
OCR0 = 127;
TCCR0 |= (1 << CS02);
return 0;
}
So anyway.
You're using the 8-bit counter0 on your Atmega32. Let's see how you set it up:
// Set Pin B3 as output, others as input
DDRB = (1 << PB3);
// Set Clear on compare match + Fast PWM mode + Counter stopped
TCCR0 |= (1 << WGM01) | (1 << WGM00) | (1 << COM01);
// Set comparator value to 127
OCR0 = 127;
// Enable clkIO/256 from prescaler, turning on the counter
TCCR0 |= (1 << CS02);
Okay. First, a few things:
On initial setup, you usually want to assign the value and not or it, to be certain of its state.
Even after, setting it instead of or-ing it avoids a useless read. No impact on behavior for this register, but might be a bit better for performance.
The documentation recommends only enabling the output after you have set it up properly, to avoid spurious output. So you should move the first line last.
I'll be reading from that version of the datasheet.
Now, in fast PWM mode, according to table 38, and 40, the counter behaves like this:
It counts from BOTTOM to MAX (0 to 0xFF).
OCR0 is only used to toggle OC0 pin, not to reset the counting.
OCR0 has double-buffering. Its actual value is not updated until next cycle.
This might be your issue. If any of those are true:
Counter doesn't start properly (could happen if CS2-0 are not correct due to or-ing them instead of setting them).
Counter is stopped early (because your program ends and if the studio detects it, it could disable it at that point - I d'ont use the studio so I cannot really tell).
Then it is possible the value you write to the double buffer never makes it to the actual register. Alas the datasheet doesn't explain in detail how this is handled. Nor does it tell whether reading OCR0 while double buffering is active returns current value or awaiting value.
Related
I am wondering if it is possible to speed up the ISR without changing the prescaler.
I have a timer with 2 compare registers A and B.
COMPA is used for a PWM output from around 22% up to 100%. This has a fixed frequency and I am not allowed to change it at least not much.
Now I would like to use the COMPB with around 4 times the speed but with a fixed duty cycle of 50%.
If I set the OCIE0B bit in TIMSK0 for the attiny13 can I do the following to speed things up?
Or am I misunderstanding something here?
ISR(TIM0_COMPB_vect){
switch (timing){
case 0:
OCR0B = 63;
PORTB ^= (1 << PB3);
timing = 1;
break;
case 1:
OCR0B = 127;
PORTB ^= (1 << PB3);
timing = 2;
break;
case 2:
OCR0B = 191;
PORTB ^= (1 << PB3);
timing = 3;
break;
case 3:
OCR0B = 255;
PORTB ^= (1 << PB3);
timing = 0;
break;
}
}
Any help appreciated.
Thanx :D
You can do this very efficiently by creatively using the Normal Mode.
The trick is to set the prescaller to get a clock period that is double what you want the variable-duty PWM signal to run at. So if, for example, you want that to PWM at 1Mhz, set the prescaller to 2Mhz.
Assume the variable duty cycle PWM is on pin A and the fixed 50% 4x clock signal is on pin B. (You can also swap these and and also update the code everything will still work)
Enable interrupts for "On compare match B" and "Overflow".
Force pin A high with a force compare match. (Alternately you can skip this step and instead use the inverse of the desired duty cycle in step 7)
Set the COM bits for 'A' to Toggle on match.
Leave the COM bits for B to off. Assumes you have DDR set for this pin to be normal GPIO.
Set the OCR for B to 128.
Set the WGM timer mode to 0 - "Normal Mode".
Set the OCR for A whatever you want the variable duty cycle to be. Note that you might need to special case here for extreme values of 0 and/or 255 depending on what you want to have happen (just turn the pin ON of OFF with GPIO).
You can repeat step 6 anytime you want to change the duty cycle of A and it will update on the next TOP.
Once you do these steps, the A pin will output the desired duty cycle at 1/2 the prescaller clock and the B will output 50% duty at 2x the prescaller clock (which is the desired 4x of the A period).
Here is the ISR code (note that I am not sure what the TOV vector is called in the attiny13 headers [it is sometimes different across AVRs] so you might have to edit the TIM0_OVF_vect name)...
ISR(TIM0_COMPB_vect,TIM0_OVF_vect){
PINB |= (1 << PB3); // Compiles to a single cycle SBI
}
See how this works?
Note that setting a bit in the PIN register actually toggles the PORT bit. This is a quirk of the AVR GPIOs that is documented in the datasheets.
Hopefully this is fast enough. If you really want to squeeze every last cycle out, you can even potentially save the 2 cycles of the RJMP from the interrupt vector by putting the single SBI instruction that the ISR compiles down to directly into the interrupt vector table with a trailing RETI, but this is more complicated!
Focusing solely on the C code aspects, then this can be trivially optimized as:
ISR(TIM0_COMPB_vect)
{
static const uint8_t OCR[4] = {63,127,191,255};
OCR0B = OCR[timing];
PORTB ^= 1u << PB3;
timing++;
if(timing==4)
timing=0;
}
Disassembled on gcc AVR -O3 (with all variables/registers volatile) this brings down the amount of instructions from ~50 to ~20, so it's about twice as fast and takes less memory.
If you just want the fastest equivalent version of the supplied code, then here it is...
ISR(TIM0_COMPB_vect){
OCR0B += 64;
PINB |= (1 << PB3);
}
OCR0B will overflow every 4 passes, which is defined behavior. Probably wise to initialize OCR0B to some non-zero number like 1 to avoid edge cases.
This avoids all variables and memory access - only register access.
Avoids all compares and braches.
The PINB method of toggling the pin compiles down to a single SBI instruction rather than a PUSH, load, XOR, store, POP sequence.
...but again, none of this matters if it does not work and unless you are using one of the two "immediate OCR update" modes, then updating OCR in the middle of a timer cycle will have no effect.
With timers, I want to toggle an LED every one second. I'm using ATMega32 and the clock frequency is 1MHz. I can get to 0.1 second using the 8-bit counter, and for each 10 timer interrupts, I blink the led.
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
typedef unsigned char u8_t;
typedef unsigned short u16_t;
void func();
int main(void)
{
DDRC = 0x80;
TCCR0 |= (1 << WGM01); // CTC bit.
TCCR0 |= (1 << CS02) | (1 << CS00); // Prescalar = 1024.
OCR0 = 98; // 98 ticks correspond to roughly 0.1 second with 1024 prescaler
TIMSK |= (1 << OCIE0);
TCNT0 = 0;
sei();
while(1)
{
if (!(TIFR & (1 << OCF0))) {
func();
}
}
}
void func()
{
static u8_t extra_time = 0;
if (extra_time == 10)
{
extra_time = 0;
PORTC ^= 0x80;
}
else extra_time++;
TIFR |= (1 << OCF0);
}
In the preceding code, I do not define an ISR for the TIMER0_COMP_vect interrupt.
From the datasheet:
The OCF0 bit is set (one) when a compare match occurs between the Timer/Counter0 and the
data in OCR0 – Output Compare Register0. OCF0 is cleared by hardware when executing the
corresponding interrupt handling vector. Alternatively, OCF0 is cleared by writing a logic one to
the flag. When the I-bit in SREG, OCIE0 (Timer/Counter0 Compare Match Interrupt Enable), and
OCF0 are set (one), the Timer/Counter0 Compare Match Interrupt is executed.
emphasis mine.
Therefore, by the emphasized sentence, I can check for the OCF0 bit for being a zero, and if so, I can "handle" the on-compare-match event.
However, the LED blinks much more frequently (not even a tenth second between each blink but I cannot measure of course).
This works fine if I just set an ISR on TIMER0_COMP_vect and check for nothing, but I want to know why is the OCF0 always(?) logic 0, hence "on", even though I set it to high on each func() call. And what's the problem with this method.
Keep reading the next line in the data sheet
When the I-bit in SREG, OCIE0 (Timer/Counter0 Compare Match Interrupt Enable), and OCF0 are set (one), the Timer/Counter0 Compare Match Interrupt is executed.
then take a look at your code
you have Enabled Compare Match Interrupt
TIMSK |= (1 << OCIE0);
you have Enabled the Global interrupt (I-bit in SREG)
sei();
so whenever output compare flag OCF0 is set then all the 3 conditions for interrupt have occurred and interrupt is automatically fired
when an interrupt has been fired the program flow of execution will jump to a specific memory location corresponding to this interrupt to execute the code and handle it,
but you did not provide any code for this interrupt (no ISR), so the microcontroller does not know what he can do because you did not tell him, so simply he will RESET
and so on, interrupt with no Handler keep fired makes the microcontroller keep
reset
finally, when you add an empty ISR you Provide a code which tell the microcontroller to do nothing if this interrupt is fired and the micro will not reset because he knows how to handle it
if you want to keep track OCF0 flag by yourself delete this line
TIMSK |= (1 << OCIE0);
I dont know why but instead of increasing brightness, LED pulses, the period between each pulse is getting shorter. This is copied code from tutorial, in his video it worked fine but for me it didnt, even in simulator. How can that happen?
Using avr 328p.
#define F_CPU 20000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
double dutyCycle = 0;
int main(void)
{
DDRD = (1 << PORTD6);
TCCR0A = (1 << COM0A1) | (1 << WGM00) | (1 << WGM01);
TIMSK0 = (1 << TOIE0);
OCR0A = (dutyCycle/100.0)*255.0;
sei();
TCCR0B = (1 << CS00) | (1 << CS02);
while(1)
{
_delay_ms(100);
dutyCycle += 10;
if(dutyCycle > 100){
dutyCycle = 0;
}
}
}
ISR(TIMER0_OVF_vect){ OCR0A = (dutyCycle/100.0)*255;}
1) If some variable is used simultaneously in the main code and in an interrupt, then it has to be marked as volatile. Then every read or write to it will be compiled as reading/writing of the corresponding memory cell. Otherwise, the compiler can optimize, minimizing memory access. So, writing to the variable inside the main program will not be visible in the interrupt.
2) Why are you using double? Do not use floating point unless it strongly necessary. AVR has no hardware support for the floating-point arithmetic, so each floating-point operation will be represented as multiple operations. In your example, nothing stops from use integer variable which changes from 0 to 255. Even if you want to use 0-100 range variable, you can recalculate it using integer arithmetics.
3) Be aware updating variables which are more than 1 byte long. AVR is an 8-bit architecture. That means, updating of variables in memory more than 8-bit wide, requires a series of multiple operations. double which is 8 bytes long, requires too much of such operations. The interrupt may fire in any moment in the middle of that series, that means, the value of the variable, obtained inside the ISR will be updated only partially, causing unpredictable results. In the main code eclose in cli() - sei() any update of variables which are used inside the ISR and more than 1 byte wide.
3) Avoid hard calculations in the ISR. As a rule of thumb: any ISR should complete as soon as possible, all intense calculations should be placed outside the ISR.
4) In this example, you need no ISR at all! You can write OCR0A just inside the main code.
I have some trouble with, I guess, the overflow interrupt (used to increase resolution on 8-bit timer from 16µs/step to 1µs/step) in my CODE. It seems like the overflow interrupt triggers while the program is in the if-statements in my main loop and thereby screws thigns up!
if(pInt == 1) //PCNINT-if-statment
{
pulse16 = (tot_overflow << 8) | TCNT1; //adds tot_overflow and TCNT1 to be able to set if-statements in PCINT-while-loop with µs
if(PINB & (1 << PINB3)) //if PB3 is HIGH
{
TCNT1 = 0; //resets Timer/Counter1
tot_overflow = 0; //resets tot_overflow variable
}
else
{
if (pulse16 >1555) //when stick 1 travels from 1555 µs towards 2006 µs
{
PORTB &= ~(1 << relayPin); //relay pole switch, + & - on motor
PORTB |= (1 << greenLED); //LED green indicates forward motion
PORTB &= ~(1 << redLED); //turn off red LED
}
else if (pulse16 <1490) //when stick 1 travels from 1490 ms towards 920 µs
{
PORTB |= (1 << relayPin); //relay pole switch, - & + on motor
PORTB &= ~(1 << greenLED); //turn off green LED
PORTB |= (1 << redLED); //LED red indicates backward motion
}
else //if µs is 1490> or <1555 - dead-span to prevent gliteches on relay when stick is in centre position
{
}
}
pInt = 0; //resets pInt to exit PCNINT-if-statment
}
The pInt is a "flag-variable" that indicates PCINT is triggered.
The tot_overflow variable is increment every time the overflow interrupt is triggered.
I use an ATtiny85 as a RC-switch, it should go LOW on PB2-pin when µs from receiver is above 1555 and go HIGH when µs goes below 1490.
What happens is the following: when checking if µs is above 1555 or below 1490 and using overflow interrupt it sometimes turn the PB2-pin HIGH/LOW in the "dead-span" of 1490-1555 when it shouldn't, and sometimes outside the "dead-span"! Here's a VIDEO on the glitch. Notice that the green LED is the redLED, and the yellow LED is greenLED in my code.
I'm quite new at this and I'm not sure why this is happening and I don't understand why the code won't work. I have looked at the CTC function but I can't see that it would help since I still have to use the timer overflow interrupt to get my wanted reolution of 1µs/step.
EDIT
I have tried a couple of variations (of #yann-vernier's suggestions) and still don't get it to work properly, this is what gets closest to a working code:
while(1) //leave and/or put your own code here
{
static uint8_t tot_overflow; //variable to count the number of Timer/Counter1 overflows
if (TIFR & (1 << TOV1) )
{
TIFR |= (1 << TOV1); // clear timer-overflow-flag
tot_overflow ++;
}
if(GIFR & (1 << PCIF) ) //PCINT-flag idicates PCINT
{
uint16_t pulse; //variable to make a 16 bit integer from tot_overflow and TCNT1
// PORTB |= (1 << debugPin); //pin is HIGH on when interrupt is intialized
pulse = (tot_overflow << 8) | TCNT1; //adds tot_overflow and TCNT1 to be able to set if-statements in PCINT-while-loop with µs
this part I don't get to work:
if ( ((TIFR & (1 << TOV1)) && ((pulse & 0xff))) < 0x80)
{
pulse += 0x100; // Overflow had not been counted
}
Im not sure I get what is happening above, the only thing I know is that I probably do it the wrong way! When I comment the above part it works the same as mu old code!
else
{
if(PINB & (1 << PINB3)) //if PB3 is HIGH
{
TCNT1 = 0; //resets Timer/Counter1
tot_overflow = 0; //resets tot_overflow variable
}
else
{
if (pulse > 1555) //when stick 1 travels from 1555 µs towards 2006 µs
{
PORTB &= ~(1 << relayPin); //relay pole switch, + & - on motor
PORTB |= (1 << greenLED); //LED green indicates forward motion
PORTB &= ~(1 << redLED); //turn off red LED
}
else if (pulse < 1490) //when stick 1 travels from 1490 ms towards 920 µs
{
PORTB |= (1 << relayPin); //relay pole switch, - & + on motor
PORTB &= ~(1 << greenLED); //turn off green LED
PORTB |= (1 << redLED); //LED red indicates backward motion
}
else //if µs is 1490> or <1555 - dead-span to prevent gliteches on relay when stick is in centre position
{
// PORTB |= (1 << greenLED); //for debug to indicate dead-span
// PORTB |= (1 << redLED); //for debug to indicate dead-span
}
}
}
GIFR |= (1 << PCIF); //clear PCINT-flag
}
else
{
}
}
}
ISR(TIMER1_OVF_vect) //when Counter/Timer1 overflows
{
}
ISR(PCINT0_vect) //when pin-level changes on PB3
{
}
Is it close or am I still out in the blue?
Yes, the overflow interrupt could happen at any time (although it does happen regularly). So could the pin change interrupt. Each of them in this case only touch a single 8-bit volatile variable (tot_overflow and pInt respectively), which in turn are polled by your main loop. This construction doesn't really help you unless the main loop has other work to do which may take longer than one full timer period (256*8=2048 cycles in this case).
So instead of enabling interrupts, you could check GIFR bit PCIF (instead of pInt) and TIFR bit TOV1 in your main loop, which would get you more easily understood behaviour. Resetting them is a special case of writing a 1 to that bit and only that bit. This would save you time for the pin change interrupt, as the main loop check could happen more frequently and would not need the latency of jumping to the interrupt service routine.
It would not, however, fix your problem. You are trying to measure a pulse width, which on slightly larger AVRs is easily done using the timer input capture feature. The timers in the ATtiny85 don't have this feature. On AVRs that do, the input capture and timer overflow interrupts are arranged in such a way that the input capture interrupt can safely read the software driven overflow counter.
When you get a timer overflow, you increment tot_overflow, and when you've detected a pin change, you read TCNT1 to combine the values. These two counters, while one feeds the other, are not read at the same time. Your threshold values are 0x5d2 and 0x613. If the rollover occurs after reading tot_overflow but before reading TCNT1, you may well get a time like 0x501 at a time which should be 0x601. Similarly if you stop tot_overflow from updating. If you read TCNT1 before tot_overflow, you might get 0x6fe when you should have read 0x5fe. Simply put, there is no safe order - but there is a relation. What we need to know is if the overflow count value was up to date or not at the time the counter value was read.
static uint8_t ovf;
if (TIFR & 1<<TOV1) {
TIFR = 1<<TOV1; // Clear overflow flag
ovf++;
}
if (GIFR & 1<<PCIF) {
GIFR = 1<<PCIF; // clear pin change flag
uint16_t timestamp = ovf<<8 | TCNT1;
if (TIFR&1<<TOV1 && (timestamp&0xff)<0x80)
timestamp += 0x100; // Overflow had not been counted
// Do what we like with the timestamp here
}
The key is that we check for an overflow after we have already loaded the timer value. If the overflow occurred before we read the value, the value read must be low; otherwise we want the old count. This particular sample actually relies on the overflow not being handled in an interrupt, but you can use the same method by enclosing the block in an interrupt masking. We need the two reads of TOV1 and ovf to match, and to read TOV1 after TCNT1. What we don't want is to have an interrupt process and thus clear TOV1 so that we can't infer the order of ovf and TCNT1. Note that using a pin change interrupt to do this logic grants us that automatically, since interrupt handlers run with interrupts disabled.
You won't get higher precision on your pulse widths than the latency variance for responding to the pin change, and in the code you've shown, the timer reset (which should also reset the prescaler, bit PSR1 in GTCCR). This usually means you do want to read the timer in the interrupt handler itself. We can also observe that you could choose a timer pace that makes your thresholds fit in the 8 bit value; for instance with timer1 running at 8MHz/64, your thresholds would be at 186 and 194, with an offset of 16-24µs. One might even do tricks like setting one threshold precisely at an overflow since the timer doesn't have to start at 0.
#YannVernier Thanks for pushing me in the right direction, or giving me the rigth way to do it! ;-) I think I finally nailed it, with a litle extra help from a friend that is!
Here is the final CODE
I didn't first get that I had to remove the TIMSK enable ande sei() plus the ISR routines, also the else-statement that was accidently put after:
if ( ((TIFR & (1 << TOV1)) && ((pulse & 0xff))) < 0x80)
{
pulse += 0x100; // Overflow had not been counted
}
Running the code below, when I send any character to the Arduino from the Serial Monitor, the Arduino does not print "a" back. I think it's something wrong with the timer1 code, but it should work because this code was given to me by my teacher in C class.
void setup() {
Serial.begin(115200);
// http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
noInterrupts();
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set compare match register for 1000000hz increments with 8 bits prescaler
OCR1A = 1;// = (16*10^6) / (1000000*8) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS11 bit for 8 prescaler. Each timer has a different bit
// code to each prescaler
TCCR1B |= (1 << CS11);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
interrupts();
}
void loop() {
if (Serial.available()) {
Serial.println("a");
}
}
See also: http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
Side Note: your code comment about 8 bits prescaler is misleading. It is not an 8-bit prescaler, rather, it is simply a prescaler of 8, meaning the decimal value 8. All that means is the timer's clock tick rate is 8x slower than the main clock, since you divide the main clock frequency by the prescaler to get the timer's clock frequency.
Now for my answer:
The way you set TCCR1A and TCCR1B is all correct.
However, you have 2 major problems, 1 minor problem, and 1 recommendation.
See the 660-pg ATmega328 datasheet pgs. 132~135 for more help & info if you want to know where to look from now on for low-level help.
Update: the new ATmega328 sales page is here: https://www.microchip.com/wwwproducts/en/ATmega328. Its new datasheet is available here: https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061B.pdf. So, the page numbers I mention above and below will likely no longer quite match since I was using an older version of the datasheet when I wrote this.
Here are the 2 major problems which are completely breaking your code:
Since you are enabling the Timer Compare Match 1A interrupt (TIMSK1 |= (1 << OCIE1A);), you MUST also define the Interrupt Service Routine (ISR) which will be called when this happens, or else you will have run-time (but not compile-time) problems. Namely, if you do not define the ISR for Output Compare Match A, once the Output Compare A interrupt occurs, the processor will get stuck in an infinite, empty, dummy ISR created for you by the compiler, and your main loop will not progress (see code below for proof of this).
Add this to the bottom of your code:
ISR(TIMER1_COMPA_vect)
{
// insert your code here that you want to run every time the counter
// reaches OCR1A
}
It takes a couple microseconds to step into an ISR, and a couple microseconds to step out of an ISR, plus whatever time is required to run your code IN the ISR, you need to use an OCR1A value that is large enough that the ISR even has time to execute, rather than being continually called so quickly that you never exit the ISR (this would lock up your code essentially into an infinite loop....which is happening in your case as well).
I recommend you call an ISR no more often than every 10us. Since you are using CTC mode (Clear Timer on Compare match), with a prescaler of 8, I recommend setting OCR1A to nothing less than 20 or so. OCR1A = 20 would call the ISR every 10us. (A prescaler of 8 means that each Timer1 tick take 0.5us, and so OCR1A = 20 would call the ISR every 20*0.5 = 10us).
If you set OCR1A = 20, and add the ISR code as described above, your code will run just fine.
1 Minor problem:
It is good practice to set OCR1A after you configure the rest of the timer, or else under some situations the timer may not start counting. See "Thorsten's" comment here (emphasis added):
Thorsten said...
Thanks for explaining this matter so extensively! I was looking for a way to generate 1 MHz on one of the Arduino-pins. Your post helped me a great deal to accomplish that.
The reason I am writing this comment is the following: It took me almost 6 hours till I found out (mainly in sheer desperation) that the order of setting the timer control registers TCCR2* and the output compare registers OCR2* seems to matter! If you assign an OCR before setting the corresponding TCCR the timer simply doesn't start counting.
February 13, 2011 at 11:47 AM
So, move OCR1A = 20; to after your last TCCR1B line and before your TIMSK1 line.
1 recommendation:
Get rid of your calls to noInterrupts() and interrupts(). They are not needed here.
Functional code:
Now, here is some functional code I wrote which will better demonstrate what you're trying to do, and what I'm talking about:
/*
timer1-arduino-makes-serial-not-work.ino
- a demo to help out this person here:
http://stackoverflow.com/questions/28880226/timer1-arduino-makes-serial-not-work
By Gabriel Staples
http://electricrcaircraftguy.blogspot.com/
5 March 2015
- using Arduino 1.6.0
*/
// Note: ISR stands for Interrupt Service Routine
// Global variables
volatile unsigned long numISRcalls = 0; // number of times the ISR is called
void setup()
{
Serial.begin(115200);
// http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
// noInterrupts(); // Not necessary
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// better to put this line AFTER configuring TCCR1A and TCCR1B below, but in
// Arduino 1.6.0 it appears to be ok here (may crash code in older versions),
// see comment by "Thorsten" here:
// http://www.righto.com/2009/07/secrets-of-arduino-pwm.html?showComment=1297626476152#c2692242728647297320
OCR1A = 20;
// SETTING OCR1A TO 1 OR 2 FOR SURE BREAKS THE CODE, as it calls the interrupt
// too often to even allow the main loop to run at all.
// OCR1A = 1;
// turn on CTC mode [Clear Timer on Compare match---to make timer restart at
// OCR1A; see datasheet pg. 133]
TCCR1B |= (1 << WGM12);
// Set CS11 bit for 8 prescaler [0.5us ticks, datasheet pg. 135]. Each timer
// has a different bit code to each prescaler
TCCR1B |= (1 << CS11);
// enable timer compare match 1A interrupt; NOW YOU *MUST* SET UP THE
// CORRESPONDING ISR OR THIS LINE BREAKS THE CODE
// IT IS RECOMMENDED TO SET OCR1A HERE, *after* first configuring both the
// TCCR1A and TCCR1B registers, INSTEAD OF ABOVE! Like this:
// OCR1A = 20;
TIMSK1 |= (1 << OCIE1A);
// interrupts(); // Not necessary
Serial.println("setup done, input a character");
}
void loop()
{
if (Serial.available())
{
// read and throw away the first byte in the incoming serial buffer (or else
// the next line will get called every loop once you send the Arduino a
// single char)
Serial.read();
Serial.println("a");
// also print out how many times OCR1A has been reached by Timer 1's counter
noInterrupts(); // turn off interrupts while reading non-atomic (> 1 byte)
// volatile variables that could be modified by an ISR at
// any time--incl while reading the variable itself.
unsigned long numISRcalls_copy = numISRcalls;
interrupts();
Serial.print("numISRcalls = "); Serial.println(numISRcalls_copy);
}
// Serial.println("test");
// delay(1000);
}
// SINCE YOU ARE ENABLING THE COMPARE MATCH 1A INTERRUPT ABOVE, YOU *MUST*
// INCLUDE THIS CORRESPONDING INTERRUPT SERVICE ROUTINE CODE
ISR(TIMER1_COMPA_vect)
{
// insert your code here that you want to run every time the counter reaches
// OCR1A
numISRcalls++;
}
Run it and see what you think.
Proof that "Major Problem 1" above is real
(at least as far as I understand it--and based on tests on an Arduino Nano, using IDE 1.6.0):
This code below compiles, but will not continue to print the "a" (it may print it once, however). Note that for simplicity-sake I commented out the portion waiting for serial data, and simply told it to print an "a" every half second:
void setup() {
Serial.begin(115200);
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS11 bit for 8 prescaler. Each timer has a different bit code to each
// prescaler
TCCR1B |= (1 << CS11);
OCR1A = 20;
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
}
void loop() {
//if (Serial.available()) {
// Serial.println("a");
//}
Serial.println("a");
delay(500);
}
// ISR(TIMER1_COMPA_vect)
// {
// // insert your code here that you want to run every time the counter reaches
// // OCR1A
// }
This code below, on the other hand, works, and the "a" will continue to print out. The only difference between this one and the one just above is that this one has the ISR declaration uncommented at the bottom:
void setup() {
Serial.begin(115200);
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS11 bit for 8 prescaler. Each timer has a different bit code to each
// prescaler
TCCR1B |= (1 << CS11);
OCR1A = 20;
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
}
void loop() {
//if (Serial.available()) {
// Serial.println("a");
//}
Serial.println("a");
delay(500);
}
ISR(TIMER1_COMPA_vect)
{
// insert your code here that you want to run every time the counter reaches
// OCR1A
}
If this answer solves your problem, please upvote it and accept it as the correct answer. Thanks!
Extra Resources:
I keep a running list of the most helpful Arduino resources I come across at the bottom of an article I wrote here: http://electricrcaircraftguy.blogspot.com/2014/01/the-power-of-arduino.html. Check them out.
Especially look at the first links, under the "Advanced" section, by Ken Shirriff and Nick Gammon. They are excellent!
Nick Gammon's answer here
[my answer] Which Arduinos support ATOMIC_BLOCK? And how can I duplicate this concept in C with __attribute__((__cleanup__(func_to_call_when_x_exits_scope))) and in C++ with class constructors and destructors?
[my own Question and answer] C++ decrementing an element of a single-byte (volatile) array is not atomic! WHY? (Also: how do I force atomicity in Atmel AVR mcus/Arduino)
Gabriel Staples is quite correct, the reason you are not seeing the "a" is because you have not provided an ISR handler for the interrupt. Thus, the compiler-generated code jumps back to address 0x0000 and your sketch restarts.
An alternative to providing the "empty" ISR handler is this:
EMPTY_INTERRUPT (TIMER1_COMPA_vect);
With the EMPTY_INTERRUPT handler there I got a response (the "a") with OCR1A as low as 1:
OCR1A = 1;
Although, one has to wonder why you enable interrupts if you aren't planning to do anything with them.
More information about interrupts on the Arduino.
Depending on what the program needs to do with such a fast interrupt, e.g. generating a high-speed clock on an output pin, one can set it in hardware using COM bits in TCCR1A (out of my memory the 4 most significant bits) to toggle the output on a pin associated with the timer without the need to write any ISR() callback to handle the timer interrupt in software.
You wrote this register 2 times:
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS11);
while I think that it could probably be:
TCCR1A |= (1 << WGM12);
TCCR1B |= (1 << CS11);
Probably the only mistake is there, because you forgot to set TCCR1A and you set the other one 2 times.
TCCR1A |= (1 << WGM12); is a bitwise operation (bitwise OR).
In this particular case is setting only one bit of TCCR1A, the one in position WGM12.
TCCR1B |= (1 << CS11); is setting a different bit in position CS11.