Adjusting TCNT1, Any Issues???

Go To Last Post
60 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is my partial code:

TCCR1B=0x05; // divide by 1024
	TIMSK|=0x04;
	SREG |= 0x80;

Before these lines, I am calculating TCNT1 value this way:

if(param_T<=64)
	{
		x1=1000000 * param_T;	
		x2=1024;
		x3=x1/x2;
		x4=65535 - x3;
		remender_seconds=0;
		excess_timer_flag=0;
		TCNT1=x4;
		Original_TCNT1=x4;		
	}
	else
	{
		excess_seconds_over_64=param_T/64;
		remender_seconds=param_T - (excess_seconds_over_64*64);
		excess_timer_flag=1;
		TCNT1=0;			
				
	}	

param_T is the calculated value in decimal format. Datatype is static double. param_T is expected delay in seconds.

This code is using interrupts.

Code goes fine if this code is called ONCE.
It fails when called again and again. Its in a loop, where param_T value is changed at runtime
I am using 1MHZ internal crystal and ATmega8.

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

hey all friends, I need you now... i am stucked badly....

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

You know that datatypes float and double are equal for AVR devices?
Both types are alwys 32 Bit variables.

All the listed operations can be done with integer arithmetic as well by consuming less flash
and gaining much faster ececution.

What happens when "it fails"?
- Is the ISR not executed anymore
- Is the ISR executed by random?
...

Regards
Sebastian

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

This is what happenes:

In first loop if INPUTVALUE > SETVALUE then
it calculates param_T ans assignes to TCNT1.

In further Loopings, it checkes
if the param_T is not the same as the previously calculated value
if NOT same then re-calculate the value for TCNT1 based on new param_T and assign to TCNT1

if this re-assign happenes then ISR is not called atall.

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

Could it be that you rewrite register TCNT1 over and over.
Then the Timer won't ever overflow and therefore the ISR is never called.

Regards
Sebastian

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

Yes i am.
But same time i am stoping timer and sreg=0 too.

Then how to re-adjust TCNT1?

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

and in addition to it i am calculating the TCNT1 values in such a way that i will consider the already "PASSED" time, while re-assigning it.
e.g. initially i set value for 15 seconds and later in next loop for 16 seconds. so while caluclating tcnt1 value for 16 seconds, i am considering time lappsed since timer hase started.....

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

this is that section where i am taking care to consider the lappsed time:

if(start_timer_flag==1 && remender_seconds==0)
	{
				Lapsed_Time=((TCNT1 - Original_TCNT1)*976.56)/1000000;
		param_T=param_T-Lapsed_Time;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What I mean is the following:

- You start timer1 with for example TCNT1 = 0x1234
- Before Timer1 overflows you set TCNT1 to a new value. Example: TCNT1 = 0x0234
- Before Timer1 overflows you set TCNT1 to a new value. Example: TCNT1 = 0x4321
- Before Timer1 overflows you set TCNT1 to a new value. Example: TCNT1 = 0xABCD
...

Do you see that Timer1 won't ever overflow in my example since TCNT1 is reset
to new values again and again?
There is no chance that the overflow interrupt will occur, independent if you
stop the timer before writing or you disable all interrupts.

Note: To disable and enable interrupts better use cli() and sei().
When you write SREG = 0 all other flags in the Status Register will be cleared, too.
I don't think that it is your intention.

Regards
Sebastian

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

have you seen my further posts?

I am deducting the time lapssed since timer1 is started......

any solution....

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

Quote:
Lapsed_Time=((TCNT1 - Original_TCNT1)*976.56)/1000000;

Could it be that the result Could become negative.
Do you make this operation on a fixed timed point? (For Example After Timer1 Overflow)

Are all variable types floats (double)?
Can you post all variable declarations?

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
double ISet;
double temp_ISet; //note as above
static double T;
static double T_ORIGINAL;
static double Original_TCNT1;
static double Lapsed_Time;
static double T_LAPSED;
static double T_PARTIAL_LAPSED;
//static double Original_param_T;
static long excess_seconds_over_64; //used to store loop count for Timer ISR if time delay excedding 65 seconds
static int excess_timer_flag;
static long remender_seconds;
static int start_timer_flag; //used to indicate that timer has started by setting value =1

and next is the section of code i put into a project and run:

int main(void)
{
	double param_T,T_ORIGINAL,Lapsed_Time;
	
	
	T_ORIGINAL=15;
	param_T=20;
	
	
		
	Lapsed_Time=((22000 - 20000)*976.56)/1000000;
	param_T=param_T - Lapsed_Time;
	
	DDRB=0xff;
	PORTB=param_T;
	

return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you just want to calculate the elapsed time since start of Timer1 you might use the CTC mode of Timer1:

TCNT1H=0x00;
TCNT1L=0x00;
OCR1AH=0x3D;
OCR1AL=0x08;
TCCR1A=0x00;
TCCR1B=0x0B;

this will cause a Compare Match A interrupt every second.
The ISR just needs to increment a global variable (volatile)
To calculate the accurate elapsed time,you can read register TCNT1.
If the global variable is 16Bit or larger then you have to
disable interrupts before accessing the value.

Regards
Sebastian

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

Quote:
Lapsed_Time=((22000 - 20000)*976.56)/1000000;
param_T=param_T - Lapsed_Time;

above is the code i used for testing. the actual code is :

Lapsed_Time=((TCNT1 - Original_TCNT1)*976.56)/1000000;
		param_T=param_T-Lapsed_Time;
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

this way i am reading accurate time lappsed by reading TCNT1.

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

Seems like I'm not able to help you.
Maybe the other forum members will do it better.

Regards
Sebastian

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

I think S-Sohn has already pointed out your difficulties:

1) Your Lapsed_Time computation is going negative
2) You're continually setting TCNT1 back, so the interrupt never happens

but I'll try different words. Fundamentally, you're getting into trouble by
mixing signed/unsigned and fixed-bit-width/float.

Lapsed_Time=((TCNT1 - Original_TCNT1)*976.56)/1000000;
param_T=param_T-Lapsed_Time;

Consider doing this right after an overflow: TCNT1 is a small integer, and
Original_TCNT1 is much larger. After the arithmetic, Lapsed_Time is
negative (float is implicitly signed), so you're actually Adding to Param_T,
making it Larger. When you go through the other arithmetic, Original_TCNT1
then becomes larger than TCNT1, and param_T continues to grow, eventually
exceeding 64, at which point you continually set TCNT1=0, so you never
see an overflow.

Doing TCNT arithmetic typically doesn't get you in trouble as long as you
stick with 16-bit unsigned values, where the modulo arithmetic works out.
I suggest you toss out all the floating point, and, where you need extra
precision, force the arithmetic to "unsigned long" then back to "unsigned
int". Or, use CTC mode to generate a fixed-tick (1ms, e.g.) and do your
delta-timer in software.

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

Sebastian, you have taken a great effort to help me out. Yesterday, with my last message, i closed my day. Now, back in office to finish the task.
mckenney, you too explained me well.
I am in office now to close the matter. Will update you in some time about the final working code. Thanks friends!!!

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

Friends, I am through with the task. Its all due to your help.

As you suggested, I used CTC for every 1ms aprox with error correction of 1 ms every 50ms. Let my client decide the exact tolerance.

Sabistine, your idea of incrementing global variable worked out.

This is my ISR now:

ISR (TIMER1_COMPA_vect)
{ 
	glb_ms_counter++;
	error_corrector++;
	if(error_corrector==50)
	{
		error_corrector=0;
		glb_ms_counter--;
	}
	if(glb_ms_counter>=glb_max_ms)
	{	
		sbi(DDRC,5);
		cbi(PORTC,5);	 		
		while(1){}	
	}
}

and this is the CTC init routine for Timer 1 with ATmega8 for 1MHz internal crystal:

void Init_Timer1_CTC(void)
{
		
		TCNT1H=0x00; 
		TCNT1L=0x00; 	
		OCR1AH=0x00; 
		OCR1AL=0x01; 
	
		TCCR1A=0x00; 
		TCCR1B=0x0D;
		TIMSK|=0x10;
		SREG |= 0x80;
	
}

and simple few lines to calculate the lapssed time:

if(start_timer_flag==0)
		{
			Init_Timer1_CTC();		
		}
		
		if(backup_T <= glb_ms_counter)
		{
			sbi(DDRC,5);
			cbi(PORTC,5);	 
			while(1){}
		}
		else
		{
			glb_max_ms = backup_T - glb_ms_counter;
		}

Heyy, let me say ZAKAAS!!! This mean "Great work" in my language. I can go home for sunday lunch in time as I promised my wife.
Thanks all!!!

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

yellowboy_75:
Fine that you got it working now!
Nice that we could even make a little positive contribution to your mariage.

mckenney:
Thank you very much for your support!!!

Regards
Sebastian

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

Will this code generate 1 ms interrupt generation with atmega8 at 1mhz internal osc.?
I am experiencing the problem. It is generating double delay than expected? Why?

#include  
#include  
#include  

#ifndef cbi 
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 
#endif 
#ifndef sbi 
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 
#endif 


 static double glb_ms_counter; 
 static double glb_max_ms; 
 static int error_corrector; 
ISR (TIMER1_COMPA_vect) //(SIG_OVERFLOW1) 
{ 
   glb_ms_counter ++; 
   error_corrector++; 
    
   if(error_corrector==50) 
   { 
      error_corrector=0; 
      glb_ms_counter--; 
   } 
    
   if(glb_ms_counter==glb_max_ms) 
   { 
      sbi(DDRC,5); 
      cbi(PORTC,5); 
      while(1){} 
   } 
       
    
} 

int main(void) 
{ 
   sbi(DDRC,5); 
   sbi(PORTC,5); 
    
   sbi(DDRC,4); 
   sbi(PORTC,4); 
    
   glb_ms_counter=0; 
   glb_max_ms=1000; 
   error_corrector=0; 
    
    
    
   sbi(DDRC,4); 
   cbi(PORTC,4); 
    
   TCNT1H=0x00; 
   TCNT1L=0x00;     
   OCR1AH=0x00; 
   OCR1AL=0x01;    //for 1ms CTC 
   TCCR1A=0x00; 
   TCCR1B=0x0D; // CTC + 1024 presclar 
   TIMSK|=0x10; // CTC interrupt    
   SREG |= 0x80; //global interrupt          
    
    
   while(1){ 
   _delay_us(200); 
    
   } 

   return 0; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You get the half cycle because the timer must be incremented once before a compare match can occur
TCNT1 = 0
TCNT1 = 1 -> COMPARE MATCH, Call ISR
TCNT1 = 0
TCNT1 = 1 -> COMPARE MATCH, Call ISR
TCNT1 = 0
TCNT1 = 1 -> COMPARE MATCH, Call ISR
...

Note that you won't get an 1ms cycle even with setting OCR1A = 0 since you have selected a prescaler of 1024:
1 MHz / 1024 = 976.5625Hz
So you'll get an interrupt each 1.024ms

You better don't prescale the Timer1 clock and set OCR1A = 999.

Another point:
Which accuracy do you need???
The internal oscillator frequency depends on the power supply and on the temperature:
I suggest you take a good look at page 275 of the ATmega8 datasheet.

If you need more accuracy you'll find many material at avrfreaks.net (including complete source):
Some examples:
https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=36895&start=0
https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=37170&start=0

Regards
Sebastian

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

Thnaks!!! Its working...
I have posted this same query with new topic "1ms interrupt....." some time back. There I got a feedback that I must write Calibration code......

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

With your code I am getting 6.17 or 6.18 sec when I set 6000 ms to count.

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

yellowboy_75 wrote:
With your code I am getting 6.17 or 6.18 sec when I set 6000 ms to count.

So you got an error of 3% at a fix temperature and a fix supply voltage
for a single AVR device.
I think you can expect an error of 5% over all parameter.
(Supply voltage +-0.5V, temperature 0-60°C)

Is this error critical for your application?

Regards
Sebastian

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

I suggest you download Dean Camera's ButtLoad
https://www.avrfreaks.net/index.php?module=FreaksAcademy&func=viewItem&item_id=517&item_type=project

His project contains the files OSCCal.c and OSCCal.h which manage the calbration of the internal oscillator.
The code is written for the ATmega169 but I think it can be easily adjusted for your ATmega8.
One important difference is that register OSCCAL of ATmega169 is a 7 bit value while ATmega8 has a 8 bit register.

Regards
Sebastian

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

Quote:
Is this error critical for your application?

Yes. It is.
6 sec should be 6 sec only. Hmm working for it.

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

S-Sohn wrote:
I suggest you download Dean Camera's ButtLoad
https://www.avrfreaks.net/index.php?module=FreaksAcademy&func=viewItem&item_id=517&item_type=project

His project contains the files OSCCal.c and OSCCal.h which manage the calbration of the internal oscillator.
The code is written for the ATmega169 but I think it can be easily adjusted for your ATmega8.
One important difference is that register OSCCAL of ATmega169 is a 7 bit value while ATmega8 has a 8 bit register.

Regards
Sebastian

The code is also avaliable from the Tutorials section here, in the post concerning calibrating the USART for 115200 baud serial communications (which requires an accurate clock). It requires a 32.768KHz watch crystal attached to an asynchronous timer.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

I checked the butload.
It rerquires an external Crystal for calibration. Can I avoid it?

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

In order to calibrate the internal oscillator, you need some sort of accurate low-frequency external signal. This can be of any frequency so long as it is guaranteed to be accurate (as well as less than the desired main clock frequency by quite a bit) and all you would need to do would be to change the reference frequency in the header file. If you use an external clock rather than a crystal, then you'll have to change the timer mode.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Are there any reasons why you can't use an crystal oscillator?
- Price
- PCB size
- ...

Colin O'Flynn made a summray "Why you need a clock source".
I think this article points out very excellent the pros and cons.
https://www.avrfreaks.net/index.php?module=dpDocs&func=index&cid=9

Regards
Sebastian

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

If the power supply of your ATmega8 comes from the wall socket
you can use the AC frequency to calibrate the internal oscillator.
In Germany the frequency of the mains voltage is exactly 50.000Hz.
I'm not sure how exact the frequency in india is.

If you don't have any experience in handling perilous voltages
please reject this idea and flush it from your mind.

If this is a possible solution for you, I'll make some sugestions
how you can implement this idea.

Regards
Sebastian

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

Quote:
Are there any reasons why you can't use an crystal oscillator?
- Price
- PCB size
- ...

Reason is, on my development board, i dont have any provision ready for it. I have to solder it now externally.
Today, client told me to make it perfect, as the readings are 6.3sec against 6.00.
So I have to add calibration into it.
Which pin should i solder the Crystal? Will 11.0592Mhz or 6Mhz will work with calibration routines provided by butload's project.

YB

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

Since what you want is an exact timer interrupt and nothing else, I'd go the 32.768KHz crystal attached to an asynchronous timer. That means you can run the AVR off the internal clock while using the cheap but accurate watch crystal to create 1ms exact interrupts (use a prescaler of 64 and a compare value of 0x33).

You could certainly use an external crystal on an asynchronous timer to calibrate the internal oscillator, but it would be less accurate and since you can use the external crystal to feed the timer it is unnecessary.

Other frequencies than 32.768KHz may work, but the internal asynch timer crystal driver is designed specifically for 32.768KHz crystals. Other values will require external capacitors.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Sorry Dean, I could not understand much from your reply.

This is what i understood:
1. DO not calibrate
2. Use asynchronous timer mode by connecting 32.768KHz crystal

Correct?

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

Yes.

Calibrating requires a reasonably low frequency crystal, the slower the better (up to a point). The most common low frequency crystal is a 32.768KHz watch crystal as the AVRs are designed to be able to run them on an asynchronous timer and they are also available cheaply.

Calibrating the internal oscillator will not yield perfect results, you'd only get "very close to" the speed you want. However, the 32.768KHz crystal frequency is solid as a rock - mainly because it is indeed a rock :).

Attaching a 32.768KHz crystal to an asynchronous timer means you can then generate exact 1ms interrupts via the timer's CTC (Clear on Timer Compare) mode. If you use the timer's internal prescaler set to divide the incomming steady 32.768KHz signal by a factor of 64, then each time the timer reaches the value 0x33 a period of 1ms will have elapsed. Set to CTC mode with a compare value of 0x33 you can then make the timer generate an exact 1ms interrupt which you can then use in software.

If you need some sample code I could write some for you.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Good Learning.
Based on your input, I am writing a code for timer init. Will post it in next few minutes.
Do i need any disc capacitor with crystal?

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

Not with a 32.768KHz crystal. The AVRs which feature crystal input on an asynchronous timer have the capacitors located inside the chip. This is very useful.

Because 32.768KHz is a frequency easily divided down to decimal periods (for example 1ms, as I have stated above) it is used in time keeping devices and RTC applications. Atmel knows this and so have designed the timer crystal input to accept the most common crystal frequency.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

This is my code to initialize timer2 in async mode using external crystal.

ISR (TIMER2_COMP_vect) 
{ 
	//will be called every 1ms

}


void Init_Timer2_CTC(void)
{	
		sbi(ASSR,AS2); // External Crystal of 32.768KHz will be used
		TCNT2=0x00; //initial value		 	
		OCR2=0x33;  //for 1ms delay			
		TCCR2=0x0c; // CTC + 64 presclar
		TIMSK|=0x80; // CTC interrupt
		SREG |= 0x80; //global interrupt	
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have to drive to market to buy the crystal...
Is this code ok?

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

Looks good, but I'd suggest using the GCC symbolic bit names instead of "magic number" constants on the control registers such as "PS20" and such. It won't make any difference performance wise, but it makes it a lot easier to read.

Also:

SREG |= 0x80; //global interrupt

If you include the GCC header file "avr/interrupt.h" the macros "sei()" and "cli()" are exposed. You can then enable global interrupts via:

#include 

sei();

Which is also easier to read.

Finally, external crystals take a few ms to become stable when first activated. I use the following in my own code:

while (ASSR & ((1 << TCN2UB) | (1 << TCR2UB) | (1 << OCR2UB))); // Wait for external crystal to become stable

I place this before I enable interrupts, and before I clear the timer value. This code runs a loop which hangs the processor until the "external crystal ready" timer control bits are set.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

I got the crystals. But code is not working.
This is my full code for ATmega8 with 1MHZ internal oscillator and 32.768Khz external crystal.

#include 
#include 
#include 

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

long glb_ms_counter;
long glb_max_ms;

 
void Init_Timer2_CTC(void);

ISR (TIMER2_COMP_vect) 
{ 
	//will be called every 1ms
	glb_ms_counter ++;	
	
	if(glb_ms_counter==glb_max_ms) 
	{
		sbi(DDRD,5);
		cbi(PORTD,5);
		while(1){}
	}
		
}


void Init_Timer2_CTC(void)
{	
		sbi(ASSR,AS2); // External Crystal of 32.768KHz will be used
		TCNT2=0x00; 		 	
		OCR2=0x33;				
		TCCR2=0x0c; // CTC + 64 presclar
		TIMSK|=0x80; // CTC interrupt
		SREG |= 0x80; //global interrupt	
}


int main(void)
{

	_delay_ms(1000);
	
	sbi(DDRD,5);
	sbi(PORTD,5);
	
	sbi(DDRD,4);
	sbi(PORTD,4);
	
	glb_ms_counter=0;
	glb_max_ms=12000;
		
	sbi(DDRD,4);
	cbi(PORTD,4);
	
	Init_Timer2_CTC();
	
	while(1){
	_delay_us(200);
	
	}

	return 0;
}
Last Edited: Wed. Jul 5, 2006 - 09:28 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dean: 32768 Hz / 64 / (0x33 + 1) = 9.84615384615...Hz
I don't understand how this will generate a compare match interrupt each 1 ms?
Can you try to make it clear for me???

Regards
Sebastian

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

You can poll the Overflow or OCR Flag manually in the mainloop for first test if timer is running.
Perhaps you have something forgotten to enable the interrupts...

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

Quote:

ISR (TIMER2_COMP_vect)
{
   //will be called every 1ms
   glb_ms_counter ++;   
   
   if(glb_ms_counter==glb_max_ms)
   {
      sbi(DDRD,5);
      cbi(PORTD,5);
      while(1){}
   }
}

Never place an endless loop inside an ISR!
Since all Interrupts are disabled inside the ISR the loop will take forever and won't ever be interrupted.

You should clear variable "glb_ms_counter" inside the if block or it will take a loooong time until the if condition will match again.

Since glb_max_ms is 12000 you don't need to declare your global variables as long. unsigned int would fit perfectly
and would reduce the size of the ISR considerable.

Using #define for a constant would save RAM since these values are located in FLASH:
#define GLB_MAX_MS 12000

Regards
Sebastian

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

Sebastian,

I used the wrong value in AVRCalc :?. Using the correct crystal frequency, with NO prescaler and a compare value of 0x20, you can get an interrupt frequency of 1.024ms, as close to 1ms as is possible at 32.768 (and closer than if you calibrated via the internal oscillator).

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Thanks!!
In ISR, Once it enters into the if statement, i dont want it to get back to main program. I have done it purposely. And as you pointed out to "Dean", i am not getting a 1ms delay. now how to solve it. The program is such way that i dont want to count the OCR as baer.ac mentioned......... lost again....

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

If you only need a resolution of 1s (You're trying to count 12000ms = 12s)
you can use a prescaler of 256 for Timer2 and set OCR2 = 127.
This would be the most exact solution.

Regards
Sebastian

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

Quote:

--------------------------------------------------------------------------------
I used the wrong value in AVRCalc . Using the correct crystal frequency, with NO prescaler and a compare value of 0x20, you can get an interrupt frequency of 1.024ms, as close to 1ms as is possible at 32.768 (and closer than if you calibrated via the internal oscillator).

And this is my changed init fn:

void Init_Timer2_CTC(void)
{	
		sbi(ASSR,AS2); // External Crystal of 32.768KHz will be used
		TCNT2=0x00; 		 	
		OCR2=0x20;				
		TCCR2=0x09; // CTC + 64 presclar
		TIMSK|=0x80; // CTC interrupt
		SREG |= 0x80; //global interrupt	
}

No Interrupt generation atall !!!

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

Quote:
If you only need a resolution of 1s (You're trying to count 12000ms = 12s)
you can use a prescaler of 256 for Timer2 and set OCR2 = 127.
This would be the most exact solution.

I have a much larger actual project, of which, i am stucked at 1ms exact delay part.
The 12000ms = 12s is used for testing, but in actual project it could be from 0.1 sec to several minutes.

So i simply need exact 1ms interrupt routine....

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

Havn't checked this, but I just knocked this up in notepad:

#include 
#include 

int main (void)
{
	// Set timer 2 to asyncronous mode (32.768KHz crystal)
	ASSR   = (1 << AS2);
        
	// Timer 2 overflow interrupt enable
	TIMSK2 = (1 << OCIE2);

	// Start timer 2 with no prescale
	TCCR2A = (1 << CS20);

	// Set timer 2 compare value
	OCR2 = 0x20;

	// Enable Interrupts
	sei();
	 	 
	// Wait until timer 2's external 32.768KHz crystal is stable
	while (ASSR & ((1 << TCN2UB) | (1 << TCR2UB) | (1 << OCR2UB)));
    
	// Clear the timer value
	TCNT2  = 0;

	// Eternal loop
	while (1);
}

ISR(TIMER2_COMP_vect) // Occurs every 1.024ms per second
{
   // ISR CODE HERE
}

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Pages