# Using crystals with PICs and their accuracy ..#2

#### cmartinez

Joined Jan 17, 2007
7,174
EDIT:
$-2 takes you back 2 instructions - is that what you want? It doesn't hurt here but just so you know. I've been confused about that detail for a while now. I thought that$-2 took the code back two bytes, not two instructions. And since one instruction has 14 bits in the Harvard architecture, I thought that the MCU or the compiler were rounding off. But experience trumps assumptions... so I trust you must be right.

I'm going to tweak the code with your suggestion, and see how it behaves.

#### JohnInTX

Joined Jun 26, 2012
4,344
I've been confused about that detail for a while now. I thought that $-2 took the code back two bytes, not two instructions. And since one instruction has 14 bits in the Harvard architecture, I thought that the MCU or the compiler were rounding off. But experience trumps assumptions... so I trust you must be right. I'm going to tweak the code with your suggestion, and see how it behaves. Ha! I single stepped it to be sure In 16F1xxx, the program memory is organized as 14 bit 'words' that are fetched as one word per PC increment. The 18F instructions are 16 bits wide and are addressable as bytes. That means that the 18F PC advances by 2 for each instruction instead of by 1 as in the midrange/baseline range. To back up one instruction in the 18F you would indeed use a goto$-2.

But.. I just use a short label with an underscore to be sure. I work in several families at once and just don't want to go through the grief of mis-remembering. I also like to be reminded of why I am looping when I look at the code 6 months, or a day at my age, later.
_wait:
btfsc Some_flag
goto _wait

YMMV

BTW, the code is still running without error. I'll leave it going overnight.

Last edited:

#### JohnInTX

Joined Jun 26, 2012
4,344
Good morning!
It ran al night w/no errors so using the TIMER1 oscillator as system clock appears to be sync'd enough to allow the CCP at the low Fosc. Interesting..

Something to consider. Waiting for the TIMER 1 oscillator to come up will lock up the system if there is a problem with the XTAL circuit:
Code:
    banksel OSCSTAT
_waitTMRosc:
btfss   OSCSTAT,T1OSCR    ; wait until timer osc is up
goto    _waitTMRosc
I'd recommend you incorporate a guard timer to escape if the oscillator doesn't come up. You can incorporate this test in a counting/delay loop or (preferably) use one of the other timers temporarily. Set the timer, poll the TMRxIF and T1OSCR in the loop. If T1OSCR comes up, stop the guard timer and do the changeover. If the guard timer runs out, don't change system clock and go to some error handler - maybe flash the LED rapidly or something. You'll have a still-live system with a nice diagnostic. I like using a hardware timer because the guard time is easy to tune without a bunch of Tcyc counting.

Just thinkin' out loud.

#### cmartinez

Joined Jan 17, 2007
7,174
Ha! I single stepped it to be sure

In 16F1xxx, the program memory is organized as 14 bit 'words' that are fetched as one word per PC increment. The 18F instructions are 16 bits wide and are addressable as bytes. That means that the 18F PC advances by 2 for each instruction instead of by 1 as in the midrange/baseline range. To back up one instruction in the 18F you would indeed use a goto $-2. But.. I just use a short label with an underscore to be sure. I work in several families at once and just don't want to go through the grief of mis-remembering. I also like to be reminded of why I am looping when I look at the code 6 months, or a day at my age, later. _wait: btfsc Some_flag goto _wait YMMV BTW, the code is still running without error. I'll leave it going overnight. Here's a note from the MPASM user's guide: So It seems that the number added or subtracted after the$ sign stands for the number of instructions to skip, and not bytes.

#### JohnInTX

Joined Jun 26, 2012
4,344
So It seems that the number added or subtracted after the $sign stands for the number of instructions to skip, and not bytes. Instructions to skip in the 16F1xxx, bytes in the 18F. Technically it modifies the program counter to$ + 1. $is the current value of the program counter at the goto instruction so this evaluates to whatever the assembler has determined the PC of the current instruction is and adds or subtracts as noted. In the 16F1xxx and midrange, each PC count is one instruction however wide it is. goto$-1 hits the instruction just before that goto
goto $goes to the address of the goto - which stops the program right there goto$+1 goes to the next instruction. It is essentially a nop BUT, since any goto, call, or return flushes the instruction pipeline, it takes twice as long to execute (2 Tcyc instead of 1) so you get the delay of two nops for the price on one instruction. Useful for tuning delay loops, short delays etc.
The call to Rtrn is a cheap way to get 4 nops.

I don't know if the reference explains the difference between baseline/midrange/enhanced midrange and the 18F but it is an important distinction.

As I've said, I don't use the $-x construct, preferring labels. I do use the$+1 and call to a dummy return construct but in macros to avoid confustion. I use an include file to include the macro set for the processor I am using.

dnop macro ; double nop
goto $+1 ; for midrange/baseline endm dnop macro ; double nop goto$+2 ; for 18F
endm

With that construct the source is the same for 16F or 18F and the assembler figures it out. Easier on my little brain.

Sounds like you are having fun!

EDIT: I should say that after 30+years w/uCHIP, I can safely say that they're better than they used to be but they and I still have vastly different opinions of what constitutes good programming practice.

Last edited:

#### jpanhalt

Joined Jan 18, 2008
10,525
I've been confused about that detail for a while now. I thought that $-2 took the code back two bytes, not two instructions. And since one instruction has 14 bits in the Harvard architecture, I thought that the MCU or the compiler were rounding off. But experience trumps assumptions... so I trust you must be right. It is the number of instructions to skip. As John in Tx said, relative jumps (e.g, bra or$-1) as well as goto's are based on instructions (i.e., program counter). NB: Labels are not counted. Thus:
Code:
     instrX
insrrY
instrZ
Label
instrA
instrB
instrC

bra   Label     ;This would go to instrA
bra   Label+1   ;This would go to instrB
bra   Label-1   ;This would go to instrZ  (i.e., instrA -1 location)
movlw Label     ;This would move the program counter for instrA to WREG

(The above code will not assemble as "instr_" is recognized as a label in the wrong column.
And obviously, one would never get to the second bra instruction.)
FSR jumps are a bit different, as they reference data/bytes/registers.

#### cmartinez

Joined Jan 17, 2007
7,174

#### JohnInTX

Joined Jun 26, 2012
4,344
Be sure to review the errata for your chip. I was scanning it and sec 1.2 has this little jewel:
1.2 Clock Switching
When switching clock sources between INTOSC
clock source and an external clock source, one
corrupted instruction may be executed after the
switch occurs.

This issue does not affect Two-Speed Start-up or
the Fail-Safe Clock Monitor operation.
Work around
When switching from an external oscillator clock
source, first switch to 16 MHz HFINTOSC. Once
running at 16 MHz HFINTOSC, configure IRCF to
run at desired internal oscillator frequency.
When switching from an internal oscillator
(INTOSC) to an external oscillator clock source,
first switch to HFINTOSC High-Power mode (8
MHz or 16 MHz). Once running from HFINTOSC,
switch to the external oscillator clock source.
I don't know if that applies to the TIMER1 oscillator. Something to think about at any rate.

Also, are you planning to sleep the processor between 1 sec tiks?

J

#### Attachments

• 134.2 KB Views: 0

#### Tesla23

Joined May 10, 2009
411
I was just browsing EDN and saw: https://www.edn.com/rtc-design-part-2-temperature-compensation-is-critical/ which is really an advertorial for MAX31343. This will probably blow your budget at about \$2.50 ish, but it offers 5ppm (-40 - 85C), a full RTC running at under 1.5uA in standby, You can program it to give you 1 sec interrupts etc., and is 2.1 x 2.3mm. It's a pretty awesome little bug.

Note that I suspect that some of the power savings comes from keeping the 32kHz signal inside the chip and only sending much lower frequencies (e.g. a 1 sec interrupt) to the pins. Driving an external chip pin with 32,768Hz, assuming a 3V logic level and a 5pF load, consumes 0.49uA simply to charge and discharge the capacitance.

Last edited: