From e1a660eb9d011a75f9afcbc4ed1377c26034e7be Mon Sep 17 00:00:00 2001 From: chrysn Date: Sun, 4 Mar 2012 16:59:20 +0100 Subject: [PATCH] efm32 cmu: convenience functions includes a fix for the register definitions (subtle differences between two fields) --- .../efm32/tinygecko/cmu.convenienceheaders | 63 +++++++++++++++ include/libopencm3/efm32/tinygecko/cmu.h | 79 +++++++++++++++++-- include/libopencm3/efm32/tinygecko/cmu.yaml | 12 ++- 3 files changed, 144 insertions(+), 10 deletions(-) diff --git a/include/libopencm3/efm32/tinygecko/cmu.convenienceheaders b/include/libopencm3/efm32/tinygecko/cmu.convenienceheaders index e69de29b..212405d9 100644 --- a/include/libopencm3/efm32/tinygecko/cmu.convenienceheaders +++ b/include/libopencm3/efm32/tinygecko/cmu.convenienceheaders @@ -0,0 +1,63 @@ +/** CMU convenience functions + * + * These functions assist in clock switching, and are intended to be safer to + * use than direct fiddling with registers. They try to be suitable for typical + * applications, and will invest some bytes of code in order to minimize power + * consumption. + * + * @todo Work on this module is stalled until I can figure out if there is a + * way to have a cmu_shutdown_unused function at all. + * + * @defgroup EFM32TG_CMU_convenience CMU convenience functions + * @{ + */ + +/** Disable all oscillators not currently in use. + * + * The implementation follows d0034_efm32tg_reference_manual.pdf figure 11.1. + * The clock out pin configurations are not depicted there, but described in + * section 11.3.4. + * + * @todo This function is ignorant of ongoing calibrations. + * + * @todo This doesn't work at all: Fields like HFCLKSEL are write-only. + * */ +static void cmu_shutdown_unused(void) +{ + /* Is HFXO needed? */ + if (!( + (CMU_CMD & CMU_CMD_HFCLKSEL_MASK) == CMU_CMD_HFCLKSEL_HFXO || + ( + (CMU_CTRL & CMU_CTRL_CLKOUTSEL1_MASK) == CMU_CTRL_CLKOUTSEL1_HFXOQ && + (CMU_ROUTE & CMU_ROUTE_CLKOUT1PEN) + ) || ( + (CMU_CTRL & CMU_CTRL_CLKOUTSEL0_MASK) == CMU_CTRL_CLKOUTSEL0_HFXO && + (CMU_ROUTE & CMU_ROUTE_CLKOUT0PEN) + ))) + CMU_OSCENCMD = CMU_OSCENCMD_HFXODIS; + + /* Is HFRCO neede? */ + if (!( + (CMU_CMD & CMU_CMD_HFCLKSEL_MASK) == CMU_CMD_HFCLKSEL_HFRCO || + ( + (CMU_CTRL & CMU_CTRL_CLKOUTSEL1_MASK) == CMU_CTRL_CLKOUTSEL1_HFRCOQ && + (CMU_ROUTE & CMU_ROUTE_CLKOUT1PEN) + ) || ( + (CMU_CTRL & CMU_CTRL_CLKOUTSEL0_MASK) == CMU_CTRL_CLKOUTSEL0_HFRCO && + (CMU_ROUTE & CMU_ROUTE_CLKOUT0PEN) + ))) + {} +// CMU_OSCENCMD = CMU_OSCENCMD_HFRCODIS; +} + +/** Switch HFCLK to LFRC. This call is not only blocking, but even freezes + * everything depending on HFCLK until LFRC is stable. The procedure is + * sketched in d0034_efm32tg_reference_manual.pdf figure 11.2. */ +static void cmu_hfclk_switch_blocking(void) +{ + CMU_OSCENCMD = CMU_OSCENCMD_LFRCOEN; + CMU_CMD = CMU_CMD_HFCLKSEL_LFRCO; + CMU_OSCENCMD = CMU_OSCENCMD_HFRCODIS; +} + +/** @} */ diff --git a/include/libopencm3/efm32/tinygecko/cmu.h b/include/libopencm3/efm32/tinygecko/cmu.h index aafb261b..210a6382 100644 --- a/include/libopencm3/efm32/tinygecko/cmu.h +++ b/include/libopencm3/efm32/tinygecko/cmu.h @@ -100,14 +100,14 @@ #define CMU_CTRL_CLKOUTSEL1_HFRCOQ (6<<23) #define CMU_CTRL_CLKOUTSEL1_AUXHFRCOQ (7<<23) #define CMU_CTRL_CLKOUTSEL1_MASK (0x7<<23) -#define CMU_CTRL_CLKOUTSEL0_LFRCO (0<<20) -#define CMU_CTRL_CLKOUTSEL0_LFXO (1<<20) -#define CMU_CTRL_CLKOUTSEL0_HFCLK (2<<20) -#define CMU_CTRL_CLKOUTSEL0_LFXOQ (3<<20) -#define CMU_CTRL_CLKOUTSEL0_HFXOQ (4<<20) -#define CMU_CTRL_CLKOUTSEL0_LFRCOQ (5<<20) -#define CMU_CTRL_CLKOUTSEL0_HFRCOQ (6<<20) -#define CMU_CTRL_CLKOUTSEL0_AUXHFRCOQ (7<<20) +#define CMU_CTRL_CLKOUTSEL0_HFRCO (0<<20) +#define CMU_CTRL_CLKOUTSEL0_HFXO (1<<20) +#define CMU_CTRL_CLKOUTSEL0_HFCLK2 (2<<20) +#define CMU_CTRL_CLKOUTSEL0_HFCLK4 (3<<20) +#define CMU_CTRL_CLKOUTSEL0_HFCLK8 (4<<20) +#define CMU_CTRL_CLKOUTSEL0_HFCLK16 (5<<20) +#define CMU_CTRL_CLKOUTSEL0_ULFRCO (6<<20) +#define CMU_CTRL_CLKOUTSEL0_AUXHFRCO (7<<20) #define CMU_CTRL_CLKOUTSEL0_MASK (0x7<<20) #define CMU_CTRL_LFXOTIMEOUT_8CYCLES (0<<18) #define CMU_CTRL_LFXOTIMEOUT_1KCYCLES (1<<18) @@ -580,6 +580,69 @@ /** @} */ +/** CMU convenience functions + * + * These functions assist in clock switching, and are intended to be safer to + * use than direct fiddling with registers. They try to be suitable for typical + * applications, and will invest some bytes of code in order to minimize power + * consumption. + * + * @todo Work on this module is stalled until I can figure out if there is a + * way to have a cmu_shutdown_unused function at all. + * + * @defgroup EFM32TG_CMU_convenience CMU convenience functions + * @{ + */ + +/** Disable all oscillators not currently in use. + * + * The implementation follows d0034_efm32tg_reference_manual.pdf figure 11.1. + * The clock out pin configurations are not depicted there, but described in + * section 11.3.4. + * + * @todo This function is ignorant of ongoing calibrations. + * + * @todo This doesn't work at all: Fields like HFCLKSEL are write-only. + * */ +static void cmu_shutdown_unused(void) +{ + /* Is HFXO needed? */ + if (!( + (CMU_CMD & CMU_CMD_HFCLKSEL_MASK) == CMU_CMD_HFCLKSEL_HFXO || + ( + (CMU_CTRL & CMU_CTRL_CLKOUTSEL1_MASK) == CMU_CTRL_CLKOUTSEL1_HFXOQ && + (CMU_ROUTE & CMU_ROUTE_CLKOUT1PEN) + ) || ( + (CMU_CTRL & CMU_CTRL_CLKOUTSEL0_MASK) == CMU_CTRL_CLKOUTSEL0_HFXO && + (CMU_ROUTE & CMU_ROUTE_CLKOUT0PEN) + ))) + CMU_OSCENCMD = CMU_OSCENCMD_HFXODIS; + + /* Is HFRCO neede? */ + if (!( + (CMU_CMD & CMU_CMD_HFCLKSEL_MASK) == CMU_CMD_HFCLKSEL_HFRCO || + ( + (CMU_CTRL & CMU_CTRL_CLKOUTSEL1_MASK) == CMU_CTRL_CLKOUTSEL1_HFRCOQ && + (CMU_ROUTE & CMU_ROUTE_CLKOUT1PEN) + ) || ( + (CMU_CTRL & CMU_CTRL_CLKOUTSEL0_MASK) == CMU_CTRL_CLKOUTSEL0_HFRCO && + (CMU_ROUTE & CMU_ROUTE_CLKOUT0PEN) + ))) + {} +// CMU_OSCENCMD = CMU_OSCENCMD_HFRCODIS; +} + +/** Switch HFCLK to LFRC. This call is not only blocking, but even freezes + * everything depending on HFCLK until LFRC is stable. The procedure is + * sketched in d0034_efm32tg_reference_manual.pdf figure 11.2. */ +static void cmu_hfclk_switch_blocking(void) +{ + CMU_OSCENCMD = CMU_OSCENCMD_LFRCOEN; + CMU_CMD = CMU_CMD_HFCLKSEL_LFRCO; + CMU_OSCENCMD = CMU_OSCENCMD_HFRCODIS; +} + +/** @} */ /** @} */ diff --git a/include/libopencm3/efm32/tinygecko/cmu.yaml b/include/libopencm3/efm32/tinygecko/cmu.yaml index 0229de19..bba053c4 100644 --- a/include/libopencm3/efm32/tinygecko/cmu.yaml +++ b/include/libopencm3/efm32/tinygecko/cmu.yaml @@ -19,7 +19,7 @@ registers: - name: CLKOUTSEL1 shift: 23 length: 3 - values: &CLKOUTSEL1_values + values: - {name: LFRCO, value: 0} - {name: LFXO, value: 1} - {name: HFCLK, value: 2} @@ -31,7 +31,15 @@ registers: - name: CLKOUTSEL0 shift: 20 length: 3 - values: *CLKOUTSEL1_values + values: + - {name: HFRCO, value: 0} + - {name: HFXO, value: 1} + - {name: HFCLK2, value: 2} + - {name: HFCLK4, value: 3} + - {name: HFCLK8, value: 4} + - {name: HFCLK16, value: 5} + - {name: ULFRCO, value: 6} + - {name: AUXHFRCO, value: 7} - name: LFXOTIMEOUT shift: 18 length: 2