Hi!
I'm assembling my FreeRTOS environment to a TWR-K65F devboard. The MCUXpresso SDK is SDK_2.9.0_MK65FN2M0xxx18. This package contains the same clock config scheme in many instances (under boards/frdmk66f with the name of config_clock.c). My preferred selection is the 180MHz high speed mode, so the following are taken from config_clock.c:
const mcg_config_t mcgConfig_BOARD_BootClockHSRUN = {
.mcgMode = kMCG_ModePEE, /* PEE - PLL Engaged External */
.irclkEnableMode = kMCG_IrclkEnable | kMCG_IrclkEnableInStop, /* MCGIRCLK enabled as well as in STOP mode */
.ircs = kMCG_IrcSlow, /* Slow internal reference clock selected */
.fcrdiv = 0x0U, /* Fast IRC divider: divided by 1 */
.frdiv = 0x0U, /* FLL reference clock divider: divided by 32 */
.drs = kMCG_DrsLow, /* Low frequency range */
.dmx32 = kMCG_Dmx32Default, /* DCO has a default range of 25% */
.oscsel = kMCG_OscselOsc, /* Selects System Oscillator (OSCCLK) */
.pll0Config =
{
.enableMode = MCG_PLL_DISABLE, /* MCGPLLCLK disabled */
.prdiv = 0x0U, /* PLL Reference divider: divided by 1 */
.vdiv = 0xeU, /* VCO divider: multiplied by 30 */
},
.pllcs = kMCG_PllClkSelPll0, /* PLL0 output clock is selected */
};
const sim_clock_config_t simConfig_BOARD_BootClockHSRUN = {
.pllFllSel = SIM_PLLFLLSEL_MCGPLLCLK_CLK, /* PLLFLL select: MCGPLLCLK clock */
.pllFllDiv = 0, /* PLLFLLSEL clock divider divisor: divided by 1 */
.pllFllFrac = 0, /* PLLFLLSEL clock divider fraction: multiplied by 1 */
.er32ksrc=SIM_OSC32KSEL_RTC32KCLK_CLK, /* OSC32KSEL select: RTC32KCLK clock (32.768kHz) */
.clkdiv1 = 0x2260000U, /* SIM_CLKDIV1 - OUTDIV1: /1, OUTDIV2: /3, OUTDIV3: /3, OUTDIV4: /7 */
};
const osc_config_t oscConfig_BOARD_BootClockHSRUN = {
.freq = 12000000U, /* Oscillator frequency: 12000000Hz */
.capLoad = (OSC_CAP0P), /* Oscillator capacity load: 0pF */
.workMode = kOSC_ModeOscLowPower, /* Oscillator low power */
.oscerConfig = {
.enableMode =
kOSC_ErClkEnable, /* Enable external reference clock, disable external reference clock in STOP mode */
.erclkDiv = 0, /* Divider for OSCERCLK: divided by 1 */
}};
/*******************************************************************************
* Code for BOARD_BootClockHSRUN configuration
******************************************************************************/
void BOARD_BootClockHSRUN(void)
{
/* Set HSRUN power mode */
SMC_SetPowerModeProtection(SMC, kSMC_AllowPowerModeAll);
SMC_SetPowerModeHsrun(SMC);
while (SMC_GetPowerModeState(SMC) != kSMC_PowerStateHsrun)
{
}
/* Set the system clock dividers in SIM to safe value. */
CLOCK_SetSimSafeDivs();
/* Initializes OSC0 according to board configuration. */
CLOCK_InitOsc0(&oscConfig_BOARD_BootClockHSRUN);
CLOCK_SetXtal0Freq(oscConfig_BOARD_BootClockHSRUN.freq);
/* Configure the Internal Reference clock (MCGIRCLK). */
CLOCK_SetInternalRefClkConfig(mcgConfig_BOARD_BootClockHSRUN.irclkEnableMode, mcgConfig_BOARD_BootClockHSRUN.ircs,
mcgConfig_BOARD_BootClockHSRUN.fcrdiv);
/* Configure FLL external reference divider (FRDIV). */
CLOCK_CONFIG_SetFllExtRefDiv(mcgConfig_BOARD_BootClockHSRUN.frdiv);
/* Set MCG to PEE mode. */
CLOCK_BootToPeeMode(mcgConfig_BOARD_BootClockHSRUN.oscsel, mcgConfig_BOARD_BootClockHSRUN.pllcs,
&mcgConfig_BOARD_BootClockHSRUN.pll0Config);
/* Set the clock configuration in SIM module. */
CLOCK_SetSimConfig(&simConfig_BOARD_BootClockHSRUN);
/* Set SystemCoreClock variable. */
SystemCoreClock = BOARD_BOOTCLOCKHSRUN_CORE_CLOCK;
}
Everything is fine as long as I want to set up UART2 (PTE16-17) for 115200-8N1 console purposes. (UART2 is wired to the companion Kinetis MCU on the board and that converts it to a USB device appearing as /dev/ttACM* in linux). This is the key part in my console driver:
UART_Init(desc->uart, &ucfg, CLOCK_GetBusClkFreq());
After transmitting bytes with UART2, only garbage can be seen in minicom terminal emulator. However, if I change the above statement to this:
UART_Init(desc->uart, &ucfg, 80000000UL);
minicom begins receiving what it's supposed to.
I don't think that either minicom or linux CDC ACM driver is faulty. Instead, that 80MHz is very suspicious. In theory (and according to SIM clockdiv settings) the peripheral bus cannot go over 60MHz, but with 60MHz in UART_Init the baudrate is inadequate. Raising it to 80MHz seems to generate nice baudrate (the real expected 115200bps). I simply don't understand this (calculation error in UART driver module?).
The same happens if I select the 120MHz config.
The manual says peripheral bus must not run over 60MHz, and inspecting SIM clockdiv settings the divisor for peripheral bus clock is proper.
Also suspicious that 80MHz is 33% more than 60MHz.
Could you please help me out with this? I don't want to use 80000000 instead of 60000000, because it's a hack and I'll have to use UART for other purposes too (e.g. RS485) where the exact baudrate generation is crucial.