timer0 compa it doesn't work.

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,my code in below.A program that simply lights a led 4 seconds after the program is running.interrupt frequency 1000 Hz:
But why doesn't it work?
My mcu: Attiny84A

 

#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdio.h>

volatile unsigned int counter = 0;

ISR(TIMER0_COMPA_vect){
   //interrupt commands for TIMER 0 here
   counter++;
}

void timerprogram_init()
{
// TIMER 0 for interrupt frequency 1000 Hz:
cli(); // stop interrupts
TCCR0A = 0; // set entire TCCR0A register to 0
TCCR0B = 0; // same for TCCR0B
TCNT0  = 0; // initialize counter value to 0
// set compare match register for 1000 Hz increments
OCR0A = 124; // = 8000000 / (64 * 1000) - 1 (must be <256)
// turn on CTC mode
TCCR0B |= (1 << WGM01);
// Set CS02, CS01 and CS00 bits for 64 prescaler
TCCR0B |= (0 << CS02) | (1 << CS01) | (1 << CS00);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
sei(); // allow interrupts

}

int main(void)
{
	/* Replace with your application code */

	 timerprogram_init();

	DDRA|=(1<<7);
	PORTA &=~ (1<<7);

	while (1)
	{
		if(counter>4000)
		PORTA |= (1<<7);

	}
}

 

Last Edited: Fri. Nov 27, 2020 - 03:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Have you already tested the LED just to see that the port turns it on (using no interrupt, just port).

 

what range does unsigned int have?   I only use  uint_8t,  unit_16t, etc

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Fri. Nov 27, 2020 - 04:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I fixed it in one place and it worked fine.

    // turn on CTC mode
//  TCCR0B |= (1 << WGM01);
    TCCR0A |= (1 << WGM01);

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Define what "don't work" means ??

 

Anyway one observation is that "counter" is not atomic (it's more than 1 byte wide) so you need atomic protection when reading it.

 

Anyway it looks a lot like you have misplaced the WGM01 bit. YOu have

// turn on CTC mode
TCCR0B |= (1 << WGM01);

but the datasheet says:

So the WGM01 bit is in the A not the B register.

 

Also when I build I am getting:

		C:\Program Files (x86)\Atmel\Studio\7.0\Packs\Atmel\ATtiny_DFP\1.4.310\include/avr/iotn84a.h
		.././main.c: In function 'TIMER0_COMPA_vect':
D:\test\test\main.c(9,1): warning: 'TIMER0_COMPA_vect' appears to be a misspelled signal handler, missing __vector prefix [-Wmisspelled-isr]
		 ISR(TIMER0_COMPA_vect){
		 ^

and looking at the ioxx.h file I see:

 

So the vector is called TIM0_COMPA_vect not TIMER0_COMPA_vect that you have in the code.

 

When I correct those two things and simulate it all appears to be working but after a few minutes "counter" has only reached 61 out of 4000 and life is too short to wait to see it complete - but I suspect it will eventually.

Last Edited: Fri. Nov 27, 2020 - 04:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for informations,It just didn't work when I did the "TCCR0A" fix. But it worked when I did the "TIM0_COMPA" fix.But I did not understand the incident of reaching 61.And do I need to turn off the interrupts and reopen them after reading to safely read the counter value?What is the most reliable version of this code?The aim is a reliable forward counter.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

and simulate it

Why aren't you using a chip?  How did you test your LED? Of course a simulation will be thousands of time slower. 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

 

So the vector is called TIM0_COMPA_vect not TIMER0_COMPA_vect that you have in the code.

 

When I correct those two things and simulate it all appears to be working but after a few minutes "counter" has only reached 61 out of 4000 and life is too short to wait to see it complete - but I suspect it will eventually.


It worked just fine when I tried it.Why?Where did 61 come from? Is this structure correct?Should i use another code?

current code:

#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdio.h>

volatile unsigned int counter = 0;

ISR(TIM0_COMPA_vect){
   //interrupt commands for TIMER 0 here
   counter++;
}

void timerprogram_init()
{
// TIMER 0 for interrupt frequency 1000 Hz:
cli(); // stop interrupts
TCCR0A = 0; // set entire TCCR0A register to 0
TCCR0B = 0; // same for TCCR0B
TCNT0  = 0; // initialize counter value to 0
// set compare match register for 1000 Hz increments
OCR0A = 124; // = 8000000 / (64 * 1000) - 1 (must be <256)
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS02, CS01 and CS00 bits for 64 prescaler
TCCR0B |= (0 << CS02) | (1 << CS01) | (1 << CS00);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
sei(); // allow interrupts

}

int main(void)
{
	/* Replace with your application code */

	 timerprogram_init();

	DDRA|=(1<<7);
	PORTA &=~ (1<<7);

	while (1)
	{
		if(counter>4000)
		PORTA |= (1<<7);

	}
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

why don't you simply say 

TCCR0A = (1 << WGM01); //turn on CTC mode
TCCR0B = (0 << CS02) | (1 << CS01) | (1 << CS00); //Set CS02, CS01 and CS00 bits for 64 prescaler TCCR0B |= (0 << CS02) | (1 << CS01) | (1 << CS00);
TIMSK0 = (1 << OCIE0A); // enable timer compare interrupt
TCNT0 = 0; //initialize counter value to 0
OCR0A = 124; // = 8000000 / (64 * 1000) - 1 (must be <256)

It's a bit easier on the eyes!

 

Did you try a smaller number than 4000, like 40?  If it doesn't simulate, you might not be waiting long enough.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


avrcandies wrote:

why don't you simply say 

TCCR0A = (1 << WGM01); //turn on CTC mode
TCCR0B = (0 << CS02) | (1 << CS01) | (1 << CS00); //Set CS02, CS01 and CS00 bits for 64 prescaler TCCR0B |= (0 << CS02) | (1 << CS01) | (1 << CS00);
TIMSK0 = (1 << OCIE0A); // enable timer compare interrupt
TCNT0 = 0; //initialize counter value to 0
OCR0A = 124; // = 8000000 / (64 * 1000) - 1 (must be <256)

It's a bit easier on the eyes!

 

Did you try a smaller number than 4000, like 40?  If it doesn't simulate, you might not be waiting long enough.



I added the simulation results below. I don't see a problem. Everything is as it should be. But the @clawson above said that the counter,life cycle ends at 61.I'll use this code in an important place. I don't want it to be an error. The answers here are important to me. The current code works. But if there is a more secure code, I would like to use it.


  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I added the simulation results below. I

 Don't you think you should say what these are?  What results??   Is this the timer value--why be vague?  Do you expect clawson to wait around all day?  He stopped looking at 61

 

 

Clawson: but after a few minutes "counter" has only reached 61 out of 4000 and life is too short to wait to see

But the @clawson above said that the counter,life cycle ends at 61

 You'd better look again at what he said.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


avrcandies wrote:

and simulate it

Why aren't you using a chip? 

Indeed:

 

 

 

avrcandies wrote:
Of course (sic) a simulation will be thousands of time slower. 

Although the Atmel Microchip Studio simulator is known to be horrendously slow, there is no inherent reason why that has to be the case - the Keil simulator for the 8051 had the opposite "problem"!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

I added the simulation results below. I

 Don't you think you should say what these are?  What results??   Is this the timer value--why be vague?  Do you expect clawson to wait around all day?  He stopped looking at 61

 

 

 


Sorry,values in the picture values is "counter variable" values .When it comes to speaking 61,I thought he said that the normal counting "counter variable" suddenly broke down after reaching 61 values later.My simulation results do not seem wrong.But if there is an error or missing, I want to fix it.Such as,I made the following improvement.
 

unsigned int read_counter()
{
  unsigned int m;
  uint8_t oldSREG = SREG;

  cli();
  m = counter;
  SREG = oldSREG;

  return m;
}

Full code is here :
 

#define F_CPU 1000000UL //ckdiv8 active
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <SoftwareSerial.h>
#define RX    2   // PA1
#define TX    8   // PB2
SoftwareSerial Serial(RX, TX);

volatile unsigned int counter = 0; //global variable

ISR(TIM0_COMPA_vect){
   //interrupt commands for TIMER 0 here
   counter++;
}

void timerprogram_init()
{
cli(); // stop interrupts
TCCR0A = 0; // set entire TCCR0A register to 0
TCCR0B = 0; // same for TCCR0B
TCNT0  = 0; // initialize counter value to 0
// set compare match register for 1000 Hz increments
OCR0A = 124; // = 1000000 / (8 * 1000) - 1 (must be <256)
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS02, CS01 and CS00 bits for 8 prescaler
TCCR0B |= (0 << CS02) | (1 << CS01) | (0 << CS00);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
sei(); // allow interrupts
}

unsigned int read_counter()
{
  unsigned int m;
  uint8_t oldSREG = SREG;

  cli();
  m = counter;
  SREG = oldSREG;

  return m;
}

void reset_counter() //???
{

}

int main(void)
{
  /* Replace with your application code */
   Serial.begin(9600);
   timerprogram_init();

  while (1)
  {
    Serial.println(read_counter());

  }
}

Any other missing or errors?Also I'm not sure how to configure my reset function.

Last Edited: Tue. Dec 22, 2020 - 12:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You put in cli in read counter...now what do you suppose will happen???!!!

 

Also I'm not sure how to configure my reset function.

Have you thought or defined what you want it to do?  Who told you to have one? 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The point I made was that my limited human patience gave out at 61, not that anything in the code/simulation gave up at that value. Just me.
.
Perhaps you have more patience and could be arsed to wait all the way to 4000.
.
The implication is "simulation is so feckin slow you probably want to reduce the limit below 4000 during development"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

You put in cli in read counter...now what do you suppose will happen???!!! 


clawson said atomic protection needed,when reading counter.I did that too.Also, the millis function in arduino also has this structure.I don't know much about the real cause.Maybe if you know, I'll be happy to listen.

 

avrcandies wrote:

Have you thought or defined what you want it to do?  Who told you to have one? 


I should be able to reset the counter in the program whenever I want.Otherwise,It will reset itself after 65536.I want the reset to be in my control.Sometimes it is necessary to stop the timer. I can do this by setting the prescaler values to 0.But some time after stopping the timer, if I want to start it again, it should start at 0.
So,I need a safe reset function.