diff options
| author | Scott Shawcroft <scott@tannewt.org> | 2018-06-01 14:10:24 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-06-01 14:10:24 -0700 |
| commit | 317bb6d2ce75daa0737fb3ca8a2fb152160f1a7a (patch) | |
| tree | f58337b777b0e4df67125cb478a2f22de09a9d86 | |
| parent | 6479cb08060d7fb29b9189430a1ee8d105d37b26 (diff) | |
| parent | e158702a68637a975c97c34cc0a564c4d693faa5 (diff) | |
Merge pull request #888 from notro/samd51_clock_rework
atmel-samd/samd51: Refactor clock setup + implement samd.clock
| -rw-r--r-- | ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h | 2 | ||||
| -rw-r--r-- | ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h | 2 | ||||
| -rw-r--r-- | ports/atmel-samd/samd51_clocks.c | 390 | ||||
| -rw-r--r-- | ports/atmel-samd/supervisor/port.c | 6 |
4 files changed, 394 insertions, 6 deletions
diff --git a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h index 64b22acd5..b5af61ba6 100644 --- a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h +++ b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h @@ -32,6 +32,8 @@ #include "external_flash/external_flash.h" +#define BOARD_HAS_CRYSTAL 1 + #define DEFAULT_I2C_BUS_SCL (&pin_PA13) #define DEFAULT_I2C_BUS_SDA (&pin_PA12) diff --git a/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h b/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h index cda43d95e..7aef929f7 100644 --- a/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h +++ b/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h @@ -33,6 +33,8 @@ #include "external_flash/external_flash.h" +#define BOARD_HAS_CRYSTAL 1 + #define DEFAULT_I2C_BUS_SCL (&pin_PB03) #define DEFAULT_I2C_BUS_SDA (&pin_PB02) diff --git a/ports/atmel-samd/samd51_clocks.c b/ports/atmel-samd/samd51_clocks.c index cc3dd7917..6f8b1f010 100644 --- a/ports/atmel-samd/samd51_clocks.c +++ b/ports/atmel-samd/samd51_clocks.c @@ -28,6 +28,7 @@ #include "hpl_gclk_config.h" +#include "bindings/samd/Clock.h" #include "shared-bindings/microcontroller/__init__.h" #include "py/runtime.h" @@ -51,9 +52,26 @@ void disconnect_gclk_from_peripheral(uint8_t gclk, uint8_t peripheral) { GCLK->PCHCTRL[peripheral].reg = 0; } +static void enable_clock_generator_sync(uint8_t gclk, uint32_t source, uint16_t divisor, bool sync) { + uint32_t divsel = 0; + // The datasheet says 8 bits and max value of 512, how is that possible? + if (divisor > 255) { // Generator 1 has 16 bits + divsel = GCLK_GENCTRL_DIVSEL; + for (int i = 15; i > 0; i--) { + if (divisor & (1 << i)) { + divisor = i - 1; + break; + } + } + } + + GCLK->GENCTRL[gclk].reg = GCLK_GENCTRL_SRC(source) | GCLK_GENCTRL_DIV(divisor) | divsel | GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN; + if (sync) + while ((GCLK->SYNCBUSY.vec.GENCTRL & (1 << gclk)) != 0) {} +} + void enable_clock_generator(uint8_t gclk, uint32_t source, uint16_t divisor) { - GCLK->GENCTRL[gclk].reg = GCLK_GENCTRL_SRC(source) | GCLK_GENCTRL_DIV(divisor) | GCLK_GENCTRL_GENEN; - while ((GCLK->SYNCBUSY.vec.GENCTRL & (1 << gclk)) != 0) {} + enable_clock_generator_sync(gclk, source, divisor, true); } void disable_clock_generator(uint8_t gclk) { @@ -61,26 +79,394 @@ void disable_clock_generator(uint8_t gclk) { while ((GCLK->SYNCBUSY.vec.GENCTRL & (1 << gclk)) != 0) {} } +static void init_clock_source_osculp32k(void) { + // Calibration value is loaded at startup + OSC32KCTRL->OSCULP32K.bit.EN1K = 1; + OSC32KCTRL->OSCULP32K.bit.EN32K = 0; +} + +static void init_clock_source_xosc32k(void) { + OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_ONDEMAND | + OSC32KCTRL_XOSC32K_EN1K | + OSC32KCTRL_XOSC32K_XTALEN | + OSC32KCTRL_XOSC32K_ENABLE | + OSC32KCTRL_XOSC32K_CGM(1); +} + +static void init_clock_source_dpll0(void) +{ + GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(5); + OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0) | OSCCTRL_DPLLRATIO_LDR(59); + OSCCTRL->Dpll[0].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK(0); + OSCCTRL->Dpll[0].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE; + + while (!(OSCCTRL->Dpll[0].DPLLSTATUS.bit.LOCK || OSCCTRL->Dpll[0].DPLLSTATUS.bit.CLKRDY)) {} +} + +void clock_init(void) { + // DFLL48M is enabled by default + + init_clock_source_osculp32k(); + + if (board_has_crystal()) { + init_clock_source_xosc32k(); + OSC32KCTRL->RTCCTRL.bit.RTCSEL = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K_Val; + } else { + OSC32KCTRL->RTCCTRL.bit.RTCSEL = OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K_Val; + } + + MCLK->CPUDIV.reg = MCLK_CPUDIV_DIV(1); + + enable_clock_generator_sync(0, GCLK_GENCTRL_SRC_DPLL0_Val, 1, false); + enable_clock_generator_sync(1, GCLK_GENCTRL_SRC_DFLL_Val, 1, false); + enable_clock_generator_sync(4, GCLK_GENCTRL_SRC_DPLL0_Val, 1, false); + enable_clock_generator_sync(5, GCLK_GENCTRL_SRC_DFLL_Val, 24, false); + + init_clock_source_dpll0(); +} + +static bool clk_enabled(uint8_t clk) { + return GCLK->PCHCTRL[clk].bit.CHEN; +} + +static uint8_t clk_get_generator(uint8_t clk) { + return GCLK->PCHCTRL[clk].bit.GEN; +} + +static uint8_t generator_get_source(uint8_t gen) { + return GCLK->GENCTRL[gen].bit.SRC; +} + +static bool osc_enabled(uint8_t index) { + switch (index) { + case GCLK_SOURCE_XOSC0: + return OSCCTRL->XOSCCTRL[0].bit.ENABLE; + case GCLK_SOURCE_XOSC1: + return OSCCTRL->XOSCCTRL[1].bit.ENABLE; + case GCLK_SOURCE_OSCULP32K: + return true; + case GCLK_SOURCE_XOSC32K: + return OSC32KCTRL->XOSC32K.bit.ENABLE; + case GCLK_SOURCE_DFLL: + return OSCCTRL->DFLLCTRLA.bit.ENABLE; + case GCLK_SOURCE_DPLL0: + return OSCCTRL->Dpll[0].DPLLCTRLA.bit.ENABLE; + case GCLK_SOURCE_DPLL1: + return OSCCTRL->Dpll[1].DPLLCTRLA.bit.ENABLE; + }; + return false; +} + +static uint32_t osc_get_source(uint8_t index) { + uint8_t dpll_index = index - GCLK_SOURCE_DPLL0; + uint32_t refclk = OSCCTRL->Dpll[dpll_index].DPLLCTRLB.bit.REFCLK; + switch (refclk) { + case 0x0: + return generator_get_source(GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0 + dpll_index].bit.GEN); + case 0x1: + return GCLK_SOURCE_XOSC32K; + case 0x2: + return GCLK_SOURCE_XOSC0; + case 0x3: + return GCLK_SOURCE_XOSC1; + } + return 0; +} + +static uint32_t osc_get_frequency(uint8_t index); + +static uint32_t generator_get_frequency(uint8_t gen) { + uint8_t src = GCLK->GENCTRL[gen].bit.SRC; + uint32_t div; + if (GCLK->GENCTRL[gen].bit.DIVSEL) { + div = 1 << (GCLK->GENCTRL[gen].bit.DIV + 1); + } else { + div = GCLK->GENCTRL[gen].bit.DIV; + if (!div) + div = 1; + } + + return osc_get_frequency(src) / div; +} + +static uint32_t dpll_get_frequency(uint8_t index) { + uint8_t dpll_index = index - GCLK_SOURCE_DPLL0; + uint32_t refclk = OSCCTRL->Dpll[dpll_index].DPLLCTRLB.bit.REFCLK; + uint32_t freq; + + switch (refclk) { + case 0x0: // GCLK + freq = generator_get_frequency(GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0 + dpll_index].bit.GEN); + break; + case 0x1: // XOSC32 + freq = 32768; + break; + case 0x2: // XOSC0 + case 0x3: // XOSC1 + return 0; // unknown + } + + return (freq * (OSCCTRL->Dpll[dpll_index].DPLLRATIO.bit.LDR + 1)) + + (freq * OSCCTRL->Dpll[dpll_index].DPLLRATIO.bit.LDRFRAC / 32); +} + +static uint32_t osc_get_frequency(uint8_t index) { + switch (index) { + case GCLK_SOURCE_XOSC0: + case GCLK_SOURCE_XOSC1: + return 0; // unknown + case GCLK_SOURCE_OSCULP32K: + case GCLK_SOURCE_XOSC32K: + return 32768; + case GCLK_SOURCE_DFLL: + return 48000000; + case GCLK_SOURCE_DPLL0: + case GCLK_SOURCE_DPLL1: + return dpll_get_frequency(index); + } + return 0; +} + bool clock_get_enabled(uint8_t type, uint8_t index) { + if (type == 0) + return osc_enabled(index); + if (type == 1) + return clk_enabled(index); + if (type == 2) + return SysTick->CTRL & SysTick_CTRL_ENABLE_Msk; return false; } bool clock_get_parent(uint8_t type, uint8_t index, uint8_t *p_type, uint8_t *p_index) { + if (type == 0 && osc_enabled(index)) { + if (index == GCLK_SOURCE_DPLL0 || index == GCLK_SOURCE_DPLL1) { + *p_type = 0; + *p_index = osc_get_source(index); + return true; + } + return false; + } + if (type == 1 && index <= 47 && clk_enabled(index)) { + *p_type = 0; + *p_index = generator_get_source(clk_get_generator(index)); + return true; + } + if (type == 2) { + switch (index) { + case 0: + case 1: + *p_type = 0; + *p_index = generator_get_source(0); + return true; + case 2: + *p_type = 0; + switch (OSC32KCTRL->RTCCTRL.bit.RTCSEL) { + case 0: + case 1: + *p_index = GCLK_SOURCE_OSCULP32K; + return true; + case 4: + case 5: + *p_index = GCLK_SOURCE_XOSC32K; + return true; + } + return false; + } + } return false; } uint32_t clock_get_frequency(uint8_t type, uint8_t index) { + if (type == 0) { + return osc_get_frequency(index); + } + if (type == 1 && index <= 47 && clk_enabled(index)) { + return generator_get_frequency(clk_get_generator(index)); + } + if (type == 2) { + switch (index) { + case 0: + return clock_get_frequency(0, generator_get_source(0)) / SysTick->LOAD; + case 1: + return clock_get_frequency(0, generator_get_source(0)) / MCLK->CPUDIV.bit.DIV; + case 2: + switch (OSC32KCTRL->RTCCTRL.bit.RTCSEL) { + case 0: + case 4: + return 1024; + case 1: + case 5: + return 32768; + } + } + } return 0; } uint32_t clock_get_calibration(uint8_t type, uint8_t index) { + if (type == 0) { + switch (index) { + case GCLK_SOURCE_OSCULP32K: + return OSC32KCTRL->OSCULP32K.bit.CALIB; + }; + } + if (type == 2 && index == 0) { + return SysTick->LOAD + 1; + } return 0; } int clock_set_calibration(uint8_t type, uint8_t index, uint32_t val) { + if (type == 0) { + switch (index) { + case GCLK_SOURCE_OSCULP32K: + if (val > 0x3f) + return -1; + OSC32KCTRL->OSCULP32K.bit.CALIB = val; + return 0; + }; + } + if (type == 2 && index == 0) { + if (val < 0x1000 || val > 0x1000000) + return -1; + SysTick->LOAD = val - 1; + return 0; + } return -2; } +#include <instance/can0.h> +#include <instance/can1.h> +#include <instance/i2s.h> +#include <instance/sdhc1.h> +#include <instance/sercom6.h> +#include <instance/sercom7.h> +#include <instance/tcc4.h> + +CLOCK_SOURCE(XOSC0); +CLOCK_SOURCE(XOSC1); +CLOCK_SOURCE(GCLKIN); +CLOCK_SOURCE(GCLKGEN1); +CLOCK_SOURCE(OSCULP32K); +CLOCK_SOURCE(XOSC32K); +CLOCK_SOURCE(DFLL); +CLOCK_SOURCE(DPLL0); +CLOCK_SOURCE(DPLL1); + +CLOCK_GCLK_(OSCCTRL, DFLL48); +CLOCK_GCLK_(OSCCTRL, FDPLL0); +CLOCK_GCLK_(OSCCTRL, FDPLL1); +CLOCK_GCLK_(OSCCTRL, FDPLL032K); // GCLK_OSCCTRL_FDPLL1_32K, GCLK_SDHC0_SLOW, GCLK_SDHC1_SLOW, GCLK_SERCOM[0..7]_SLOW +CLOCK_GCLK(EIC); +CLOCK_GCLK_(FREQM, MSR); +// 6: GCLK_FREQM_REF +CLOCK_GCLK_(SERCOM0, CORE); +CLOCK_GCLK_(SERCOM1, CORE); +CLOCK(TC0_TC1, 1, 9); +CLOCK_GCLK(USB); +CLOCK_GCLK_(EVSYS, 0); +CLOCK_GCLK_(EVSYS, 1); +CLOCK_GCLK_(EVSYS, 2); +CLOCK_GCLK_(EVSYS, 3); +CLOCK_GCLK_(EVSYS, 4); +CLOCK_GCLK_(EVSYS, 5); +CLOCK_GCLK_(EVSYS, 6); +CLOCK_GCLK_(EVSYS, 7); +CLOCK_GCLK_(EVSYS, 8); +CLOCK_GCLK_(EVSYS, 9); +CLOCK_GCLK_(EVSYS, 10); +CLOCK_GCLK_(EVSYS, 11); +CLOCK_GCLK_(SERCOM2, CORE); +CLOCK_GCLK_(SERCOM3, CORE); +CLOCK(TCC0_TCC1, 1, 25); +CLOCK(TC2_TC3, 1, 26); +CLOCK_GCLK(CAN0); +CLOCK_GCLK(CAN1); +CLOCK(TCC2_TCC3, 1, 29); +CLOCK(TC4_TC5, 1, 30); +CLOCK_GCLK(PDEC); +CLOCK_GCLK(AC); +CLOCK_GCLK(CCL); +CLOCK_GCLK_(SERCOM4, CORE); +CLOCK_GCLK_(SERCOM5, CORE); +CLOCK_GCLK_(SERCOM6, CORE); +CLOCK_GCLK_(SERCOM7, CORE); +CLOCK_GCLK(TCC4); +CLOCK(TC6_TC7, 1, 39); +CLOCK_GCLK(ADC0); +CLOCK_GCLK(ADC1); +CLOCK_GCLK(DAC); +CLOCK_GCLK_(I2S, 0); +CLOCK_GCLK_(I2S, 1); +CLOCK_GCLK(SDHC0); +CLOCK_GCLK(SDHC1); +// 47: GCLK_CM4_TRACE + +CLOCK(SYSTICK, 2, 0); +CLOCK(CPU, 2, 1); +CLOCK(RTC, 2, 2); + + STATIC const mp_rom_map_elem_t samd_clock_global_dict_table[] = { + CLOCK_ENTRY(XOSC0), + CLOCK_ENTRY(XOSC1), + CLOCK_ENTRY(GCLKIN), + CLOCK_ENTRY(GCLKGEN1), + CLOCK_ENTRY(OSCULP32K), + CLOCK_ENTRY(XOSC32K), + CLOCK_ENTRY(DFLL), + CLOCK_ENTRY(DPLL0), + CLOCK_ENTRY(DPLL1), + + CLOCK_ENTRY_(OSCCTRL, DFLL48), + CLOCK_ENTRY_(OSCCTRL, FDPLL0), + CLOCK_ENTRY_(OSCCTRL, FDPLL1), + CLOCK_ENTRY_(OSCCTRL, FDPLL032K), + CLOCK_ENTRY(EIC), + CLOCK_ENTRY_(FREQM, MSR), + CLOCK_ENTRY_(SERCOM0, CORE), + CLOCK_ENTRY_(SERCOM1, CORE), + CLOCK_ENTRY(TC0_TC1), + CLOCK_ENTRY(USB), + CLOCK_ENTRY_(EVSYS, 0), + CLOCK_ENTRY_(EVSYS, 1), + CLOCK_ENTRY_(EVSYS, 2), + CLOCK_ENTRY_(EVSYS, 3), + CLOCK_ENTRY_(EVSYS, 4), + CLOCK_ENTRY_(EVSYS, 5), + CLOCK_ENTRY_(EVSYS, 6), + CLOCK_ENTRY_(EVSYS, 7), + CLOCK_ENTRY_(EVSYS, 8), + CLOCK_ENTRY_(EVSYS, 9), + CLOCK_ENTRY_(EVSYS, 10), + CLOCK_ENTRY_(EVSYS, 11), + CLOCK_ENTRY_(SERCOM2, CORE), + CLOCK_ENTRY_(SERCOM3, CORE), + CLOCK_ENTRY(TCC0_TCC1), + CLOCK_ENTRY(TC2_TC3), + CLOCK_ENTRY(CAN0), + CLOCK_ENTRY(CAN1), + CLOCK_ENTRY(TCC2_TCC3), + CLOCK_ENTRY(TC4_TC5), + CLOCK_ENTRY(PDEC), + CLOCK_ENTRY(AC), + CLOCK_ENTRY(CCL), + CLOCK_ENTRY_(SERCOM4, CORE), + CLOCK_ENTRY_(SERCOM5, CORE), + CLOCK_ENTRY_(SERCOM6, CORE), + CLOCK_ENTRY_(SERCOM7, CORE), + CLOCK_ENTRY(TCC4), + CLOCK_ENTRY(TC6_TC7), + CLOCK_ENTRY(ADC0), + CLOCK_ENTRY(ADC1), + CLOCK_ENTRY(DAC), + CLOCK_ENTRY_(I2S, 0), + CLOCK_ENTRY_(I2S, 1), + CLOCK_ENTRY(SDHC0), + CLOCK_ENTRY(SDHC1), + + CLOCK_ENTRY(SYSTICK), + CLOCK_ENTRY(CPU), + CLOCK_ENTRY(RTC), }; MP_DEFINE_CONST_DICT(samd_clock_globals, samd_clock_global_dict_table); diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index a92ab2913..55304e8ba 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -181,11 +181,9 @@ safe_mode_t port_init(void) { #ifdef SAMD21 hri_nvmctrl_set_CTRLB_RWS_bf(NVMCTRL, 2); _pm_init(); - clock_init(); -#endif -#ifdef SAMD51 - init_mcu(); #endif + clock_init(); + board_init(); // Configure millisecond timer initialization. |
