kinetis: Simplify MCG state traversal algorithm

The new implementation uses a precalculated map of which mode to switch
to next if going from mode A to mode B. This simplifies the
implementation for moving between modes which are not direct neighbors.
See mcg.h documentation for a diagram of the state machine for the
clocking modes. Also found in the CPU reference manual of all Kinetis
CPUs, MCG chapter, MCG mode state diagram.
This commit is contained in:
Joakim Nohlgård 2017-04-27 15:37:40 +02:00
parent f9ed160fe2
commit a8450f2952

View File

@ -1,5 +1,6 @@
/* /*
* 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 @@
* @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,18 @@
#if KINETIS_CPU_USE_MCG #if KINETIS_CPU_USE_MCG
/* MCG neighbor modes matrix */ /* Pathfinding for the clocking modes, this table lists the next mode in the
static uint8_t mcg_pm[8] = {0x02, 0x15, 0x12, 0x20, 0xe6, 0xd8, 0xb0, 0xf0}; * 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;
@ -361,124 +373,39 @@ 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) { case KINETIS_MCG_PEE:
kinetis_mcg_set_fei();
}
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_pee();
return 0;
}
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_pbe();
break;
case KINETIS_MCG_BLPE:
kinetis_mcg_set_blpe(); kinetis_mcg_set_blpe();
return 0; break;
} case KINETIS_MCG_BLPI:
if (current_mode == KINETIS_MCG_FEE) {
/* set FBE -> BLPE */
kinetis_mcg_set_fbe();
kinetis_mcg_set_blpe();
return 0;
}
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 */
/** @} */