View previous topic :: View next topic |
Author |
Message |
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
TMR1 & TMR3 errata on new chips |
Posted: Thu Feb 23, 2006 10:30 pm |
|
|
Can someone please clarify the TMR1 & TMR3 errata on the newer PIC18FXXX0 chips?
1. The errata does not affect Timer READs, right?
2. If I want to clear TMR1 for example, is this the proper procedure (or is it overkill?):
a. disable_interrupts();
b. stop timer 1;
c. set_timer1(0);
d. enable_interrupts(GLOBAL);
Is it necessary to clear interrupts? Or is it just necessary to stop the timer first? The errata says not to let any events occur between the writing of the register pair, thus i felt it necessary to disable interrupts. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 26, 2006 3:34 pm |
|
|
Quote: | Can someone please clarify the TMR1 & TMR3 errata on the newer PIC18FXXX0 chips? |
Can you post the exact part number of the PIC ? The we can download
the errata for it and look at it. |
|
|
valemike Guest
|
|
Posted: Tue Feb 28, 2006 11:12 am |
|
|
It's the PIC18F4580-I/PT. This has an errata for TMR1 and TMR2. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 28, 2006 2:58 pm |
|
|
I've deleted this post because it referred to 8-bit read/write mode
for Timer1, but CCS uses 16-bit mode, so my post wasn't applicable.
I've deleted it to avoid causing confusion. See my new post below.
Last edited by PCM programmer on Wed Mar 01, 2006 1:47 pm; edited 1 time in total |
|
|
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Wed Mar 01, 2006 3:46 am |
|
|
I'm just worried about the 16-bit mode.
The accompanying errata document says you cannot write to a free running timer without losing a few cycles, nor should you allow an 'event' to occur between a timer write.
I did not realize that set_timer1() may not work right in these chips! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 01, 2006 1:41 pm |
|
|
Disregard that post. I jumped the gun on it. If Timer1 was running in
8-bit read/write mode, then that post would be applicable. But CCS is
actually initializing Timer1 to run in 16-bit read/write mode.
Here's the setup code for the 18F4550, compiled with PCH vs. 3.245.
The top bit of T1CON is set, which puts Timer1 into 16-bit R/W mode.
Code: |
.... setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
0018: MOVLW A5
001A: MOVWF T1CON
|
The 18F4550 data sheet says that in 16-bit R/W mode, you should write
to the TMR1H register first and then write to TMR1L. CCS does this.
Code: | ..... set_timer1(0);
001C: CLRF TMR1H
001E: CLRF TMR1L |
The errata says:
Quote: |
Module: Timer1/Timer3
When Timer1/Timer3 is operating in 16-bit mode
and the prescale setting is not 1:1, a write to the
TMR1H/TMR3H Buffer registers may lengthen the
duration of the period between the increments of
the timer for the period in which TMR1H/TMR3H
was written.
Work around
Do not write to TMR1H/TMR3H while Timer1/
Timer3 is running, or else write to TMR1L/TMR3L
immediately following a write to TMR1H/TMR3H.
Do not write to TMR1H/TMR3H and then wait for
another event before also updating TMR1L/TMR3H.
|
CCS follows the method that I've underlined above, but what if an
interrupt occurred between the two instructions ? Then the errata
problem could occur. So the following code would be best:
Code: | disable_interrupts(GLOBAL);
set_timer1(0);
enable_interrupts(GLOBAL); |
|
|
|
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Wed Mar 01, 2006 4:30 pm |
|
|
Quote: |
Work around
Do not write to TMR1H/TMR3H while Timer1/
Timer3 is running, or else write to TMR1L/TMR3L
immediately following a write to TMR1H/TMR3H.
|
The wording is a bit confusing. It directly says not to write to TMR1H while the timer is running, thus it is probably more appropriate to stop timer1 first.
Quote: |
Do not write to TMR1H/TMR3H and then wait for
another event before also updating TMR1L/TMR3H.
|
The above sentence then warrants the need to disable interrupts.
Thus shouldn't we add in a statement to stop timer1 in addition to disabling interrupts?
Code: |
disable_interrupts(GLOBAL);
setup_timer_1(T1_DISABLED); // stops timer 1; is this necessary?
set_timer1(0);
enable_interrupts(GLOBAL);
|
I'm really confused on the wording of the errata and the workaround, and it's probably harmless anyways since I am ultimately setting the timer to 0x0000. So it probably doesn't matter if I "...lengthen the
duration of the period between the increments of
the timer for the period in which TMR1H/TMR3H
was written."...since i'll probably lose a harmless 2 or 3 machine cycles (which is an occasional few nanoseconds every now and then)
I also hope that this errata doesn't apply to Timer1 READs! With the lengthening lead times of the '0'-less legacy chips (which have less erratas), I feel like i'm between a rock and a hard place. |
|
|
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Wed Mar 01, 2006 4:31 pm |
|
|
Quote: |
Work around
Do not write to TMR1H/TMR3H while Timer1/
Timer3 is running, or else write to TMR1L/TMR3L
immediately following a write to TMR1H/TMR3H.
|
The wording is a bit confusing. It directly says not to write to TMR1H while the timer is running, thus it is probably more appropriate to stop timer1 first.
Quote: |
Do not write to TMR1H/TMR3H and then wait for
another event before also updating TMR1L/TMR3H.
|
The above sentence then warrants the need to disable interrupts.
Thus shouldn't we add in a statement to stop timer1 in addition to disabling interrupts?
Code: |
disable_interrupts(GLOBAL);
setup_timer_1(T1_DISABLED); // stops timer 1; is this necessary?
set_timer1(0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
enable_interrupts(GLOBAL);
|
I'm really confused on the wording of the errata and the workaround, and it's probably harmless anyways since I am ultimately setting the timer to 0x0000. So it probably doesn't matter if I "...lengthen the
duration of the period between the increments of
the timer for the period in which TMR1H/TMR3H
was written."...since i'll probably lose a harmless 2 or 3 machine cycles (which is an occasional few nanoseconds every now and then)
I also hope that this errata doesn't apply to Timer1 READs! With the lengthening lead times of the '0'-less legacy chips (which have less erratas), I feel like i'm between a rock and a hard place. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 01, 2006 4:38 pm |
|
|
The use of "or else" implies two solutions. It means you can fix it by
using the first method or the 2nd method.
The errata doesn't mention Read operations. It only applies to Writes. |
|
|
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Wed Mar 01, 2006 4:56 pm |
|
|
I sort of see now. So for the first suggested workaround:
Quote: | Work around
Do not write to TMR1H/TMR3H while Timer1/
Timer3 is running,... |
If I follow this workaround, then I simply need to stop timer1 first, write the value to the tmr1 register pair, and then restart timer1. (** no interrupts disabled here **)
Quote: | ... or else write to TMR1L/TMR3L
immediately following a write to TMR1H/TMR3H. |
And if I follow this workaround, then I need NOT stop timer1. I just disable interrupts like you showed me earlier, then write the value i want to tmr1h/tmr1L, in the proper order, then re-enable interrupts.
Actually, in my original implementation on the '458, the only time I 'restart' timer1 from 0 is when I get an RB0 (external) interrupt. Since I don't have high priority interrupts enabled, then since I am in an ISR with interrupts already disabled, then I can simply write:
Code: |
#int_ext
void my_rb0_isr(void)
{
...
set_timer_1(0);
}
|
I guess it is much less complicated than I first thought. |
|
|
|