|
|
View previous topic :: View next topic |
Author |
Message |
apakSeO
Joined: 07 Dec 2016 Posts: 60 Location: Northeast USA
|
How to use FCMEN correctly & startup clock switching to |
Posted: Thu Sep 05, 2019 12:31 pm |
|
|
PIC16F1779
CCS v5.081
I have search/viewed every similar topic here but have not found an adequate solution as of yet, so I am posting a new topic.
There is a TCXO = 30.72MHz connected to the OSC IN pin of the uC. In my test setup where the TXCO was always enabled ( its EN pin hard-wired to VDD ) I get expected results, expected delays, etc. This is achieved using the usual #fuses ECH statement for external high-speed oscillators.
In the real application, the TCXO is off by default because power isn't applied to the system yet. My goal is to (1) first have the uC boot and startup using some/any internal oscillator, (2) the first instruction in main() flips the EN pin of the TCXO high, thus starting the TCXO (3) The uC switches to using the 30.72MHz external clock from that point on, executing instructions in the remaining program. (4) At some future point in its operation, the uC will be put into a sleep state, the EN pin of TCXO will be pulled low, and the uC will go to sleep. Upon a wake-from-sleep routine, the uC again begins operation using one of its internal clocks ( doesn't matter which; not a time-sensitive startup in my application ), executes a few user-interface reads, and then again flips EN of the TCXO high again to resume using the fast external clock.
The first part of my inquiry involves the use of #fuses FCMEN If the ECH clock isn't found, FCMEN reverts the clock to some failsafe internal clock. But that is not what I am seeing. I see that no instructions are ever executed ... EN_TCXO never goes high ... until I manually poke the EN pin of the TCXO with 3.3V at which point the uC starts executing instructions.
Its as if #fuses FCMEN does not do what it intends to do ... code example below.
Code: |
#include <16F1779.h>
#device PIC16F1779
#device ICD=TRUE
#device ADC=10
#use delay(OSC=30.72MHZ, CLOCK=30.72MHZ) // Sets default system oscillator thru FOSC bits in OSCCON
#fuses ECH
#fuses NOWDT
#fuses FCMEN // Fail-safe clock monitor enable ... check this works over all corners!!!
#fuses NOPROTECT
#fuses DEBUG
#fuses CLKOUT
#fuses NOBROWNOUT
#fuses NOPUT
#define EN_TCXO PIN_A0
#define TEST_LED PIN_B0
void main(void)
{
output_high(EN_TCXO);
while(1)
{
output_high(TEST_LED);
delay_ms(500);
output_low(TEST_LED);
delay_ms(500);
}
}
|
So TEST_LED never goes high, until I manually poke EN_TCXO with 3.3V, then code executes as expected.
Why, despite the FCMEN fuse being enabled, is the first instruction to set high EN_TCXO never executed?
Now, the second part of this question involves switching back and forth between any internal clock <--> ECH clock. Are there any code examples out there for doing this exact back-and-forth clock source switching? It may simplify matters to know that any low-speed/internal clock being used will only be used right after a power-on condition or a wake-from-sleep condition, then execute a few pin reads, and flip EN_TCXO high. No delays, no timers used during this wake/PUC phase. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19541
|
|
Posted: Thu Sep 05, 2019 12:58 pm |
|
|
This is one of the things (like the watchdog), that the often doesn't work with
ICD. Check the actual fuses being generated (in the .lst file). You may well
find that FSCM is actually off. This is done because it causes issues on
some debuggers.
You have to test it for real, not with the debugger. |
|
|
apakSeO
Joined: 07 Dec 2016 Posts: 60 Location: Northeast USA
|
|
Posted: Thu Sep 05, 2019 1:57 pm |
|
|
Ttelmah wrote: | This is one of the things (like the watchdog), that the often doesn't work with
ICD. Check the actual fuses being generated (in the .lst file). You may well
find that FSCM is actually off. This is done because it causes issues on
some debuggers.
You have to test it for real, not with the debugger. |
Thanks Ttelmah, you are correct yet again.
Removing both the #device ICD=TRUE and the #fuses DEBUG lines allows FCMEN to do its thing, thus allowing the example program to run, albeit with bad timing due to the delay() function thinking its running at 30.72MHz. I'll fix that soon.
Now that I got FCMEN out of the way ... onto switching between an internal RC oscillator <--> external ECH oscillator ...
The setup_oscillator() prototype bif in the header file shows the following options only for the 16F1779:
Code: |
/////////////////// INTERNAL RC
// Oscillator Prototypes:
_bif void setup_oscillator(int8 mode);
// Constants used in setup_oscillator() are:
// First parameter:
#define OSC_31KHZ 0
#define OSC_31250 (2*8)
#define OSC_62KHZ (4*8)
#define OSC_125KHZ (5*8)
#define OSC_250KHZ (6*8)
#define OSC_500KHZ (7*8)
#define OSC_1MHZ (11*8)
#define OSC_2MHZ (12*8)
#define OSC_4MHZ (13*8)
#define OSC_8MHZ (14*8)
#define OSC_16MHZ (15*8)
// The following may be OR'ed in with the above using |
#define OSC_TIMER1 1
#define OSC_INTRC 2
#define OSC_NORMAL 0
// The following may be OR'ed in with the above using |
#define OSC_PLL_ON 0x80
#define OSC_PLL_OFF 0
|
How does one use setup_oscillator() to switch between internal RC and external ECH during program run time? I do not see an option for ECH in the header file. Is there another way to achieve this clock source switching? |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Fri Sep 06, 2019 6:16 am |
|
|
OSC_NORMAL selects whatever the fuses specify
OSC_INTRC selects the internal oscillator
OSC_TIMER1 selects the secondary oscillator on Timer1
Make sure your fuses select your external oscillator and then this is the OSC_NORMAL selection. |
|
|
|
|
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
|