From 153a9ddb4905bf8c58105fbfb18c0787ff793023 Mon Sep 17 00:00:00 2001 From: Sissors Date: Tue, 14 Jan 2014 22:57:43 +0100 Subject: [PATCH] Added MCGPLLFLL clock function, squished some 'bugs' PWM bug mentioned here: https://mbed.org/questions/2315/BUG-Exporting-to-ARM-GCC-does-not-work-n/ Fast internal osc prescaler wasn't taken into account at us_ticker interrupt clock source, now it is. --- .../TARGET_Freescale/TARGET_KL25Z/clk_freqs.h | 21 +++++++++++++++++-- .../TARGET_KL25Z/pwmout_api.c | 11 ++++++++-- .../TARGET_KL25Z/serial_api.c | 13 +++++++++--- .../TARGET_Freescale/TARGET_KL25Z/us_ticker.c | 16 ++++++++++++-- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/clk_freqs.h b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/clk_freqs.h index 4273872b70..e50e0cd227 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/clk_freqs.h +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/clk_freqs.h @@ -72,8 +72,8 @@ static uint32_t extosc_frequency(void) { } } else { //PLL is selected divider = (1u + (MCG->C5 & MCG_C5_PRDIV0_MASK)); - multiplier = ((MCG->C6 & MCG_C6_VDIV0_MASK) + 24u); - return MCGClock * divider / multiplier; + multiplier = ((MCG->C6 & MCG_C6_VDIV0_MASK) + 24u); + return MCGClock * divider / multiplier; } } @@ -83,6 +83,23 @@ static uint32_t extosc_frequency(void) { return 0; } +//Get MCG PLL/2 or FLL frequency, depending on which one is active, sets PLLFLLSEL bit +static uint32_t mcgpllfll_frequency(void) { + if ((MCG->C1 & MCG_C1_CLKS_MASK) != MCG_C1_CLKS(0)) //PLL/FLL is not selected + return 0; + + uint32_t MCGClock = SystemCoreClock * (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)); + if ((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u) { //FLL is selected + SIM->SOPT2 &= ~SIM_SOPT2_PLLFLLSEL_MASK; //MCG peripheral clock is FLL output + return MCGClock; + } else { //PLL is selected + SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK; //MCG peripheral clock is PLL output + return (MCGClock >> 1); + } + + //It is possible the SystemCoreClock isn't running on the PLL, and the PLL is still active + //for the peripherals, this is however an unlikely setup +} #ifdef __cplusplus } diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/pwmout_api.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/pwmout_api.c index 447d1c6e5b..48861646f9 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/pwmout_api.c +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/pwmout_api.c @@ -18,6 +18,7 @@ #include "cmsis.h" #include "pinmap.h" #include "error.h" +#include "clk_freqs.h" static const PinMap PinMap_PWM[] = { // LEDs @@ -73,7 +74,14 @@ void pwmout_init(pwmout_t* obj, PinName pin) { error("PwmOut pin mapping failed"); uint32_t clkdiv = 0; - float clkval = SystemCoreClock / 1000000.0f; + float clkval; + if (mcgpllfll_frequency()) { + SIM->SOPT2 |= SIM_SOPT2_TPMSRC(1); // Clock source: MCGFLLCLK or MCGPLLCLK + clkval = mcgpllfll_frequency() / 1000000.0f; + } else { + SIM->SOPT2 |= SIM_SOPT2_TPMSRC(2); // Clock source: ExtOsc + clkval = extosc_frequency() / 1000000.0f; + } while (clkval > 1) { clkdiv++; @@ -89,7 +97,6 @@ void pwmout_init(pwmout_t* obj, PinName pin) { SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port); SIM->SCGC6 |= 1 << (SIM_SCGC6_TPM0_SHIFT + tpm_n); - SIM->SOPT2 |= SIM_SOPT2_TPMSRC(1); // Clock source: MCGFLLCLK or MCGPLLCLK TPM_Type *tpm = (TPM_Type *)(TPM0_BASE + 0x1000 * tpm_n); tpm->SC = TPM_SC_CMOD(1) | TPM_SC_PS(clkdiv); // (clock)MHz / clkdiv ~= (0.75)MHz diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/serial_api.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/serial_api.c index fe986519bc..e1b882e3c4 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/serial_api.c +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/serial_api.c @@ -71,8 +71,8 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) { obj->uart = (UARTLP_Type *)uart; // enable clk switch (uart) { - case UART_0: if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0)) //PLL/FLL is selected - SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK | (1<SOPT2 |= (1<SOPT2 |= (2<SCGC5 |= SIM_SCGC5_PORTA_MASK; SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break; @@ -123,7 +123,14 @@ void serial_baud(serial_t *obj, int baudrate) { // Disable UART before changing registers obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK); - uint32_t PCLK = (obj->uart == UART0) ? SystemCoreClock : bus_frequency(); + uint32_t PCLK; + if (obj->uart == UART0) { + if (mcgpllfll_frequency() != 0) + PCLK = mcgpllfll_frequency(); + else + PCLK = extosc_frequency(); + } else + PCLK = bus_frequency(); // First we check to see if the basic divide with no DivAddVal/MulVal // ratio gives us an integer result. If it does, we set DivAddVal = 0, diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/us_ticker.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/us_ticker.c index 2b33130b2f..3f0bf61b68 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/us_ticker.c +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/us_ticker.c @@ -102,10 +102,22 @@ static void lptmr_init(void) { } } } - //No suitable external oscillator clock -> Use fast internal oscillator (4MHz) + //No suitable external oscillator clock -> Use fast internal oscillator (4MHz / divider) MCG->C1 |= MCG_C1_IRCLKEN_MASK; MCG->C2 |= MCG_C2_IRCS_MASK; - LPTMR0->PSR = LPTMR_PSR_PCS(0) | LPTMR_PSR_PRESCALE(1); + LPTMR0->PSR = LPTMR_PSR_PCS(0); + switch (MCG->SC & MCG_SC_FCRDIV_MASK) { + case MCG_SC_FCRDIV(0): //4MHz + LPTMR0->PSR |= LPTMR_PSR_PRESCALE(1); + break; + case MCG_SC_FCRDIV(1): //2MHz + LPTMR0->PSR |= LPTMR_PSR_PRESCALE(0); + break; + default: //1MHz or anything else, in which case we put it on 1MHz + MCG->SC &= ~MCG_SC_FCRDIV_MASK; + MCG->SC |= MCG_SC_FCRDIV(2); + LPTMR0->PSR |= LPTMR_PSR_PBYP_MASK; + } }