forked from micropython/micropython
-
Notifications
You must be signed in to change notification settings - Fork 4
/
clocks_extra.c
142 lines (123 loc) · 4.77 KB
/
clocks_extra.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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico.h"
#include "clocks_extra.h"
#include "hardware/regs/clocks.h"
#include "hardware/platform_defs.h"
#include "hardware/clocks.h"
#include "hardware/watchdog.h"
#include "hardware/pll.h"
#include "hardware/xosc.h"
#include "hardware/irq.h"
#include "hardware/gpio.h"
#include "hardware/ticks.h"
#if PICO_RP2040
// The RTC clock frequency is 48MHz divided by power of 2 (to ensure an integer
// division ratio will be used in the clocks block). A divisor of 1024 generates
// an RTC clock tick of 46875Hz. This frequency is relatively close to the
// customary 32 or 32.768kHz 'slow clock' crystals and provides good timing resolution.
#define RTC_CLOCK_FREQ_HZ (USB_CLK_KHZ * KHZ / 1024)
#endif
static void start_all_ticks(void) {
uint32_t cycles = clock_get_hz(clk_ref) / MHZ;
// Note RP2040 has a single tick generator in the watchdog which serves
// watchdog, system timer and M0+ SysTick; The tick generator is clocked from clk_ref
// but is now adapted by the hardware_ticks library for compatibility with RP2350
// npte: hardware_ticks library now provides an adapter for RP2040
for (int i = 0; i < (int)TICK_COUNT; ++i) {
tick_start((tick_gen_num_t)i, cycles);
}
}
// Wrap the SDK's clocks_init() function to save code size
void __wrap_runtime_init_clocks(void) {
runtime_init_clocks_optional_usb(true);
}
// Copy of runtime_init_clocks() from pico-sdk, with USB
// PLL and clock init made optional (for light sleep wakeup).
void runtime_init_clocks_optional_usb(bool init_usb) {
// Disable resus that may be enabled from previous software
clocks_hw->resus.ctrl = 0;
// Enable the xosc
xosc_init();
// Before we touch PLLs, switch sys and ref cleanly away from their aux sources.
hw_clear_bits(&clocks_hw->clk[clk_sys].ctrl, CLOCKS_CLK_SYS_CTRL_SRC_BITS);
while (clocks_hw->clk[clk_sys].selected != 0x1) {
tight_loop_contents();
}
hw_clear_bits(&clocks_hw->clk[clk_ref].ctrl, CLOCKS_CLK_REF_CTRL_SRC_BITS);
while (clocks_hw->clk[clk_ref].selected != 0x1) {
tight_loop_contents();
}
/// \tag::pll_init[]
pll_init(pll_sys, PLL_COMMON_REFDIV, PLL_SYS_VCO_FREQ_HZ, PLL_SYS_POSTDIV1, PLL_SYS_POSTDIV2);
if (init_usb) {
pll_init(pll_usb, PLL_COMMON_REFDIV, PLL_USB_VCO_FREQ_HZ, PLL_USB_POSTDIV1, PLL_USB_POSTDIV2);
}
/// \end::pll_init[]
// Configure clocks
// todo amy, what is this N1,2,4 meant to mean?
// RP2040 CLK_REF = XOSC (usually) 12MHz / 1 = 12MHz
// RP2350 CLK_REF = XOSC (XOSC_MHZ) / N (1,2,4) = 12MHz
// clk_ref aux select is 0 because:
//
// - RP2040: no aux mux on clk_ref, so this field is don't-care.
//
// - RP2350: there is an aux mux, but we are selecting one of the
// non-aux inputs to the glitchless mux, so the aux select doesn't
// matter. The value of 0 here happens to be the sys PLL.
clock_configure(clk_ref,
CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC,
0, // No aux mux
XOSC_KHZ * KHZ,
XOSC_KHZ * KHZ);
/// \tag::configure_clk_sys[]
// CLK SYS = PLL SYS (usually) 125MHz / 1 = 125MHz
clock_configure(clk_sys,
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
SYS_CLK_KHZ * KHZ,
SYS_CLK_KHZ * KHZ);
/// \end::configure_clk_sys[]
if (init_usb) {
// CLK USB = PLL USB 48MHz / 1 = 48MHz
clock_configure(clk_usb,
0, // No GLMUX
CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
USB_CLK_KHZ * KHZ,
USB_CLK_KHZ * KHZ);
}
// CLK ADC = PLL USB 48MHZ / 1 = 48MHz
clock_configure(clk_adc,
0, // No GLMUX
CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
USB_CLK_KHZ * KHZ,
USB_CLK_KHZ * KHZ);
#if HAS_RP2040_RTC
// CLK RTC = PLL USB 48MHz / 1024 = 46875Hz
clock_configure(clk_rtc,
0, // No GLMUX
CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
USB_CLK_KHZ * KHZ,
RTC_CLOCK_FREQ_HZ);
#endif
// CLK PERI = clk_sys. Used as reference clock for UART and SPI serial.
clock_configure(clk_peri,
0,
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
SYS_CLK_KHZ * KHZ,
SYS_CLK_KHZ * KHZ);
#if PICO_RP2350
// CLK_HSTX = clk_sys. Transmit bit clock for the HSTX peripheral.
clock_configure(clk_hstx,
0,
CLOCKS_CLK_HSTX_CTRL_AUXSRC_VALUE_CLK_SYS,
SYS_CLK_KHZ * KHZ,
SYS_CLK_KHZ * KHZ);
#endif
// Finally, all clocks are configured so start the ticks
// The ticks use clk_ref so now that is configured we can start them
start_all_ticks();
}