From 742bcad9128ed0c85c03cb960a47f2f960fcc94d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Thu, 27 Apr 2017 15:42:22 +0200 Subject: [PATCH] kinetis: Unify cpu.c, update clocking initialization Unify cpu_init for all Kinetis CPUs to reduce code duplication. Updated the MCG driver implementation to make the configuration easier. Most clock settings are initialized by kinetis_mcg_init() called from cpu_init. Board specific external clock source initialization (FRDM-K64F, PhyNode) needs to be performed in board_init instead of in cpu_init. --- boards/frdm-k22f/board.c | 28 -- boards/frdm-k22f/include/periph_conf.h | 63 +-- boards/frdm-k64f/board.c | 4 + boards/frdm-k64f/include/periph_conf.h | 61 +-- boards/mulle/board.c | 51 +-- boards/mulle/include/board.h | 27 -- boards/mulle/include/periph_conf.h | 74 ++-- boards/pba-d-01-kw2x/board.c | 33 ++ boards/pba-d-01-kw2x/include/periph_conf.h | 48 ++- cpu/k60/cpu.c | 34 -- cpu/k60/include/vendor/MK60D10.h | 1 + cpu/k64f/cpu.c | 69 ---- cpu/{k22f => kinetis_common}/cpu.c | 14 +- cpu/kinetis_common/include/mcg.h | 172 ++++---- cpu/kinetis_common/include/periph_cpu.h | 107 +++++ cpu/kinetis_common/periph/mcg.c | 454 +++++++++++---------- cpu/kw2xd/cpu.c | 85 ---- cpu/kw2xd/include/vendor/MKW22D5.h | 2 + 18 files changed, 639 insertions(+), 688 deletions(-) delete mode 100644 cpu/k60/cpu.c delete mode 100644 cpu/k64f/cpu.c rename cpu/{k22f => kinetis_common}/cpu.c (52%) delete mode 100644 cpu/kw2xd/cpu.c diff --git a/boards/frdm-k22f/board.c b/boards/frdm-k22f/board.c index 9d19449812..9a61c9e49c 100644 --- a/boards/frdm-k22f/board.c +++ b/boards/frdm-k22f/board.c @@ -25,17 +25,8 @@ #include "mcg.h" #include "periph/gpio.h" -#define SIM_CLKDIV1_48MHZ (SIM_CLKDIV1_OUTDIV1(0) | \ - SIM_CLKDIV1_OUTDIV2(1) | \ - SIM_CLKDIV1_OUTDIV3(1) | \ - SIM_CLKDIV1_OUTDIV4(1)) - -static void cpu_clock_init(void); - void board_init(void) { - /* initialize the clock system */ - cpu_clock_init(); /* initialize the CPU core */ cpu_init(); @@ -47,22 +38,3 @@ void board_init(void) gpio_set(LED1_PIN); gpio_set(LED2_PIN); } - -/** - * @brief Configure the controllers clock system - * - * | Clock name | Run mode frequency (max) | VLPR mode frequency (max) | - * - * | Core | 120 MHz | 4 MHz | - * | System | 120 MHz | 4 MHz | - * | Bus | 60 MHz | 4 MHz | - * | FlexBus | 30 MHz | 800 kHz | - * | Flash | 26.67 MHz | 4 MHz | - */ -static void cpu_clock_init(void) -{ - /* setup system prescalers */ - SIM->CLKDIV1 = (uint32_t)SIM_CLKDIV1_48MHZ; - - kinetis_mcg_set_mode(KINETIS_MCG_PEE); -} diff --git a/boards/frdm-k22f/include/periph_conf.h b/boards/frdm-k22f/include/periph_conf.h index 28c53ae9b6..35c91c351d 100644 --- a/boards/frdm-k22f/include/periph_conf.h +++ b/boards/frdm-k22f/include/periph_conf.h @@ -30,20 +30,33 @@ extern "C" * @name Clock system configuration * @{ */ -#define KINETIS_CPU_USE_MCG 1 -#define KINETIS_MCG_USE_ERC 1 -#define KINETIS_MCG_USE_PLL 1 -/* The crystal connected to OSC0 is 8 MHz */ -#define KINETIS_MCG_DCO_RANGE (48000000u) -#define KINETIS_MCG_ERC_OSCILLATOR 1 -#define KINETIS_MCG_ERC_FRDIV 3 /* ERC divider = 256 */ -#define KINETIS_MCG_ERC_RANGE 1 -#define KINETIS_MCG_ERC_FREQ (40000000u) -#define KINETIS_MCG_PLL_PRDIV 3 /* divide factor = 4 */ -#define KINETIS_MCG_PLL_VDIV0 0 /* multiply factor = 24 */ -#define KINETIS_MCG_PLL_FREQ (48000000u) - -#define CLOCK_CORECLOCK KINETIS_MCG_PLL_FREQ +static const clock_config_t clock_config = { + /* + * This configuration results in the system running from the FLL output with + * the following clock frequencies: + * Core: 60 MHz + * Bus: 30 MHz + * Flex: 20 MHz + * Flash: 20 MHz + */ + .clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | + SIM_CLKDIV1_OUTDIV3(2) | SIM_CLKDIV1_OUTDIV4(2), + .default_mode = KINETIS_MCG_MODE_FEE, + /* The crystal connected to OSC0 is 8 MHz */ + .erc_range = KINETIS_MCG_ERC_RANGE_HIGH, + .fcrdiv = 0, /* Fast IRC divide by 1 => 4 MHz */ + .oscsel = 0, /* Use OSC0 for external clock */ + .clc = 0, /* External load caps on the FRDM-K22F board */ + .fll_frdiv = 0b011, /* Divide by 256 */ + .fll_factor_fei = KINETIS_MCG_FLL_FACTOR_1464, /* FLL freq = 48 MHz */ + .fll_factor_fee = KINETIS_MCG_FLL_FACTOR_1920, /* FLL freq = 60 MHz */ + .pll_prdiv = 0b00011, /* Divide by 4 */ + .pll_vdiv = 0b00110, /* Multiply by 30 => PLL freq = 60 MHz */ + .enable_oscillator = true, + .select_fast_irc = true, + .enable_mcgirclk = false, +}; +#define CLOCK_CORECLOCK (60000000ul) #define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 2) /** @} */ @@ -211,20 +224,20 @@ static const spi_conf_t spi_config[] = { * @{ */ #define I2C_NUMOF (1U) -#define I2C_CLK CLOCK_CORECLOCK +#define I2C_CLK CLOCK_BUSCLOCK #define I2C_0_EN 1 #define I2C_IRQ_PRIO 1 -/* Low (10 kHz): MUL = 4, SCL divider = 1280, total: 5120 */ -#define KINETIS_I2C_F_ICR_LOW (0x35) -#define KINETIS_I2C_F_MULT_LOW (2) -/* Normal (100 kHz): MUL = 2, SCL divider = 240, total: 480 */ -#define KINETIS_I2C_F_ICR_NORMAL (0x1F) +/* Low (10 kHz): MUL = 2, SCL divider = 1536, total: 3072 */ +#define KINETIS_I2C_F_ICR_LOW (0x36) +#define KINETIS_I2C_F_MULT_LOW (1) +/* Normal (100 kHz): MUL = 2, SCL divider = 160, total: 320 */ +#define KINETIS_I2C_F_ICR_NORMAL (0x1D) #define KINETIS_I2C_F_MULT_NORMAL (1) -/* Fast (400 kHz): MUL = 1, SCL divider = 128, total: 128 */ -#define KINETIS_I2C_F_ICR_FAST (0x17) +/* Fast (400 kHz): MUL = 1, SCL divider = 80, total: 80 */ +#define KINETIS_I2C_F_ICR_FAST (0x14) #define KINETIS_I2C_F_MULT_FAST (0) -/* Fast plus (1000 kHz): MUL = 1, SCL divider = 48, total: 48 */ -#define KINETIS_I2C_F_ICR_FAST_PLUS (0x10) +/* Fast plus (1000 kHz): MUL = 1, SCL divider = 30, total: 30 */ +#define KINETIS_I2C_F_ICR_FAST_PLUS (0x05) #define KINETIS_I2C_F_MULT_FAST_PLUS (0) /* I2C 0 device configuration */ @@ -235,7 +248,7 @@ static const spi_conf_t spi_config[] = { #define I2C_0_IRQ_HANDLER isr_i2c0 /* I2C 0 pin configuration */ #define I2C_0_PORT PORTB -#define I2C_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTE_MASK)) +#define I2C_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTB_MASK)) #define I2C_0_PIN_AF 2 #define I2C_0_SDA_PIN 3 #define I2C_0_SCL_PIN 2 diff --git a/boards/frdm-k64f/board.c b/boards/frdm-k64f/board.c index 5f83cfb68b..bb5d78cd29 100644 --- a/boards/frdm-k64f/board.c +++ b/boards/frdm-k64f/board.c @@ -24,6 +24,10 @@ void board_init(void) { + /* RMII RXCLK pin configuration */ + SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; + PORTA->PCR[18] &= ~(PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)); + /* initialize the CPU core */ cpu_init(); diff --git a/boards/frdm-k64f/include/periph_conf.h b/boards/frdm-k64f/include/periph_conf.h index 1405ccf925..34bbfbc244 100644 --- a/boards/frdm-k64f/include/periph_conf.h +++ b/boards/frdm-k64f/include/periph_conf.h @@ -31,21 +31,34 @@ extern "C" * @name Clock system configuration * @{ */ -#define KINETIS_CPU_USE_MCG 1 - -#define KINETIS_MCG_USE_ERC 1 -#define KINETIS_MCG_USE_PLL 1 -#define KINETIS_MCG_DCO_RANGE (24000000U) -#define KINETIS_MCG_ERC_OSCILLATOR 0 -#define KINETIS_MCG_ERC_FRDIV 6 /* ERC devider = 1280 */ -#define KINETIS_MCG_ERC_RANGE 2 -#define KINETIS_MCG_ERC_FREQ 50000000 -#define KINETIS_MCG_PLL_PRDIV 19 /* divide factor = 20 */ -#define KINETIS_MCG_PLL_VDIV0 0 /* multiply factor = 24 */ -#define KINETIS_MCG_PLL_FREQ 60000000 - -#define CLOCK_CORECLOCK KINETIS_MCG_PLL_FREQ -#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 2) +static const clock_config_t clock_config = { + /* + * This configuration results in the system running from the PLL output with + * the following clock frequencies: + * Core: 60 MHz + * Bus: 60 MHz + * Flex: 20 MHz + * Flash: 20 MHz + */ + .clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | + SIM_CLKDIV1_OUTDIV3(2) | SIM_CLKDIV1_OUTDIV4(2), + .default_mode = KINETIS_MCG_MODE_PEE, + /* The board has an external RMII (Ethernet) clock which drives the ERC at 50 MHz */ + .erc_range = KINETIS_MCG_ERC_RANGE_VERY_HIGH, + .fcrdiv = 0, /* Fast IRC divide by 1 => 4 MHz */ + .oscsel = 0, /* Use EXTAL for external clock */ + .clc = 0, /* External load caps on board */ + .fll_frdiv = 0b111, /* Divide by 1536 => FLL input 32252 Hz */ + .fll_factor_fei = KINETIS_MCG_FLL_FACTOR_1464, /* FLL freq = 48 MHz */ + .fll_factor_fee = KINETIS_MCG_FLL_FACTOR_1920, /* FLL freq = 62.5 MHz */ + .pll_prdiv = 0b10011, /* Divide by 20 */ + .pll_vdiv = 0b00000, /* Multiply by 24 => PLL freq = 60 MHz */ + .enable_oscillator = false, /* Use EXTAL directly without OSC0 */ + .select_fast_irc = true, + .enable_mcgirclk = false, +}; +#define CLOCK_CORECLOCK (60000000ul) +#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 1) /** @} */ /** @@ -206,20 +219,20 @@ static const spi_conf_t spi_config[] = { * @{ */ #define I2C_NUMOF (1U) -#define I2C_CLK CLOCK_CORECLOCK +#define I2C_CLK CLOCK_BUSCLOCK #define I2C_0_EN 1 #define I2C_IRQ_PRIO 1 -/* Low (10 kHz): MUL = 4, SCL divider = 2560, total: 10240 */ -#define KINETIS_I2C_F_ICR_LOW (0x3D) +/* Low (10 kHz): MUL = 4, SCL divider = 1536, total: 6144 */ +#define KINETIS_I2C_F_ICR_LOW (0x36) #define KINETIS_I2C_F_MULT_LOW (2) -/* Normal (100 kHz): MUL = 2, SCL divider = 240, total: 480 */ -#define KINETIS_I2C_F_ICR_NORMAL (0x1F) +/* Normal (100 kHz): MUL = 2, SCL divider = 320, total: 640 */ +#define KINETIS_I2C_F_ICR_NORMAL (0x25) #define KINETIS_I2C_F_MULT_NORMAL (1) -/* Fast (400 kHz): MUL = 1, SCL divider = 128, total: 128 */ -#define KINETIS_I2C_F_ICR_FAST (0x17) +/* Fast (400 kHz): MUL = 1, SCL divider = 160, total: 160 */ +#define KINETIS_I2C_F_ICR_FAST (0x1D) #define KINETIS_I2C_F_MULT_FAST (0) -/* Fast plus (1000 kHz): MUL = 1, SCL divider = 48, total: 48 */ -#define KINETIS_I2C_F_ICR_FAST_PLUS (0x10) +/* Fast plus (1000 kHz): MUL = 1, SCL divider = 64, total: 64 */ +#define KINETIS_I2C_F_ICR_FAST_PLUS (0x12) #define KINETIS_I2C_F_MULT_FAST_PLUS (0) /* I2C 0 device configuration */ diff --git a/boards/mulle/board.c b/boards/mulle/board.c index 4d032d7586..cfe0ca4772 100644 --- a/boards/mulle/board.c +++ b/boards/mulle/board.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2015 Eistec AB + * Copyright (C) 2014-2017 Eistec AB * * This file is subject to the terms and conditions of the GNU Lesser General * Public License v2.1. See the file LICENSE in the top level directory for more @@ -74,17 +74,6 @@ static devfs_t mulle_nor_devfs = { /** @brief Initialize the GPIO pins controlling the power switches. */ static inline void power_pins_init(void); -/** - * @brief Set clock prescalers to safe values - * - * This should be done before switching to FLL/PLL as clock source to ensure - * that all clocks remain within the specified limits. - */ -static inline void set_safe_clock_dividers(void); - -/** @brief Set the FLL source clock to RTC32k */ -static inline void set_fll_source(void); - static void increase_boot_count(void); static int mulle_nvram_init(void); @@ -123,12 +112,8 @@ void board_init(void) * for debug prints as well */ rtt_init(); - /* Set up clocks */ - set_safe_clock_dividers(); - - set_fll_source(); - - kinetis_mcg_set_mode(KINETIS_MCG_FEE); + /* Set 32 kHz clock source */ + SIM->SOPT1 = (SIM->SOPT1 & ~(SIM_SOPT1_OSC32KSEL_MASK)) | SIM_SOPT1_OSC32KSEL(2); /* At this point we need to wait for 1 ms until the clock is stable. * Since the clock is not yet stable we can only guess how long we must @@ -167,36 +152,6 @@ static inline void power_pins_init(void) gpio_clear(MULLE_POWER_VSEC); } -static inline void set_safe_clock_dividers(void) -{ - /* - * We want to achieve the following clocks: - * Core/system: <100MHz - * Bus: <50MHz - * FlexBus: <50MHz - * Flash: <25MHz - * - * using dividers 1-2-2-4 will obey the above limits when using a 96MHz FLL source. - */ - SIM->CLKDIV1 = ( - SIM_CLKDIV1_OUTDIV1(CONFIG_CLOCK_K60_SYS_DIV) | /* Core/System clock divider */ - SIM_CLKDIV1_OUTDIV2(CONFIG_CLOCK_K60_BUS_DIV) | /* Bus clock divider */ - SIM_CLKDIV1_OUTDIV3(CONFIG_CLOCK_K60_FB_DIV) | /* FlexBus divider, not used in Mulle */ - SIM_CLKDIV1_OUTDIV4(CONFIG_CLOCK_K60_FLASH_DIV)); /* Flash clock divider */ - -} - -static inline void set_fll_source(void) -{ - /* Select FLL as source (as opposed to PLL) */ - SIM->SOPT2 &= ~(SIM_SOPT2_PLLFLLSEL_MASK); - /* Use external 32kHz RTC clock as source for OSC32K */ - SIM->SOPT1 = (SIM->SOPT1 & ~(SIM_SOPT1_OSC32KSEL_MASK)) | SIM_SOPT1_OSC32KSEL(2); - - /* Select RTC 32kHz clock as reference clock for the FLL */ - MCG->C7 = (MCG_C7_OSCSEL_MASK); -} - static int mulle_nvram_init(void) { union { diff --git a/boards/mulle/include/board.h b/boards/mulle/include/board.h index 8c2c3e674f..af24f75886 100644 --- a/boards/mulle/include/board.h +++ b/boards/mulle/include/board.h @@ -176,32 +176,5 @@ extern mtd_dev_t *mtd0; #define MULLE_VBAT_ADC_LINE ADC_LINE(6) #define MULLE_VCHR_ADC_LINE ADC_LINE(7) /** @} */ - -/** - * @name K60 clock dividers - */ -/** @{ */ -/** - * System clock divider setting, the actual hardware register value, see reference manual for details. - */ -#define CONFIG_CLOCK_K60_SYS_DIV 0x00 - -/** - * Bus clock divider setting, the actual hardware register value, see reference manual for details - */ -#define CONFIG_CLOCK_K60_BUS_DIV 0x01 - -/** - * Flexbus clock divider setting, the actual hardware register value, see reference manual for details - */ -#define CONFIG_CLOCK_K60_FB_DIV 0x01 - -/** - * Flash clock divider setting, the actual hardware register value, see reference manual for details - */ -#define CONFIG_CLOCK_K60_FLASH_DIV 0x03 - -/** @} */ - #endif /* BOARD_H */ /** @} */ diff --git a/boards/mulle/include/periph_conf.h b/boards/mulle/include/periph_conf.h index fecdf2930e..5ddcb7fdb2 100644 --- a/boards/mulle/include/periph_conf.h +++ b/boards/mulle/include/periph_conf.h @@ -33,30 +33,42 @@ extern "C" * @name Clock system configuration * @{ */ -#define KINETIS_CPU_USE_MCG 1 - -#define KINETIS_MCG_USE_ERC 1 -#define KINETIS_MCG_USE_PLL 0 -#define KINETIS_MCG_DCO_RANGE (96000000U) -#define KINETIS_MCG_ERC_OSCILLATOR 0 -#define KINETIS_MCG_ERC_FRDIV 0 -#define KINETIS_MCG_ERC_RANGE 0 -#define KINETIS_MCG_ERC_FREQ (32768U) - -/** Value of the external crystal or oscillator clock frequency in Hz */ -#define CPU_XTAL_CLK_HZ 8000000u -/** Value of the external 32k crystal or oscillator clock frequency in Hz */ -#define CPU_XTAL32k_CLK_HZ 32768u -/** Value of the slow internal oscillator clock frequency in Hz */ -#define CPU_INT_SLOW_CLK_HZ 32768u -/** Value of the fast internal oscillator clock frequency in Hz */ -#define CPU_INT_FAST_CLK_HZ 4000000u -/** Default System clock value */ -#define DEFAULT_SYSTEM_CLOCK (CPU_XTAL32k_CLK_HZ * 2929u) - -/* bus clock for the peripherals */ -#define CLOCK_CORECLOCK (DEFAULT_SYSTEM_CLOCK) -#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 2) +static const clock_config_t clock_config = { + /* + * This configuration results in the system running from the FLL output with + * the following clock frequencies: + * Core: 48 MHz + * Bus: 48 MHz + * Flex: 24 MHz + * Flash: 24 MHz + */ + /* The board has a 16 MHz crystal, though it is not used in this configuration */ + /* This configuration uses the RTC crystal to provide the base clock, it + * should have better accuracy than the internal slow clock, and lower power + * consumption than using the 16 MHz crystal and the OSC0 module */ + .clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | + SIM_CLKDIV1_OUTDIV3(2) | SIM_CLKDIV1_OUTDIV4(2), + .default_mode = KINETIS_MCG_MODE_FEE, + .erc_range = KINETIS_MCG_ERC_RANGE_LOW, /* Input clock is 32768 Hz */ + .fcrdiv = 0, /* Fast IRC divide by 1 => 4 MHz */ + .oscsel = 1, /* Use RTC for external clock */ + /* 16 pF capacitors yield ca 10 pF load capacitance as required by the + * onboard xtal, not used when OSC0 is disabled */ + .clc = 0b0001, + .fll_frdiv = 0b000, /* Divide by 1 => FLL input 32768 Hz */ + .fll_factor_fei = KINETIS_MCG_FLL_FACTOR_1464, /* FLL freq = 48 MHz */ + .fll_factor_fee = KINETIS_MCG_FLL_FACTOR_1464, /* FLL freq = 48 MHz */ + /* PLL is unavailable when using a 32768 Hz source clock, so the + * configuration below can only be used if the above config is modified to + * use the 16 MHz crystal instead of the RTC. */ + .pll_prdiv = 0b00111, /* Divide by 8 */ + .pll_vdiv = 0b01100, /* Multiply by 36 => PLL freq = 72 MHz */ + .enable_oscillator = false, /* the RTC module provides the clock input signal */ + .select_fast_irc = true, /* Only used for FBI mode */ + .enable_mcgirclk = false, +}; +#define CLOCK_CORECLOCK (48000000ul) +#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 1) /** @} */ /** @@ -328,9 +340,9 @@ static const spi_conf_t spi_config[] = { * @name I2C baud rate configuration * @{ */ -/* Low (10 kHz): MUL = 4, SCL divider = 2560, total: 10240 */ +/* Low (10 kHz): MUL = 2, SCL divider = 2560, total: 5120 */ #define KINETIS_I2C_F_ICR_LOW (0x3D) -#define KINETIS_I2C_F_MULT_LOW (2) +#define KINETIS_I2C_F_MULT_LOW (1) /* Normal (100 kHz): MUL = 2, SCL divider = 240, total: 480 */ #define KINETIS_I2C_F_ICR_NORMAL (0x1F) #define KINETIS_I2C_F_MULT_NORMAL (1) @@ -378,8 +390,14 @@ static const spi_conf_t spi_config[] = { * to the data sheet, the K60 will have a 5 pF parasitic capacitance on the * XTAL32/EXTAL32 connection. The board traces might give some minor parasitic * capacitance as well. */ -/* enable 6pF load capacitance, might need adjusting.. */ -#define RTT_LOAD_CAP_BITS (RTC_CR_SC4P_MASK | RTC_CR_SC2P_MASK | RTC_CR_SC1P_MASK) +/* Use the equation + * CL = (C1 * C2) / (C1 + C2) + Cstray + * with C1 == C2: + * C1 = 2 * (CL - Cstray) + */ +/* enable 14pF load capacitor which will yield a crystal load capacitance of 12 pF */ +#define RTC_LOAD_CAP_BITS (RTC_CR_SC8P_MASK | RTC_CR_SC4P_MASK | RTC_CR_SC2P_MASK) + /** @} */ diff --git a/boards/pba-d-01-kw2x/board.c b/boards/pba-d-01-kw2x/board.c index 31bb8d3cb1..923e665833 100644 --- a/boards/pba-d-01-kw2x/board.c +++ b/boards/pba-d-01-kw2x/board.c @@ -21,8 +21,39 @@ */ #include "board.h" +#include "bit.h" #include "periph/gpio.h" +static inline void modem_clock_init(void) +{ + /* Use the CLK_OUT of the modem as the clock source. */ + + /* Enable GPIO clock gates */ + KW2XDRF_PORT_CLKEN(); + KW2XDRF_CLK_CTRL_CLKEN(); + + /* Modem RST_B is connected to PTB19 and can be used to reset the modem. */ + KW2XDRF_PORT_DEV->PCR[KW2XDRF_RST_PIN] = PORT_PCR_MUX(1); + bit_set32(&KW2XDRF_GPIO->PDDR, KW2XDRF_RST_PIN); + KW2XDRF_GPIO->PCOR = (1 << KW2XDRF_RST_PIN); + + /* Modem GPIO5 is connected to PTC0 and can be used to select CLK_OUT frequency, */ + /* set PTC0 high for CLK_OUT=32.787kHz and low for CLK_OUT=4MHz. */ + KW2XDRF_CLK_CTRL_PORT_DEV->PCR[KW2XDRF_CLK_CTRL_PIN] = PORT_PCR_MUX(1); + bit_set32(&KW2XDRF_CLK_CTRL_GPIO->PDDR, KW2XDRF_CLK_CTRL_PIN); + KW2XDRF_CLK_CTRL_GPIO->PCOR = (1 << KW2XDRF_CLK_CTRL_PIN); + + /* Modem IRQ_B is connected to PTB3, modem interrupt request to the MCU. */ + KW2XDRF_PORT_DEV->PCR[KW2XDRF_IRQ_PIN] = PORT_PCR_MUX(1); + bit_clear32(&KW2XDRF_GPIO->PDDR, KW2XDRF_IRQ_PIN); + + /* release the reset */ + KW2XDRF_GPIO->PSOR = (1 << KW2XDRF_RST_PIN); + + /* wait for modem IRQ_B interrupt request */ + while (KW2XDRF_GPIO->PDIR & (1 << KW2XDRF_IRQ_PIN)); +} + void board_init(void) { /* initialize the on-board LEDs */ @@ -33,6 +64,8 @@ void board_init(void) gpio_init(LED2_PIN, GPIO_OUT); gpio_set(LED2_PIN); + modem_clock_init(); + /* initialize the CPU core */ cpu_init(); } diff --git a/boards/pba-d-01-kw2x/include/periph_conf.h b/boards/pba-d-01-kw2x/include/periph_conf.h index 5dfd2d1a79..e53671ee5f 100644 --- a/boards/pba-d-01-kw2x/include/periph_conf.h +++ b/boards/pba-d-01-kw2x/include/periph_conf.h @@ -33,21 +33,33 @@ extern "C" * @name Clock system configuration * @{ */ -#define KINETIS_CPU_USE_MCG 1 - -#define KINETIS_MCG_USE_ERC 1 -#define KINETIS_MCG_USE_PLL 1 -#define KINETIS_MCG_DCO_RANGE (24000000U) -#define KINETIS_MCG_ERC_OSCILLATOR 0 -#define KINETIS_MCG_ERC_FRDIV 2 -#define KINETIS_MCG_ERC_RANGE 1 -#define KINETIS_MCG_ERC_FREQ 4000000 -#define KINETIS_MCG_PLL_PRDIV 1 -#define KINETIS_MCG_PLL_VDIV0 0 -#define KINETIS_MCG_PLL_FREQ 48000000 - -#define CLOCK_CORECLOCK KINETIS_MCG_PLL_FREQ -#define CLOCK_BUSCLOCK CLOCK_CORECLOCK +static const clock_config_t clock_config = { + /* + * This configuration results in the system running from the PLL output with + * the following clock frequencies: + * Core: 48 MHz + * Bus: 48 MHz + * Flash: 24 MHz + */ + .clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | + SIM_CLKDIV1_OUTDIV4(1), + .default_mode = KINETIS_MCG_MODE_PEE, + /* The modem generates a 4 MHz clock signal */ + .erc_range = KINETIS_MCG_ERC_RANGE_HIGH, + .fcrdiv = 0, /* Fast IRC divide by 1 => 4 MHz */ + .oscsel = 0, /* Use EXTAL0 for external clock */ + .clc = 0, /* OSC0 is unused*/ + .fll_frdiv = 0b010, /* Divide by 128 */ + .fll_factor_fei = KINETIS_MCG_FLL_FACTOR_1464, /* FLL freq = 48 MHz */ + .fll_factor_fee = KINETIS_MCG_FLL_FACTOR_1280, /* FLL freq = 40 MHz */ + .pll_prdiv = 0b00001, /* Divide by 2 */ + .pll_vdiv = 0b00000, /* Multiply by 24 => PLL freq = 48 MHz */ + .enable_oscillator = false, /* Use modem clock from EXTAL0 */ + .select_fast_irc = true, + .enable_mcgirclk = false, +}; +#define CLOCK_CORECLOCK (48000000ul) +#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 1) /** @} */ /** @@ -236,12 +248,12 @@ static const spi_conf_t spi_config[] = { * @{ */ #define I2C_NUMOF (1U) -#define I2C_CLK (48e6) +#define I2C_CLK (CLOCK_BUSCLOCK) #define I2C_0_EN 1 #define I2C_IRQ_PRIO 1 -/* Low (10 kHz): MUL = 4, SCL divider = 2560, total: 10240 */ +/* Low (10 kHz): MUL = 2, SCL divider = 2560, total: 5120 */ #define KINETIS_I2C_F_ICR_LOW (0x3D) -#define KINETIS_I2C_F_MULT_LOW (2) +#define KINETIS_I2C_F_MULT_LOW (1) /* Normal (100 kHz): MUL = 2, SCL divider = 240, total: 480 */ #define KINETIS_I2C_F_ICR_NORMAL (0x1F) #define KINETIS_I2C_F_MULT_NORMAL (1) diff --git a/cpu/k60/cpu.c b/cpu/k60/cpu.c deleted file mode 100644 index 50818f99f6..0000000000 --- a/cpu/k60/cpu.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2015 Eistec AB - * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License v2.1. See the file LICENSE in the top level directory for more - * details. - */ - -#include "cpu.h" -#include "board.h" -#include "periph/init.h" - -/** - * @ingroup cpu_k60 - * @{ - * - * @file - * @brief Implementation of K60 CPU initialization. - * - * @author Joakim Nohlgård - */ - -/** - * @brief Initialize the CPU, set IRQ priorities - */ -void cpu_init(void) -{ - /* initialize the Cortex-M core */ - cortexm_init(); - /* trigger static peripheral initialization */ - periph_init(); -} - -/** @} */ diff --git a/cpu/k60/include/vendor/MK60D10.h b/cpu/k60/include/vendor/MK60D10.h index 0500f52ba8..588b486ded 100644 --- a/cpu/k60/include/vendor/MK60D10.h +++ b/cpu/k60/include/vendor/MK60D10.h @@ -14581,6 +14581,7 @@ typedef struct { #define SIM_SCGC5_LPTMR_MASK SIM_SCGC5_LPTIMER_MASK #define SIM_SCGC5_LPTMR_SHIFT SIM_SCGC5_LPTIMER_SHIFT #define OSC0 OSC +#define MCG_C7_OSCSEL(x) (((uint32_t)(x) << MCG_C7_OSCSEL_SHIFT) & MCG_C7_OSCSEL_MASK) /*! * @} diff --git a/cpu/k64f/cpu.c b/cpu/k64f/cpu.c deleted file mode 100644 index cfb6583bc6..0000000000 --- a/cpu/k64f/cpu.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2015 PHYTEC Messtechnik GmbH - * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License v2.1. See the file LICENSE in the top level directory for more - * details. - */ - -/** - * @ingroup cpu_k64f - * @{ - * - * @file - * @brief Implementation of the K64F CPU initialization - * - * @author Hauke Petersen - * @author Johann Fischer - * @} - */ - -#include -#include "cpu.h" -#include "mcg.h" -#include "cpu_conf.h" -#include "periph/init.h" - -#define SIM_CLKDIV1_60MHZ (SIM_CLKDIV1_OUTDIV1(0) | \ - SIM_CLKDIV1_OUTDIV2(0) | \ - SIM_CLKDIV1_OUTDIV3(1) | \ - SIM_CLKDIV1_OUTDIV4(2)) - -static void cpu_clock_init(void); - -/** - * @brief Initialize the CPU, set IRQ priorities - */ -void cpu_init(void) -{ - /* initialize the Cortex-M core */ - cortexm_init(); - /* initialize the clock system */ - cpu_clock_init(); - /* trigger static peripheral initialization */ - periph_init(); -} - -/** - * @brief Configure the controllers clock system - * - * | Clock name | Run mode frequency (max) | VLPR mode frequency (max) | - * - * | Core | 120 MHz | 4 MHz | - * | System | 120 MHz | 4 MHz | - * | Bus | 60 MHz | 4 MHz | - * | FlexBus | 50 MHz | 800 kHz | - * | Flash | 25 MHz | 4 MHz | - */ -static void cpu_clock_init(void) -{ - /* setup system prescalers */ - SIM->CLKDIV1 = (uint32_t)SIM_CLKDIV1_60MHZ; - - /* RMII RXCLK */ - SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; - PORTA->PCR[18] &= ~(PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)); - - kinetis_mcg_set_mode(KINETIS_MCG_PEE); -} diff --git a/cpu/k22f/cpu.c b/cpu/kinetis_common/cpu.c similarity index 52% rename from cpu/k22f/cpu.c rename to cpu/kinetis_common/cpu.c index 64050322ed..b4182c7334 100644 --- a/cpu/k22f/cpu.c +++ b/cpu/kinetis_common/cpu.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Eistec AB + * Copyright (C) 2017 SKF AB * * This file is subject to the terms and conditions of the GNU Lesser General * Public License v2.1. See the file LICENSE in the top level directory for more @@ -7,11 +7,11 @@ */ /** - * @ingroup cpu_k22f + * @ingroup cpu_kinetis_common * @{ * * @file - * @brief Implementation of the K22F CPU initialization + * @brief Kinetis CPU initialization * * @author Joakim Nohlgård * @} @@ -19,6 +19,7 @@ #include "cpu.h" #include "periph/init.h" +#include "mcg.h" /** * @brief Initialize the CPU, set IRQ priorities @@ -27,6 +28,13 @@ void cpu_init(void) { /* initialize the Cortex-M core */ cortexm_init(); + /* Clear LLS protection */ + /* Clear VLPS, VLPW, VLPR protection */ + /* Note: This register can only be written once after each reset, so we must + * enable all power modes that we wish to use. */ + SMC->PMPROT |= SMC_PMPROT_ALLS_MASK | SMC_PMPROT_AVLP_MASK; + /* initialize the CPU clocking provided by the MCG module */ + kinetis_mcg_init(); /* trigger static peripheral initialization */ periph_init(); } diff --git a/cpu/kinetis_common/include/mcg.h b/cpu/kinetis_common/include/mcg.h index 70eb2f6b16..04ebabb56d 100644 --- a/cpu/kinetis_common/include/mcg.h +++ b/cpu/kinetis_common/include/mcg.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 PHYTEC Messtechnik GmbH + * Copyright (C) 2017 Eistec AB * * This file is subject to the terms and conditions of the GNU Lesser General * Public License v2.1. See the file LICENSE in the top level directory for more @@ -12,31 +13,16 @@ * @brief Implementation of the Kinetis Multipurpose Clock Generator * (MCG) driver * - * Please add mcg.h in cpu conf.h + * Please add mcg.h in cpu_conf.h * and MCG configuration to periph_conf.h * - * MCG neighbor modes matrix: + * The configuration consists of the clock_config struct + * (@ref clock_config_t) and two macros @ref CLOCK_CORECLOCK, + * @ref CLOCK_BUSCLOCK. The two macros are used by other periph + * driver configurations to tell the driver what value the module + * clock is running at. * - * x | FEI | FEE | FBI | FBE | BLPI | BLPE | PBE | PEE - * :---:|:---:|:---:|:---:|:---:|:----:|:----:|:---:|:---: - * PEE | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 - * PBE | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 - * BLPE | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 - * BLPI | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 - * FBE | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 - * FBI | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 - * FEE | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 - * FEI | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 - * - * Each neighbor mode can be selected directly. - * Further, the paths between the following modes are defined: - * - FEI -> PEE - * - BLPE -> PEE - * - PEE -> BLPE - * - FEE -> BLPE - * - FEE -> BLPI - * - BLPE -> FEE - * - BLPI -> FEE + * ### State transition map * * \dot * digraph states { @@ -62,64 +48,73 @@ * } * \enddot * + * The driver will automatically move step by step through the map + * if the requested mode is not a direct neighbor of the current mode. + * * ### MCG Configuration Examples (for periph_conf.h) ### * - * Example for FEI Mode (MCGOUTCLK = 20MHz ... 25MHz): + * #### Example for PEE Mode with an 8 MHz crystal connected to XTAL0/EXTAL0 * - * #define KINETIS_MCG_USE_ERC 0 - * #define KINETIS_MCG_DCO_RANGE (24000000U) + * The resulting PLL output frequency will be 60 MHz, the core will + * be running at the full PLL output frequency. * + * static const clock_config_t clock_config = { + * // safe clock dividers for this CPU + * .clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | + * SIM_CLKDIV1_OUTDIV3(1) | SIM_CLKDIV1_OUTDIV4(2), + * // Select default clocking mode + * .default_mode = KINETIS_MCG_MODE_PEE, + * // The crystal connected to OSC0 is 8 MHz + * .erc_range = KINETIS_MCG_ERC_RANGE_HIGH, + * .fcrdiv = 0, // Fast IRC divide by 1 => 4 MHz + * .oscsel = 0, // Use OSC0 for external clock + * .clc = 0, // Use external load caps on board + * .fll_frdiv = 0b011, // Divide by 256 + * .fll_factor_fei = KINETIS_MCG_FLL_FACTOR_1920, // FLL freq = 60 MHz ? + * .fll_factor_fee = KINETIS_MCG_FLL_FACTOR_1920, // FLL freq = 60 MHz + * .pll_prdiv = 0b00011, // Divide by 4 => PLL input freq = 2 MHz + * .pll_vdiv = 0b00110, // Multiply by 30 => PLL output freq = 60 MHz + * .enable_oscillator = true, // Enable oscillator, EXTAL0 is connected to a crystal + * .select_fast_irc = true, // Use fast IRC when in FBI mode + * .enable_mcgirclk = false, // We don't need the internal reference clock while running in PEE mode + * }; + * #define CLOCK_CORECLOCK (60000000ul) + * #define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 1) * - * Example for FEE Mode, 32768Hz Crystal, - * (MCGOUTCLK = 24MHz): + * #### Example for FEE Mode, 32.768 kHz crystal connected to RTC * - * #define KINETIS_MCG_USE_ERC 1 - * #define KINETIS_MCG_USE_PLL 0 - * #define KINETIS_MCG_DCO_RANGE (24000000U) - * #define KINETIS_MCG_ERC_OSCILLATOR 1 - * #define KINETIS_MCG_ERC_FRDIV 0 - * #define KINETIS_MCG_ERC_RANGE 0 - * #define KINETIS_MCG_ERC_FREQ (32768U) + * The resulting FLL output frequency will be circa 72 MHz, the core + * will be running at the full FLL output frequency. * + * static const clock_config_t clock_config = { + * // safe clock dividers for this CPU + * .clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | + * SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV3(2), + * .default_mode = KINETIS_MCG_MODE_FEE, + * // The board has a 16 MHz crystal, though it is not used in this configuration + * .erc_range = KINETIS_MCG_ERC_RANGE_VERY_HIGH, + * .fcrdiv = 0, // Fast IRC divide by 1 => 4 MHz + * .oscsel = 1, // Use RTC for external clock + * .clc = 0b0001, // 16 pF capacitors yield ca 10 pF load capacitance + * .fll_frdiv = 0b000, // Divide by 1 => FLL input 32768 Hz + * .fll_factor_fei = KINETIS_MCG_FLL_FACTOR_1920, // FLL freq = 60 MHz ? + * .fll_factor_fee = KINETIS_MCG_FLL_FACTOR_2197, // FLL freq = 71.991296 MHz + * .pll_prdiv = 0b00111, // Divide by 8 + * .pll_vdiv = 0b01100, // Multiply by 36 => PLL freq = 72 MHz + * .enable_oscillator = false, // OSC0 disabled + * .select_fast_irc = true, // Use fast IRC for internal reference clock + * .enable_mcgirclk = false, // We don't need the internal reference clock while running in FEE mode + * }; + * #define CLOCK_CORECLOCK (71991296ul) + * #define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 2) * - * Example for FEE Mode, external 4MHz reference - * (\f$MCGOUTCLK - * = \frac{ERC_{\mathrm{freq}}\cdot FFL_{\mathrm{Factor}}}{FRDIV} - * = \frac{4\,\mathrm{MHz}\cdot 732}{128} = 22.875\,\mathrm{MHz}\f$): - * - * #define KINETIS_MCG_USE_ERC 1 - * #define KINETIS_MCG_USE_PLL 0 - * #define KINETIS_MCG_DCO_RANGE (24000000U) - * #define KINETIS_MCG_ERC_OSCILLATOR 0 - * #define KINETIS_MCG_ERC_FRDIV 2 - * #define KINETIS_MCG_ERC_RANGE 1 - * #define KINETIS_MCG_ERC_FREQ (4000000U) - * - * Example for PEE Mode, external 4MHz reference - * (\f$MCGOUTCLK - * = \frac{ERC_{\mathrm{freq}}\cdot VDIV0}{PRDIV} - * = \frac{4\,\mathrm{MHz}\cdot 24}{2} = 48\,\mathrm{MHz}\f$): - * - * #define KINETIS_MCG_USE_ERC 1 - * #define KINETIS_MCG_USE_PLL 1 - * #define KINETIS_MCG_DCO_RANGE (24000000U) - * #define KINETIS_MCG_ERC_OSCILLATOR 0 - * #define KINETIS_MCG_ERC_FRDIV 2 - * #define KINETIS_MCG_ERC_RANGE 1 - * #define KINETIS_MCG_ERC_FREQ (4000000U) - * #define KINETIS_MCG_PLL_PRDIV 1 - * #define KINETIS_MCG_PLL_VDIV0 0 - * #define KINETIS_MCG_PLL_FREQ (48000000U) - * - * - * The desired mode can be selected in cpu.c:cpu_clock_init() - * with kinetis_mcg_set_mode(KINETIS_MCG_PEE); * @{ * * @file * @brief Interface definition for the Kinetis MCG driver. * * @author Johann Fischer + * @author Joakim Nohlgård */ #ifndef MCG_H @@ -127,35 +122,52 @@ #include "periph_conf.h" -#if KINETIS_CPU_USE_MCG - #ifdef __cplusplus extern "C" { #endif -typedef enum kinetis_mcg_mode { - KINETIS_MCG_PEE = 0, /**< PLL Engaged External Mode */ - KINETIS_MCG_PBE, /**< PLL Bypassed External Mode */ - KINETIS_MCG_BLPE, /**< FLL Bypassed Low Power External Mode */ - KINETIS_MCG_BLPI, /**< FLL Bypassed Low Power Internal Mode */ - KINETIS_MCG_FBE, /**< FLL Bypassed External Mode */ - KINETIS_MCG_FBI, /**< FLL Bypassed Internal Mode */ - KINETIS_MCG_FEE, /**< FLL Engaged External Mode */ - KINETIS_MCG_FEI, /**< FLL Engaged Internal Mode */ -} kinetis_mcg_mode_t; +#if DOXYGEN +/** + * @brief Core clock frequency, used by the ARM core and certain hardware modules in Kinetis CPUs + * + * The clock is derived from the MCG output clock divided by an integer divisor, + * which is controlled by the @ref clock_config_t::clkdiv1 settings + */ +#define CLOCK_CORECLOCK (MCGOUTCLK) +/** + * @brief Bus clock frequency, used by several hardware modules in Kinetis CPUs + * + * The clock is derived from the MCG output clock divided by an integer divisor, + * which is controlled by the @ref clock_config_t::clkdiv1 settings + */ +#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / x) +#endif + +/** + * @brief Switch the MCG to the specified clocking mode + * + * Depending on the current clocking mode, this function may step through + * several other clocking modes in order to be able to reach the target mode. + * + * @param[in] mode Target mode + * + * @return 0 on success + * @return <0 on error + */ +int kinetis_mcg_set_mode(kinetis_mcg_mode_t mode); /** * @brief Initialize the MCG * + * The configuration is found in the clock_config struct defined in periph_conf.h */ -int kinetis_mcg_set_mode(kinetis_mcg_mode_t mode); +void kinetis_mcg_init(void); #ifdef __cplusplus } #endif -#endif /* KINETIS_CPU_USE_MCG */ /** @} */ #endif /* MCG_H */ diff --git a/cpu/kinetis_common/include/periph_cpu.h b/cpu/kinetis_common/include/periph_cpu.h index 428cfc8c0e..9e7188425f 100644 --- a/cpu/kinetis_common/include/periph_cpu.h +++ b/cpu/kinetis_common/include/periph_cpu.h @@ -20,6 +20,7 @@ #define PERIPH_CPU_H #include +#include #include "cpu.h" @@ -323,6 +324,112 @@ typedef struct { uint8_t mode; /**< UART mode: data bits, parity, stop bits */ } uart_conf_t; +#if !defined(KINETIS_HAVE_PLL) +#if defined(MCG_C6_PLLS_MASK) || DOXYGEN +/** + * @brief Defined to 1 if the MCG in this Kinetis CPU has a PLL + */ +#define KINETIS_HAVE_PLL 1 +#else +#define KINETIS_HAVE_PLL 0 +#endif +#endif /* !defined(KINETIS_HAVE_PLL) */ + +/** + * @brief Kinetis possible MCG modes + */ +typedef enum kinetis_mcg_mode { + KINETIS_MCG_MODE_FEI = 0, /**< FLL Engaged Internal Mode */ + KINETIS_MCG_MODE_FEE = 1, /**< FLL Engaged External Mode */ + KINETIS_MCG_MODE_FBI = 2, /**< FLL Bypassed Internal Mode */ + KINETIS_MCG_MODE_FBE = 3, /**< FLL Bypassed External Mode */ + KINETIS_MCG_MODE_BLPI = 4, /**< FLL Bypassed Low Power Internal Mode */ + KINETIS_MCG_MODE_BLPE = 5, /**< FLL Bypassed Low Power External Mode */ +#if KINETIS_HAVE_PLL + KINETIS_MCG_MODE_PBE = 6, /**< PLL Bypassed External Mode */ + KINETIS_MCG_MODE_PEE = 7, /**< PLL Engaged External Mode */ +#endif + KINETIS_MCG_MODE_NUMOF, /**< Number of possible modes */ +} kinetis_mcg_mode_t; + +/** + * @brief Kinetis MCG FLL multiplier settings + */ +typedef enum { + /** FLL multiplier = 640 */ + KINETIS_MCG_FLL_FACTOR_640 = (MCG_C4_DRST_DRS(0)), + /** FLL multiplier = 732 */ + KINETIS_MCG_FLL_FACTOR_732 = (MCG_C4_DRST_DRS(0) | MCG_C4_DMX32_MASK), + /** FLL multiplier = 1280 */ + KINETIS_MCG_FLL_FACTOR_1280 = (MCG_C4_DRST_DRS(1)), + /** FLL multiplier = 1464 */ + KINETIS_MCG_FLL_FACTOR_1464 = (MCG_C4_DRST_DRS(1) | MCG_C4_DMX32_MASK), + /** FLL multiplier = 1920 */ + KINETIS_MCG_FLL_FACTOR_1920 = (MCG_C4_DRST_DRS(2)), + /** FLL multiplier = 2197 */ + KINETIS_MCG_FLL_FACTOR_2197 = (MCG_C4_DRST_DRS(2) | MCG_C4_DMX32_MASK), + /** FLL multiplier = 2560 */ + KINETIS_MCG_FLL_FACTOR_2560 = (MCG_C4_DRST_DRS(3)), + /** FLL multiplier = 2929 */ + KINETIS_MCG_FLL_FACTOR_2929 = (MCG_C4_DRST_DRS(3) | MCG_C4_DMX32_MASK), +} kinetis_mcg_fll_t; + +/** + * @brief Kinetis FLL external reference clock range settings + */ +typedef enum { + KINETIS_MCG_ERC_RANGE_LOW = MCG_C2_RANGE0(0), /**< for 31.25-39.0625 kHz crystal */ + KINETIS_MCG_ERC_RANGE_HIGH = MCG_C2_RANGE0(1), /**< for 3-8 MHz crystal */ + KINETIS_MCG_ERC_RANGE_VERY_HIGH = MCG_C2_RANGE0(2), /**< for 8-32 MHz crystal */ +} kinetis_mcg_erc_range_t; + +/** + * @brief Clock configuration for Kinetis CPUs + */ +typedef struct { + /** Clock divider bitfield setting, see reference manual for SIM_CLKDIV1 */ + uint32_t clkdiv1; + /** MCG mode used after initialization, see kinetis_mcg_mode_t */ + kinetis_mcg_mode_t default_mode; + /** ERC range setting, see kinetis_mcg_erc_range_t */ + kinetis_mcg_erc_range_t erc_range; + /** Fast internal reference clock divider, see reference manual for MCG_SC[FCRDIV] */ + uint8_t fcrdiv; + /** Oscillator selection, see reference manual for MCG_C7[OSCSEL] */ + uint8_t oscsel; + /** Capacitor Load configuration bits, see reference manual for OSC_CR */ + uint8_t clc; + /** FLL ERC divider setting, see reference manual for MCG_C1[FRDIV] */ + uint8_t fll_frdiv; + /** FLL multiplier when running in FEI mode */ + kinetis_mcg_fll_t fll_factor_fei; + /** FLL multiplier when running in FEE mode */ + kinetis_mcg_fll_t fll_factor_fee; +#if KINETIS_HAVE_PLL + /** PLL ERC divider setting, see reference manual for MCG_C5[PRDIV] */ + uint8_t pll_prdiv; + /** PLL VCO divider setting, see reference manual for MCG_C6[VDIV0] */ + uint8_t pll_vdiv; +#endif /* KINETIS_HAVE_PLL */ + /** + * @brief External reference clock selection + * + * True: Use oscillator circuit with external crystal. + * False: Use external clock signal directly. + */ + bool enable_oscillator; + /** + * @brief Use fast internal reference clock for MCGIRCLK + * + * See reference manual for MCG module and MCG_C2[IRCS] + */ + bool select_fast_irc; + /** + * @brief Enable MCGIRCLK output from MCG for use as alternate clock in some modules + */ + bool enable_mcgirclk; +} clock_config_t; + /** * @brief CPU internal function for initializing PORTs * diff --git a/cpu/kinetis_common/periph/mcg.c b/cpu/kinetis_common/periph/mcg.c index bbcd16c525..b5eaa3f734 100644 --- a/cpu/kinetis_common/periph/mcg.c +++ b/cpu/kinetis_common/periph/mcg.c @@ -21,126 +21,35 @@ */ #include -#include "mcg.h" #include "periph_conf.h" - -#if KINETIS_CPU_USE_MCG - -#if defined(MCG_C6_PLLS_MASK) -#define KINETIS_HAVE_PLL 1 -#else -#define KINETIS_HAVE_PLL 0 -#endif +#include "mcg.h" +#include "bit.h" /* Pathfinding for the clocking modes, this table lists the next mode in the * chain when moving from mode to mode */ static const uint8_t mcg_mode_routing[8][8] = { - {0, 1, 1, 1, 1, 1, 1, 1}, /* from PEE */ - {0, 1, 2, 4, 4, 4, 4, 4}, /* from PBE */ - {1, 1, 2, 4, 4, 4, 4, 4}, /* from BLPE */ - {5, 5, 5, 3, 5, 5, 5, 5}, /* from BLPI */ - {1, 1, 2, 5, 4, 5, 6, 7}, /* from FBE */ - {4, 4, 4, 3, 4, 5, 6, 7}, /* from FBI */ - {4, 4, 4, 5, 4, 5, 6, 7}, /* from FEE */ - {4, 4, 4, 5, 4, 5, 6, 7}, /* from FEI */ + {0, 1, 2, 3, 2, 3, 3, 3}, /* from FEI */ + {0, 1, 2, 3, 2, 3, 3, 3}, /* from FEE */ + {0, 1, 2, 3, 4, 3, 3, 3}, /* from FBI */ + {0, 1, 2, 3, 2, 5, 6, 6}, /* from FBE */ + {2, 2, 2, 2, 4, 2, 2, 2}, /* from BLPI */ + {3, 3, 3, 3, 3, 5, 6, 6}, /* from BLPE */ + {3, 3, 3, 3, 3, 5, 6, 7}, /* from PBE */ + {6, 6, 6, 6, 6, 6, 6, 7}, /* from PEE */ }; -static uint8_t current_mode = KINETIS_MCG_FEI; - -#define KINETIS_MCG_FLL_FACTOR_640 0 -#define KINETIS_MCG_FLL_FACTOR_732 (MCG_C4_DRST_DRS(0) | MCG_C4_DMX32_MASK) -#define KINETIS_MCG_FLL_FACTOR_1280 (MCG_C4_DRST_DRS(1)) -#define KINETIS_MCG_FLL_FACTOR_1464 (MCG_C4_DRST_DRS(1) | MCG_C4_DMX32_MASK) -#define KINETIS_MCG_FLL_FACTOR_1920 (MCG_C4_DRST_DRS(2)) -#define KINETIS_MCG_FLL_FACTOR_2197 (MCG_C4_DRST_DRS(2) | MCG_C4_DMX32_MASK) -#define KINETIS_MCG_FLL_FACTOR_2560 (MCG_C4_DRST_DRS(3)) -#define KINETIS_MCG_FLL_FACTOR_2929 (MCG_C4_DRST_DRS(3) | MCG_C4_DMX32_MASK) - -#ifndef KINETIS_MCG_DCO_RANGE -#define KINETIS_MCG_DCO_RANGE (48000000U) -#endif - -/* Default DCO_RANGE should be defined in periph_conf.h */ -#if (KINETIS_MCG_DCO_RANGE == 24000000U) -#define KINETIS_MCG_FLL_FACTOR_FEI KINETIS_MCG_FLL_FACTOR_640 -#define KINETIS_MCG_FLL_FACTOR_FEE KINETIS_MCG_FLL_FACTOR_732 -#elif (KINETIS_MCG_DCO_RANGE == 48000000U) -#define KINETIS_MCG_FLL_FACTOR_FEI KINETIS_MCG_FLL_FACTOR_1280 -#define KINETIS_MCG_FLL_FACTOR_FEE KINETIS_MCG_FLL_FACTOR_1464 -#elif (KINETIS_MCG_DCO_RANGE == 72000000U) -#define KINETIS_MCG_FLL_FACTOR_FEI KINETIS_MCG_FLL_FACTOR_1920 -#define KINETIS_MCG_FLL_FACTOR_FEE KINETIS_MCG_FLL_FACTOR_2197 -#elif (KINETIS_MCG_DCO_RANGE == 96000000U) -#define KINETIS_MCG_FLL_FACTOR_FEI KINETIS_MCG_FLL_FACTOR_2560 -#define KINETIS_MCG_FLL_FACTOR_FEE KINETIS_MCG_FLL_FACTOR_2929 -#else -#error "KINETIS_MCG_DCO_RANGE is wrong" -#endif - -#ifndef KINETIS_MCG_USE_FAST_IRC -#define KINETIS_MCG_USE_FAST_IRC 0 -#endif - -#if (KINETIS_MCG_USE_ERC == 0) -#define KINETIS_MCG_USE_ERC 0 -#define KINETIS_MCG_USE_PLL 0 -#define KINETIS_MCG_ERC_FREQ 0 -#define KINETIS_MCG_ERC_FRDIV 0 -#define KINETIS_MCG_ERC_RANGE 0 -#define KINETIS_MCG_ERC_OSCILLATOR 0 -#endif - -#if (KINETIS_MCG_USE_PLL == 0) -#define KINETIS_MCG_PLL_PRDIV 0 -#define KINETIS_MCG_PLL_VDIV0 0 -#define KINETIS_MCG_PLL_FREQ 0 -#endif - -#ifndef KINETIS_MCG_OSC_CLC -#define KINETIS_MCG_OSC_CLC 0 -#endif - -#ifndef KINETIS_MCG_ERC_OSCILLATOR -#error "KINETIS_MCG_ERC_OSCILLATOR not defined in periph_conf.h" -#endif - -#ifndef KINETIS_MCG_ERC_FREQ -#error "KINETIS_MCG_ERC_FREQ not defined in periph_conf.h" -#endif - -#ifndef KINETIS_MCG_ERC_FRDIV -#error "KINETIS_MCG_ERC_FRDIV not defined in periph_conf.h" -#endif - -#ifndef KINETIS_MCG_ERC_RANGE -#error "KINETIS_MCG_ERC_RANGE not defined in periph_conf.h" -#endif - -#if KINETIS_HAVE_PLL -#ifndef KINETIS_MCG_PLL_PRDIV -#error "KINETIS_MCG_PLL_PRDIV not defined in periph_conf.h" -#endif - -#ifndef KINETIS_MCG_PLL_VDIV0 -#error "KINETIS_MCG_PLL_VDIV0 not defined in periph_conf.h" -#endif - -#ifndef KINETIS_MCG_PLL_FREQ -#error "KINETIS_MCG_PLL_FREQ not defined in periph_conf.h" -#endif +/* The CPU is in FEI mode after hardware reset */ +static kinetis_mcg_mode_t current_mode = KINETIS_MCG_MODE_FEI; /** * @brief Disable Phase Locked Loop (PLL) - * */ static inline void kinetis_mcg_disable_pll(void) { - MCG->C5 = (uint8_t)0; - MCG->C6 = (uint8_t)0; -} -#else -static inline void kinetis_mcg_disable_pll(void) {} +#if KINETIS_HAVE_PLL + bit_clear8(&MCG->C6, MCG_C6_PLLS_SHIFT); #endif /* KINETIS_HAVE_PLL */ +} /** * @brief Set Frequency Locked Loop (FLL) factor. @@ -149,58 +58,48 @@ static inline void kinetis_mcg_disable_pll(void) {} * FLL factor will be selected by DRST_DRS and DMX32 bits * and depends on KINETIS_MCG_DCO_RANGE value. */ -static inline void kinetis_mcg_set_fll_factor(uint8_t factor) +static inline void kinetis_mcg_set_fll_factor(kinetis_mcg_fll_t factor) { - MCG->C4 &= ~(uint8_t)(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK); - MCG->C4 |= (uint8_t)(factor); + MCG->C4 = (MCG->C4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (uint8_t)factor; } -#ifdef OSC0 -/* Kinetis with OSC module */ /** * @brief Enable Oscillator module - * - * The module settings depend on KINETIS_MCG_ERC_RANGE - * KINETIS_MCG_ERC_OSCILLATOR values. */ static void kinetis_mcg_enable_osc(void) { - if (KINETIS_MCG_ERC_RANGE == 1) { - /* select high frequency range and oscillator clock */ - MCG->C2 = (uint8_t)(MCG_C2_RANGE0(1)); - } - else if (KINETIS_MCG_ERC_RANGE == 2) { - /* select very high frequency range and osciallor clock */ - MCG->C2 = (uint8_t)(MCG_C2_RANGE0(2)); - } - else { - /* select low frequency range and osciallor clock */ - MCG->C2 = (uint8_t)(MCG_C2_RANGE0(0)); - } - - OSC0->CR = (uint8_t)(OSC_CR_ERCLKEN_MASK | OSC_CR_EREFSTEN_MASK - | (KINETIS_MCG_OSC_CLC & 0xf)); + /* Configure ERC range for the DCO input. */ + MCG->C2 = (MCG->C2 & ~MCG_C2_RANGE0_MASK) | clock_config.erc_range; +#if defined(OSC0) + /* Kinetis CPU with OSC module */ /* Enable Oscillator */ - if (KINETIS_MCG_ERC_OSCILLATOR) { - MCG->C2 |= (uint8_t)(MCG_C2_EREFS0_MASK); + if (clock_config.enable_oscillator) { + /* Configure oscillator */ + OSC0->CR = (uint8_t)(OSC_CR_ERCLKEN_MASK | OSC_CR_EREFSTEN_MASK | + (clock_config.clc & 0xf)); + bit_set8(&MCG->C2, MCG_C2_EREFS0_SHIFT); - /* wait fo OSC initialization */ + /* wait for OSC initialization */ while ((MCG->S & MCG_S_OSCINIT0_MASK) == 0) {} } -} + else { + bit_clear8(&MCG->C2, MCG_C2_EREFS0_SHIFT); + } #elif defined(RSIM) -/** - * @brief Enable oscillator from RSIM module - * - * This is for Kinetis CPUs with a radio system integration module which can - * provide an oscillator output. - */ -static void kinetis_mcg_enable_osc(void) -{ + /* Kinetis CPU with a radio system integration module which can provide an + * oscillator output. */ + + /* The CPUs with RSIM (currently only KW41Z, KW31Z, KW21Z) ignore the EREFS0 + * bit in MCG_C2 because they have no OSC module. These CPUs need to use the + * RF oscillator inside the RSIM module if an oscillator is needed. */ + /* The external reference clock line on these CPUs is permanently connected + * to the RSIM clock output, thus the RSIM, instead of the MCG, controls the + * external clock source selection. */ + /* Enable RF oscillator circuit */ /* Current setting is that the OSC only runs in RUN and WAIT modes, see ref.man. */ - *bme_bitfield32(&RSIM->CONTROL, RSIM_CONTROL_RF_OSC_EN_SHIFT, 4) = RSIM_CONTROL_RF_OSC_EN(1); + RSIM->CONTROL = (RSIM->CONTROL & ~RSIM_CONTROL_RF_OSC_EN_MASK) | RSIM_CONTROL_RF_OSC_EN(1); /* Chip errata * e10224: RSIM: XTAL_OUT_EN signal from the pin is enabled by default * @@ -214,10 +113,19 @@ static void kinetis_mcg_enable_osc(void) */ bit_set32(&RSIM->RF_OSC_CTRL, RSIM_RF_OSC_CTRL_RADIO_EXT_OSC_OVRD_EN_SHIFT); - /* Wait for oscillator ready signal */ - while((RSIM->CONTROL & RSIM_CONTROL_RF_OSC_READY_MASK) == 0) {} + if (clock_config.enable_oscillator) { + /* Disable RF oscillator bypass, if it was enabled before */ + bit_clear32(&RSIM->RF_OSC_CTRL, RSIM_RF_OSC_CTRL_RF_OSC_BYPASS_EN_SHIFT); + /* Wait for oscillator ready signal */ + while((RSIM->CONTROL & RSIM_CONTROL_RF_OSC_READY_MASK) == 0) {} + } + else { + /* Enable RF oscillator bypass, to use the EXTAL pin as external clock + * source without the oscillator circuit */ + bit_set32(&RSIM->RF_OSC_CTRL, RSIM_RF_OSC_CTRL_RF_OSC_BYPASS_EN_SHIFT); + } +#endif /* defined OSC0/RSIM */ } -#endif /** * @brief Initialize the FLL Engaged Internal Mode. @@ -228,12 +136,15 @@ static void kinetis_mcg_enable_osc(void) */ static void kinetis_mcg_set_fei(void) { - kinetis_mcg_set_fll_factor(KINETIS_MCG_FLL_FACTOR_FEI); - /* enable and select slow internal reference clock */ - MCG->C1 = (uint8_t)(MCG_C1_CLKS(0) | MCG_C1_IREFS_MASK); + /* The internal reference clock frequency and source is configured during + * initialization */ + /* Select the correct FLL multiplier for the target frequency */ + kinetis_mcg_set_fll_factor(clock_config.fll_factor_fei); + /* select slow internal reference clock for FLL source and use FLL output clock */ + MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | (MCG_C1_CLKS(0) | MCG_C1_IREFS_MASK); - /* set to defaults */ - MCG->C2 = (uint8_t)0; + /* Make sure FLL is enabled if we have somehow ended up in an unknown state */ + bit_clear8(&MCG->C2, MCG_C2_LP_SHIFT); /* source of the FLL reference clock shall be internal reference clock */ while ((MCG->S & MCG_S_IREFST_MASK) == 0) {} @@ -241,8 +152,7 @@ static void kinetis_mcg_set_fei(void) /* Wait until output of the FLL is selected */ while (MCG->S & (MCG_S_CLKST_MASK)) {} - kinetis_mcg_disable_pll(); - current_mode = KINETIS_MCG_FEI; + current_mode = KINETIS_MCG_MODE_FEI; } /** @@ -255,16 +165,15 @@ static void kinetis_mcg_set_fei(void) static void kinetis_mcg_set_fee(void) { kinetis_mcg_enable_osc(); - kinetis_mcg_set_fll_factor(KINETIS_MCG_FLL_FACTOR_FEE); + kinetis_mcg_set_fll_factor(clock_config.fll_factor_fee); - /* select external reference clock and divide factor */ - MCG->C1 = (uint8_t)(MCG_C1_CLKS(0) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV)); + /* enable and select external reference clock */ + MCG->C1 = (MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(0)); /* Wait until output of FLL is selected */ while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(0)) {} - kinetis_mcg_disable_pll(); - current_mode = KINETIS_MCG_FEE; + current_mode = KINETIS_MCG_MODE_FEE; } /** @@ -278,17 +187,16 @@ static void kinetis_mcg_set_fee(void) */ static void kinetis_mcg_set_fbi(void) { - /* select IRC source */ - if (KINETIS_MCG_USE_FAST_IRC) { - MCG->C2 = (uint8_t)(MCG_C2_IRCS_MASK); - } - else { - MCG->C2 = (uint8_t)(0); - } + /* The internal reference clock frequency and source is configured during + * initialization */ + /* Select the correct FLL multiplier for the target frequency */ + kinetis_mcg_set_fll_factor(clock_config.fll_factor_fei); - kinetis_mcg_set_fll_factor(KINETIS_MCG_FLL_FACTOR_FEI); - /* enable and select slow internal reference clock */ - MCG->C1 = (uint8_t)(MCG_C1_CLKS(1) | MCG_C1_IREFS_MASK); + /* Re-enable FLL when coming from BLPI mode */ + bit_clear8(&MCG->C2, MCG_C2_LP_SHIFT); + + /* enable and select slow internal reference clock for the FLL */ + MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | (MCG_C1_CLKS(1) | MCG_C1_IREFS_MASK); /* Wait until output of IRC is selected */ while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(1)) {} @@ -296,8 +204,7 @@ static void kinetis_mcg_set_fbi(void) /* source of the FLL reference clock shall be internal reference clock */ while ((MCG->S & MCG_S_IREFST_MASK) == 0) {} - kinetis_mcg_disable_pll(); - current_mode = KINETIS_MCG_FBI; + current_mode = KINETIS_MCG_MODE_FBI; } /** @@ -311,19 +218,20 @@ static void kinetis_mcg_set_fbi(void) static void kinetis_mcg_set_fbe(void) { kinetis_mcg_enable_osc(); - kinetis_mcg_set_fll_factor(KINETIS_MCG_FLL_FACTOR_FEE); + /* Select the correct FLL multiplier for the target frequency */ + kinetis_mcg_set_fll_factor(clock_config.fll_factor_fee); - /* FLL is not disabled in bypass mode */ - MCG->C2 &= ~(uint8_t)(MCG_C2_LP_MASK); + /* Re-enable FLL when coming from BLPE mode */ + bit_clear8(&MCG->C2, MCG_C2_LP_SHIFT); - /* select external reference clock and divide factor */ - MCG->C1 = (uint8_t)(MCG_C1_CLKS(2) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV)); + /* select external reference clock for FLL source */ + MCG->C1 = (MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(2)); /* Wait until ERC is selected */ while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) {} kinetis_mcg_disable_pll(); - current_mode = KINETIS_MCG_FBE; + current_mode = KINETIS_MCG_MODE_FBE; } @@ -331,26 +239,28 @@ static void kinetis_mcg_set_fbe(void) * @brief Initialize the FLL Bypassed Low Power Internal Mode. * * MCGOUTCLK is derived from IRC. - * FLL and PLL are disable. + * FLL and PLL are disabled. * Previous and next allowed mode is FBI. */ static void kinetis_mcg_set_blpi(void) { - MCG->C2 |= (uint8_t)(MCG_C2_LP_MASK); - current_mode = KINETIS_MCG_BLPI; + bit_set8(&MCG->C2, MCG_C2_LP_SHIFT); + kinetis_mcg_disable_pll(); + current_mode = KINETIS_MCG_MODE_BLPI; } /** * @brief Initialize the FLL Bypassed Low Power External Mode. * * MCGOUTCLK is derived from ERC. - * FLL and PLL are disable. + * FLL and PLL are disabled. * Previous and next allowed mode: FBE or PBE. */ static void kinetis_mcg_set_blpe(void) { - MCG->C2 |= (uint8_t)(MCG_C2_LP_MASK); - current_mode = KINETIS_MCG_BLPE; + bit_set8(&MCG->C2, MCG_C2_LP_SHIFT); + kinetis_mcg_disable_pll(); + current_mode = KINETIS_MCG_MODE_BLPE; } #if KINETIS_HAVE_PLL @@ -366,23 +276,17 @@ static void kinetis_mcg_set_blpe(void) */ static void kinetis_mcg_set_pbe(void) { - /* select external reference clock and divide factor */ - MCG->C1 = (uint8_t)(MCG_C1_CLKS(2) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV)); + /* PLL is enabled, but put in bypass mode */ + bit_clear8(&MCG->C2, MCG_C2_LP_SHIFT); + + /* select external reference clock instead of FLL/PLL */ + MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(2); /* Wait until ERC is selected */ while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) {} - /* PLL is not disabled in bypass mode */ - MCG->C2 &= ~(uint8_t)(MCG_C2_LP_MASK); - - /* set external reference devider */ - MCG->C5 = (uint8_t)(MCG_C5_PRDIV0(KINETIS_MCG_PLL_PRDIV)); - - /* set external reference devider */ - MCG->C6 = (uint8_t)(MCG_C6_VDIV0(KINETIS_MCG_PLL_VDIV0)); - /* select PLL */ - MCG->C6 |= (uint8_t)(MCG_C6_PLLS_MASK); + bit_set8(&MCG->C6, MCG_C6_PLLS_SHIFT); /* Wait until the source of the PLLS clock is PLL */ while ((MCG->S & MCG_S_PLLST_MASK) == 0) {} @@ -390,7 +294,7 @@ static void kinetis_mcg_set_pbe(void) /* Wait until PLL locked */ while ((MCG->S & MCG_S_LOCK0_MASK) == 0) {} - current_mode = KINETIS_MCG_PBE; + current_mode = KINETIS_MCG_MODE_PBE; } /** @@ -407,50 +311,162 @@ static void kinetis_mcg_set_pee(void) /* Wait until output of the PLL is selected */ while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) {} - current_mode = KINETIS_MCG_PEE; + current_mode = KINETIS_MCG_MODE_PEE; } #endif /* KINETIS_HAVE_PLL */ int kinetis_mcg_set_mode(kinetis_mcg_mode_t mode) { - if (mode > KINETIS_MCG_FEI) { + if (mode >= KINETIS_MCG_MODE_NUMOF) { return -1; } - while (current_mode != mode) { + + /* Using `do` because if we already are on the desired mode we still want to + * update the hardware settings, e.g. when using FEI mode (since FEI is the + * hardware reset default) */ + do { switch(mcg_mode_routing[current_mode][mode]) { + case KINETIS_MCG_MODE_FEI: + kinetis_mcg_set_fei(); + break; + case KINETIS_MCG_MODE_FEE: + kinetis_mcg_set_fee(); + break; + case KINETIS_MCG_MODE_FBI: + kinetis_mcg_set_fbi(); + break; + case KINETIS_MCG_MODE_FBE: + kinetis_mcg_set_fbe(); + break; + case KINETIS_MCG_MODE_BLPI: + kinetis_mcg_set_blpi(); + break; + case KINETIS_MCG_MODE_BLPE: + kinetis_mcg_set_blpe(); + break; #if KINETIS_HAVE_PLL - case KINETIS_MCG_PEE: + case KINETIS_MCG_MODE_PEE: kinetis_mcg_set_pee(); break; - case KINETIS_MCG_PBE: + case KINETIS_MCG_MODE_PBE: kinetis_mcg_set_pbe(); break; #endif /* KINETIS_HAVE_PLL */ - case KINETIS_MCG_BLPE: - kinetis_mcg_set_blpe(); - break; - case KINETIS_MCG_BLPI: - kinetis_mcg_set_blpi(); - break; - case KINETIS_MCG_FBE: - kinetis_mcg_set_fbe(); - break; - case KINETIS_MCG_FBI: - kinetis_mcg_set_fbi(); - break; - case KINETIS_MCG_FEE: - kinetis_mcg_set_fee(); - break; - case KINETIS_MCG_FEI: - kinetis_mcg_set_fei(); - break; default: return -1; } - } + } while (current_mode != mode); return 0; } -#endif /* KINETIS_CPU_USE_MCG */ +/** + * @brief Go to a safe clocking mode that should work for all boards regardless + * of external components + * + * If the board is warm rebooting, for example when starting RIOT from a boot loader, + * the MCG may be in a different state than what we expect. We need to carefully + * step back to a mode which is clocked by the internal reference clock before + * trying to modify the clock settings. + */ +static void kinetis_mcg_set_safe_mode(void) +{ + if (MCG->C2 & MCG_C2_LP_MASK) { + /* We are currently in BLPE or BLPI */ + /* Leave LP mode */ + /* Moving to either of FBI, FBE, PBE */ + bit_clear8(&MCG->C2, MCG_C2_LP_SHIFT); + } +#if KINETIS_HAVE_PLL + /* See if the PLL is engaged */ + if (MCG->C6 & MCG_C6_PLLS_MASK) { + if ((MCG->C1 & MCG_C1_CLKS_MASK) == 0) { + /* we are currently in PEE mode, we need to step back to PBE */ + /* switch MCGOUTCLK from PLL output to ERC */ + MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(2); + + /* Wait until ERC is selected */ + while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) {} + } + bit_clear8(&MCG->C6, MCG_C6_PLLS_SHIFT); + /* Wait until the source of the PLLS clock is FLL */ + while ((MCG->S & MCG_S_PLLST_MASK) != 0) {} + } +#endif + /* when we reach this line we are in one of the FLL modes: FEI, FBI, FEE, FBE */ + /* Move to FEI mode with minimum multiplier factor */ + /* Select the correct FLL multiplier for the target frequency */ + kinetis_mcg_set_fll_factor(KINETIS_MCG_FLL_FACTOR_640); + /* select slow internal reference clock for FLL source and use FLL output clock */ + MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | (MCG_C1_CLKS(0) | MCG_C1_IREFS_MASK); + + /* source of the FLL reference clock shall be internal reference clock */ + while ((MCG->S & MCG_S_IREFST_MASK) == 0) {} + + /* Wait until output of the FLL is selected */ + while (MCG->S & (MCG_S_CLKST_MASK)) {} + + current_mode = KINETIS_MCG_MODE_FEI; + /* We avoid messing with the settings of the internal reference clock here + * because it may be driving the LPTMR */ + /* At this point the core will be clocked from the FLL running off the slow + * internal reference clock (32768 Hz) with a 640 multiplier which yields + * 32.768 kHz x 640 = 20.971520 MHz. This should be safe regardless of the + * SIM_CLKDIV1 settings used, for all supported Kinetis CPUs */ +} + +void kinetis_mcg_init(void) +{ + unsigned mask = irq_disable(); + /* Go to FBI mode for safety */ + kinetis_mcg_set_safe_mode(); + /* at this point the core should be running from the internal reference + * clock, slow or fast, which is 32.768 kHz up to 4 MHz, depending on + * previous settings */ + + /* Set module clock dividers */ + SIM->CLKDIV1 = clock_config.clkdiv1; + + /* Select external reference clock source for the FLL */ + MCG->C7 = MCG_C7_OSCSEL(clock_config.oscsel); + + /* Set external reference clock divider for the FLL */ + MCG->C1 = (MCG->C1 & ~MCG_C1_FRDIV_MASK) | MCG_C1_FRDIV(clock_config.fll_frdiv); + +#if KINETIS_HAVE_PLL + /* set ERC divider for the PLL */ + MCG->C5 = (uint8_t)(MCG_C5_PRDIV0(clock_config.pll_prdiv)); + + /* set PLL VCO divider */ + MCG->C6 = (uint8_t)(MCG_C6_VDIV0(clock_config.pll_vdiv)); +#endif /* KINETIS_HAVE_PLL */ + + /* Configure internal reference clock */ + if (clock_config.select_fast_irc) { + /* Fast IRC divider setting */ + uint8_t tmp = MCG->SC; + /* Avoid clearing w1c flags during writeback */ + tmp &= ~(MCG_SC_ATMF_MASK | MCG_SC_LOCS0_MASK); + /* Write new FCRDIV setting */ + tmp &= ~MCG_SC_FCRDIV_MASK; + tmp |= MCG_SC_FCRDIV(clock_config.fcrdiv); + MCG->SC = tmp; + bit_set8(&MCG->C2, MCG_C2_IRCS_SHIFT); + } + else { + bit_clear8(&MCG->C2, MCG_C2_IRCS_SHIFT); + } + /* Enable/disable MCGIRCLK */ + /* MCGIRCLK can be used as an alternate clock source for certain modules */ + if (clock_config.enable_mcgirclk) { + bit_set8(&MCG->C1, MCG_C1_IRCLKEN_SHIFT); + } + else { + bit_clear8(&MCG->C1, MCG_C1_IRCLKEN_SHIFT); + } + /* Switch to the selected MCG mode */ + kinetis_mcg_set_mode(clock_config.default_mode); + irq_restore(mask); +} + /** @} */ diff --git a/cpu/kw2xd/cpu.c b/cpu/kw2xd/cpu.c deleted file mode 100644 index a822c6c947..0000000000 --- a/cpu/kw2xd/cpu.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2014 PHYTEC Messtechnik GmbH - * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License v2.1. See the file LICENSE in the top level directory for more - * details. - */ - -/** - * @ingroup cpu_kw2xd - * @{ - * - * @file - * @brief Implementation of the KW2xD CPU initialization - * - * @author Hauke Petersen - * @author Johann Fischer - * @} - */ - -#include -#include "cpu.h" -#include "mcg.h" -#include "cpu_conf.h" -#include "periph/init.h" - -#define FLASH_BASE (0x00000000) - -static void cpu_clock_init(void); - -/** - * @brief Initialize the CPU, set IRQ priorities - */ -void cpu_init(void) -{ - /* initialize the Cortex-M core */ - cortexm_init(); - /* initialize the clock system */ - cpu_clock_init(); - /* trigger static peripheral initialization */ - periph_init(); -} - -static inline void modem_clock_init(void) -{ - /* Use the CLK_OUT of the modem as the clock source. */ - - /* Enable GPIO clock gates */ - KW2XDRF_PORT_CLKEN(); - KW2XDRF_CLK_CTRL_CLKEN(); - - /* Modem RST_B is connected to PTB19 and can be used to reset the modem. */ - KW2XDRF_PORT_DEV->PCR[KW2XDRF_RST_PIN] = PORT_PCR_MUX(1); - BITBAND_REG32(KW2XDRF_GPIO->PDDR, KW2XDRF_RST_PIN) = 1; - KW2XDRF_GPIO->PCOR = (1 << KW2XDRF_RST_PIN); - - /* Modem GPIO5 is connected to PTC0 and can be used to select CLK_OUT frequency, */ - /* set PTC0 high for CLK_OUT=32.787kHz and low for CLK_OUT=4MHz. */ - KW2XDRF_CLK_CTRL_PORT_DEV->PCR[KW2XDRF_CLK_CTRL_PIN] = PORT_PCR_MUX(1); - BITBAND_REG32(KW2XDRF_CLK_CTRL_GPIO->PDDR, KW2XDRF_CLK_CTRL_PIN) = 1; - KW2XDRF_CLK_CTRL_GPIO->PCOR = (1 << KW2XDRF_CLK_CTRL_PIN); - - /* Modem IRQ_B is connected to PTB3, modem interrupt request to the MCU. */ - KW2XDRF_PORT_DEV->PCR[KW2XDRF_IRQ_PIN] = PORT_PCR_MUX(1); - BITBAND_REG32(KW2XDRF_GPIO->PDDR, KW2XDRF_IRQ_PIN) = 0; - - /* release the reset */ - KW2XDRF_GPIO->PSOR = (1 << KW2XDRF_RST_PIN); - - /* wait for modem IRQ_B interrupt request */ - while (KW2XDRF_GPIO->PDIR & (1 << KW2XDRF_IRQ_PIN)); -} - -/** - * @brief Configure the controllers clock system - */ -static void cpu_clock_init(void) -{ - /* setup system prescalers */ - SIM->CLKDIV1 = (uint32_t)SIM_CLKDIV1_OUTDIV4(1); - - modem_clock_init(); - kinetis_mcg_set_mode(KINETIS_MCG_PEE); -} diff --git a/cpu/kw2xd/include/vendor/MKW22D5.h b/cpu/kw2xd/include/vendor/MKW22D5.h index da313d4580..3ac4cc645b 100644 --- a/cpu/kw2xd/include/vendor/MKW22D5.h +++ b/cpu/kw2xd/include/vendor/MKW22D5.h @@ -9282,6 +9282,8 @@ typedef struct { #define UART_TIDT_TIDT(x) This_symbol_has_been_deprecated #define OSC0 ((OSC_Type *)OSC_BASE) +#define MCG_C7_OSCSEL(x) (((uint32_t)(x) << MCG_C7_OSCSEL_SHIFT) & MCG_C7_OSCSEL_MASK) + /*! * @} */ /* end of group Backward_Compatibility_Symbols */