8000 atmel-samd/samd21: Rework clock setup · godlygeek/circuitpython@4adba51 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4adba51

Browse files
committed
atmel-samd/samd21: Rework clock setup
Make clock setup explicit instead of using the convoluted asf4 macro setup. enable_clock_generator(): - Add GCLK_GENCTRL_OE to stick with the current setup. - Handle divisor larger than 31 for generator 2 - Change the source argument so it can take the GCLK_GENCTRL_SRC_XXXX_Val macros without casting to uint8_t. This patch should not introduce any functional changes except keeping GCLK_GENCTRL_OE enabled when the I2S clock is enabled.
1 parent f21c249 commit 4adba51

File tree

4 files changed

+68
-5
lines changed

4 files changed

+68
-5
lines changed

ports/atmel-samd/clocks.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ void reset_gclks(void);
5050
void connect_gclk_to_peripheral(uint8_t gclk, uint8_t peripheral);
5151
void disconnect_gclk_from_peripheral(uint8_t gclk, uint8_t peripheral);
5252

53-
void enable_clock_generator(uint8_t gclk, uint8_t source, uint16_t divisor);
53+
void enable_clock_generator(uint8_t gclk, uint32_t source, uint16_t divisor);
5454
void disable_clock_generator(uint8_t gclk);
5555

56+
void clock_init(void);
57+
5658
#endif // MICROPY_INCLUDED_ATMEL_SAMD_CLOCKS_H

ports/atmel-samd/samd21_clocks.c

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,68 @@ void disconnect_gclk_from_peripheral(uint8_t gclk, uint8_t peripheral) {
5757
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(peripheral) | GCLK_CLKCTRL_GEN(gclk);
5858
}
5959

60-
void enable_clock_generator(uint8_t gclk, uint8_t source, uint16_t divisor) {
60+
void enable_clock_generator(uint8_t gclk, uint32_t source, uint16_t divisor) {
61+
uint32_t divsel = 0;
62+
if (gclk == 2 && divisor > 31) {
63+
divsel = GCLK_GENCTRL_DIVSEL;
64+
for (int i = 15; i > 4; i++) {
65+
if (divisor & (1 << i)) {
66+
divisor = i - 1;
67+
break;
68+
}
69+
}
70+
}
6171
GCLK->GENDIV.reg = GCLK_GENDIV_ID(gclk) | GCLK_GENDIV_DIV(divisor);
62-
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(gclk) | GCLK_GENCTRL_SRC(source) | GCLK_GENCTRL_GENEN;
72+
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(gclk) | GCLK_GENCTRL_SRC(source) | divsel | GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN;
6373
while (GCLK->STATUS.bit.SYNCBUSY != 0) {}
6474
}
6575

6676
void disable_clock_generator(uint8_t gclk) {
6777
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(gclk);
6878
while (GCLK->STATUS.bit.SYNCBUSY != 0) {}
6979
}
80+
81+
static void init_clock_source_osc8m(void) {
82+
// Preserve CALIB and FRANGE
83+
SYSCTRL->OSC8M.bit.ONDEMAND = 0;
84+
SYSCTRL->OSC8M.bit.PRESC = 3;
85+
SYSCTRL->OSC8M.bit.ENABLE = 1;
86+
while (!SYSCTRL->PCLKSR.bit.OSC8MRDY) {}
87+
}
88+
89+
static void init_clock_source_osc32k(void) {
90+
uint32_t calib = (*((uint32_t *)FUSES_OSC32K_CAL_ADDR) & FUSES_OSC32K_CAL_Msk) >> FUSES_OSC32K_CAL_Pos;
91+
SYSCTRL->OSC32K.reg = SYSCTRL_OSC32K_CALIB(calib) |
92+
SYSCTRL_OSC32K_EN32K |
93+
SYSCTRL_OSC32K_ENABLE;
94+
while (!SYSCTRL->PCLKSR.bit.OSC32KRDY) {}
95+
}
96+
97+
static void init_clock_source_dfll48m(void) {
98+
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
99+
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
100+
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) |
101+
SYSCTRL_DFLLMUL_FSTEP(1) |
102+
SYSCTRL_DFLLMUL_MUL(48000);
103+
uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk) >> FUSES_DFLL48M_COARSE_CAL_Pos;
104+
if (coarse == 0x3f)
105+
coarse = 0x1f;
106+
SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) |
107+
SYSCTRL_DFLLVAL_FINE(512);
108+
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS |
109+
SYSCTRL_DFLLCTRL_USBCRM |
110+
SYSCTRL_DFLLCTRL_MODE |
111+
SYSCTRL_DFLLCTRL_ENABLE;
112+
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
113+
while (GCLK->STATUS.bit.SYNCBUSY) {}
114+
}
115+
116+
void clock_init(void)
117+
{
118+
init_clock_source_osc8m();
119+
init_clock_source_osc32k();
120+
8000 enable_clock_generator(0, GCLK_GENCTRL_SRC_DFLL48M_Val, 1);
121+
enable_clock_generator(1, GCLK_GENCTRL_SRC_DFLL48M_Val, 150);
122+
init_clock_source_dfll48m();
123+
enable_clock_generator(2, GCLK_GENCTRL_SRC_OSC32K_Val, 32);
124+
}

ports/atmel-samd/samd51_clocks.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void disconnect_gclk_from_peripheral(uint8_t gclk, uint8_t peripheral) {
5151
GCLK->PCHCTRL[peripheral].reg = 0;
5252
}
5353

54-
void enable_clock_generator(uint8_t gclk, uint8_t source, uint16_t divisor) {
54+
void enable_clock_generator(uint8_t gclk, uint32_t source, uint16_t divisor) {
5555
GCLK->GENCTRL[gclk].reg = GCLK_GENCTRL_SRC(source) | GCLK_GENCTRL_DIV(divisor) | GCLK_GENCTRL_GENEN;
5656
while ((GCLK->SYNCBUSY.vec.GENCTRL & (1 << gclk)) != 0) {}
5757
}

ports/atmel-samd/supervisor/port.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line number 6D40 Diff line change
@@ -120,8 +120,14 @@ safe_mode_t port_init(void) {
120120
}
121121
#endif
122122

123+
#ifdef SAMD21
124+
hri_nvmctrl_set_CTRLB_RWS_bf(NVMCTRL, 2);
125+
_pm_init();
126+
clock_init();
127+
#endif
128+
#ifdef SAMD51
123129
init_mcu();
124-
130+
#endif
125131
board_init();
126132

127133
// Configure millisecond timer initialization.

0 commit comments

Comments
 (0)
0