Skip to content

Commit 2a38531

Browse files
robert-hhdpgeorge
authored andcommitted
samd/mcu: Reduce the startup time after hard reset.
With Crystal: set the crystal startup wait time to 1 second. It was 2 seconds before, and that seeemed too long. With USB-Sync: scan for up to 1 second for the USB to be registered and carry on with boot as soon as it it. Before, the code just waited for 500ms. Side change: improve related comments. Signed-off-by: robert-hh <robert@hammelrath.com>
1 parent 9844567 commit 2a38531

File tree

2 files changed

+56
-40
lines changed

2 files changed

+56
-40
lines changed

ports/samd/mcu/samd21/clock_config.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ uint32_t get_peripheral_freq(void) {
5252

5353
void set_cpu_freq(uint32_t cpu_freq_arg) {
5454

55-
// Set 1 waitstate to be safe
55+
// Set 1 wait state to be safe
5656
NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_MANW | NVMCTRL_CTRLB_RWS(1);
5757

5858
int div = MAX(DFLL48M_FREQ / cpu_freq_arg, 1);
@@ -75,7 +75,7 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
7575
while (GCLK->STATUS.bit.SYNCBUSY) {
7676
}
7777
// configure the FDPLL96
78-
// CtrlB: Set the ref ource to GCLK, set the Wakup-Fast Flag.
78+
// CtrlB: Set the ref source to GCLK, set the Wakeup-Fast Flag.
7979
SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_REFCLK_GCLK | SYSCTRL_DPLLCTRLB_WUF;
8080
// Set the FDPLL ratio and enable the DPLL.
8181
int ldr = cpu_freq / FDPLL_REF_FREQ;
@@ -106,25 +106,36 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
106106
while (GCLK->STATUS.bit.SYNCBUSY) {
107107
}
108108
}
109-
// Set 0 waitstates for slower CPU clock
109+
// Set 0 wait states for slower CPU clock
110110
NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_MANW | NVMCTRL_CTRLB_RWS(cpu_freq > 24000000 ? 1 : 0);
111111
SysTick_Config(cpu_freq / 1000);
112112
}
113113

114114
void check_usb_recovery_mode(void) {
115115
#if !MICROPY_HW_XOSC32K
116-
mp_hal_delay_ms(500);
117-
// Check USB status. If not connected, switch DFLL48M back to open loop
118-
if (USB->DEVICE.DeviceEndpoint[0].EPCFG.reg == 0) {
119-
// Set/keep the open loop mode of the device.
120-
SYSCTRL->DFLLVAL.reg = dfll48m_calibration;
121-
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_ENABLE;
116+
// Check USB status for up to 1 second. If not connected,
117+
// switch DFLL48M back to open loop
118+
for (int i = 0; i < 100; i++) {
119+
if (USB->DEVICE.DeviceEndpoint[0].EPCFG.reg != 0) {
120+
return;
121+
}
122+
mp_hal_delay_ms(10);
122123
}
124+
// Set/keep the open loop mode of the device.
125+
SYSCTRL->DFLLVAL.reg = dfll48m_calibration;
126+
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_ENABLE;
123127
#endif // MICROPY_HW_XOSC32K
124128
}
125129

126130
// Purpose of the #defines for the clock configuration.
127131
//
132+
// The CPU is either driven by the FDPLL96 oscillator for f >= 48MHz,
133+
// or by the DFLL48M for lower frequencies. The FDPLL96 takes 32768 Hz
134+
// as reference frequency, supplied through GCLK1.
135+
//
136+
// DFLL48M is used for the peripheral clock, e.g. for PWM, UART, SPI, I2C.
137+
// DFLL48M is either free running, or controlled by the 32kHz crystal, or
138+
// Synchronized with the USB clock.
128139
// Both CPU and peripheral devices are clocked by the DFLL48M clock.
129140
// DFLL48M is either free running, or controlled by the 32kHz crystal, or
130141
// Synchronized with the USB clock.
@@ -136,18 +147,18 @@ void check_usb_recovery_mode(void) {
136147
// The crystal is used, unless MICROPY_HW_MCU_OSC32KULP is set.
137148
// In that case GCLK1 (and the CPU clock) is driven by the 32K Low power oscillator.
138149
// The reason for offering this option is a design flaw of the Adafruit
139-
// Feather boards, where the RGB Led and Debug signals interfere with the
150+
// Feather boards, where the RGB LED and Debug signals interfere with the
140151
// crystal, causing the CPU to fail if it is driven by the crystal.
141152
//
142153
// If MICROPY_HW_XOSC32K = 0, the 32kHz signal for GCLK1 (and the CPU) is
143154
// created by dividing the 48MHz clock of DFLL48M, but not used otherwise.
144155
//
145156
// If MICROPY_HW_DFLL_USB_SYNC = 0, the DFLL48M oscillator is free running using
146157
// the pre-configured trim values. In that mode, the peripheral clock is
147-
// not exactly 48Mhz and has a substantional temperature drift.
158+
// not exactly 48Mhz and has a substitutional temperature drift.
148159
//
149160
// If MICROPY_HW_DFLL_USB_SYNC = 1, the DFLL48 is synchronized with the 1 kHz USB sync
150-
// signal. If after boot there is no USB sync within 500ms, the configuration falls
161+
// signal. If after boot there is no USB sync within 1000 ms, the configuration falls
151162
// back to a free running 48Mhz oscillator.
152163
//
153164
// In all modes, the 48MHz signal has a substantial jitter, largest when
@@ -181,7 +192,7 @@ void init_clocks(uint32_t cpu_freq) {
181192
NVMCTRL->CTRLB.bit.RWS = 1; // 1 read wait state for 48MHz
182193

183194
#if MICROPY_HW_XOSC32K
184-
// Set up OSC32K according datasheet 17.6.3
195+
// Set up OSC32K according data sheet 17.6.3
185196
SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP(0x3) | SYSCTRL_XOSC32K_EN32K |
186197
SYSCTRL_XOSC32K_XTALEN;
187198
SYSCTRL->XOSC32K.bit.ENABLE = 1;
@@ -211,12 +222,12 @@ void init_clocks(uint32_t cpu_freq) {
211222
while (GCLK->STATUS.bit.SYNCBUSY) {
212223
}
213224

214-
// Enable access to the DFLLCTRL reg acc. to Errata 1.2.1
225+
// Enable access to the DFLLCTRL register according to Errata 1.2.1
215226
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
216227
while (SYSCTRL->PCLKSR.bit.DFLLRDY == 0) {
217228
}
218229
// Step 2: Set the coarse and fine values.
219-
// Get the coarse value from the calib data. In case it is not set,
230+
// Get the coarse value from the calibration data. In case it is not set,
220231
// set a midrange value.
221232
uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk)
222233
>> FUSES_DFLL48M_COARSE_CAL_Pos;

ports/samd/mcu/samd51/clock_config.c

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -117,27 +117,32 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
117117

118118
void check_usb_recovery_mode(void) {
119119
#if !MICROPY_HW_XOSC32K
120-
mp_hal_delay_ms(500);
121-
// Check USB status. If not connected, switch DFLL48M back to open loop
122-
if (USB->DEVICE.DeviceEndpoint[0].EPCFG.reg == 0) {
123-
// as per Errata 2.8.3
124-
OSCCTRL->DFLLMUL.reg = 0;
125-
while (OSCCTRL->DFLLSYNC.bit.DFLLMUL == 1) {
126-
}
127-
// Set the mode to open loop mode
128-
OSCCTRL->DFLLCTRLB.reg = 0;
129-
while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB == 1) {
130-
}
131-
OSCCTRL->DFLLCTRLA.reg = OSCCTRL_DFLLCTRLA_RUNSTDBY | OSCCTRL_DFLLCTRLA_ENABLE;
132-
while (OSCCTRL->DFLLSYNC.bit.ENABLE == 1) {
133-
}
134-
OSCCTRL->DFLLVAL.reg = dfll48m_calibration; // Reload DFLLVAL register
135-
while (OSCCTRL->DFLLSYNC.bit.DFLLVAL == 1) {
136-
}
137-
// Set the mode to open loop mode
138-
OSCCTRL->DFLLCTRLB.reg = 0;
139-
while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB == 1) {
120+
// Check USB status for up to 1 second. If not connected,
121+
// switch DFLL48M back to open loop
122+
for (int i = 0; i < 100; i++) {
123+
if (USB->DEVICE.DeviceEndpoint[0].EPCFG.reg != 0) {
124+
return;
140125
}
126+
mp_hal_delay_ms(10);
127+
}
128+
// No connection. Switch back to open loop mode.
129+
// as per Errata 2.8.3
130+
OSCCTRL->DFLLMUL.reg = 0;
131+
while (OSCCTRL->DFLLSYNC.bit.DFLLMUL == 1) {
132+
}
133+
// Set the mode to open loop mode
134+
OSCCTRL->DFLLCTRLB.reg = 0;
135+
while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB == 1) {
136+
}
137+
OSCCTRL->DFLLCTRLA.reg = OSCCTRL_DFLLCTRLA_RUNSTDBY | OSCCTRL_DFLLCTRLA_ENABLE;
138+
while (OSCCTRL->DFLLSYNC.bit.ENABLE == 1) {
139+
}
140+
OSCCTRL->DFLLVAL.reg = dfll48m_calibration; // Reload DFLLVAL register
141+
while (OSCCTRL->DFLLSYNC.bit.DFLLVAL == 1) {
142+
}
143+
// Set the mode to open loop mode
144+
OSCCTRL->DFLLCTRLB.reg = 0;
145+
while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB == 1) {
141146
}
142147
#endif // MICROPY_HW_XOSC32K
143148
}
@@ -169,10 +174,10 @@ void check_usb_recovery_mode(void) {
169174
//
170175
// If MICROPY_HW_DFLL_USB_SYNC = 0, the DFLL48M oscillator is free running using
171176
// the pre-configured trim values. In that mode, the peripheral clock is
172-
// not exactly 48Mhz and has a substantional temperature drift.
177+
// not exactly 48Mhz and has a substitutional temperature drift.
173178
//
174179
// If MICROPY_HW_DFLL_USB_SYNC = 1, the DFLL48 is synchronized with the 1 kHz USB sync
175-
// signal. If after boot there is no USB sync within 500ms, the configuration falls
180+
// signal. If after boot there is no USB sync within 1000 ms, the configuration falls
176181
// back to a free running 48Mhz oscillator.
177182
//
178183
// In all modes, the 48MHz signal has a substantial jitter, largest when
@@ -223,16 +228,16 @@ void init_clocks(uint32_t cpu_freq) {
223228
OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K;
224229
// Setup XOSC32K
225230
OSC32KCTRL->INTFLAG.reg = OSC32KCTRL_INTFLAG_XOSC32KRDY | OSC32KCTRL_INTFLAG_XOSC32KFAIL;
226-
OSC32KCTRL->CFDCTRL.bit.CFDEN = 1; // Fall back to internal Osc on crystal fail
231+
OSC32KCTRL->CFDCTRL.bit.CFDEN = 1; // Fall back to internal oscillator on crystal fail
227232
OSC32KCTRL->XOSC32K.reg =
228233
OSC32KCTRL_XOSC32K_CGM_HS |
229234
OSC32KCTRL_XOSC32K_XTALEN |
230235
OSC32KCTRL_XOSC32K_EN32K |
231236
OSC32KCTRL_XOSC32K_EN1K |
232237
OSC32KCTRL_XOSC32K_RUNSTDBY |
233-
OSC32KCTRL_XOSC32K_STARTUP(4) |
238+
OSC32KCTRL_XOSC32K_STARTUP(3) |
234239
OSC32KCTRL_XOSC32K_ENABLE;
235-
// make sure osc32kcrtl is ready
240+
// Wait until the oscillator is running and stable
236241
while (OSC32KCTRL->STATUS.bit.XOSC32KRDY == 0) {
237242
}
238243

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy