CTC mode issues

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

I am trying to set  timer interrupt in CTC mode . I am not using any prescalar value and I am using the max count for 16 bit OCR register .

this should give me a delay of 592ms according to my calculations .

In the ISR I am multiplying this period by 10 so I should get a delay of around 6 secs  but I see my control goes to the ISR routine but I am not getting 6 secs

delays.

iam using ATMEGA1284p with 11.0592MHz  clock.

 

what am I missing here?

 

uint16_t  HeartBeat=0;

void timer1_init()
{
/*---------------------------------------------------------------
required_delay=(timer_counter+1)Xclock_time_period  //11.0592MHz
=(65535+1)x 9.04x10E-6  = 592ms
----------------------------------------------------------------*/
// set up timer1 with no prescaler and CTC mode
 TCCR1A |= (1 << WGM11);
 TCCR1B |= (1 << CS10);

 // initialize counter
 TCNT1 = 0;
 
 // initialize compare value
 OCR1A = 65535;
 
 // enable compare interrupt
 TIMSK1 |= (1 << OCIE1A);
 
 // enable global interrupts
 sei();
}

ISR (TIMER1_COMPA_vect)
{
 HeartBeat++;                           
 if(HeartBeat > 10)              
 {
  HeartBeat = 0;
  TFT_String(10,100,"HERE..." ,RED,txt_bg_color,3);
        _delay_ms(1000);
    TFT_String(10,100,"HERE..." ,txt_bg_color,txt_bg_color,3);
 
 }
}

 

This topic has a solution.
Last Edited: Tue. Feb 23, 2016 - 01:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's because you are using a delay inside an ISR. As a general rule, never ever do that. Instead, simply set a flag inside the ISR to inform the application that 6 seconds have elapsed.

 

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

I removed the delay loop from the ISR and just increment the heartbeat counter , but even with a multiplier value of 400 I get a constant delay of about 1 sec.

It does not matter what value I give to the multiplier its not changing the msg displaying frequency

 

void check_heartbeat()
{
 if(HeartBeat > 400)
 {
  HeartBeat = 0;
  TFT_String(10,100,"HERE..." ,RED,txt_bg_color,3);           // display the text
  _delay_ms(1000);                                            // I sec delay
  TFT_String(10,100,"HERE..." ,txt_bg_color,txt_bg_color,3);  //turns the text off 
   
 }
}
ISR (TIMER1_COMPA_vect)
{
 HeartBeat++;                            

}

 

Last Edited: Sun. Feb 21, 2016 - 11:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

 Try making the variable HeartBeat be volatile.   Initialize it like this:  uint16_t volatile HeartBeat;

 

This lets the compiler know that the value can be changed by a process outside the main code; here that's the ISR.  It also stores the value in SRAM instead of on the stack, and it prevents the optimizer from removing HeartBeat because it isn't written to by the main code.

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

I declared the variable as volatile still code is behaving the same .

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

But your references to Heartbeat are not atomic - you'll get random results. Since heartbeat is a uint16 - two bytes. What happens if the interrupt hits between writing the first byte and the second byte? Wierd stuff is what happens.

 

Use a uint8_t shared variable and have the isr set it to 1. Keep count of the heartbeats in the isr and do the compare in the isr. When heartbeats gets to 400, set the uint8_t variable to 1. I wrote a tutorial that does this - search for kartman multi-tasking in the tutorial section.

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

hi Kartman I found  your tutorial and I made my code accordingly (as below) but still no luck ,its not displaying the text after the delay I introduce with the multiplying factor.  the text just flickers on the screen telling me the text is being displayed in less than a second .

 

uint8_t  volatile HeartBeat=1;

while(1)
 {
  if (HeartBeat)
  {
  HeartBeat = 0;
  TFT_String(10,100,"HERE1..." ,RED,txt_bg_color,3);
  _delay_ms(1000);
  TFT_String(10,100,"HERE1..." ,txt_bg_color,txt_bg_color,3);     
  }
 }


ISR (TIMER1_COMPA_vect)
{
 HeartBeat++;     
 if(HeartBeat > 20)
 {
  HeartBeat = 1;
  
 }                       

}

 

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

if(HeartBeat) will always be evaluated to true.
Either use if (HeartBeat==1) or declare another variable which is set to 1 once heartbeat crosses twenty. Then in the loop, check if that variable is set to one.
As much as i know 'type modifiers' should beplaced in the beginning. Shouldn't it be volatile uint8_t instead of uint8_t volatile ?

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

The timer will interrupt every 6ms, so times 20 equals 120ms.
Your calc is only off by a factor of 100.

Last Edited: Mon. Feb 22, 2016 - 07:40 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In that case, it should be if ( HeartBeat>400) as Kartman said in post #6.

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

Oh that explains the reason im not seeibg delays as it is just too short.
So my calculatiion in post #1 is not cirrect ? Whats the formula to get the time delay for max timer value ?

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

Follow Dean's tutorials. He explains it thoroughly.
www.avrfreaks.net/forum/tut-c-newbies-guide-avr-timers

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

There's a few things that seem to be incorrect to me in your post.

 

First off:

aliyesami wrote:

// set up timer1 with no prescaler and CTC mode
 TCCR1A |= (1 << WGM11);
 TCCR1B |= (1 << CS10);

According to the 1284p datasheet, WGM11 is mode 2 which is "PWM, Phase Correct, 9-bit." This is not CTC mode. It's TOP count is 0x1FF. I believe what you want is WGM12, which is mode 2 for CTC and TOP is OCR1A.

See Table 16-5 from the datasheet:

 

Also, your math seems to be incorrect to me. If your clock is indeed 11.0592 MHz, then that is 11,059,200 clocks per second. If your timer counts up to 65535 (65536 cycles), then it would take the timer about 169 times at the interrupt to achieve one second when not using a prescaler. Therefore you either need to count up to about 1013 to achieve 6 seconds (your interrupt would need to happen about 1013 times) or use a larger prescaler with a smaller OCR1A value to achieve one second and then count seconds until you reach 6.

 

[EDIT] Mistakenly wrote 1023 instead of 1013

[EDIT2] Added some extra text explaining the 1013

My digital portfolio: www.jamisonjerving.com

My game company: www.polygonbyte.com

Last Edited: Mon. Feb 22, 2016 - 06:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The formula was correct, you just didn't type the numbers into the calculator right. You were a 100 times off with the crystal osc period. It is 9e-8 not 9e-6.

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

The formula was correct, you just didn't type the numbers into the calculator right. You were a 100 times off with the crystal osc period. It is 9e-8 not 9e-6

thanks Kartman . I am getting 6ms as you pointed out  and now iam checking for count 2000 to reach which is 12sec , still the code is not doing what its suppose to do , display the text ever 12 sec.

I have increased the  variable to  uint16_t  instead of uint8_t  .  

also as some reader pointed out that I should use WGM12 bit but I am not sure why , I am looking at atmega1284 datasheet and its showing CTC mode as WGM1  bit set.   I did try WGM12 bit set but of no use.

 

 

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

aliyesami wrote:
also as some reader pointed out that I should use WGM12 bit but I am not sure why , I am looking at atmega1284 datasheet and its showing CTC mode as WGM1  bit set.   I did try WGM12 bit set but of no use.

The table you are looking at is 15-8, which belongs to section 15 of the manual. That section is for Timer 0. That is not the 16-bit timer; it is an 8-bit timer. The mode of operation table is different for the 16-bit timer. Look at table 16-5 (as I attached previously) on page 130 of the manual.

 

You will notice in the Table 16-5 it refers to WGMn1. The n refers to the index of the timer you are using. In your case, it would be Timer 1 (again, Timer 0 is the 8-bit timer), so you need WGM12 for Timer 1 in CTC mode.

 

 

 

My digital portfolio: www.jamisonjerving.com

My game company: www.polygonbyte.com

Last Edited: Tue. Feb 23, 2016 - 06:46 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks its working fine now