dsPIC33A Clock System
Overview
The dsPIC33A clock system supplies clocking to the CPU and peripherals. The module is based on a number of clock generators (CLKGENs) and PLL generators (PLLGENs). The CLKGENs are preassigned to the CPU and peripherals. Each clock generator selects a clock source from the available oscillators or PLLs and passes it to a selectable divider circuit.
The clock system has the following main functions/features:
- Multiple Oscillators
- Internal Fast RC (FRC): 8 MHz nominal
- Internal Backup Fast RC (BFRC): 8 MHz nominal
- Internal Low-Power RC (LPRC): 32.786 kHz (implemented as BFRC/244)
- Primary Oscillator (POSC): 3.5 MHz to 32 MHz (requires external crystal or resonator)
- External clock sources
- Multiple 1.6 GHz Phase-Locked Loop (PLLs), each with:
- Selectable clock source
- A backup clock source
- Primary and secondary outputs
- Multiple Clock Generators, each with:
- Selectable clock source
- A backup clock source
- Fail-safe clock monitors
- Clock Monitor Module, providing
- Clock failure detection
- Clock frequency drift detection
- Fault Injection capability
- Frequency, pulse width and duty cycle measurements
Clock Generators
Here we see a detailed block diagram for the clock generator:
Note that the clock generators are associated with a specific feature or peripheral, for example in the dsPIC33AK128MC106:
Configuring the Clock Generator
Each clock generator contains a configuration register that configures clock switching, clock division, and fail-safe backup oscillator options. In this example, we’ve defined a clock initialization function which performs several configuration changes to the CPU and Peripheral Clock Generator (CLKGEN1):
- Sets up the FRC as the backup oscillator
- Changes the clock source to the BFRC
- And divides this by 2, producing a 4 MHz CPU clock, and 4, 2, and 1 MHz peripheral clocks
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
{
// CLK1GEN (CPU & Peripheral Clocks) Configuration Example
// Default clock configuration:
// CLKGEN1 enabled with 8 MHz FRC source
// CPU clock = 8 MHz, Fast, Std. and Slow Peripheral clocks = 8, 4, and 2 MHz
// Desired clock configuration:
// CLKGEN1 enabled with 8 MHz BFRC source, and divided by 2
// Fail-safe backup enabled (FRC)
// CPU clock = 4 MHz, Fast, Std. and Slow Peripheral clocks = 4, 2, and 1 MHz
// Enable CLKxGEN if not already enabled
// CLK1CONbits.ON = 1;
// Configure FRC as backup osc.
CLK1CONbits.BOSC = 1; // Set up FRC as backup osc.
CLK1CONbits.FSCMEN = 1; // Enable fail safe
// Change clock source to BFRC and divide by 2
CLK1CONbits.NOSC = 2; // Select new osc. source = BFRC
CLK1CONbits.OSWEN = 1; // Request osc. switch to selection by NOSC
while(CLK1CONbits.OSWEN); // Wait for osc. switch
CLK1DIVbits.INTDIV = 1; // Select new integer clock divisor
CLK1CONbits.DIVSWEN = 1; // Request change to new integer clock divisor
while(CLK1CONbits.DIVSWEN) // Wait for change to be completed
// Wait for all changes to be applied
while(!CLK1CONbits.CLKRDY);
// Enable the CLK1GEN clock fail interrupt
IFS0bits.C1FAILIF = 0;
IEC0bits.C1FAILIE = 1;
}
Notice the request/grant protocol in which the firmware requests, then waits for each configuration step to be completed before proceeding to the next step and finally polling for the CLKRDY flag to be clear before continuing. Also, notice in this example that we’ve enabled a clock failure interrupt to be issued in the event of a source clock failure and switchover to the backup clock source for CLKGEN1.
Phase-Locked Loop (PLL)
The Primary Oscillator and Internal FRC Oscillator sources can optionally use an on-chip PLL to obtain higher operating speeds.
Several key requirements must be met to use the PLL:
- The PLL Input Frequency (FPLLI)
- The PLL VCO Output Frequency
- The PLL Feedback Divider
- The PLL Output Frequency
Consult your device data sheet for specific requirements for your device.
Using the PLL with the 8 MHz FRC to Generate a 200 MHz System Clock
Each PLL contains several configuration registers that control the PLL and configure input and feedback dividers. In this example, we’ve defined a clock initialization function that configures PLL1 to produce a 200 MHz clock source, then updates CLKGEN1 to use this source to provide a 200 MHz CPU and peripheral clock source.
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
{
// Default clock configuration:
// CLKGEN1 enabled with 8 MHz FRC source
// CPU clock = 8 MHz, Fast, Std and Slow Peripheral clocks = 8, 4, and 2 MHz
// Desired clock configuration:
// CLKGEN1 enabled with 200 MHz PLL1 source
// Fail-safe backup enabled (BFRC))
// CPU clock = 200 MHz, Fast, Std and Slow Peripheral clocks = 200, 100, and 50 MHz
// Step 1. Configure/Enable PLL1
// Enable the PLL1 Oscillator
OSCCTRLbits.PLL1EN = 1;
while(!OSCCTRLbits.PLL1RDY);
// Configure backup oscillator in case of failure
PLL1CONbits.BOSC = 2; // BFRC as backup clock source
PLL1CONbits.FSCMEN = 1; // Enable fail-safe
// Configure PLL values
PLL1DIVbits.PLLFBDIV = 200; // Feedback Divider
PLL1DIVbits.PLLPRE = 1; // Reference clock divider
PLL1DIVbits.POSTDIV1 = 4; // Post Divider #1
PLL1DIVbits.POSTDIV2 = 2; // Post Divider #2
// PLL Fout = Fin*FBDIV / (PLLPRE * POSTDIV1 * POSTDIV2)
// PLL Fout = 8M*200 / (1*4*2) = 200 MHz
// Enable PLL Input and Feedback Divider update
PLL1CONbits.PLLSWEN = 1;
while(PLL1CONbits.PLLSWEN);
// Enable PLL Output Divider update
PLL1CONbits.FOUTSWEN = 1;
while(PLL1CONbits.FOUTSWEN);
// Select FRC as clock source for PLL1
PLL1CONbits.NOSC = 1;
// Enable the clock source switch
PLL1CONbits.OSWEN = 1;
while(PLL1CONbits.OSWEN);
// Enable/Wait for the PLL clock to be ready
PLL1CONbits.ON = 1;
while(!PLL1CONbits.CLKRDY);
// Step 2. Update CLKGEN1
// Enable CLKxGEN if not already enabled
// CLK1CONbits.ON = 1;
// Configure BFRC as backup osc.
CLK1CONbits.BOSC = 2; // Set up BFRC as backup osc.
CLK1CONbits.FSCMEN = 1; // Enable fail safe
// Change clock source to PLL1
CLK1CONbits.NOSC = 5; // Select new osc. source = PLL1
CLK1CONbits.OSWEN = 1; // Request osc. switch to selection by NOSC
while(CLK1CONbits.OSWEN); // Wait for osc. switch
// Wait for all changes to be applied
while(!CLK1CONbits.CLKRDY);
// Enable the CLK1GEN clock fail interrupt
IFS0bits.C1FAILIF = 0;
IEC0bits.C1FAILIE = 1;
}