Skip to content
Snippets Groups Projects
Commit 5f0b8e5b authored by Francisco Acosta's avatar Francisco Acosta Committed by GitHub
Browse files

Merge pull request #6978 from gebart/pr/kinetis-mcg

kinetis: MCG improvements
parents 863bda7b 8efb714e
No related branches found
No related tags found
No related merge requests found
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
* @defgroup cpu_kinetis_common_mcg Kinetis MCG * @defgroup cpu_kinetis_common_mcg Kinetis MCG
* @ingroup cpu_kinetis_common * @ingroup cpu_kinetis_common
* @brief Implementation of the Kinetis Multipurpose Clock Generator * @brief Implementation of the Kinetis Multipurpose Clock Generator
* (MCG) driver. * (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 * and MCG configuration to periph_conf.h
* *
...@@ -37,6 +38,30 @@ ...@@ -37,6 +38,30 @@
* - BLPE -> FEE * - BLPE -> FEE
* - BLPI -> FEE * - BLPI -> FEE
* *
* \dot
* digraph states {
* layout=dot
* nodesep=0.5
* {rank=same Reset [shape=none] FEI FEE}
* {rank=same FBI FBE}
* {rank=same BLPI BLPE}
* Reset -> FEI
* FEI -> FEE [dir="both"]
* FEI -> FBE [dir="both"]
* FEI -> FBI [dir="both"]
* FEE -> FBI [dir="both"]
* FEE -> FBE [dir="both"]
* FBI -> FBE [dir="both"]
* FBI -> BLPI [dir="both"]
* FBE -> BLPE [dir="both"]
* PBE
* PEE
* FBE -> PBE [dir="both"]
* BLPE -> PBE [dir="both"]
* PBE -> PEE [dir="both"]
* }
* \enddot
*
* ### MCG Configuration Examples (for periph_conf.h) ### * ### MCG Configuration Examples (for periph_conf.h) ###
* *
* Example for FEI Mode (MCGOUTCLK = 20MHz ... 25MHz): * Example for FEI Mode (MCGOUTCLK = 20MHz ... 25MHz):
......
/* /*
* Copyright (C) 2015 PHYTEC Messtechnik GmbH * 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 * 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 * Public License v2.1. See the file LICENSE in the top level directory for more
...@@ -14,7 +15,8 @@ ...@@ -14,7 +15,8 @@
* @brief Implementation of the Kinetis Multipurpose Clock Generator * @brief Implementation of the Kinetis Multipurpose Clock Generator
* *
* @author Johann Fischer <j.fischer@phytec.de> * @author Johann Fischer <j.fischer@phytec.de>
* @} * @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*
*/ */
#include <stdint.h> #include <stdint.h>
...@@ -23,8 +25,24 @@ ...@@ -23,8 +25,24 @@
#if KINETIS_CPU_USE_MCG #if KINETIS_CPU_USE_MCG
/* MCG neighbor modes matrix */ #if defined(MCG_C6_PLLS_MASK)
static uint8_t mcg_pm[8] = {0x02, 0x15, 0x12, 0x20, 0xe6, 0xd8, 0xb0, 0xf0}; #define KINETIS_HAVE_PLL 1
#else
#define KINETIS_HAVE_PLL 0
#endif
/* Pathfinding for the clocking modes, this table lists the next mode in the
* chain when moving from mode <first> to mode <second> */
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 */
};
static uint8_t current_mode = KINETIS_MCG_FEI; static uint8_t current_mode = KINETIS_MCG_FEI;
...@@ -97,6 +115,7 @@ static uint8_t current_mode = KINETIS_MCG_FEI; ...@@ -97,6 +115,7 @@ static uint8_t current_mode = KINETIS_MCG_FEI;
#error "KINETIS_MCG_ERC_RANGE not defined in periph_conf.h" #error "KINETIS_MCG_ERC_RANGE not defined in periph_conf.h"
#endif #endif
#if KINETIS_HAVE_PLL
#ifndef KINETIS_MCG_PLL_PRDIV #ifndef KINETIS_MCG_PLL_PRDIV
#error "KINETIS_MCG_PLL_PRDIV not defined in periph_conf.h" #error "KINETIS_MCG_PLL_PRDIV not defined in periph_conf.h"
#endif #endif
...@@ -118,6 +137,9 @@ static inline void kinetis_mcg_disable_pll(void) ...@@ -118,6 +137,9 @@ static inline void kinetis_mcg_disable_pll(void)
MCG->C5 = (uint8_t)0; MCG->C5 = (uint8_t)0;
MCG->C6 = (uint8_t)0; MCG->C6 = (uint8_t)0;
} }
#else
static inline void kinetis_mcg_disable_pll(void) {}
#endif /* KINETIS_HAVE_PLL */
/** /**
* @brief Set Frequency Locked Loop (FLL) factor. * @brief Set Frequency Locked Loop (FLL) factor.
...@@ -161,7 +183,7 @@ static void kinetis_mcg_enable_osc(void) ...@@ -161,7 +183,7 @@ static void kinetis_mcg_enable_osc(void)
MCG->C2 |= (uint8_t)(MCG_C2_EREFS0_MASK); MCG->C2 |= (uint8_t)(MCG_C2_EREFS0_MASK);
/* wait fo OSC initialization */ /* wait fo OSC initialization */
while ((MCG->S & MCG_S_OSCINIT0_MASK) == 0); while ((MCG->S & MCG_S_OSCINIT0_MASK) == 0) {}
} }
} }
...@@ -182,10 +204,10 @@ static void kinetis_mcg_set_fei(void) ...@@ -182,10 +204,10 @@ static void kinetis_mcg_set_fei(void)
MCG->C2 = (uint8_t)0; MCG->C2 = (uint8_t)0;
/* source of the FLL reference clock shall be internal reference clock */ /* source of the FLL reference clock shall be internal reference clock */
while ((MCG->S & MCG_S_IREFST_MASK) == 0); while ((MCG->S & MCG_S_IREFST_MASK) == 0) {}
/* Wait until output of the FLL is selected */ /* Wait until output of the FLL is selected */
while (MCG->S & (MCG_S_CLKST_MASK)); while (MCG->S & (MCG_S_CLKST_MASK)) {}
kinetis_mcg_disable_pll(); kinetis_mcg_disable_pll();
current_mode = KINETIS_MCG_FEI; current_mode = KINETIS_MCG_FEI;
...@@ -207,7 +229,7 @@ static void kinetis_mcg_set_fee(void) ...@@ -207,7 +229,7 @@ static void kinetis_mcg_set_fee(void)
MCG->C1 = (uint8_t)(MCG_C1_CLKS(0) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV)); MCG->C1 = (uint8_t)(MCG_C1_CLKS(0) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV));
/* Wait until output of FLL is selected */ /* Wait until output of FLL is selected */
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(0)); while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(0)) {}
kinetis_mcg_disable_pll(); kinetis_mcg_disable_pll();
current_mode = KINETIS_MCG_FEE; current_mode = KINETIS_MCG_FEE;
...@@ -237,10 +259,10 @@ static void kinetis_mcg_set_fbi(void) ...@@ -237,10 +259,10 @@ static void kinetis_mcg_set_fbi(void)
MCG->C1 = (uint8_t)(MCG_C1_CLKS(1) | MCG_C1_IREFS_MASK); MCG->C1 = (uint8_t)(MCG_C1_CLKS(1) | MCG_C1_IREFS_MASK);
/* Wait until output of IRC is selected */ /* Wait until output of IRC is selected */
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(1)); while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(1)) {}
/* source of the FLL reference clock shall be internal reference clock */ /* source of the FLL reference clock shall be internal reference clock */
while ((MCG->S & MCG_S_IREFST_MASK) == 0); while ((MCG->S & MCG_S_IREFST_MASK) == 0) {}
kinetis_mcg_disable_pll(); kinetis_mcg_disable_pll();
current_mode = KINETIS_MCG_FBI; current_mode = KINETIS_MCG_FBI;
...@@ -266,7 +288,7 @@ static void kinetis_mcg_set_fbe(void) ...@@ -266,7 +288,7 @@ static void kinetis_mcg_set_fbe(void)
MCG->C1 = (uint8_t)(MCG_C1_CLKS(2) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV)); MCG->C1 = (uint8_t)(MCG_C1_CLKS(2) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV));
/* Wait until ERC is selected */ /* Wait until ERC is selected */
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)); while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) {}
kinetis_mcg_disable_pll(); kinetis_mcg_disable_pll();
current_mode = KINETIS_MCG_FBE; current_mode = KINETIS_MCG_FBE;
...@@ -299,6 +321,7 @@ static void kinetis_mcg_set_blpe(void) ...@@ -299,6 +321,7 @@ static void kinetis_mcg_set_blpe(void)
current_mode = KINETIS_MCG_BLPE; current_mode = KINETIS_MCG_BLPE;
} }
#if KINETIS_HAVE_PLL
/** /**
* @brief Initialize the PLL Bypassed External Mode. * @brief Initialize the PLL Bypassed External Mode.
* *
...@@ -315,7 +338,7 @@ static void kinetis_mcg_set_pbe(void) ...@@ -315,7 +338,7 @@ static void kinetis_mcg_set_pbe(void)
MCG->C1 = (uint8_t)(MCG_C1_CLKS(2) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV)); MCG->C1 = (uint8_t)(MCG_C1_CLKS(2) | MCG_C1_FRDIV(KINETIS_MCG_ERC_FRDIV));
/* Wait until ERC is selected */ /* Wait until ERC is selected */
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)); while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) {}
/* PLL is not disabled in bypass mode */ /* PLL is not disabled in bypass mode */
MCG->C2 &= ~(uint8_t)(MCG_C2_LP_MASK); MCG->C2 &= ~(uint8_t)(MCG_C2_LP_MASK);
...@@ -330,10 +353,10 @@ static void kinetis_mcg_set_pbe(void) ...@@ -330,10 +353,10 @@ static void kinetis_mcg_set_pbe(void)
MCG->C6 |= (uint8_t)(MCG_C6_PLLS_MASK); MCG->C6 |= (uint8_t)(MCG_C6_PLLS_MASK);
/* Wait until the source of the PLLS clock is PLL */ /* Wait until the source of the PLLS clock is PLL */
while ((MCG->S & MCG_S_PLLST_MASK) == 0); while ((MCG->S & MCG_S_PLLST_MASK) == 0) {}
/* Wait until PLL locked */ /* Wait until PLL locked */
while ((MCG->S & MCG_S_LOCK0_MASK) == 0); while ((MCG->S & MCG_S_LOCK0_MASK) == 0) {}
current_mode = KINETIS_MCG_PBE; current_mode = KINETIS_MCG_PBE;
} }
...@@ -350,135 +373,52 @@ static void kinetis_mcg_set_pee(void) ...@@ -350,135 +373,52 @@ static void kinetis_mcg_set_pee(void)
MCG->C1 &= ~(uint8_t)(MCG_C1_CLKS_MASK); MCG->C1 &= ~(uint8_t)(MCG_C1_CLKS_MASK);
/* Wait until output of the PLL is selected */ /* Wait until output of the PLL is selected */
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)); while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) {}
current_mode = KINETIS_MCG_PEE; current_mode = KINETIS_MCG_PEE;
} }
#endif /* KINETIS_HAVE_PLL */
int kinetis_mcg_set_mode(kinetis_mcg_mode_t mode) int kinetis_mcg_set_mode(kinetis_mcg_mode_t mode)
{ {
if (mode > KINETIS_MCG_FEI) { if (mode > KINETIS_MCG_FEI) {
return -1; return -1;
} }
while (current_mode != mode) {
if (mcg_pm[current_mode] & (1 << mode)) { switch(mcg_mode_routing[current_mode][mode]) {
if (mode == KINETIS_MCG_FEI) { #if KINETIS_HAVE_PLL
kinetis_mcg_set_fei(); case KINETIS_MCG_PEE:
}
if (mode == KINETIS_MCG_FBI) {
kinetis_mcg_set_fbi();
}
if (mode == KINETIS_MCG_FEE) {
kinetis_mcg_set_fee();
}
if (mode == KINETIS_MCG_FBE) {
kinetis_mcg_set_fbe();
}
if (mode == KINETIS_MCG_BLPI) {
kinetis_mcg_set_blpi();
}
if (mode == KINETIS_MCG_BLPE) {
kinetis_mcg_set_blpe();
}
if (mode == KINETIS_MCG_PBE) {
kinetis_mcg_set_pbe();
}
if (mode == KINETIS_MCG_PEE) {
kinetis_mcg_set_pee();
}
return 0;
}
switch (mode) {
case KINETIS_MCG_PEE:
/* cppcheck-suppress duplicateExpression */
if (!(KINETIS_MCG_USE_ERC || KINETIS_MCG_USE_PLL)) {
return -1;
}
if (current_mode == KINETIS_MCG_FEI) {
/* set FBE -> PBE -> PEE */
kinetis_mcg_set_fbe();
kinetis_mcg_set_pbe();
kinetis_mcg_set_pee(); kinetis_mcg_set_pee();
return 0; break;
} case KINETIS_MCG_PBE:
if (current_mode == KINETIS_MCG_BLPE) {
/* set PBE -> PEE */
kinetis_mcg_set_pbe(); kinetis_mcg_set_pbe();
kinetis_mcg_set_pee(); break;
return 0; #endif /* KINETIS_HAVE_PLL */
} case KINETIS_MCG_BLPE:
break;
case KINETIS_MCG_BLPE:
if (!KINETIS_MCG_USE_ERC) {
return -1;
}
if (current_mode == KINETIS_MCG_PEE) {
/* set PBE -> BLPE */
kinetis_mcg_set_pbe();
kinetis_mcg_set_blpe();
return 0;
}
if (current_mode == KINETIS_MCG_FEE) {
/* set FBE -> BLPE */
kinetis_mcg_set_fbe();
kinetis_mcg_set_blpe(); kinetis_mcg_set_blpe();
return 0; break;
} case KINETIS_MCG_BLPI:
break;
case KINETIS_MCG_BLPI:
if (current_mode == KINETIS_MCG_FEE) {
/* set FBI -> BLPI */
kinetis_mcg_set_fbi();
kinetis_mcg_set_blpi(); kinetis_mcg_set_blpi();
return 0; break;
} case KINETIS_MCG_FBE:
break;
case KINETIS_MCG_FEE:
if (!KINETIS_MCG_USE_ERC) {
return -1;
}
if (current_mode == KINETIS_MCG_BLPE) {
/* set FBE -> FEE */
kinetis_mcg_set_fbe(); kinetis_mcg_set_fbe();
kinetis_mcg_set_fee(); break;
return 0; case KINETIS_MCG_FBI:
}
if (current_mode == KINETIS_MCG_BLPI) {
/* set FBI -> FEE */
kinetis_mcg_set_fbi(); kinetis_mcg_set_fbi();
break;
case KINETIS_MCG_FEE:
kinetis_mcg_set_fee(); kinetis_mcg_set_fee();
return 0; break;
} case KINETIS_MCG_FEI:
kinetis_mcg_set_fei();
break; break;
default:
default: return -1;
break; }
} }
return -1; return 0;
} }
#endif /* KINETIS_CPU_USE_MCG */ #endif /* KINETIS_CPU_USE_MCG */
/** @} */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment