-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathosc.c
78 lines (68 loc) · 2.87 KB
/
osc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <xc.h>
#include <stdint.h>
#include <stdbool.h>
#include "osc.h"
//private vars
//if ext clock or sosc clock in use, set crystal frequency here
//=============================================================================
const uint32_t m_extfreq;
const uint32_t m_soscfreq;
// private funcs
// get system clock by reading clock registers
//.............................................................................
void
m_osc_sysclk()
{
osc_osc_t src = (osc_osc_t)OSCCON2 & 0x70;
uint8_t div = OSCCON2 & 0x0F;
osc_sysclk = 0;
if(src == osc_EXTOSC) osc_sysclk = m_extfreq>>div;
else if(src == osc_SOSC) osc_sysclk = m_soscfreq>>div;
else if(src == osc_EXTOSC4X) osc_sysclk = (m_extfreq<<2)>>div;
else if(src == osc_LFOSC) osc_sysclk = 31000>>div;
//we have to run the following even if sysclk already found
//to get hf int osc freq
uint8_t i = OSCFRQbits.HFFRQ;
uint32_t hff = 1000000;
if(i == osc_HFFREQ12){
hff = 12000000;
} else {
if(i > osc_HFFREQ12) i--;
for( ; i; i--, hff<<=1);
}
osc_hfclk = hff; //store hf clk freq
if(src == osc_HFINTOSC2X) hff<<=1; //2x
//now store to osc_sysclk if not already set
if( osc_sysclk == 0 ) osc_sysclk = hff>>div;
}
// set oscillator selection with divider value
// should never end up with an invalid clock as we check if the switch to the
// new clock is ready before we allow the switch- if times out, don't use
// (assuming the fuses are set to use internal frc)
//=============================================================================
bool
osc_set (osc_osc_t nosc, osc_div_t div)
{
OSCCON3bits.CSWHOLD = 1; //allows us to abandon if timeout
OSCCON1 = nosc | div; //set new src and div at same time
//a loop 'timeout' in case does not switch
for( volatile uint16_t i = 8192; i; i-- ){
if(OSCCON3bits.NOSCR == 0) continue; //not ready
OSCCON3bits.CSWHOLD = 0;//ok, now let it switch
m_osc_sysclk(); //compute new value
return true;
}
//failed to switch in time, set back to current osc settings
//(since using cswhold, a switch cannot occur in this little
// bit of time after the loop)
OSCCON1 = OSCCON2;
return false;
}
//set HF internal oscillator frequency
//=============================================================================
void
osc_hffreq (osc_hffreq_t freq)
{
OSCFRQ = freq;
m_osc_sysclk(); //compute new value
}