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.
pull/145/head
Sissors 2014-01-14 22:57:43 +01:00
parent aa0f7a7026
commit 153a9ddb49
4 changed files with 52 additions and 9 deletions

View File

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

View File

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

View File

@ -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<<SIM_SOPT2_UART0SRC_SHIFT);
case UART_0: if (mcgpllfll_frequency() != 0) //PLL/FLL is selected
SIM->SOPT2 |= (1<<SIM_SOPT2_UART0SRC_SHIFT);
else
SIM->SOPT2 |= (2<<SIM_SOPT2_UART0SRC_SHIFT);
SIM->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,

View File

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