CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

PIC12F629 Timer issue
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Hans Wedemeyer



Joined: 15 Sep 2003
Posts: 226

View user's profile Send private message

PIC12F629 Timer issue
PostPosted: Sat Jul 22, 2006 8:32 pm     Reply with quote

Using 10MHz osc. I'm trying to run both timer0 and timer1 to generate
two frequencies 1100Hz and 1500Hz

To toggle the pin each half cycle in the ISR:
Timer0Value = 256 - (0.00033333/(8/(10000000/4)))
Timer1Value = 65536 - (0.000454545/(1/(10000000/4)))

The output is not what I expected, allowing for the timer resolution these values are too far off.
Measured output 1063Hz not 1100Hz
Measured output 1430Hz not 1500Hz

The resonator is running a little high, the measured frequency 10,050,250 Hz. Yet the outputs are far too low !

Did I do something wrong or is there something strange with the 12F629 ?

Thanks.
Hans W

#FUSES HS, NOMCLR, NOPROTECT, NOWDT, NOBROWNOUT, PUT
#use delay(clock=10000000)

#use fast_io(a)

int Timer0Value;
long Timer1Value;

#int_TIMER0
TIMER0_isr()
{
output_toggle(PIN_A1);
set_Timer0 ( Timer0Value );
}

#int_TIMER1
TIMER1_isr()
{
output_toggle(PIN_A2);
set_Timer1 ( Timer1Value );
}

void main()
{
Timer0Value = 152;
Timer1Value = 64400L;

set_tris_A(0b00101000);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

enable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);

set_Timer0 ( Timer0Value );
set_Timer1 ( Timer1Value );

while(1){;} // do nothing

}
epideath



Joined: 07 Jun 2006
Posts: 47

View user's profile Send private message

PostPosted: Sat Jul 22, 2006 10:44 pm     Reply with quote

Looks like you got some numbers crossed

Timer0Value = 256 - (0.00033333/(8/(10000000/4)))
Timer1Value = 65536 - (0.000454545/(1/(10000000/4)))

should be

Timer0Value = 256 - (0.000454545/(8/(10000000/4)))
Timer1Value = 65536 - (0.00033333/(1/(10000000/4)))

Note the .0004545454 and the .000333333333

If you take the half scycle speed for 1100 hz so 2200. 1/2200 = .000454545

If you take the half scycle speed for 1500 hz so 3000. 1/3000 = .0003333333


So the numbers should be
Timer0Value = 141
Timer1Value = 64703L

Hope this helps
Hans Wedemeyer



Joined: 15 Sep 2003
Posts: 226

View user's profile Send private message

Timer1 will control the 1100Hz
PostPosted: Sun Jul 23, 2006 5:04 am     Reply with quote

epideath wrote:
Looks like you got some numbers crossed

Timer0Value = 256 - (0.00033333/(8/(10000000/4)))
Timer1Value = 65536 - (0.000454545/(1/(10000000/4)))



No it's correct as is.
In the end I want the ability to fine tune Timer1 which controls the 1100Hz.

Timer0 controls the 1500Hz which is not as critical.
I can allow it to be off frequency, but the 1100Hz needs to be as good as possible.

The final "tweaked" value for Timer1 turns out to be 64435

Thanks.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Sun Jul 23, 2006 10:09 am     Reply with quote

The problem is the interrupt latency. In your interrupt, you are setting timer1 to a value. When the interrupt occurs, timer1's value is 0. By the time the interrupt is processed, many instructions (and time) has gone by. By setting the timer with your "roll over value" you lose this time in your calculations and thus the difference in what you see. From the numbers, it appears to be off by about 35 instructions which is about how many instructions it takes to process the interrupts. A better approach would be to add the "roll over value" to the current timer1 value so that you don't lose its count.
Hans Wedemeyer



Joined: 15 Sep 2003
Posts: 226

View user's profile Send private message

Not sure
PostPosted: Mon Jul 24, 2006 3:39 pm     Reply with quote

Mark wrote:
A better approach would be to add the "roll over value" to the current timer1 value so that you don't lose its count.


Thanks forthe reply.
Not sure I understand this!

Do you mean the Set_Timer1(value) is taking too long ?

How would adding a value be any quicker ?

Can you please show me in code how the ISR can be any simpler than it is now !

As it is the ISR (not accounting for CCS interrupt stuff) is about as tight as assembly could do it.

#int_TIMER1
TIMER1_isr()
{
.................... output_toggle(PIN_A2);
0047: MOVLW 04
0048: XORWF 05,F
.................... set_Timer1(Timer1Value); // reload 16 bit value
0049: MOVF 2F,W
004A: MOVWF 0F
004B: MOVF 2E,W
004C: MOVWF 0E
.................... }
Guest








Re: Not sure
PostPosted: Mon Jul 24, 2006 8:20 pm     Reply with quote

[quote="Hans Wedemeyer"]
Mark wrote:
A better approach would be to add the "roll over value" to the current timer1 value so that you don't lose its count.


Quote:
Thanks forthe reply.
Not sure I understand this!

Do you mean the Set_Timer1(value) is taking too long ?

How would adding a value be any quicker ?


I think you should subtract from your original timer value the time spent in the interrupt routine + time in CCS interrupt stuff.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Mon Jul 24, 2006 8:33 pm     Reply with quote

By the time the interrupt is processed, timer1 already has a count. Run the code in the simulator and put a break point just before the set timer function. Take a look at the value of timer1. I think it will become clear then. It is not that the isr code is fat, it is the saving of all the registers that happens behind the scene. Since timer1 is not 0, when you set timer1 to a value, you lose the time hince the adjusted value. If you want to avoid this, you cannot lose this time so if you add the timer1 value to the computed value this will correct it. Actually, adding the value will produce a slightly larger isr routine but will keep in time better.
Hans Wedemeyer



Joined: 15 Sep 2003
Posts: 226

View user's profile Send private message

Re: Not sure
PostPosted: Mon Jul 24, 2006 8:44 pm     Reply with quote

[quote="Anonymous"]
Hans Wedemeyer wrote:
Mark wrote:
A better approach would be to add the "roll over value" to the current timer1 value so that you don't lose its count.


Quote:
Thanks forthe reply.
Not sure I understand this!

Do you mean the Set_Timer1(value) is taking too long ?

How would adding a value be any quicker ?


I think you should subtract from your original timer value the time spent in the interrupt routine + time in CCS interrupt stuff.


Well that's what I did when I adjusted the values. see earlier post.
Thanks.
Hans Wedemeyer



Joined: 15 Sep 2003
Posts: 226

View user's profile Send private message

OK and here is another solution
PostPosted: Mon Jul 24, 2006 8:56 pm     Reply with quote

Mark wrote:
By the time the interrupt is processed, timer1 already has a count. Run the code in the simulator and put a break point just before the set timer function. Take a look at the value of timer1. I think it will become clear then. It is not that the isr code is fat, it is the saving of all the registers that happens behind the scene. Since timer1 is not 0, when you set timer1 to a value, you lose the time hince the adjusted value. If you want to avoid this, you cannot lose this time so if you add the timer1 value to the computed value this will correct it. Actually, adding the value will produce a slightly larger isr routine but will keep in time better.


Adding means I also have to determine the value to be added, and then add the value. That brings up other issues. There will be a further delay to take into account forthe code that adds the value ! This could get messy.

Although I wanted maximum resolution for adjusting Timer1 hence the div. 1 in Timer1 setup.

If I set Timer1 prescaler to Div 8 then Timer1 will increment 8 times slower then it does now, but the ISR will still be processed at full speed. That should bring the error down.

Another solution would be to do my own Interrupt handler and minimize the overhead, CCS interrupt handling is not as lean as perhaps it wcould be.

Final solution is to live with it and use a tweeked value to compensate for the error.

Thanks for the help.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Mon Jul 24, 2006 9:08 pm     Reply with quote

If you do it like
Code:

#include <12F629>
#FUSES HS, NOMCLR, NOPROTECT, NOWDT, NOBROWNOUT, PUT
#use delay(clock=10000000)

#use fast_io(a)

int Timer0Value;
long Timer1Value;

long Timer1Reg;
#locate Timer1Reg = 0x0E

#int_TIMER0
TIMER0_isr()
{
output_toggle(PIN_A1);
set_Timer0 ( Timer0Value );
}

#int_TIMER1
TIMER1_isr()
{
output_toggle(PIN_A2);
Timer1Reg += Timer1Value;
}

void main()
{
Timer0Value = 152;
Timer1Value = 64400L;

set_tris_A(0b00101000);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

enable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);

set_Timer0 ( Timer0Value );
set_Timer1 ( Timer1Value );

while(1){;} // do nothing

}


then it is just a bit more code
Code:
.................... output_toggle(PIN_A2);   
0047:  MOVLW  04
0048:  XORWF  05,F
.................... Timer1Reg += Timer1Value;   
0049:  MOVF   2F,W
004A:  ADDWF  0E,F
004B:  BTFSC  03.0
004C:  INCF   0F,F
004D:  MOVF   30,W
004E:  ADDWF  0F,F
.................... }   
Guest








Re: Not sure
PostPosted: Tue Jul 25, 2006 12:41 am     Reply with quote

Quote:
Well that's what I did when I adjusted the values. see earlier post.
Thanks.


What about extra time when both interrupts happen at the same time, or one isr is running and the other is pending ?

I made a quick and dirty calculation and this might happen every fifteenth interrupt of the 1100Hz routine.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Tue Jul 25, 2006 6:36 am     Reply with quote

Use the #priority to have the Timer1 int go first. This will take care of some of the cases. There will be other cases where you will be in the timer0 interrupt when the timer1 int fires. This will cause a slight error in the signal. In the way I suggested, the frequency will remain the same but the duty cycle will change slightly when the timer0 int fires just before the timer1 int does. To improve upon this even further, you can embed a goto at the end of the timer0 routine to jump back to the beginning of the interrupt flag test in the CCS interrupt handler. If timer1 int has occurred, then it will get executed. Note that the registers have already been saved so you save this amount of time. You could also write your own int handler or use the global handler and do your own bit testing.
Hans Wedemeyer



Joined: 15 Sep 2003
Posts: 226

View user's profile Send private message

PostPosted: Tue Jul 25, 2006 4:15 pm     Reply with quote

Mark wrote:
If you do it like
#int_TIMER1
TIMER1_isr()
{
output_toggle(PIN_A2);
Timer1Reg += Timer1Value;
}


OK now I see it thanks{
I'll try it, and let you know.
Good point about the two timers interrupts happening at the same time, I'll take care of that.

hansw
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jul 25, 2006 4:22 pm     Reply with quote

Quote:
you can embed a goto at the end of the timer0 routine to jump back to the beginning of the interrupt flag test in the CCS interrupt handler.

That seems very risky. Why not do a test of the interrupt flag for
Timer1 while inside the Timer0 isr ? Then if it's set, clear it, and
execute the Timer1 isr code at that time. (Put a copy of the Timer1
code inside the Timer0 isr). Do a similar thing for the other Timer isr.
This is much more clean method.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Tue Jul 25, 2006 9:17 pm     Reply with quote

PCM programmer wrote:
Quote:
you can embed a goto at the end of the timer0 routine to jump back to the beginning of the interrupt flag test in the CCS interrupt handler.

That seems very risky. Why not do a test of the interrupt flag for
Timer1 while inside the Timer0 isr ? Then if it's set, clear it, and
execute the Timer1 isr code at that time. (Put a copy of the Timer1
code inside the Timer0 isr). Do a similar thing for the other Timer isr.
This is much more clean method.


With all that trouble, he'd be better off just using the int_global and testing the flags. The best approach if his isr's are as simple as what is posted is to just write his own int handler.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group