![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
Stopping and re-starting a timer |
Posted: Sat May 14, 2022 1:46 am |
|
|
The PIC18LF46K22 datasheet has this paragraph in Section 12.5.1 (READING AND WRITING TIMER1/3/5 IN ASYNCHRONOUS COUNTER MODE):
"Reading TMRxH or TMRxL while the timer is running from an external asynchronous clock will ensure a valid read (taken care of in hardware). However, the user should keep in mind that reading the 16-bit timer in two 8-bit values itself, poses certain problems, since the timer may overflow between the reads. For writes, it is recommended that the user simply stop the timer and write the desired values. A write contention may occur by writing to the timer registers, while the register is incrementing. This may produce an unpredictable value in the TMRxH:TMRxL register pair."
Questions:
1. How does one stop and re-start Timer1, or for that matter, any other timer, without accessing the register directly and without affecting the other settings of the timer?
2. Is it correct that if we use the get_timer1() function, which returns a 16-bit integer, the above read problem will never happen?
3. Similarly, is it correct that if we use the set_timer1() function to write a value to Timer1, the above write problem will never happen?
Last edited by kgng97ccs on Sat May 14, 2022 3:33 am; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: Stopping and re-starting a timer |
Posted: Sat May 14, 2022 12:13 pm |
|
|
For question #2:
kgng97ccs wrote: |
2. Is it correct that if we use the get_timer1() function, which
returns a 16-bit integer, the above read problem will never happen?
|
Look at the code for 18F46K22:
Code: |
...... setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1 | T1_ENABLE_SOSC);
00022: MOVLW 8F // Set RD16 bit (bit 1)
00024: MOVWF T1CON
00026: CLRF T1GCON
......
...... temp = get_timer1();
00028: MOVF TMR1L,W
0002A: MOVWF temp
0002C: MOVFF TMR1H,temp+1 |
The method above follows the 18F46K22 data sheet in section:
12.6 Timer1/3/5 16-Bit Read/Write Mode
So yes, this method should safely get the 16-bit value without
risk of rollover between bytes.
The compiler also sets the RD16 bit =1 if the internal oscillator is used
as the Timer1 clock source:
Code: |
...... setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
00022: MOVLW 07 // Set RD16 bit (bit 1)
00024: MOVWF T1CON
00026: CLRF T1GCON
......
...... temp = get_timer1();
00028: MOVF TMR1L,W
0002A: MOVWF temp
0002C: MOVFF TMR1H,temp+1 |
You should be able to get the answer to your 3rd question just by
following the same method as above. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Mon May 16, 2022 12:28 am |
|
|
And, on '1', this depends on the timer, and what you actually 'mean'.
For example if you look at Timer3, there is an 'on' bit, but it makes the
comment (for off), "Clears Timer1/3/5 Gate flip-flop". So turning this
'off' (which will stop the timer), also clears this flip-flop. Means you cannot
stop it without this changing.
Timer0, does not have this problem, and this has a T0_OFF setting.
Generally, you don't stop timers. Just reset them, read and write them.
If you want to stop their 'effect', just disable the interrupt from them. |
|
![](templates/subSilver/images/spacer.gif) |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Wed May 18, 2022 10:10 pm |
|
|
Thank you, PCM Programmer, for the link and for directing me to the assembly code. I am not familiar with assembly language but will make an effort to understand the code.
Thank you, Ttelmah, for your advice regarding stopping a timer and for highlighting its effect on the Timer1/3/5 gate flip-flop. I have taken note of that.
If you know of any good resources for learning assembly language relevant to PIC MCU programming, please do let me know. Thank you. |
|
![](templates/subSilver/images/spacer.gif) |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Tue Jul 12, 2022 10:08 pm |
|
|
We are using the PIC18LF46K22, CCS C compiler v5.078, and MPLAB IDE v8.92.
Ttelmah wrote: | Generally, you don't stop timers. Just reset them, read and write them. If you want to stop their 'effect', just disable the interrupt from them. |
We have a battery-operated application in which Timer1 and Timer3 are used alternately. Both timers use the same 32.768-kHz secondary oscillator as the clock source, and there is an ISR associated with each timer.
Code: | setup_timer_1(T1_external | T1_enable_sosc | T1_div_by_1);
setup_timer_3(T3_external | T3_enable_sosc | T3_div_by_1); |
Questions:
1. For the purpose of saving power, would it make sense to turn OFF a timer when it is not needed, and turn it back ON only when it is needed again?
2. When a timer is turned OFF, does it retain its last timer value (in the timer registers), such that the timer will count from this last value when it is turned back ON? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Tue Jul 12, 2022 10:58 pm |
|
|
Honestly enormously easier just to use one timer.....
If you need separate handling, just have a flag set to say which routine
to use inside the ISR. |
|
![](templates/subSilver/images/spacer.gif) |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Wed Jul 13, 2022 2:43 am |
|
|
Thank you, Ttelmah, for your suggestion.
Actually, the interrupt periods for both Timers are different.
Timer1 has an interrupt period of 125 ms (with a preload). I have several short PWM signal bursts that run at intervals ranging from 250 ms to 1 second (= 2 to 4 Timer1 interrupt periods). The int_timer1 ISR only sets some flags (no time-consuming tasks).
Timer3 has a much longer interrupt period of 2 seconds (no preload). I have one long PWM signal burst that runs for 60 seconds (= 30 Timer3 interrupt periods). The int_timer3 ISR only counts the number of Timer3 interrupts (no other tasks). Once the count reaches 30, I stop the long PWM signal burst.
As I do not wish for the long PWM signal burst to be distorted too much by the MCU having to take time off to execute an ISR, and also to save power, I thought I would do this:
(a) Minimize the number of Timer3 interrupts during the 60-second period, by choosing the longest interrupt period (2 seconds) that can be provided by Timer3 and the SOSC.
(b) During the 60-second period, turn ON Timer3; and turn OFF Timer1 so that the MCU will not need to execute any Timer1 ISR, and also to save power.
(c) When the 60-second period is over, turn OFF Timer3 and turn ON Timer1; I would turn ON Timer3 again only when needed.
For a similar reason, when sending the short PWM signal bursts, I would ensure that Timer3 is OFF.
If I use just one timer (in this case, it has to be Timer1), there will be 480 interrupts (480 x 125 ms = 60 seconds) during the 60-second period when I am sending the long PWM signal burst. By using a separate timer (Timer3) for the long PWM signal burst, the number of interrupts is reduced to only 30.
Does this approach sound reasonable? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Wed Jul 13, 2022 5:41 am |
|
|
Point is the timer setups are the same. It is only the preload you are changing.
So:
Code: |
int1 quick_timer=FALSE;
#INT_TIMER1
void tick(void)
{
if (quick_timer)
{
//Do your preload here for the quick timer, and anything
//else you want this to do
return;
}
//here you have the slow timer code
}
|
All you do is set 'quick_timer' to TRUE when you want the fast reload.
Understand that the interrupts are polled. So every extra interrupt you
have slows down the actual master interrupt handling time for all the
later interrupts, even if this is disabled, and the timer is not running.
It is just much simpler to use one timer, and then toggle the bit to change
the speed.
The stuff after the return does not get executed or affect the handler
time at all. The test is just a bit test, so a single instruction. This is
faster than an added test in the global interrupt handler, since this actually
has to test two bits. Both the interrupt bit itself, and the enabled bit as
well. |
|
![](templates/subSilver/images/spacer.gif) |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Sun Jul 17, 2022 11:54 pm |
|
|
Thank you, Ttelmah, for your explanation and advice.
Your illustration code gave me several ideas on how to manage timing with one timer. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|