aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/ports/KINETIS/KL2x/hal_lld.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/hal/ports/KINETIS/KL2x/hal_lld.c')
-rw-r--r--os/hal/ports/KINETIS/KL2x/hal_lld.c227
1 files changed, 196 insertions, 31 deletions
diff --git a/os/hal/ports/KINETIS/KL2x/hal_lld.c b/os/hal/ports/KINETIS/KL2x/hal_lld.c
index dce1588..77addf0 100644
--- a/os/hal/ports/KINETIS/KL2x/hal_lld.c
+++ b/os/hal/ports/KINETIS/KL2x/hal_lld.c
@@ -40,7 +40,7 @@
#ifdef __CC_ARM
__attribute__ ((section(".ARM.__at_0x400")))
#else
-__attribute__ ((used, section(".cfmconfig")))
+__attribute__ ((used,section(".cfmconfig")))
#endif
const uint8_t _cfm[0x10] = {
0xFF, /* NV_BACKKEY3: KEY=0xFF */
@@ -55,9 +55,20 @@ const uint8_t _cfm[0x10] = {
0xFF, /* NV_FPROT2: PROT=0xFF */
0xFF, /* NV_FPROT1: PROT=0xFF */
0xFF, /* NV_FPROT0: PROT=0xFF */
+#if defined(KINETIS_NV_FSEC_BYTE)
+ #warning Please triple check your FSEC setting: KEYEN!=b10, MEEN==b10, SEC!=b10 leads to an unmodifiable chip.
+ KINETIS_NV_FSEC_BYTE,
+#else /* KINETIS_NV_FSEC_BYTE */
0x7E, /* NV_FSEC: KEYEN=1,MEEN=3,FSLACC=3,SEC=2 */
+#endif /* KINETIS_NV_FSEC_BYTE */
+#if defined(KINETIS_NV_FOPT_BYTE)
+ KINETIS_NV_FOPT_BYTE,
+#else /* KINETIS_NV_FOPT_BYTE */
0xFF, /* NV_FOPT: ??=1,??=1,FAST_INIT=1,LPBOOT1=1,RESET_PIN_CFG=1,
NMI_DIS=1,EZPORT_DIS=1,LPBOOT0=1 */
+ /* on KL27: bit7-6:BOOTSRC_SEL=0b11 (11=from ROM; 00=from FLASH)
+ bit1:BOOTPIN_OPT=1 (NMI pin not sampled at boot) */
+#endif /* KINETIS_NV_FOPT_BYTE */
0xFF,
0xFF
};
@@ -91,6 +102,7 @@ void hal_lld_init(void) {
*/
void kl2x_clock_init(void) {
#if !KINETIS_NO_INIT
+
/* Disable COP watchdog */
SIM->COPC = 0;
@@ -107,16 +119,118 @@ void kl2x_clock_init(void) {
/* System oscillator drives 32 kHz clock (OSC32KSEL=0) */
SIM->SOPT1 &= ~SIM_SOPT1_OSC32KSEL_MASK;
+#if KINETIS_HAS_MCG_LITE
+/* MCU only has MCG_Lite */
+
+#if KINETIS_MCGLITE_MODE == KINETIS_MCGLITE_MODE_LIRC8M
+ /* Out of reset, the MCU is in LIRC8M mode. */
+ /* Except when coming out of the ROM bootloader, then
+ * the MCU is in HIRC mode; so better set it explicitly here. */
+
+ /* Switching to LIRC8M mode, page 414 of the KL27Z manual. */
+
+ /* (1) Write 1b to MCG_C2[IRCS] to select LIRC 8M. */
+ MCG->C2 |= MCG_C2_IRCS;
+
+ /* (2) Write 1b to MCG_C1[IRCLKEN] to enable LIRC clock (optional). */
+ MCG->C1 |= MCG_C1_IRCLKEN;
+
+ /* (2) Write 01b to MCG_C1[CLKS] to select LIRC clock source. */
+ MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS_LIRC;
+
+ /* (3) Check MCG_S[CLKST] to confirm LIRC clock source is selected. */
+ while( (MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST_LIRC )
+ ;
+
+#elif KINETIS_MCGLITE_MODE == KINETIS_MCGLITE_MODE_HIRC
+ /* Switching to HIRC mode, page 413 of the KL27Z manual. */
+
+ /* (1) Write 1b to MCG_MC[HIRCEN] to enable HIRC (optional). */
+ MCG->MC |= MCG_MC_HIRCEN;
+
+ /* (2) Write 00b to MCG_C1[CLKS] to select HIRC clock source. */
+ MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS_HIRC;
+
+ /* (3) Check MCG_S[CLKST] to confirm HIRC clock source is selected. */
+ while( (MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST_HIRC )
+ ;
+
+#elif KINETIS_MCGLITE_MODE == KINETIS_MCGLITE_MODE_EXT
+ /* Assuming we have an external crystal, frequency
+ * specified with KINETIS_XTAL_FREQUENCY.
+ *
+ * Note: Except with 32768 kHz crystal (low-freq mode),
+ * external load capacitors and a feedback resistor
+ * are *required*. Additionally, a series resistor is
+ * required in the high-gain mode, and forbidden in
+ * the low-power mode.
+ * In this case, the internal caps can be configured
+ * via KINETIS_BOARD_OSCILLATOR_SETTING.
+ * (Page 420 of the KL27 manual.) */
+
+ /* EXTAL0 and XTAL0 */
+ PORTA->PCR[18] &= ~0x01000700; /* Set PA18 to analog (default) */
+ PORTA->PCR[19] &= ~0x01000700; /* Set PA19 to analog (default) */
+
+ /* Internal capacitors for crystal */
+#if defined(KINETIS_BOARD_OSCILLATOR_SETTING)
+ OSC0->CR = KINETIS_BOARD_OSCILLATOR_SETTING;
+#else /* KINETIS_BOARD_OSCILLATOR_SETTING */
+ /* Disable the internal capacitors */
+ OSC0->CR = 0;
+#endif /* KINETIS_BOARD_OSCILLATOR_SETTING */
+
+ /* Switching to EXT mode, page 413 of the KL27 manual. */
+
+ /* (1) Configure MCG_C2[EREFS0] for external clock source selection. */
+ #if KINETIS_XTAL_FREQUENCY == 32768 /* low range */
+ MCG->C2 = (MCG->C2 & ~MCG_C2_RANGE0_MASK) | MCG_C2_RANGE0(0);
+ #elif (KINETIS_XTAL_FREQUENCY >= 1000000 && \
+ KINETIS_XTAL_FREQUENCY <= 8000000) /* high range */
+ MCG->C2 = (MCG->C2 & ~MCG_C2_RANGE0_MASK) | MCG_C2_RANGE0(1);
+ #elif (KINETIS_XTAL_FREQUENCY > 8000000 && \
+ KINETIS_XTAL_FREQUENCY <= 32000000) /* very high range */
+ MCG->C2 = (MCG->C2 & ~MCG_C2_RANGE0_MASK) | MCG_C2_RANGE0(2);
+ #else /* KINETIS_XTAL_FREQUENCY == */
+ #error KINETIS_XTAL_FREQUENCY not in allowed range
+ #endif /* KINETIS_XTAL_FREQUENCY == */
+
+ #if defined(KINETIS_XTAL_HIGH_GAIN) && KINETIS_XTAL_HIGH_GAIN
+ MCG->C2 |= MCG_C2_HGO0;
+ #endif /* KINETIS_XTAL_HIGH_GAIN */
+
+ /* Oscillator requested. */
+ MCG->C2 |= MCG_C2_EREFS0;
+
+ /* (2) Write 10b to MCG_C1[CLKS] to select external clock source. */
+ MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS_EXT;
+
+ /* (3) Check MCG_S[CLKST] to confirm external clock source is selected. */
+ while( (MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST_EXT )
+ ;
+
+#else /* KINETIS_MCGLITE_MODE */
+#error Unimplemented KINETIS_MCGLITE_MODE
+#endif /* KINETIS_MCGLITE_MODE */
+
+#else /* KINETIS_HAS_MCG_LITE */
+/* MCU has full blown MCG */
+
#if KINETIS_MCG_MODE == KINETIS_MCG_MODE_FEI
/* This is the default mode at reset. */
/* The MCGOUTCLK is divided by OUTDIV1 and OUTDIV4:
* OUTDIV1 (divider for core/system and bus/flash clock)
* OUTDIV4 (additional divider for bus/flash clock) */
SIM->CLKDIV1 =
- SIM_CLKDIV1_OUTDIV1(1) | /* OUTDIV1 = divide-by-2 => 24 MHz */
- SIM_CLKDIV1_OUTDIV4(0); /* OUTDIV4 = divide-by-1 => 24 MHz */
+ SIM_CLKDIV1_OUTDIV1(KINETIS_CLKDIV1_OUTDIV1-1) |
+ SIM_CLKDIV1_OUTDIV4(KINETIS_CLKDIV1_OUTDIV4-1);
+
+ /* Configure FEI mode */
+ MCG->C4 = MCG_C4_DRST_DRS(KINETIS_MCG_FLL_DRS) |
+ (KINETIS_MCG_FLL_DMX32 ? MCG_C4_DMX32 : 0);
#elif KINETIS_MCG_MODE == KINETIS_MCG_MODE_FEE
+ /* TODO: check this, for generality */
/*
* FLL Enabled External (FEE) MCG Mode
* 24 MHz core, 12 MHz bus - using 32.768 kHz crystal with FLL.
@@ -138,14 +252,20 @@ void kl2x_clock_init(void) {
* OUTDIV1 (divider for core/system and bus/flash clock)
* OUTDIV4 (additional divider for bus/flash clock) */
SIM->CLKDIV1 =
- SIM_CLKDIV1_OUTDIV1(KINETIS_MCG_FLL_OUTDIV1 - 1) |
- SIM_CLKDIV1_OUTDIV4(KINETIS_MCG_FLL_OUTDIV4 - 1);
+ SIM_CLKDIV1_OUTDIV1(KINETIS_CLKDIV1_OUTDIV1 - 1) |
+ SIM_CLKDIV1_OUTDIV4(KINETIS_CLKDIV1_OUTDIV4 - 1);
/* EXTAL0 and XTAL0 */
PORTA->PCR[18] &= ~0x01000700; /* Set PA18 to analog (default) */
PORTA->PCR[19] &= ~0x01000700; /* Set PA19 to analog (default) */
+ /* Internal capacitors for crystal */
+#if defined(KINETIS_BOARD_OSCILLATOR_SETTING)
+ OSC0->CR = KINETIS_BOARD_OSCILLATOR_SETTING;
+#else /* KINETIS_BOARD_OSCILLATOR_SETTING */
+ /* Disable the internal capacitors */
OSC0->CR = 0;
+#endif /* KINETIS_BOARD_OSCILLATOR_SETTING */
/* From KL25P80M48SF0RM section 24.5.1.1 "Initializing the MCG". */
/* To change from FEI mode to FEE mode: */
@@ -183,35 +303,40 @@ void kl2x_clock_init(void) {
seems to omit it. */
#elif KINETIS_MCG_MODE == KINETIS_MCG_MODE_PEE
+ uint32_t ratio, frdiv;
+ uint32_t ratios[] = { 32, 64, 128, 256, 512, 1024, 1280, 1536 };
+ uint8_t ratio_quantity = sizeof(ratios) / sizeof(ratios[0]);
+ uint8_t i;
+
/*
* PLL Enabled External (PEE) MCG Mode
- * 48 MHz core, 24 MHz bus - using 8 MHz crystal with PLL.
+ * Uses external crystal (KINETIS_XTAL_FREQUENCY) with PLL.
* f_MCGOUTCLK = (OSCCLK / PLL_R) * M
- * = 8 MHz / 2 * 24 = 96 MHz
+ * OSCCLK = KINETIS_XTAL_FREQUENCY
* PLL_R is the reference divider selected by C5[PRDIV0]
+ * (OSCCLK/PLL_R must be between 2 and 4 MHz)
* M is the multiplier selected by C6[VDIV0]
*
+ * Running from PLL, so assuming PLLCLK = MCGOUTCLK.
+ *
* Then the core/system and bus/flash clocks are divided:
* f_SYS = f_MCGOUTCLK / OUTDIV1 = 96 MHz / 2 = 48 MHz
* f_BUS = f_MCGOUTCLK / OUTDIV1 / OUTDIV4 = 96 MHz / 4 = 24 MHz
*/
- /* The MCGOUTCLK is divided by OUTDIV1 and OUTDIV4:
- * OUTDIV1 (divider for core/system and bus/flash clock)
- * OUTDIV4 (additional divider for bus/flash clock) */
- SIM->CLKDIV1 =
- SIM_CLKDIV1_OUTDIV1(1) | /* OUTDIV1 = divide-by-2 => 48 MHz */
- SIM_CLKDIV1_OUTDIV4(1); /* OUTDIV4 = divide-by-2 => 24 MHz */
-
- SIM->SOPT2 =
- SIM_SOPT2_TPMSRC(1) | /* MCGFLLCLK clock or MCGPLLCLK/2 */
- SIM_SOPT2_PLLFLLSEL; /* PLLFLLSEL=MCGPLLCLK/2 */
-
/* EXTAL0 and XTAL0 */
PORTA->PCR[18] &= ~0x01000700; /* Set PA18 to analog (default) */
PORTA->PCR[19] &= ~0x01000700; /* Set PA19 to analog (default) */
+ /* Start in FEI mode */
+
+ /* Internal capacitors for crystal */
+#if defined(KINETIS_BOARD_OSCILLATOR_SETTING)
+ OSC0->CR = KINETIS_BOARD_OSCILLATOR_SETTING;
+#else /* KINETIS_BOARD_OSCILLATOR_SETTING */
+ /* Disable the internal capacitors */
OSC0->CR = 0;
+#endif /* KINETIS_BOARD_OSCILLATOR_SETTING */
/* From KL25P80M48SF0RM section 24.5.1.1 "Initializing the MCG". */
/* To change from FEI mode to FBE mode: */
@@ -220,15 +345,27 @@ void kl2x_clock_init(void) {
resistor since FRDM-KL25Z has feedback resistor R25 unpopulated.
Use high-gain mode by setting C2[HGO0] instead if external
feedback resistor Rf is installed. */
- MCG->C2 =
- MCG_C2_RANGE0(2) | /* very high frequency range */
- MCG_C2_EREFS0; /* external reference (using a crystal) */
+ MCG->C2 = MCG_C2_EREFS0; /* external reference (using a crystal) */
+ if (KINETIS_XTAL_FREQUENCY > 8000000UL)
+ MCG->C2 |= MCG_C2_RANGE0(2);
+ else
+ MCG->C2 |= MCG_C2_RANGE0(1);
/* (2) Write to C1 to select the clock mode. */
+ frdiv = 7;
+ ratio = KINETIS_XTAL_FREQUENCY / 31250UL;
+ for (i = 0; i < ratio_quantity; ++i) {
+ if (ratio == ratios[i]) {
+ frdiv = i;
+ break;
+ }
+ }
+
+ /* Switch to crystal as clock source, FLL input of 31.25 KHz */
MCG->C1 = /* Clear the IREFS bit to switch to the external reference. */
- MCG_C1_CLKS_ERCLK | /* Use ERCLK for system clock, MCGCLKOUT. */
- MCG_C1_FRDIV(3); /* Divide ERCLK / 256 for FLL reference. */
- /* Note: FLL reference frequency must be 31.25 kHz to 39.0625 kHz.
- 8 MHz / 256 = 31.25 kHz. */
+ MCG_C1_CLKS_ERCLK | /* Use Ext Ref Clock for system clock, MCGCLKOUT. */
+ MCG_C1_FRDIV(frdiv); /* Divide ERCLK / 256 for FLL reference. */
+ /* Note: FLL reference frequency must be 31.25 kHz to 39.0625 kHz. */
+
MCG->C4 &= ~(MCG_C4_DMX32 | MCG_C4_DRST_DRS_MASK);
MCG->C6 = 0; /* PLLS=0: Select FLL as MCG source, not PLL */
@@ -254,11 +391,25 @@ void kl2x_clock_init(void) {
/* (2) Then configure C5[PRDIV0] to generate the
correct PLL reference frequency. */
- MCG->C5 = MCG_C5_PRDIV0(1); /* PLL External Reference Divide by 2 */
+ #define KINETIS_PLLIN_FREQUENCY 2000000UL
+ /* TODO: Make sure KINETIS_XTAL_FREQUENCY >= 2Mhz && <= 50Mhz */
+ /* PLL External Reference Divide by ... */
+ MCG->C5 = MCG_C5_PRDIV0((KINETIS_XTAL_FREQUENCY/KINETIS_PLLIN_FREQUENCY) - 1);
/* (3) Then from FBE transition to PBE mode. */
/* (3)(b) C6[PLLS]=1 to select PLL. */
- /* (3)(b) C6[VDIV0]=5'b0000 (x24) 2 MHz * 24 = 48 MHz. */
- MCG->C6 = MCG_C6_PLLS | MCG_C6_VDIV0(0);
+ /* (3)(b) C6[VDIV0]= PLLIN MHz * i = PLLCLK MHz. */
+ /* Config PLL output to match KINETIS_SYSCLK_FREQUENCY
+ * TODO: make sure KINETIS_SYSCLK_FREQUENCY is a match */
+ for(i = 24; i < 56; i++) {
+ if(i == (KINETIS_PLLCLK_FREQUENCY/KINETIS_PLLIN_FREQUENCY)) {
+ /* Config PLL to match KINETIS_PLLCLK_FREQUENCY */
+ MCG->C6 = MCG_C6_PLLS | MCG_C6_VDIV0(i-24);
+ break;
+ }
+ }
+ if(i>=56) /* Config PLL for 96 MHz output as default setting */
+ MCG->C6 = MCG_C6_PLLS | MCG_C6_VDIV0(0);
+
/* (3)(d) Loop until S[PLLST], indicating PLL
is the PLLS clock source. */
while ((MCG->S & MCG_S_PLLST) == 0)
@@ -270,14 +421,26 @@ void kl2x_clock_init(void) {
/* --- MCG mode: PBE (PLL bypassed, external crystal) --- */
+ /* Set the PLL dividers for the different clocks */
+ /* The MCGOUTCLK is divided by OUTDIV1 and OUTDIV4:
+ * OUTDIV1 (divider for core/system and bus/flash clock)
+ * OUTDIV4 (additional divider for bus/flash clock)
+ * - these are computed in .h */
+ SIM->CLKDIV1 =
+ SIM_CLKDIV1_OUTDIV1(KINETIS_CLKDIV1_OUTDIV1-1) |
+ SIM_CLKDIV1_OUTDIV4(KINETIS_CLKDIV1_OUTDIV4-1);
+
+ SIM->SOPT2 =
+ SIM_SOPT2_TPMSRC(1) | /* MCGFLLCLK clock or MCGPLLCLK/2 */
+ SIM_SOPT2_PLLFLLSEL; /* PLLFLLSEL=MCGPLLCLK/2 */
+
/* (4) Transition from PBE mode to PEE mode. */
/* (4)(a) C1[CLKS] = 2'b00 to select PLL output as system clock source. */
// Switch to PEE mode
// Select PLL output (CLKS=0)
- // FLL external reference divider (FRDIV=3)
+ // FLL external reference divider (FRDIV) already set
// External reference clock for FLL (IREFS=0)
- MCG->C1 = MCG_C1_CLKS(0) |
- MCG_C1_FRDIV(3);
+ MCG->C1 = MCG_C1_CLKS(0);
/* (4)(b) Loop until S[CLKST] are 2'b11, indicating the PLL output is selected for MCGOUTCLK. */
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST_PLL)
; /* wait until clock switched to PLL output */
@@ -288,6 +451,8 @@ void kl2x_clock_init(void) {
#error Unimplemented KINETIS_MCG_MODE
#endif /* KINETIS_MCG_MODE != KINETIS_MCG_MODE_PEE */
+#endif /* KINETIS_HAS_MCG_LITE */
+
#endif /* !KINETIS_NO_INIT */
}