View previous topic :: View next topic |
Author |
Message |
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
Using external crystal oscillators as clock source |
Posted: Thu Apr 28, 2022 10:40 pm |
|
|
I will be using a PIC18LF46K22 MCU, and CCS PCWHD compiler v5.078 within MPLAB IDE v8.92, and I am new to PIC MCU programming.
I have a 16-MHz crystal oscillator circuit across OSC1 and OCS2, and a 32.768-kHz crystal oscillator circuit across SOSCI and SOSCO.
I wanted to explore how I can use the 16-MHz crystal oscillator as the clock source for Timer0, and the 32.768-kHz crystal oscillator as the clock source for Timer1.
I tried the following code:
Code: | #include "18LF46K22.h"
#fuses HSM
#use delay(xtal=16MHz, clock=16MHz)
...
void main()
{
...
setup_timer_0(T0_EXT_L_TO_H | T0_DIV_256);
setup_timer_1(T1_ENABLE_SOSC | T1_DIV_BY_2);
...
} |
Questions:
1. Are these statements correct? I observed that T1CON shows 0x18 (0001 1000), which suggests that the dedicated secondary oscillator circuit is enabled (bit 3) and Timer1 is OFF (bit 0). I thought Timer1 should be ON.
2. Is it necessary to do a “setup_oscillator(osc_16MHz) before the “setup_timer_X” statements?
I will appreciate any corrections or suggestions. Thank you. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Apr 29, 2022 1:55 pm |
|
|
You can't directly connect the CLKO pin to the T0CKI pin. It loads
down the oscillator and reduces the output signal amplitude so it
only goes from 0.4 to 3.5v. The PIC data sheet says that T0CKI is
a Schmitt Trigger input pin. So it must have at least 4.0v signal
amplitude to drive it. (With a 5v Vdd).
I would never try to drive some other circuit off my crystal oscillator.
I know people do it, but I don't believe in it. I want safety. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Sat Apr 30, 2022 3:49 am |
|
|
Thank you, PCM programmer. It is the weekend now, and I do not have the schematic in front of me, but I know that the hardware engineer has designed oscillator circuits similar to those in these links:
For 16-MHz external crystal oscillator across OSC1 and OSC2: https://microchipdeveloper.com/8bit:lp
For 32.768-kHz secondary crystal oscillator across SOSCI and SOSCO: https://microchipdeveloper.com/8bit:t1secosc
I would like to know how to use the CCS directives and functions correctly to choose the external 16-MHz crystal oscillator as the Timer0 clock source and MCU primary clock source, and the 32.768-kHz secondary crystal oscillator as the Timer1 clock source. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Sat Apr 30, 2022 5:11 am |
|
|
The oscillators are completely normal. Driving a second pin from the oscillator
is the problem. It can be done. You have to use the output pin to do the
driving, but it reduces the accuracy of the oscillator. You have to use the
OSC2 pin as the source of the drive, and then reduce the load capacitor
on this side of the crystal to correct for the extra loading (say 3pF for the
extra pin, and another 5pF for the extra tracks).
Unless you get this right, it results in an asymmetric loading of the
crystal, distorting the waveform and giving incorrect timings.
Then the setup for the timer, is just the same as for using any external
clock input.
It is a less than recommended configuration. Much better (given the low
cost of these now), to use an external oscillator module to generate the
clock. These have internal buffering so are not affected by the extra load. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Tue May 03, 2022 9:27 pm |
|
|
Thank you, Ttelmah, for sharing your thoughts. I am in discussion with the hardware engineer to understand better the intent of the circuit design. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Wed May 04, 2022 7:44 am |
|
|
As an obvious comment, why on earth clock the timer from the master
clock externally?. Just use the internal Fosc/4 clock. Reduce your
prescaler to /64, and it'll run at exactly the same speed, and you have saved
the T0CKI pin, and got rid of the need for an extra load on the master
oscillator.... |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Thu May 05, 2022 4:28 am |
|
|
Thank you, Ttelmah, for your suggestion.
It turns out that I have erred in my understanding of the circuit design and the CCS function “setup_timer_0()”.
Yes, indeed, we should use the instruction clock (Fosc/4) for Timer0. That was the original intent, but I had misunderstood the CCS mode “T0_EXT_xxxx” to refer to the external crystal oscillator mode (crystal connected to the MCU across OSC1 and OSC2 pins), when I should have used “T0_INTERNAL” instead.
I have now corrected the timer setup statements for both Timer0 and Timer1, to the following (hope they are correct now):
Code: | setup_timer_0(T0_INTERNAL | T0_DIV_256); /* prescale to be decided later */
setup_timer_1(T1_EXTERNAL | T1_ENABLE_SOSC | T1_DIV_BY_32); /* prescale to be decided later */ |
Thanks again, Ttelmah.
Last edited by kgng97ccs on Thu May 05, 2022 7:23 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu May 05, 2022 6:20 am |
|
|
I see. Using the secondary oscillator on T1, led to confusion here.
T0 does not support an oscillator at all. Can only be fed by an external
signal.
Fun source of confusion... |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Sat May 07, 2022 12:50 am |
|
|
Thank you, Ttelmah.
Code: | #include "18LF46K22.h"
#fuses NOMCLR
#fuses HSM /* use external 16-MHz crystal oscillator across OSC1 and OSC2 pins */
#fuses FCMEN /* enable fail-safe clock monitor */
#fuses IESO /* enable internal/external oscillator switchover mode */
#use delay(xtal=16MHz, clock=16MHz) /* use clock frequency of 16 MHz for delays */
…
void main()
{
...
setup_oscillator(osc_16MHz);
...
} |
If I am using a 16-MHz external crystal oscillator as the primary system clock source, but would like to provide for the system clock source to be automatically changed to the internal RC oscillator should the external crystal oscillator fail, do I need to also set up the internal oscillator using the statement “setup_oscillator(osc_16MHz)”?
Will the “setup_oscillator(osc_16MHz)” statement cause the MCU to switch to the internal RC oscillator, instead of the external crystal oscillator, as the primary system clock source? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Sat May 07, 2022 1:47 am |
|
|
What you have to do is have the IRCF bits set to the frequency you want
the internal oscillator to go to. You do this with:
Code: |
setup_oscillator(OSC_16MHZ | OSC_NORMAL);
//This sets the frequency selection of the internal oscillator to 16MHz
//but does not select it. At the start of your code.
//You can also test at any time if FCMEN has triggered with:
if (interrupt_active(INT_OSCF))
//Or have an interrupt handler for this.
|
The default action is to remain on the selected default clock, but specifying
OSC_NORMAL makes sure this is done. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Sat May 07, 2022 3:24 am |
|
|
Thank you, Ttelmah.
Code: | #include "18LF46K22.h"
#fuses NOMCLR
#fuses HSM /* use external 16-MHz crystal oscillator across OSC1 and OSC2 pins */
#fuses FCMEN /* enable fail-safe clock monitor */
#fuses IESO /* enable internal/external oscillator switchover mode */
#use delay(xtal=16MHz, clock=16MHz) /* use clock frequency of 16 MHz for delays */
#byte clock_source=getenv("clock")
…
void main()
{
...
setup_oscillator(osc_16MHz | osc_NORMAL);
...
printf("clock source = %LX\n", clock_source);
...
} |
1. I wanted to see what FOSC<3:0> of the CONFIG1H register shows, by using getenv("clock"). It shows 0x00. I was expecting it to show 0x3, according to the datasheet ("0011= HS oscillator (medium power, 4 MHz-16 MHz)", page 345). Why is this happening. I am using the MPLAB SIM debugger in MPLAB IDE v8.92.
2. Is there any way to read the full CONFIG1H register using CCS functions?
Last edited by kgng97ccs on Sat May 07, 2022 5:22 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Sat May 07, 2022 3:59 am |
|
|
Your getenv will be returning the clock rate. Probably too large to fit
into whatever you ae putting it into.
The easiest way to see config values, is to simply open the .lst file.
They are are the bottom of this. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Sat May 07, 2022 4:18 am |
|
|
I see. Thank you so much, Ttelmah.
I have also been wondering how to check the configuration fuses, and I am glad you pointed me to the .lst file. I found them. |
|
|
kgng97ccs
Joined: 02 Apr 2022 Posts: 97
|
|
Posted: Sat May 07, 2022 9:32 am |
|
|
I notice the following information in the header file "18LF46K22.h":
Quote: | // A second optional parameter may be used with this part to fine
// tune the speed (signed int,-32 to 31)
// Result may be (ignore all other bits)
#define OSC_STATE_STABLE 4
#define OSC_STATE_EXT_RUNNING 8 |
What do the numbers -32 to 31 mean?
How should one use OSC_STATE_STABLE (bit 3 of OSCCON?) and OSC_STATE_EXT_RUNNING (bit 7 of OSCCON?) with the setup_oscillator() function? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Sat May 07, 2022 10:50 am |
|
|
You need to read the data sheet.
When running from the internal oscillator, the clock can be 'fine tuned'.
The tuning amount allowed is a signed integer +31 to -32. A lower
number decreases the oscillator frequency, a higher one increases it.
The factory calibrated value corresponds to 0.
To adjust this you would need some sort of external frequency that you
can use as a calibration source. For example a clock coming into a timer,
an external serial clock, or perhaps a zero crossing detected from the mains.
You can then increment/decrement the tweak value till the timing is right.
Code: |
if ((setup_oscillator() & OSC_STATE_EXT_RUNNING) ==0)
{
//you would get here if the external oscillator was not running
}
|
|
|
|
|