The code snippet below is for the new oscillator arrangement in some of the latest PIC chips
The snippet is specifically for a 24EP512GU810 which can run internally at 140Mhz from in my case a 8Mhz external Xtal
You should modify the PLL_N1 PLL_M PLL_N2 PLL_XTAL values to your specific needs
Look at the microchip osc setup specs to see the limitations of your chip
Note I suspect CCS hasn't yet written code to allow #use delay(clock=xxMHz,xtal=yyMhz) to autoset up the newer chips.
#fuses XT,PR_PLL,PLLWAIT,ICSP1,PUT128,IESO,NOJTAG
#define PLL_N1 2
#define PLL_M 70
#define PLL_N2 2
#define PLL_XTAL 8
/// setup_pll(N1,M,N2) xtal 8Mhz is ((8/2)*70)/2=140Mhz
#use delay(clock=140Mhz) // have to let the compiler know we're running at 140MHz
// the switch t0 140 Mhzoccurs at the very top of main
// but the compiler needs this at compile time
#use rs232(debugger) //// monitor output on b3
////// busy low level code to get osc set up
/// since use delay(clock=140Mhz,osc=8Mhz) isn't working
/// instead we use setup_pll(PLL_N1,PLL_M,PLL_N2);
//// called in main()
#word CLKDIV = getenv("sfr:CLKDIV")
#bit PLLPOST0 = CLKDIV.6
#bit PLLPOST1 = CLKDIV.7
#word PLLFBD = getenv("sfr:PLLFBD")
struct struct_MIDDIV_M
{
int M; //0-7
int unused1; //8-15
};
struct struct_MIDDIV_M MIDDIV ;
#word MIDDIV=getenv("sfr:PLLFBD")
struct struct_DIV_N1andN2
{
int N1:5; //0-4
int1 unused1; // 5
int N2:2; //6-7
int unused2; //15
};
struct struct_DIV_N1andN2 DIV_N1andN2;
#word DIV_N1andN2=getenv("sfr:CLKDIV")
struct struct_OSCCON
{
int1 oswen; //0 // oscillator switch enable
int1 lposcen; //1 // secondary (LP) oscillator enable
int1 unused1; //2
int1 cf; //3 // clock fail detect bit
int1 unused2; //4
int1 lock; //5 // PLL lock status
int1 unused3; //6
int1 clklock; //7 // clock lock enable
int nosc:3; //8-10 // new oscillator selection
int1 unused4; //11
int cosc:3; //12-14 // current oscillator selection
int1 unused5; //15
};
struct struct_OSCCON OSCCON;
#word OSCCON = getenv("sfr:OSCCON")
#byte OSCCONL = OSCCON
#byte OSCCONH = OSCCON+1
//#byte OSCCONL = 0x0742
//#byte OSCCONH = 0x0743
void setup_pll(int8 N1,int8 M,int8 N2)
{
// This function is required because the 24HJ cannot startup with a 8MHz xtal
// from powerup (not reliably, anyway). Must start the PIC using the internal
// RC oscillator, then switch over to the external xtal with PLL. This also
// requires a very time sensitive unlock sequence to directly access the
// necessary registers to perform this task. #asm taken directly from
// a microchip app note.
// 8MHz xtal -> PLLPRE divider (N1) -> multiplier -> VCO -> PLLPOST divider (N2) -> Fosc
// ^ |
// |------PLLDIV (M)
// 8MHz / 2 = 4MHz x 40 = 160MHz / 2 = 80MHz
// N1 M N2
// M = 38 (40 - 2), N1 = 1 (3 - 2), N2 = 0 (2)
// N1
CLKDIV = N1-2; // PLLPRE
// N2
//11 = Output/8
//10 = Reserved
//01 = Output/4 (default)
//00 = Output/2
if (n2==2)
{
PLLPOST0 = 0;
PLLPOST1 = 0;
}
if (n2==4)
{
PLLPOST0 = 1;
PLLPOST1 = 0;
}
if (n2==8)
{
PLLPOST0 = 1;
PLLPOST1 = 1;
}
// M
PLLFBD = M-2;
#asm
MOV #0x03, w0
MOV OSCCONH, w1
MOV #0x78, w2
MOV #0x9A, w3
MOV.B w2, [w1]
MOV.B w3, [w1]
MOV.B w0, [w1]
MOV #0x01, w0
MOV OSCCONL, w1
MOV #0x46, w2
MOV #0x57, w3
MOV.B w2, [w1]
MOV.B w3, [w1]
MOV.B w0, [w1]
#endasm
while(OSCCON.cosc != 3); // wait for switchover to occur
while (!OSCCON.lock); // wait for PLL to lock
OSCCON.clklock = 1;
}
///and in main call
setup_pll(PLL_N1,PLL_M,PLL_N2); /// setup_pll(N1,M,N2) xtal 8Mhz is ((8/2)*70)/2=140Mhz
The 15.xxMhz you are getting is very likely the 16Mhz internal RC oscillator freq