diff --git a/docs/samd/quickref.rst b/docs/samd/quickref.rst index aa3d563f7c..cdfb0a4750 100644 --- a/docs/samd/quickref.rst +++ b/docs/samd/quickref.rst @@ -42,8 +42,10 @@ The :mod:`machine` module:: machine.freq(96_000_000) # set the CPU frequency to 96 MHz The range accepted by the function call is 1_000_000 to 200_000_000 (1 MHz to 200 MHz) -for SAMD51 and 1_000_000 to 48_000_000 (1 MHz to 48 MHz) for SAMD21. The safe -range for SAMD51 according to the data sheet is 96 MHz to 120 MHz. +for SAMD51 and 1_000_000 to 54_000_000 (1 MHz to 54 MHz) for SAMD21. The safe +range for SAMD51 according to the data sheet is up to 120 MHz, for the SAMD21 up to 48Mhz. +Frequencies below 48Mhz are set by dividing 48Mhz by an integer, limiting the number of +discrete frequencies to 24Mhz, 16Mhz, 12MHz, and so on. At frequencies below 8 MHz USB will be disabled. Changing the frequency below 48 MHz impacts the baud rates of UART, I2C and SPI. These have to be set again after changing the CPU frequency. The ms and µs timers are not affected by the frequency diff --git a/ports/samd/mcu/samd21/clock_config.c b/ports/samd/mcu/samd21/clock_config.c index 4473be5afc..630b5c0a4a 100644 --- a/ports/samd/mcu/samd21/clock_config.c +++ b/ports/samd/mcu/samd21/clock_config.c @@ -78,8 +78,9 @@ void set_cpu_freq(uint32_t cpu_freq_arg) { // CtrlB: Set the ref ource to GCLK, set the Wakup-Fast Flag. SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_REFCLK_GCLK | SYSCTRL_DPLLCTRLB_WUF; // Set the FDPLL ratio and enable the DPLL. - int ldr = cpu_freq_arg / FDPLL_REF_FREQ - 1; - SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR(ldr); + int ldr = cpu_freq / FDPLL_REF_FREQ; + int frac = ((cpu_freq - ldr * FDPLL_REF_FREQ) / (FDPLL_REF_FREQ / 16)) & 0x0f; + SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR((frac << 16 | ldr) - 1); SYSCTRL->DPLLCTRLA.reg = SYSCTRL_DPLLCTRLA_ENABLE; // Wait for the DPLL lock. while (!SYSCTRL->DPLLSTATUS.bit.LOCK) { diff --git a/ports/samd/mcu/samd21/mpconfigmcu.h b/ports/samd/mcu/samd21/mpconfigmcu.h index 7d787cacfe..150a378a3e 100644 --- a/ports/samd/mcu/samd21/mpconfigmcu.h +++ b/ports/samd/mcu/samd21/mpconfigmcu.h @@ -22,6 +22,9 @@ #define MICROPY_PY_CMATH (0) #endif +#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (trng_random_u32()) +unsigned long trng_random_u32(void); + #define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages; #ifndef MICROPY_HW_UART_TXBUF diff --git a/ports/samd/samd_isr.c b/ports/samd/samd_isr.c index 1d6febaaa2..838800bdbb 100644 --- a/ports/samd/samd_isr.c +++ b/ports/samd/samd_isr.c @@ -42,6 +42,9 @@ extern void EIC_Handler(void); const ISR isr_vector[]; volatile uint32_t systick_ms; volatile uint32_t ticks_us64_upper; +#if defined(MCU_SAMD21) +volatile uint32_t rng_state; +#endif void Reset_Handler(void) __attribute__((naked)); void Reset_Handler(void) { @@ -91,6 +94,12 @@ void Default_Handler(void) { } void SysTick_Handler(void) { + #if defined(MCU_SAMD21) + // Use the phase jitter between the clocks to get some entropy + // and accumulate the random number register. + rng_state = (rng_state * 32310901 + 1) ^ (REG_TC4_COUNT32_COUNT >> 1); + #endif + uint32_t next_tick = systick_ms + 1; systick_ms = next_tick; @@ -99,6 +108,13 @@ void SysTick_Handler(void) { } } +#if defined(MCU_SAMD21) +uint32_t trng_random_u32(void) { + mp_hal_delay_ms(320); // wait for ten cycles of the rng_seed register + return rng_state; +} +#endif + void us_timer_IRQ(void) { #if defined(MCU_SAMD21) if (TC4->COUNT32.INTFLAG.reg & TC_INTFLAG_OVF) {