|
|
View previous topic :: View next topic |
Author |
Message |
terrylang
Joined: 24 Jun 2012 Posts: 2 Location: Aloha, Oregon
|
32KHz oscillator is not running accurately with PIC18F26K22 |
Posted: Mon Jun 25, 2012 12:28 am |
|
|
I am trying to make an accurate time of day clock.
I have used this exact code with the PIC18F2620 and other PICs and got accurate results.
What am I doing wrong?
Code: |
//------------------------------------------------------------------------------
// 32,768Hz Oscillator
//------------------------------------------------------------------------------
#if XTAL_32768HZ_EXISTS
#define X32768_TICK_EVERY_SEC 1 // Once per second.
#define X32768_TICK_EVERY_TWOSEC 0 // Once every two seconds.
unsigned int32 x32768_tod_seconds; // Increment once per second.
unsigned int timer3_timeout; // Increment 100 times per second.
extern void tod_clk_tick();
//------------------------------------------------------------------------------
// Initialize timer 3 for use with the 32,768Hz crystal.
//------------------------------------------------------------------------------
#if X32768_TICK_EVERY_TWOSEC || X32768_TICK_EVERY_SEC
void init_timer3() {
// Setup timer 3 to for 32,768Hz.
setup_timer_3(T3_EXTERNAL|T3_DIV_BY_1|T3_ENABLE_SOSC); // ASYNC mode.
T3RD16 = FALSE;
enable_interrupts(INT_TIMER3);
timer3_timeout = 0;
}
#endif
//------------------------------------------------------------------------------
// Execute timer3 once per second if the 32,768Hz crystal is installed.
// A 32,768Hz crystal is connected to PIC pins C0,C1 which is configured as
// an external oscillator to operate timer3.
//
// BUG: Clock runs fast in this code. XXX
//------------------------------------------------------------------------------
#if X32768_TICK_EVERY_SEC // Once per second.
unsigned int tmr3h_val1;
unsigned int tmr3l_val1;
unsigned int tmr3h_val2;
unsigned int tmr3l_val2;
unsigned int32 tmr3l_err;
#INT_TIMER3
void timer3_isr() {
bit_set(TMR3H,7); // Cause overflow every second.
isr2_status.x32768_sec_flag = TRUE;
isr2_status.x32768_running = TRUE;
if (isr2_status.sync_status == SYNC_NONE) {
isr2_status.sync_status = SYNC_32KHZ;
}
timer3_timeout = 0;
x32768_tod_seconds++;
tod_clk_tick();
}
#endif
//------------------------------------------------------------------------------
// Execute timer3 once per second if the 32,768Hz crystal is installed.
// A 32,768Hz crystal is connected to PIC pins C0,C1 which is configured as
// an external oscillator to operate timer3.
// The clock is accurate with this code.
//------------------------------------------------------------------------------
#if X32768_TICK_EVERY_TWOSEC // Once every two seconds.
#INT_TIMER3
void timer3_isr() {
isr2_status.x32768_sec_flag = TRUE;
isr2_status.x32768_running = TRUE;
if (isr2_status.sync_status == SYNC_NONE) {
isr2_status.sync_status = SYNC_32KHZ;
}
timer3_timeout = 0;
x32768_tod_seconds++;
x32768_tod_seconds++;
tod_clk_tick();
tod_clk_tick();
}
#endif
| [/code] |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Jun 25, 2012 2:04 am |
|
|
You are making a classic assumption about interrupt latency.
If you want to make accurate repeatable time intervals you need to either let the timer free run, as you do in the two second code, or use the hardware reloading timers, such as timer 2 which reload themselves.
The problem with reloading any timer in firmware is that it happens some time after the hardware event that triggered the interrupt. That's tens of us late. This is due to the time the processor takes to respond to the interrupt - the hardware interrupt latency - and the time the CCS code in this instance, takes to process the interrupt and steer it to your code. By the time your code gets round to resetting the timer, it has already ticked on quite a few clocks. The result is obvious: it runs slow.
For many applications this is not noticable and is often ignored in blissful ignorance. For clocks which are required to keep good time its a big issue.
RF Developer |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Mon Jun 25, 2012 4:38 am |
|
|
It'd help if you gave an idea of how far out things are.
There are so many things in the code, lacking their external definitions (and calls to functions without the code), that it is difficult to even 'hope' to answer. Personally, I'd simplify the code, throwing away the define tests, and the duplication, and just trying with the simplest subset code to begin with.
Now, obviously, you can't have used the same code on chips like the 2620, since these don't have a secondary oscillator like this, etc. etc..
Latency shouldn't be the problem. He is using an old PIC trick, of just setting the top bit in the high timer register, to effectively add 32768, in one instruction, while leaving the low bits (set by the time you get here), to run. The only problem that might apply, was if there was a wrap from the top bit of TMR3L exactly at the instruction where this bit is set in TMR3H. However with a 32KHz clock, assuming a reasonable clock rate on the main CPU, this should be unlikely. It could be happening though if there is another interrupt that is taking a long time to service, or the main CPU clock rate is slow (not given). This might actually be the most likely problem.
Other likely things are covered in the MicroChip application notes. The Sosc pins are _very_ susceptible to pickup, and (for example), having a port pin running on the board adjacent to these, can lead to extra counts. Again a likely possibility.
So, is the timer running slow or fast?. How much by?. How is the board laid out round here (normally I use the trick of having a separate 'ground ring' running round such oscillators, and removing the ground plane (because of the capacitance), in this area.
Try simplified code, and see if anything changes. How fast is the CPU oscillator?.
Best Wishes |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Mon Jun 25, 2012 8:13 am |
|
|
'accurate' ?
hmm..other possible areas to look at..
1) xtal itself...tolerence 1ppm, 1/2ppm, ???
2) power supply...rock stable ?, any induced AC 'hum' ??
3) external noise...EMI, welders,uwaves,???
4) 32KHz xtal caps...correct for the overall circuit ??
5) PCB layout,cleanliness,etc..
6) As this is a sw RTC, you do have a battery backup with glitchless turnover when the AC power supply fails ?
7) Have you looked at the SW RTC code in the code library ? I know it works flawlessley...
just some ideas....
The fact your code ,as presented ,works fine in other PICs leads me to believe you may have a hardware issue,though what is the problem....too fast,too slow,random, over what time period(seconds, days, hours, weeks). |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Mon Jun 25, 2012 9:07 am |
|
|
Have a look at Microchip AN1288. Also, as an example of the general warnings about this type of circuit, look at <http://www.emmicroelectronic.com/webfiles/product/other/EM7604_C7_DS.pdf>, and in particular the bottom right corner of page 28, and the subsequent paragraphs. Sound familiar?. This also describes the ground ring circuit that I use. There are similar warnings from every manufacturer doing chips that use such circuits. I think the ground ring reference I use, originally came from about a 30 year old TI note.
Best Wishes |
|
|
terrylang
Joined: 24 Jun 2012 Posts: 2 Location: Aloha, Oregon
|
The newer PICs just are not quite the same. |
Posted: Mon Jun 25, 2012 10:16 am |
|
|
I was using the trick of just modifying the high register for force a 1 second clock. It always worked for other PICs that I have used.
Interrupt latency is not the problem since the clock runs FAST, not slow. It gains about one minute per day.
I am running a 20MHz main PIC clock.
I cannot use the special interrupt trigger with CCP3 since I also need to use sleep mode.
My solution, for now, is to run a parallel clock that ticks at one second that is run off the millisecond timer that I already have in place for other parts of my code. And sync this timer from the 32KHz timer.
The 32KHz clock running at 2 second intervals, is accurate to one second in two days. This clock always runs while the PIC is running or in sleep ode. When I wake up, I will re synch the one second clock that is operated from the millisecond timer.
Has any one had a similar problem using the old PIC trick? Or is there another simpler solution? |
|
|
|
|
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
|