mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
kinetis: Refactor clock generator initialization
This commit is contained in:
parent
635e72db23
commit
c54f6b4fcf
@ -41,20 +41,24 @@ static const clock_config_t clock_config = {
|
||||
*/
|
||||
.clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) |
|
||||
SIM_CLKDIV1_OUTDIV3(2) | SIM_CLKDIV1_OUTDIV4(2),
|
||||
.rtc_clc = 0, /* External load caps on the FRDM-K22F board */
|
||||
.osc32ksel = SIM_SOPT1_OSC32KSEL(2),
|
||||
.clock_flags =
|
||||
KINETIS_CLOCK_OSC0_EN |
|
||||
KINETIS_CLOCK_RTCOSC_EN |
|
||||
KINETIS_CLOCK_USE_FAST_IRC |
|
||||
0,
|
||||
.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 */
|
||||
.osc_clc = 0, /* External load caps on the FRDM-K22F board */
|
||||
.oscsel = MCG_C7_OSCSEL(0), /* Use OSC0 for external clock */
|
||||
.fcrdiv = MCG_SC_FCRDIV(0), /* Fast IRC divide by 1 => 4 MHz */
|
||||
.fll_frdiv = MCG_C1_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,
|
||||
.pll_prdiv = MCG_C5_PRDIV0(0b00011), /* Divide by 4 */
|
||||
.pll_vdiv = MCG_C6_VDIV0(0b00110), /* Multiply by 30 => PLL freq = 60 MHz */
|
||||
};
|
||||
#define CLOCK_CORECLOCK (60000000ul)
|
||||
#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 2)
|
||||
|
@ -42,20 +42,24 @@ static const clock_config_t clock_config = {
|
||||
*/
|
||||
.clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) |
|
||||
SIM_CLKDIV1_OUTDIV3(2) | SIM_CLKDIV1_OUTDIV4(2),
|
||||
.rtc_clc = 0, /* External load caps on board */
|
||||
.osc32ksel = SIM_SOPT1_OSC32KSEL(2),
|
||||
.clock_flags =
|
||||
/* No OSC0_EN, use EXTAL directly without OSC0 */
|
||||
KINETIS_CLOCK_RTCOSC_EN |
|
||||
KINETIS_CLOCK_USE_FAST_IRC |
|
||||
0,
|
||||
.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 */
|
||||
.osc_clc = 0, /* External load caps on board */
|
||||
.oscsel = MCG_C7_OSCSEL(0), /* Use EXTAL for external clock */
|
||||
.fcrdiv = MCG_SC_FCRDIV(0), /* Fast IRC divide by 1 => 4 MHz */
|
||||
.fll_frdiv = MCG_C1_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,
|
||||
.pll_prdiv = MCG_C5_PRDIV0(0b10011), /* Divide by 20 */
|
||||
.pll_vdiv = MCG_C6_VDIV0(0b00000), /* Multiply by 24 => PLL freq = 60 MHz */
|
||||
};
|
||||
#define CLOCK_CORECLOCK (60000000ul)
|
||||
#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 1)
|
||||
|
@ -20,18 +20,12 @@
|
||||
|
||||
#include "board.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/rtt.h"
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
/* initialize the CPU core */
|
||||
cpu_init();
|
||||
|
||||
#if MODULE_XTIMER && !(KINETIS_XTIMER_SOURCE_PIT)
|
||||
/* Start the RTT, used as time base for xtimer when using LPTMR backend */
|
||||
rtt_init();
|
||||
#endif
|
||||
|
||||
/* initialize and turn off LEDs */
|
||||
gpio_init(LED0_PIN, GPIO_OUT);
|
||||
gpio_set(LED0_PIN);
|
||||
|
@ -39,20 +39,30 @@ static const clock_config_t clock_config = {
|
||||
* Flash: 24 MHz
|
||||
*/
|
||||
.clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV4(1),
|
||||
/* unsure if this RTC load cap configuration is correct, but it matches the
|
||||
* settings used by the example code in the NXP provided SDK */
|
||||
.rtc_clc = 0,
|
||||
/* Use the 32 kHz oscillator as ERCLK32K. Note that the values here have a
|
||||
* different mapping for the KW41Z than the values used in the Kinetis K series */
|
||||
.osc32ksel = SIM_SOPT1_OSC32KSEL(0),
|
||||
.clock_flags =
|
||||
KINETIS_CLOCK_OSC0_EN | /* Enable RSIM oscillator */
|
||||
KINETIS_CLOCK_RTCOSC_EN |
|
||||
KINETIS_CLOCK_USE_FAST_IRC |
|
||||
KINETIS_CLOCK_MCGIRCLK_EN | /* Used for LPUART clocking */
|
||||
KINETIS_CLOCK_MCGIRCLK_STOP_EN |
|
||||
0,
|
||||
/* Using FEI mode by default, the external crystal settings below are only
|
||||
* used if mode is changed to an external mode (PEE, FBE, or FEE) */
|
||||
.default_mode = KINETIS_MCG_MODE_FEI,
|
||||
/* The crystal connected to RSIM OSC is 32 MHz */
|
||||
.erc_range = KINETIS_MCG_ERC_RANGE_VERY_HIGH,
|
||||
.fcrdiv = 0, /* Fast IRC divide by 1 => 4 MHz */
|
||||
.oscsel = 0, /* Use RSIM for external clock */
|
||||
.clc = 0, /* no load cap configuration */
|
||||
.fll_frdiv = 0b101, /* Divide by 1024 */
|
||||
.osc_clc = 0, /* no load cap configuration */
|
||||
.oscsel = MCG_C7_OSCSEL(0), /* Use RSIM for external clock */
|
||||
.fcrdiv = MCG_SC_FCRDIV(0), /* Fast IRC divide by 1 => 4 MHz */
|
||||
.fll_frdiv = MCG_C1_FRDIV(0b101), /* Divide by 1024 */
|
||||
.fll_factor_fei = KINETIS_MCG_FLL_FACTOR_1464, /* FEI FLL freq = 48 MHz */
|
||||
.fll_factor_fee = KINETIS_MCG_FLL_FACTOR_1280, /* FEE FLL freq = 40 MHz */
|
||||
.enable_oscillator = true, /* Use RF module oscillator */
|
||||
.select_fast_irc = true,
|
||||
.enable_mcgirclk = true, /* Used for LPUART clocking */
|
||||
};
|
||||
/* Radio xtal frequency, either 32 MHz or 26 MHz */
|
||||
#define CLOCK_RADIOXTAL (32000000ul)
|
||||
|
@ -103,28 +103,6 @@ void board_init(void)
|
||||
/* Turn on AVDD for reading voltages */
|
||||
gpio_set(MULLE_POWER_AVDD);
|
||||
|
||||
/* Initialize RTC oscillator as early as possible since we are using it as a
|
||||
* base clock for the FLL.
|
||||
* It takes a while to stabilize the oscillator, therefore we do this as
|
||||
* soon as possible during boot in order to let it stabilize while other
|
||||
* stuff is initializing. */
|
||||
/* If the clock is not stable then the UART will have the wrong baud rate
|
||||
* for debug prints as well */
|
||||
rtt_init();
|
||||
|
||||
/* 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
|
||||
* wait. I have tried to make this as short as possible but still being able
|
||||
* to read the initialization messages written on the UART.
|
||||
* (If the clock is not stable all UART output is garbled until it has
|
||||
* stabilized) */
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
__asm__ volatile("nop\n");
|
||||
}
|
||||
|
||||
/* initialize the CPU */
|
||||
cpu_init();
|
||||
|
||||
|
@ -33,6 +33,18 @@ extern "C"
|
||||
* @name Clock system configuration
|
||||
* @{
|
||||
*/
|
||||
/* The crystal on the Mulle is designed for 12.5 pF load capacitance. According
|
||||
* 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. */
|
||||
/* 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)
|
||||
|
||||
static const clock_config_t clock_config = {
|
||||
/*
|
||||
* This configuration results in the system running from the FLL output with
|
||||
@ -48,24 +60,28 @@ static const clock_config_t clock_config = {
|
||||
* consumption than using the 16 MHz crystal and the OSC0 module */
|
||||
.clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) |
|
||||
SIM_CLKDIV1_OUTDIV3(1) | SIM_CLKDIV1_OUTDIV4(1),
|
||||
.rtc_clc = RTC_LOAD_CAP_BITS,
|
||||
.osc32ksel = SIM_SOPT1_OSC32KSEL(2),
|
||||
.clock_flags =
|
||||
/* no OSC0_EN, the RTC module provides the clock input signal for the FLL */
|
||||
KINETIS_CLOCK_RTCOSC_EN |
|
||||
KINETIS_CLOCK_USE_FAST_IRC |
|
||||
0,
|
||||
.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 */
|
||||
.osc_clc = OSC_CR_SC16P_MASK,
|
||||
.oscsel = MCG_C7_OSCSEL(1), /* Use RTC for external clock */
|
||||
.fcrdiv = MCG_SC_FCRDIV(0), /* Fast IRC divide by 1 => 4 MHz */
|
||||
.fll_frdiv = MCG_C1_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,
|
||||
.pll_prdiv = MCG_C5_PRDIV0(0b00111), /* Divide by 8 */
|
||||
.pll_vdiv = MCG_C6_VDIV0(0b01100), /* Multiply by 36 => PLL freq = 72 MHz */
|
||||
};
|
||||
#define CLOCK_CORECLOCK (48000000ul)
|
||||
#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 1)
|
||||
@ -382,21 +398,6 @@ static const spi_conf_t spi_config[] = {
|
||||
#define RTT_MAX_VALUE (0xffffffff)
|
||||
#define RTT_FREQUENCY (1) /* in Hz */
|
||||
|
||||
/**
|
||||
* RTC module crystal load capacitance configuration bits.
|
||||
*/
|
||||
/* The crystal on the Mulle is designed for 12.5 pF load capacitance. According
|
||||
* 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. */
|
||||
/* 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)
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -43,20 +43,24 @@ static const clock_config_t clock_config = {
|
||||
*/
|
||||
.clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) |
|
||||
SIM_CLKDIV1_OUTDIV4(1),
|
||||
.rtc_clc = 0, /* External load caps on the FRDM-K22F board */
|
||||
.osc32ksel = SIM_SOPT1_OSC32KSEL(2),
|
||||
.clock_flags =
|
||||
/* No OSC0_EN, use modem clock from EXTAL0 */
|
||||
KINETIS_CLOCK_RTCOSC_EN |
|
||||
KINETIS_CLOCK_USE_FAST_IRC |
|
||||
0,
|
||||
.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 */
|
||||
.osc_clc = 0, /* OSC0 is unused*/
|
||||
.oscsel = MCG_C7_OSCSEL(0), /* Use EXTAL0 for external clock */
|
||||
.fcrdiv = MCG_SC_FCRDIV(0), /* Fast IRC divide by 1 => 4 MHz */
|
||||
.fll_frdiv = MCG_C1_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,
|
||||
.pll_prdiv = MCG_C5_PRDIV0(0b00001), /* Divide by 2 */
|
||||
.pll_vdiv = MCG_C6_VDIV0(0b00000), /* Multiply by 24 => PLL freq = 48 MHz */
|
||||
};
|
||||
#define CLOCK_CORECLOCK (48000000ul)
|
||||
#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 1)
|
||||
|
@ -45,24 +45,28 @@ static const clock_config_t clock_config = {
|
||||
* consumption than using the 16 MHz crystal and the OSC0 module */
|
||||
.clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) |
|
||||
SIM_CLKDIV1_OUTDIV3(1) | SIM_CLKDIV1_OUTDIV4(1),
|
||||
/* RTC crystal has to be soldered by the user, we can't know the load cap requirements */
|
||||
.rtc_clc = 0,
|
||||
.osc32ksel = SIM_SOPT1_OSC32KSEL(2),
|
||||
.clock_flags =
|
||||
KINETIS_CLOCK_RTCOSC_EN |
|
||||
KINETIS_CLOCK_USE_FAST_IRC |
|
||||
0,
|
||||
.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 */
|
||||
.osc_clc = OSC_CR_SC16P_MASK,
|
||||
.oscsel = MCG_C7_OSCSEL(1), /* Use RTC oscillator as external clock */
|
||||
.fcrdiv = MCG_SC_FCRDIV(0), /* Fast IRC divide by 1 => 4 MHz */
|
||||
.fll_frdiv = MCG_C1_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,
|
||||
.pll_prdiv = MCG_C5_PRDIV0(0b00111), /* Divide by 8 */
|
||||
.pll_vdiv = MCG_C6_VDIV0(0b01100), /* Multiply by 36 => PLL freq = 72 MHz */
|
||||
};
|
||||
#define CLOCK_CORECLOCK (48000000ul)
|
||||
#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 1)
|
||||
|
@ -124,6 +124,10 @@ extern "C"
|
||||
/** Enable PIT clock gate */
|
||||
#define PIT_CLKEN() (bit_set32(&SIM->SCGC6, SIM_SCGC6_PIT_SHIFT))
|
||||
#endif
|
||||
#ifdef SIM_SCGC6_RTC_SHIFT
|
||||
/** Enable RTC clock gate */
|
||||
#define RTC_CLKEN() (bit_set32(&SIM->SCGC6, SIM_SCGC6_RTC_SHIFT))
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2016 Freie Universität Berlin
|
||||
* Copyright (C) 2017-2018 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
|
||||
@ -14,6 +15,7 @@
|
||||
* @brief CPU specific definitions for internal peripheral handling
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*/
|
||||
|
||||
#ifndef PERIPH_CPU_H
|
||||
@ -426,51 +428,203 @@ typedef enum {
|
||||
KINETIS_MCG_ERC_RANGE_VERY_HIGH = MCG_C2_RANGE0(2), /**< for 8-32 MHz crystal */
|
||||
} kinetis_mcg_erc_range_t;
|
||||
|
||||
/**
|
||||
* @brief Clock generation configuration flags
|
||||
*
|
||||
* @see "Clock distribution -> High-Level device clocking diagram" in every
|
||||
* Kinetis CPU reference manual
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief Turn on OSC0 oscillator
|
||||
*
|
||||
* - If this flag is set, the OSC0 oscillator expects a crystal between
|
||||
* the pins XTAL0 and EXTAL0, and the OSCCLK internal signal will be
|
||||
* provided by OSC0.
|
||||
* - If not set, the EXTAL0 pin will be used directly as the OSCCLK signal.
|
||||
*/
|
||||
KINETIS_CLOCK_OSC0_EN = (1 << 0),
|
||||
/**
|
||||
* @brief Turn on RTC oscillator
|
||||
*
|
||||
* - If this flag is set, the RTC oscillator expects a crystal between
|
||||
* the pins XTAL32 and EXTAL32.
|
||||
* - If not set, the EXTAL32 pin can be used as an external clock signal on
|
||||
* certain CPU models.
|
||||
*/
|
||||
KINETIS_CLOCK_RTCOSC_EN = (1 << 1),
|
||||
/**
|
||||
* @brief Use the fast internal reference clock as MCGIRCLK signal
|
||||
*
|
||||
* This flag corresponds to the IRCS bit in the MCG_C2 register.
|
||||
*
|
||||
* @note This flag affects the clock frequency of the CPU when using the MCG
|
||||
* in FBI, or BLPI clocking modes.
|
||||
*
|
||||
* - If this flag is set, the fast internal reference clock (up to 4 MHz,
|
||||
* depends on settings) will be routed to the MCGIRCLK internal clock signal.
|
||||
* - If not set, the slow internal reference clock (32 kHz) will be routed to
|
||||
* the MCGIRCLK internal clock signal. FBI and BLPI modes will clock the core
|
||||
* at 32 kHz.
|
||||
*/
|
||||
KINETIS_CLOCK_USE_FAST_IRC = (1 << 2),
|
||||
/**
|
||||
* @brief Enable MCGIRCLK internal clock signal
|
||||
*
|
||||
* This flag corresponds to the IRCLKEN bit in the MCG_C1 register.
|
||||
*
|
||||
* - If this flag is set, the MCG will provide MCGIRCLK for use by other
|
||||
* peripherals.
|
||||
*/
|
||||
KINETIS_CLOCK_MCGIRCLK_EN = (1 << 3),
|
||||
/**
|
||||
* @brief Enable MCGIRCLK signal during STOP modes
|
||||
*
|
||||
* This flag corresponds to the IREFSTEN bit in the MCG_SC register.
|
||||
*
|
||||
* - If this flag is set, MCGIRCLK internal clock signal will be available
|
||||
* for clocking peripherals during CPU STOP modes.
|
||||
* - If not set, the MCGIRCLK internal clock signal will be stopped during
|
||||
* CPU STOP modes.
|
||||
*/
|
||||
KINETIS_CLOCK_MCGIRCLK_STOP_EN = (1 << 4),
|
||||
} kinetis_clock_flags_t;
|
||||
|
||||
/**
|
||||
* @brief Clock configuration for Kinetis CPUs
|
||||
*/
|
||||
typedef struct {
|
||||
/** Clock divider bitfield setting, see reference manual for SIM_CLKDIV1 */
|
||||
/**
|
||||
* @brief Clock divider bitfield setting
|
||||
*
|
||||
* The value will be written to the SIM_CLKDIV1 hardware register without
|
||||
* any transformation. Use the SIM_CLKDIV1_OUTDIVx() macros to ensure the
|
||||
* proper bit shift for the chosen divider settings.
|
||||
*
|
||||
* @see CPU reference manual, SIM_CLKDIV1
|
||||
*/
|
||||
uint32_t clkdiv1;
|
||||
/** MCG mode used after initialization, see kinetis_mcg_mode_t */
|
||||
/**
|
||||
* @brief RTC oscillator Capacitor Load Configuration bits
|
||||
*
|
||||
* The bits will be passed directly to the RTC_CR register without any
|
||||
* transformation, i.e. the SC16P bit is (unintuitively) at bit position 10,
|
||||
* SC8P is at position 11, and so on (see details in the reference manual).
|
||||
* Use the RTC_CR_SCxP_MASK macros to avoid accidentally reversing the bits
|
||||
* here.
|
||||
*
|
||||
* @see CPU reference manual, RTC_CR[SCxP]
|
||||
*/
|
||||
uint32_t rtc_clc;
|
||||
/**
|
||||
* @brief ERCLK32K 32 kHz reference selection
|
||||
*
|
||||
* The bits will be passed directly to the SIM_SOPT1 register without any
|
||||
* transformation, use the SIM_SOPT1_OSC32KSEL() macro to ensure the proper
|
||||
* bit shift for the chosen setting.
|
||||
*
|
||||
* This signal is the input clock to the RTC module on some CPUs and an input
|
||||
* option for the LPTMRx modules. On other CPUs the RTC is clocked directly
|
||||
* by the RTC oscillator output without passing through this clock multiplexer.
|
||||
*
|
||||
* @see CPU reference manual, SIM_SOPT1[OSC32KSEL]
|
||||
*/
|
||||
uint32_t osc32ksel;
|
||||
/**
|
||||
* @brief Flags which will enable various clocking options at init
|
||||
*
|
||||
* @see @ref kinetis_clock_flags_t
|
||||
*/
|
||||
unsigned int clock_flags;
|
||||
/**
|
||||
* @brief MCG mode used after initialization
|
||||
*
|
||||
* @see @ref kinetis_mcg_mode_t
|
||||
*/
|
||||
kinetis_mcg_mode_t default_mode;
|
||||
/** ERC range setting, see kinetis_mcg_erc_range_t */
|
||||
/**
|
||||
* @brief ERC range setting
|
||||
*
|
||||
* @see @ref 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] */
|
||||
/**
|
||||
* @brief OSC0 Capacitor Load Configuration bits
|
||||
*
|
||||
* The bits will be passed directly to the OSC_CR register without any
|
||||
* transformation, i.e. the SC16P bit is (unintuitively) the LSB, SC8P is
|
||||
* the next bit, and so on (see details in the reference manual). Use the
|
||||
* OSC_CR_SCxP_MASK macros to avoid accidentally reversing the bits here.
|
||||
*
|
||||
* @see CPU reference manual, OSC_CR[SCxP]
|
||||
*/
|
||||
uint8_t osc_clc;
|
||||
/**
|
||||
* @brief MCG external reference oscillator selection
|
||||
*
|
||||
* The bits will be passed directly to the MCG_C7 register without any
|
||||
* transformation, use the MCG_C7_OSCSEL() macro to ensure the proper bit
|
||||
* shift for the chosen setting.
|
||||
*
|
||||
* @see CPU reference manual, 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] */
|
||||
/**
|
||||
* @brief Fast internal reference clock divider
|
||||
*
|
||||
* The bits will be passed directly to the MCG_SC register without any
|
||||
* transformation, use the MCG_SC_FCRDIV() macro to ensure the proper bit
|
||||
* shift for the chosen setting.
|
||||
*
|
||||
* @see CPU reference manual, MCG_SC[FCRDIV]
|
||||
*/
|
||||
uint8_t fcrdiv;
|
||||
/**
|
||||
* @brief FLL ERC divider setting
|
||||
*
|
||||
* The bits will be passed directly to the MCG_C1 register without any
|
||||
* transformation, use the MCG_C1_FRDIV() macro to ensure the proper bit
|
||||
* shift for the chosen setting.
|
||||
*
|
||||
* @see CPU reference manual, MCG_C1[FRDIV]
|
||||
*/
|
||||
uint8_t fll_frdiv;
|
||||
/** FLL multiplier when running in FEI mode */
|
||||
/**
|
||||
* @brief FLL multiplier when running in FEI mode
|
||||
*
|
||||
* @see @ref kinetis_mcg_fll_t
|
||||
* @see CPU reference manual, MCG_C4[DMX32, DRST_DRS]
|
||||
*/
|
||||
kinetis_mcg_fll_t fll_factor_fei;
|
||||
/** FLL multiplier when running in FEE mode */
|
||||
/**
|
||||
* @brief FLL multiplier when running in FEE mode
|
||||
*
|
||||
* @see @ref kinetis_mcg_fll_t
|
||||
* @see CPU reference manual, MCG_C4[DMX32, DRST_DRS]
|
||||
*/
|
||||
kinetis_mcg_fll_t fll_factor_fee;
|
||||
#if KINETIS_HAVE_PLL
|
||||
/** PLL ERC divider setting, see reference manual for MCG_C5[PRDIV] */
|
||||
/**
|
||||
* @brief PLL ERC divider setting
|
||||
*
|
||||
* The bits will be passed directly to the MCG_C5 register without any
|
||||
* transformation, use the MCG_C5_PRDIV0() macro to ensure the proper bit
|
||||
* shift for the chosen setting.
|
||||
*
|
||||
* @see CPU reference manual, MCG_C5[PRDIV0]
|
||||
*/
|
||||
uint8_t pll_prdiv;
|
||||
/** PLL VCO divider setting, see reference manual for MCG_C6[VDIV0] */
|
||||
/**
|
||||
* @brief PLL VCO divider setting
|
||||
*
|
||||
* The bits will be passed directly to the MCG_C6 register without any
|
||||
* transformation, use the MCG_C6_VDIV0() macro to ensure the proper bit
|
||||
* shift for the chosen setting.
|
||||
*
|
||||
* @see CPU reference manual, 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;
|
||||
|
||||
/**
|
||||
|
@ -74,10 +74,9 @@ static void kinetis_mcg_enable_osc(void)
|
||||
#if defined(OSC0)
|
||||
/* Kinetis CPU with OSC module */
|
||||
/* Enable Oscillator */
|
||||
if (clock_config.enable_oscillator) {
|
||||
if (clock_config.clock_flags & KINETIS_CLOCK_OSC0_EN) {
|
||||
/* Configure oscillator */
|
||||
OSC0->CR = (uint8_t)(OSC_CR_ERCLKEN_MASK | OSC_CR_EREFSTEN_MASK |
|
||||
(clock_config.clc & 0xf));
|
||||
OSC0->CR = OSC_CR_ERCLKEN_MASK | OSC_CR_EREFSTEN_MASK | clock_config.osc_clc;
|
||||
bit_set8(&MCG->C2, MCG_C2_EREFS0_SHIFT);
|
||||
|
||||
/* wait for OSC initialization */
|
||||
@ -97,24 +96,86 @@ static void kinetis_mcg_enable_osc(void)
|
||||
* 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. */
|
||||
RSIM->CONTROL = (RSIM->CONTROL & ~RSIM_CONTROL_RF_OSC_EN_MASK) | RSIM_CONTROL_RF_OSC_EN(1);
|
||||
|
||||
if (clock_config.enable_oscillator) {
|
||||
if (clock_config.clock_flags & KINETIS_CLOCK_OSC0_EN) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Enable RF oscillator circuit */
|
||||
/* Current setting is that the OSC only runs in RUN and WAIT modes, see ref.man. */
|
||||
RSIM->CONTROL = (RSIM->CONTROL & ~RSIM_CONTROL_RF_OSC_EN_MASK) | RSIM_CONTROL_RF_OSC_EN(1);
|
||||
|
||||
/* Wait for oscillator ready signal */
|
||||
while((RSIM->CONTROL & RSIM_CONTROL_RF_OSC_READY_MASK) == 0) {}
|
||||
#endif /* defined OSC0/RSIM */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the 32 kHz reference clock (ERCLK32K)
|
||||
*
|
||||
* This will enable the RTC oscillator if enabled in the configuration.
|
||||
*/
|
||||
static void kinetis_mcg_init_erclk32k(void)
|
||||
{
|
||||
/* Enable RTC oscillator if selected */
|
||||
if (clock_config.clock_flags & KINETIS_CLOCK_RTCOSC_EN) {
|
||||
RTC_CLKEN();
|
||||
if (!(RTC->CR & RTC_CR_OSCE_MASK)) {
|
||||
/* Only touch if it was previously not running. The RTC is not reset
|
||||
* by software resets, only by power on reset */
|
||||
RTC->CR = RTC_CR_OSCE_MASK | RTC_CR_SUP_MASK | clock_config.rtc_clc;
|
||||
}
|
||||
}
|
||||
/* Select ERCLK32K source */
|
||||
SIM->SOPT1 = (SIM->SOPT1 & ~SIM_SOPT1_OSC32KSEL_MASK) | clock_config.osc32ksel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the MCG internal reference clock (MCGIRCLK)
|
||||
*
|
||||
* This clock signal can be used for directly clocking certain peripherals, and
|
||||
* can be chosen as the MCG output clock (MCGOUTCLK).
|
||||
*/
|
||||
static void kinetis_mcg_init_mcgirclk(void)
|
||||
{
|
||||
/* Configure internal reference clock */
|
||||
if (clock_config.clock_flags & KINETIS_CLOCK_USE_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 |= 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.clock_flags & KINETIS_CLOCK_MCGIRCLK_EN) {
|
||||
bit_set8(&MCG->C1, MCG_C1_IRCLKEN_SHIFT);
|
||||
}
|
||||
else {
|
||||
bit_clear8(&MCG->C1, MCG_C1_IRCLKEN_SHIFT);
|
||||
}
|
||||
|
||||
if (clock_config.clock_flags & KINETIS_CLOCK_MCGIRCLK_STOP_EN) {
|
||||
/* Enable MCGIRCLK during STOP (but only when also IRCLKEN is set) */
|
||||
bit_set8(&MCG->C1, MCG_C1_IREFSTEN_SHIFT);
|
||||
}
|
||||
else {
|
||||
bit_clear8(&MCG->C1, MCG_C1_IREFSTEN_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the FLL Engaged Internal Mode.
|
||||
*
|
||||
@ -416,42 +477,23 @@ void kinetis_mcg_init(void)
|
||||
SIM->CLKDIV1 = clock_config.clkdiv1;
|
||||
|
||||
/* Select external reference clock source for the FLL */
|
||||
MCG->C7 = MCG_C7_OSCSEL(clock_config.oscsel);
|
||||
MCG->C7 = 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);
|
||||
MCG->C1 = (MCG->C1 & ~MCG_C1_FRDIV_MASK) | 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));
|
||||
MCG->C5 = clock_config.pll_prdiv;
|
||||
|
||||
/* set PLL VCO divider */
|
||||
MCG->C6 = (uint8_t)(MCG_C6_VDIV0(clock_config.pll_vdiv));
|
||||
MCG->C6 = 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);
|
||||
}
|
||||
kinetis_mcg_init_mcgirclk();
|
||||
|
||||
kinetis_mcg_init_erclk32k();
|
||||
|
||||
/* Switch to the selected MCG mode */
|
||||
kinetis_mcg_set_mode(clock_config.default_mode);
|
||||
irq_restore(mask);
|
||||
|
Loading…
Reference in New Issue
Block a user