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>
This commit is contained in:
robert-hh 2023-05-12 11:04:04 +02:00 committed by Damien George
parent 984456731b
commit 2a38531d73
2 changed files with 56 additions and 40 deletions

View File

@ -75,7 +75,7 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
while (GCLK->STATUS.bit.SYNCBUSY) {
}
// configure the FDPLL96
// CtrlB: Set the ref ource to GCLK, set the Wakup-Fast Flag.
// CtrlB: Set the ref source to GCLK, set the Wakeup-Fast Flag.
SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_REFCLK_GCLK | SYSCTRL_DPLLCTRLB_WUF;
// Set the FDPLL ratio and enable the DPLL.
int ldr = cpu_freq / FDPLL_REF_FREQ;
@ -113,18 +113,29 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
void check_usb_recovery_mode(void) {
#if !MICROPY_HW_XOSC32K
mp_hal_delay_ms(500);
// Check USB status. If not connected, switch DFLL48M back to open loop
if (USB->DEVICE.DeviceEndpoint[0].EPCFG.reg == 0) {
// Check USB status for up to 1 second. If not connected,
// switch DFLL48M back to open loop
for (int i = 0; i < 100; i++) {
if (USB->DEVICE.DeviceEndpoint[0].EPCFG.reg != 0) {
return;
}
mp_hal_delay_ms(10);
}
// Set/keep the open loop mode of the device.
SYSCTRL->DFLLVAL.reg = dfll48m_calibration;
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_ENABLE;
}
#endif // MICROPY_HW_XOSC32K
}
// Purpose of the #defines for the clock configuration.
//
// The CPU is either driven by the FDPLL96 oscillator for f >= 48MHz,
// or by the DFLL48M for lower frequencies. The FDPLL96 takes 32768 Hz
// as reference frequency, supplied through GCLK1.
//
// DFLL48M is used for the peripheral clock, e.g. for PWM, UART, SPI, I2C.
// DFLL48M is either free running, or controlled by the 32kHz crystal, or
// Synchronized with the USB clock.
// Both CPU and peripheral devices are clocked by the DFLL48M clock.
// DFLL48M is either free running, or controlled by the 32kHz crystal, or
// Synchronized with the USB clock.
@ -136,7 +147,7 @@ void check_usb_recovery_mode(void) {
// The crystal is used, unless MICROPY_HW_MCU_OSC32KULP is set.
// In that case GCLK1 (and the CPU clock) is driven by the 32K Low power oscillator.
// The reason for offering this option is a design flaw of the Adafruit
// Feather boards, where the RGB Led and Debug signals interfere with the
// Feather boards, where the RGB LED and Debug signals interfere with the
// crystal, causing the CPU to fail if it is driven by the crystal.
//
// If MICROPY_HW_XOSC32K = 0, the 32kHz signal for GCLK1 (and the CPU) is
@ -144,10 +155,10 @@ void check_usb_recovery_mode(void) {
//
// If MICROPY_HW_DFLL_USB_SYNC = 0, the DFLL48M oscillator is free running using
// the pre-configured trim values. In that mode, the peripheral clock is
// not exactly 48Mhz and has a substantional temperature drift.
// not exactly 48Mhz and has a substitutional temperature drift.
//
// If MICROPY_HW_DFLL_USB_SYNC = 1, the DFLL48 is synchronized with the 1 kHz USB sync
// signal. If after boot there is no USB sync within 500ms, the configuration falls
// signal. If after boot there is no USB sync within 1000 ms, the configuration falls
// back to a free running 48Mhz oscillator.
//
// In all modes, the 48MHz signal has a substantial jitter, largest when
@ -211,12 +222,12 @@ void init_clocks(uint32_t cpu_freq) {
while (GCLK->STATUS.bit.SYNCBUSY) {
}
// Enable access to the DFLLCTRL reg acc. to Errata 1.2.1
// Enable access to the DFLLCTRL register according to Errata 1.2.1
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
while (SYSCTRL->PCLKSR.bit.DFLLRDY == 0) {
}
// Step 2: Set the coarse and fine values.
// Get the coarse value from the calib data. In case it is not set,
// Get the coarse value from the calibration data. In case it is not set,
// set a midrange value.
uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk)
>> FUSES_DFLL48M_COARSE_CAL_Pos;

View File

@ -117,9 +117,15 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
void check_usb_recovery_mode(void) {
#if !MICROPY_HW_XOSC32K
mp_hal_delay_ms(500);
// Check USB status. If not connected, switch DFLL48M back to open loop
if (USB->DEVICE.DeviceEndpoint[0].EPCFG.reg == 0) {
// Check USB status for up to 1 second. If not connected,
// switch DFLL48M back to open loop
for (int i = 0; i < 100; i++) {
if (USB->DEVICE.DeviceEndpoint[0].EPCFG.reg != 0) {
return;
}
mp_hal_delay_ms(10);
}
// No connection. Switch back to open loop mode.
// as per Errata 2.8.3
OSCCTRL->DFLLMUL.reg = 0;
while (OSCCTRL->DFLLSYNC.bit.DFLLMUL == 1) {
@ -138,7 +144,6 @@ void check_usb_recovery_mode(void) {
OSCCTRL->DFLLCTRLB.reg = 0;
while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB == 1) {
}
}
#endif // MICROPY_HW_XOSC32K
}
@ -169,10 +174,10 @@ void check_usb_recovery_mode(void) {
//
// If MICROPY_HW_DFLL_USB_SYNC = 0, the DFLL48M oscillator is free running using
// the pre-configured trim values. In that mode, the peripheral clock is
// not exactly 48Mhz and has a substantional temperature drift.
// not exactly 48Mhz and has a substitutional temperature drift.
//
// If MICROPY_HW_DFLL_USB_SYNC = 1, the DFLL48 is synchronized with the 1 kHz USB sync
// signal. If after boot there is no USB sync within 500ms, the configuration falls
// signal. If after boot there is no USB sync within 1000 ms, the configuration falls
// back to a free running 48Mhz oscillator.
//
// In all modes, the 48MHz signal has a substantial jitter, largest when
@ -223,16 +228,16 @@ void init_clocks(uint32_t cpu_freq) {
OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K;
// Setup XOSC32K
OSC32KCTRL->INTFLAG.reg = OSC32KCTRL_INTFLAG_XOSC32KRDY | OSC32KCTRL_INTFLAG_XOSC32KFAIL;
OSC32KCTRL->CFDCTRL.bit.CFDEN = 1; // Fall back to internal Osc on crystal fail
OSC32KCTRL->CFDCTRL.bit.CFDEN = 1; // Fall back to internal oscillator on crystal fail
OSC32KCTRL->XOSC32K.reg =
OSC32KCTRL_XOSC32K_CGM_HS |
OSC32KCTRL_XOSC32K_XTALEN |
OSC32KCTRL_XOSC32K_EN32K |
OSC32KCTRL_XOSC32K_EN1K |
OSC32KCTRL_XOSC32K_RUNSTDBY |
OSC32KCTRL_XOSC32K_STARTUP(4) |
OSC32KCTRL_XOSC32K_STARTUP(3) |
OSC32KCTRL_XOSC32K_ENABLE;
// make sure osc32kcrtl is ready
// Wait until the oscillator is running and stable
while (OSC32KCTRL->STATUS.bit.XOSC32KRDY == 0) {
}