Author Topic: 7segment PIC clock  (Read 551 times)

0 Members and 1 Guest are viewing this topic.

Offline bogdant

  • Regular Contributor
  • *
  • Posts: 69
  • Country: ro
7segment PIC clock
« on: February 22, 2021, 08:04:17 am »
I have a clock project implemented with a PIC16F877A (an old microchip not used). The project is displaying the current hour/min on 7 segment 4 digit array. The problem I have is that the clock is remaining behind 2min /day
The second is implemented on an TIM1 interrupt, TIM1 is connect the external resonator 32.768kHz on external pins RC0/RC1 with a Cload=12pF.
The initialization of timer:
void Init_Timer1(void)
{
  /*prescaler to 1/8*/
//  T1CLKPS = 1;
//  T1CLKPS0 = 1;
  /*external quart 32k used*/
  T1OSCEN =1;
  /* synchronize with external clock,counter will run when in sleep mode*/
  T1SYNC = 1;
  /*Timer 1 clock select is : external clock*/
  TMR1CS = 1;
  /*enable Timer*/
  TMR1ON = 1;
}
The external interrupt is implemented:
void timer1_isr(void)
{
  TMR1 = PRELOAD_TIMER1 - TMR1;
  ub_task=ub_task|0x02;
  TMR1IF=0;
}
void __interrupt() external_isr(void)
{
 if (TMR0IF==1)
  timer0_isr();
 if (TMR1IF==1)
  timer1_isr();
}

void Ceas_task_secunda(void)
{

    ub_second++;
    if (ub_second>=60)
    {
        ub_minut++;
        ub_second = 0;
    }

    if(ub_minut>=60)
    {
        ub_hour++;
        ub_minut=0;
      
    }
    if(ub_hour>=24)
    {
        uw_day++;
        ub_hour=0;
    }
}
What I am missing here ?
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 9784
Re: 7segment PIC clock
« Reply #1 on: February 22, 2021, 10:05:46 am »
Your problem is:
Code: [Select]
TMR1 = PRELOAD_TIMER1 - TMR1;
See Section 12. Timer1 of the PICmicro MID-RANGE MCU Family reference manual, specifically 12.5, 12.5.2, and 12.12.

You cant safely write a running Timer1 in asynchronous mode#.  If the next 32768/8 Hz increment occurs during the instruction that writes the low byte (or the high byte when the low byte is 0xFF) the result is unpredictable.   As you are writing a large value to the timer to get the next rollover interrupt one second later, a randomly corrupted timer will loose an average of 7 seconds for every high byte collision, and an average of 31.25ms for every low byte collision, which are 256 times more frequent. Also if a low byte rollover occurs between reading the two bytes of the timer, there will be a 62.5ms error.   

Additionally, every time you write to the timer, the prescaler is cleared, discarding the number of T1OSC/T1CKI rising edges it has accumulated since the last timer increment, loosing on average 10.5 seconds a day (assuming the timer is modified once a second and the two individual writes to the high and low bytes of the timer occur within one T1OSC cycle). 

The preferred solution depends on how precise you need your clock to be, but in all cases you need to let timer 1 free-run (i.e. dont write to it or stop/start it).   If you need to display seconds, as the natural rollover rate with no (1:1) prescaler is 0.5 Hz, you have to poll the high bit of the timer and increment the seconds count if it changes.  If you need to combine this with SLEEP (only worth it if you are driving a 'bare glass' LCD display, or power down other display types during sleep), one possibility is to use the watchdog timer to wake from sleep.   Alternatively if the display is powered down, you can wake up on Timer1 rollover interrupt, and increment by TWO seconds then return to sleep, only resuming polling for the intervening seconds once user action has caused an exit from sleep mode.

If you don't display seconds, you can simply use 1:2 prescaler for a 0.25 Hz rollover interrupt rate, and count 15 interrupts per minute.

Once you've  got cycle accurate timekeeping you then need to trim the crystal frequency* by adjusting the load capacitance, as unadjusted it may result in up to +/-1.73 seconds per day error, or more if your load capacitance is out of tolerance.  You can reasonably expect to reduce this error by an order of magnitude, which will get the error down to under 0.2 seconds per day short term and together with the crystal's aging drift will have an annual error of under  +/- 4 minutes (assuming reasonably constant temperature and supply voltage).  If you need to do better you need a higher quality external time reference e.g. radio time signal, GPS, NTP, or in 1st world countries, the mains frequency is tightly controlled so the long term average of the daily cycle count is locked to realtime +/- a defined error band. 


# ... unless you poll for a LSB transition before writing and can complete writing the timer well before the next T1OSC/T1CKI rising edge.  However polling loops in ISRs are *EVIL*!

* Method depends on available test equipment.  If all you have is a phone or radio time signal its a PITA, as you need to stick on a circle of card, punched to tightly fit over the trimcap adjusting screw so you can reposition it precisely, note the error over a day or more, and adjust the trimmer to reduce the error, each time marking the card disk and noting the exact time/date of adjustment and the disk position vs error, to build up a calibration curve for the trimcap.  As you narrow in on the correct setting you'll need to check over longer intervals e.g weekly.  If you have a >6 digit frequency counter with a GOOD reference oscillator (e.g GPSDO or rubidium oscillator), you can simply use an active probe weakly capacitively  or inductively coupled by proximity to the crystal without contact so it doesn't significantly 'pull' the frequency, or even a microphone with HF response >33 KHz,  a high gain tuned amplifier, and directly adjust the frequency to 32768 Hz +/-<0.5 Hz.  If you don't have/cant build a suitable tuned amplifier, an alternative method is to clock the PIC with a 20MHz external clock to minimize jitter and latency and write code to set up timer 1 with no prescaler and toggle a pin, for a 1Hz output, then *slooooooly* adjust the trimcap for 1.00000 Hz.   You can also use this method without a frequency counter, triggering a scope set to a slow (>1s timebase) from GPS 1pps, with the PIC 1 Hz on a different channel and adjusting for minimal long term drift, ignoring short-term jitter.
« Last Edit: February 22, 2021, 10:23:40 pm by Ian.M »
 
The following users thanked this post: bogdant, I wanted a rude username

Offline bogdant

  • Regular Contributor
  • *
  • Posts: 69
  • Country: ro
Re: 7segment PIC clock
« Reply #2 on: February 23, 2021, 05:53:05 am »
I do not have seconds display, so I just delete the line loading the timer and made the minute 30sec.
It is a usual clock, so nothing fency, if I will get the to get the +10ppm as it is resonator specified then it will be fine.
I will wait several days to see what is the error. I am just comparing with my phone clock.
 

Offline MikeK

  • Frequent Contributor
  • **
  • Posts: 643
  • Country: us
Re: 7segment PIC clock
« Reply #3 on: February 23, 2021, 03:11:40 pm »
Since the crystal is connected to Timer1, the only thing you have to do is set the high bit of the counter.  You never need to mess with the value in the register.  That is, when the ISR triggers, just set TMR1H bit 7.

Also, just to be sure...a typical watch crystal with a load capacitance of 12.5pF should be using two 22pF capacitors.  (Google for the formula.)  When you get things running right, you can change one (or both) of the caps to improve accuracy.  Use a trimmer cap if you want.  Although, I just make the adjustment in software....A recent clock project of mine, with a generic watch crystal, was shown to be accurate to less than one second after a week (at a constant room temperature).
 
The following users thanked this post: Ian.M, bogdant

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 9784
Re: 7segment PIC clock
« Reply #4 on: February 23, 2021, 06:01:56 pm »
Yes, that's a good way of getting a 1Hz interrupt, with no prescaler to loose count from.  You've got fractionally over 7.8ms to service the interrupt and set TMR1H:7 after the interrupt was raised before the carry from TMR1L risks a write collision.  Shouldn't be a problem unless you also have to bit-bang a slow timing critical protocol or device.
 

Offline MikeK

  • Frequent Contributor
  • **
  • Posts: 643
  • Country: us
Re: 7segment PIC clock
« Reply #5 on: February 23, 2021, 09:54:39 pm »
Yes, that's a good way of getting a 1Hz interrupt, with no prescaler to loose count from.  You've got fractionally over 7.8ms to service the interrupt and set TMR1H:7 after the interrupt was raised before the carry from TMR1L risks a write collision.  Shouldn't be a problem unless you also have to bit-bang a slow timing critical protocol or device.

Why would there be a write collision?  Read-Modify-Write only affects output ports, no?.  That's why they implemented LATCHes on PORT's of later PIC's.  He should have an entire second to service the interrupt.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 9784
Re: 7segment PIC clock
« Reply #6 on: February 23, 2021, 10:03:02 pm »
No. Read-modify-write problems can affect any writeable SFR that is updated by hardware asynchronously to the CPU core.

Async mode timer increment of the high byte can collide with the read-modify write of the BSF setting the high bit.  IIRC the result can range from (possibly partial) failure to increment to failure to set the high bit depending on the exact increment timing relative to the instruction cycle.  As its basically a race condition the edge cases are also likely to be variable from device to device and with supply voltage and temperature.
« Last Edit: February 23, 2021, 10:07:08 pm by Ian.M »
 
The following users thanked this post: bogdant

Offline MikeK

  • Frequent Contributor
  • **
  • Posts: 643
  • Country: us
Re: 7segment PIC clock
« Reply #7 on: February 23, 2021, 10:40:35 pm »
Hmm...I'm going to have to test this now. By putting in a 20ms delay and see if that affects the clock.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 9784
Re: 7segment PIC clock
« Reply #8 on: February 23, 2021, 11:05:23 pm »
A 20ms delay from the interrupt being raised to setting the bit is *vanishingly* *unlikely* to affect the clock as it isn't an exact multiple of 256/FT1OSC 

Assuming the crystal is 'spot on', there's a high byte auto-increment every 1/128th of a second. If one hits in the middle of executing the BSF instruction, you've got a problem . . . .
« Last Edit: February 23, 2021, 11:12:58 pm by Ian.M »
 
The following users thanked this post: bogdant

Offline MikeK

  • Frequent Contributor
  • **
  • Posts: 643
  • Country: us
Re: 7segment PIC clock
« Reply #9 on: February 24, 2021, 12:42:54 am »
Oh, yeah, I get it now.  I hope we didn't distract OP.
 

Offline bogdant

  • Regular Contributor
  • *
  • Posts: 69
  • Country: ro
Re: 7segment PIC clock
« Reply #10 on: February 24, 2021, 08:40:20 am »
The clock is a 4x7segment clock with a rotatory encoder and a backup supercapacitor.
I have attach the full project files, so we have a complete picture.
 

Offline bogdant

  • Regular Contributor
  • *
  • Posts: 69
  • Country: ro
Re: 7segment PIC clock
« Reply #11 on: February 24, 2021, 08:45:17 am »
I also attached some pictures with the implementation.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf