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

Stopping and re-starting a timer

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
kgng97ccs



Joined: 02 Apr 2022
Posts: 72

View user's profile Send private message

Stopping and re-starting a timer
PostPosted: Sat May 14, 2022 1:46 am     Reply with quote

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
PCM programmer



Joined: 06 Sep 2003
Posts: 21675

View user's profile Send private message

PostPosted: Sat May 14, 2022 2:34 am     Reply with quote

For question #1, see the #int_timer1 routine in this post:
http://www.ccsinfo.com/forum/viewtopic.php?t=45458&start=5
PCM programmer



Joined: 06 Sep 2003
Posts: 21675

View user's profile Send private message

Re: Stopping and re-starting a timer
PostPosted: Sat May 14, 2022 12:13 pm     Reply with quote

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.
Ttelmah



Joined: 11 Mar 2010
Posts: 18233

View user's profile Send private message

PostPosted: Mon May 16, 2022 12:28 am     Reply with quote

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.
kgng97ccs



Joined: 02 Apr 2022
Posts: 72

View user's profile Send private message

PostPosted: Wed May 18, 2022 10:10 pm     Reply with quote

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.
kgng97ccs



Joined: 02 Apr 2022
Posts: 72

View user's profile Send private message

PostPosted: Tue Jul 12, 2022 10:08 pm     Reply with quote

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?
Ttelmah



Joined: 11 Mar 2010
Posts: 18233

View user's profile Send private message

PostPosted: Tue Jul 12, 2022 10:58 pm     Reply with quote

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.
kgng97ccs



Joined: 02 Apr 2022
Posts: 72

View user's profile Send private message

PostPosted: Wed Jul 13, 2022 2:43 am     Reply with quote

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?
Ttelmah



Joined: 11 Mar 2010
Posts: 18233

View user's profile Send private message

PostPosted: Wed Jul 13, 2022 5:41 am     Reply with quote

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.
kgng97ccs



Joined: 02 Apr 2022
Posts: 72

View user's profile Send private message

PostPosted: Sun Jul 17, 2022 11:54 pm     Reply with quote

Thank you, Ttelmah, for your explanation and advice.

Your illustration code gave me several ideas on how to manage timing with one timer.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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