1
0
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:
Joakim Nohlgård 2018-04-11 06:58:46 +02:00
parent 635e72db23
commit c54f6b4fcf
11 changed files with 361 additions and 162 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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();

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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
/** @} */
/**

View File

@ -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;
/**

View File

@ -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);