Contiki 3.x
system_MK60D10.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Eistec AB.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * This file is part of the Mulle platform port of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * Implementation of K60 clock configuration.
36  *
37  * \author
38  * Joakim Gebart <joakim.gebart@eistec.se>
39  */
40 
41 
42 
43 #include <stdint.h>
44 #include "K60.h"
45 #include "rtc.h"
46 #include "config-clocks.h"
47 
48 uint32_t SystemCoreClock = DEFAULT_SYSTEM_CLOCK; /* Current core clock frequency*/
49 uint32_t SystemSysClock = DEFAULT_SYSTEM_CLOCK; /* Current system clock frequency */
50 uint32_t SystemBusClock = DEFAULT_SYSTEM_CLOCK; /* Current bus clock frequency */
51 uint32_t SystemFlexBusClock = DEFAULT_SYSTEM_CLOCK; /* Current FlexBus clock frequency */
52 uint32_t SystemFlashClock = DEFAULT_SYSTEM_CLOCK; /* Current flash clock frequency */
53 
54 /* Initialize RTC oscillator as early as possible since we are using it as a
55  * base clock for the FLL.
56  * It takes a while to stabilize the oscillator, therefore we do this as soon as
57  * possible during boot in order to let it stabilize while other stuff is
58  * initializing. */
59 /*
60  * Arrange so that the rtc_init() function is called during early init.
61  * Start up crystal to let it stabilize while we copy data */
62 /* If the clock is not stable then the UART will have the wrong baud rate for debug prints */
63 void __attribute__((section(".preinit_array"))) (*preinit_rtc_init[])(void) = {rtc_init};
64 
65 
66 /* System clock initialization */
67 void SystemInit(void)
68 {
69  int i;
70 
71  /* Check that the running CPU revision matches the compiled revision */
72  if (SCB->CPUID != K60_EXPECTED_CPUID)
73  {
74  uint32_t CPUID = SCB->CPUID; /* This is only to ease debugging, type
75  * "print /x CPUID" in gdb */
76  uint32_t SILICON_REVISION = (SCB->CPUID & SCB_CPUID_REVISION_Msk) + 1;
77  (void)CPUID; /* prevents compiler warnings about an unused variable. */
78  (void)SILICON_REVISION;
79 
80  /* Running on the wrong CPU, the clock initialization is different
81  * between silicon revision 1.x and 2.x (LSB of CPUID) */
82  /* If you unexpectedly end up on this line when debugging:
83  * Rebuild the code using the correct value for K60_CPU_REV */
84  DEBUGGER_BREAK(BREAK_WRONG_K60_CPU_REV);
85  while(1);
86  }
87 
88  /* Set clock prescalers to safe values */
89  /*
90  * We want to achieve the following clocks:
91  * Core/system: <100MHz
92  * Bus: <50MHz
93  * FlexBus: <50MHz
94  * Flash: <25MHz
95  *
96  * using dividers 1-2-2-4 will obey the above limits when using a 96MHz FLL source.
97  */
98  SIM->CLKDIV1 = (
99  SIM_CLKDIV1_OUTDIV1(CONFIG_CLOCK_K60_SYS_DIV) | /* Core/System clock divider */
100  SIM_CLKDIV1_OUTDIV2(CONFIG_CLOCK_K60_BUS_DIV) | /* Bus clock divider */
101  SIM_CLKDIV1_OUTDIV3(CONFIG_CLOCK_K60_FB_DIV) | /* FlexBus divider, not used in Mulle */
102  SIM_CLKDIV1_OUTDIV4(CONFIG_CLOCK_K60_FLASH_DIV)); /* Flash clock divider */
103 
104  /* Select FLL as source (as opposed to PLL) */
105  SIM->SOPT2 &= ~(SIM_SOPT2_PLLFLLSEL_MASK);
106  /* Use external 32kHz RTC clock as source for OSC32K */
107  /* Check this */
108  #if K60_CPU_REV == 1
109  SIM->SOPT1 |= SIM_SOPT1_OSC32KSEL_MASK;
110  #elif K60_CPU_REV == 2
111  SIM->SOPT1 = (SIM->SOPT1 & ~(SIM_SOPT1_OSC32KSEL(0b11))) | SIM_SOPT1_OSC32KSEL(0b10);
112  #else
113  #error Unknown K60 CPU revision
114  #endif
115 
116  /* Select RTC 32kHz clock as reference clock for the FLL */
117  #if K60_CPU_REV == 1
118  /* Rev 1 parts */
119  SIM->SOPT2 |= SIM_SOPT2_MCGCLKSEL_MASK;
120  #elif K60_CPU_REV == 2
121  /* Rev 2 parts */
122  MCG->C7 = (MCG_C7_OSCSEL_MASK);
123  #else
124  #error Unknown K60 CPU revision
125  #endif
126 
127  /* Set range to low frequency input (32kHz) */
128  #if K60_CPU_REV == 1
129  /* Rev 1 parts */
130  MCG->C2 = (MCG_C2_RANGE(0));
131  #elif K60_CPU_REV == 2
132  /* Rev 2 parts renamed the parameter RANGE -> RANGE0 */
133  MCG->C2 = (MCG_C2_RANGE0(0));
134  #else
135  #error Unknown K60 CPU revision
136  #endif
137 
138  /* Select the FLL in the PLLS mux */
139  MCG->C6 &= ~(MCG_C6_PLLS_MASK);
140  while((MCG->S & MCG_S_PLLST_MASK)) {
141  /* Make sure the FLL is selected in the PLLS mux */
142  }
143 
144  /* Select FLL clock as source for the MCGCLKOUT */
145  /* Divide clock by 1 */
146  /* Select FLL as reference clock for MCG */
147  MCG->C1 = MCG_C1_CLKS(0) | MCG_C1_FRDIV(0);
148  while((MCG->S & MCG_S_IREFST_MASK) != 0u) {
149  /* Check that the source of the FLL reference clock is the external reference clock. */
150  }
151  while((MCG->S & MCG_S_CLKST_MASK) != 0x00u) {
152  /* Wait until external reference clock is selected as MCG output */
153  }
154 
155  /* Set FLL scalers to yield 96 MHz clock from 32768 Hz reference */
156  MCG->C4 = (((CONFIG_CLOCK_K60_FLL_MCG_C4_DMX32 << MCG_C4_DMX32_SHIFT) & MCG_C4_DMX32_MASK) |
157  MCG_C4_DRST_DRS(CONFIG_CLOCK_K60_FLL_MCG_C4_DRST_DRS));
158 
159  /* At this point we need to wait for 1 ms until the clock is stable.
160  * Since the clock is not yet stable we can only guess how long we must
161  * wait. I have tried to make this as short as possible but still being able
162  * to read the initialization messages written on the UART.
163  * (If the clock is not stable all UART output is garbled until it has
164  * stabilized) */
165  for(i = 0; i < 10000; ++i)
166  {
167  asm volatile ("nop\n");
168  }
169 }
170 
171 /* ----------------------------------------------------------------------------
172  -- SystemCoreClockUpdate()
173  ---------------------------------------------------------------------------- */
174 
176  uint32_t MCGOUTClock; /* Variable to store output clock frequency of the MCG module */
177  uint8_t Divider;
178 
179  if ((MCG->C1 & MCG_C1_CLKS_MASK) == 0x0u) {
180  /* Output of FLL or PLL is selected */
181  if ((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u) {
182  /* FLL is selected */
183  if ((MCG->C1 & MCG_C1_IREFS_MASK) == 0x0u) {
184  /* External reference clock is selected */
185 #if K60_CPU_REV == 1
186  /* rev.1 silicon */
187  if ((SIM->SOPT2 & SIM_SOPT2_MCGCLKSEL_MASK) == 0x0u) {
188  MCGOUTClock = CPU_XTAL_CLK_HZ; /* System oscillator drives MCG clock */
189  } else { /* (!((SIM->SOPT2 & SIM_SOPT2_MCGCLKSEL_MASK) == 0x0u)) */
190  MCGOUTClock = CPU_XTAL32k_CLK_HZ; /* RTC 32 kHz oscillator drives MCG clock */
191  } /* (!((SIM->SOPT2 & SIM_SOPT2_MCGCLKSEL_MASK) == 0x0u)) */
192 #else /* K60_CPU_REV != 1 */
193  /* rev.2 silicon */
194  if ((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u) {
195  MCGOUTClock = CPU_XTAL_CLK_HZ; /* System oscillator drives MCG clock */
196  } else { /* (!((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u)) */
197  MCGOUTClock = CPU_XTAL32k_CLK_HZ; /* RTC 32 kHz oscillator drives MCG clock */
198  } /* (!((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u)) */
199 #endif /* K60_CPU_REV != 1 */
200  Divider = (uint8_t)(1u << ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT));
201  MCGOUTClock = (MCGOUTClock / Divider); /* Calculate the divided FLL reference clock */
202  if ((MCG->C2 & MCG_C2_RANGE0_MASK) != 0x0u) {
203  MCGOUTClock /= 32u; /* If high range is enabled, additional 32 divider is active */
204  } /* ((MCG->C2 & MCG_C2_RANGE0_MASK) != 0x0u) */
205  } else { /* (!((MCG->C1 & MCG_C1_IREFS_MASK) == 0x0u)) */
206  MCGOUTClock = CPU_INT_SLOW_CLK_HZ; /* The slow internal reference clock is selected */
207  } /* (!((MCG->C1 & MCG_C1_IREFS_MASK) == 0x0u)) */
208  /* Select correct multiplier to calculate the MCG output clock */
209  switch (MCG->C4 & (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) {
210  case (0x0u):
211  MCGOUTClock *= 640u;
212  break;
213  case (MCG_C4_DRST_DRS(0b01)): /* 0x20u */
214  MCGOUTClock *= 1280u;
215  break;
216  case (MCG_C4_DRST_DRS(0b10)): /* 0x40u */
217  MCGOUTClock *= 1920u;
218  break;
219  case (MCG_C4_DRST_DRS(0b11)): /* 0x60u */
220  MCGOUTClock *= 2560u;
221  break;
222  case (MCG_C4_DMX32_MASK): /* 0x80u */
223  MCGOUTClock *= 732u;
224  break;
225  case (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0b01)): /* 0xA0u */
226  MCGOUTClock *= 1464u;
227  break;
228  case (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0b10)): /* 0xC0u */
229  MCGOUTClock *= 2197u;
230  break;
231  case (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0b11)): /* 0xE0u */
232  MCGOUTClock *= 2929u;
233  break;
234  default:
235  break;
236  }
237  } else { /* (!((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u)) */
238  /* PLL is selected */
239  Divider = (1u + (MCG->C5 & MCG_C5_PRDIV0_MASK));
240  MCGOUTClock = (uint32_t)(CPU_XTAL_CLK_HZ / Divider); /* Calculate the PLL reference clock */
241  Divider = ((MCG->C6 & MCG_C6_VDIV0_MASK) + 24u);
242  MCGOUTClock *= Divider; /* Calculate the MCG output clock */
243  } /* (!((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u)) */
244  } else if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0b01)) { /* 0x40u */
245  /* Internal reference clock is selected */
246  if ((MCG->C2 & MCG_C2_IRCS_MASK) == 0x0u) {
247  MCGOUTClock = CPU_INT_SLOW_CLK_HZ; /* Slow internal reference clock selected */
248  } else { /* (!((MCG->C2 & MCG_C2_IRCS_MASK) == 0x0u)) */
249 #if K60_CPU_REV == 1
250  /* rev.1 silicon */
251  MCGOUTClock = CPU_INT_FAST_CLK_HZ; /* Fast internal reference clock selected */
252 #else /* K60_CPU_REV != 1 */
253  /* rev.2 silicon */
254  MCGOUTClock = CPU_INT_FAST_CLK_HZ / (1 << ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT)); /* Fast internal reference clock selected */
255 #endif /* K60_CPU_REV != 1 */
256  } /* (!((MCG->C2 & MCG_C2_IRCS_MASK) == 0x0u)) */
257  } else if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0b10)) { /* 0x80u */
258  /* External reference clock is selected */
259 #if K60_CPU_REV == 1
260  /* rev.1 silicon */
261  if ((SIM->SOPT2 & SIM_SOPT2_MCGCLKSEL_MASK) == 0x0u) {
262  MCGOUTClock = CPU_XTAL_CLK_HZ; /* System oscillator drives MCG clock */
263  } else { /* (!((SIM->SOPT2 & SIM_SOPT2_MCGCLKSEL_MASK) == 0x0u)) */
264  MCGOUTClock = CPU_XTAL32k_CLK_HZ; /* RTC 32 kHz oscillator drives MCG clock */
265  } /* (!((SIM->SOPT2 & SIM_SOPT2_MCGCLKSEL_MASK) == 0x0u)) */
266 #else /* K60_CPU_REV != 1 */
267  /* rev.2 silicon */
268  if ((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u) {
269  MCGOUTClock = CPU_XTAL_CLK_HZ; /* System oscillator drives MCG clock */
270  } else { /* (!((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u)) */
271  MCGOUTClock = CPU_XTAL32k_CLK_HZ; /* RTC 32 kHz oscillator drives MCG clock */
272  } /* (!((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u)) */
273 #endif /* K60_CPU_REV != 1 */
274  } else { /* (!((MCG->C1 & MCG_C1_CLKS_MASK) == 0x80u)) */
275  /* Reserved value */
276  return;
277  } /* (!((MCG->C1 & MCG_C1_CLKS_MASK) == 0x80u)) */
278  SystemCoreClock = SystemSysClock = (MCGOUTClock / (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)));
279  SystemBusClock = (MCGOUTClock / (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT)));
280  SystemFlexBusClock = (MCGOUTClock / (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV3_MASK) >> SIM_CLKDIV1_OUTDIV3_SHIFT)));
281  SystemFlashClock = (MCGOUTClock / (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT)));
282 }
#define SCB
Definition: core_cm0.h:494
void SystemInit(void)
Initialize the system.
K60 clock configuration defines.
#define DEFAULT_SYSTEM_CLOCK
Default System clock value.
Definition: config-clocks.h:52
#define CONFIG_CLOCK_K60_BUS_DIV
Bus clock divider setting, the actual hardware register value, see reference manual for details...
Definition: config-clocks.h:62
uint32_t SystemFlexBusClock
Current FlexBus clock frequency.
uint32_t SystemFlashClock
Current flash clock frequency.
#define CONFIG_CLOCK_K60_SYS_DIV
System clock divider setting, the actual hardware register value, see reference manual for details...
Definition: config-clocks.h:57
void __attribute__((interrupt))
This ISR handles most of the business interacting with the 1-wire bus.
Definition: onewire.c:174
#define CPU_XTAL_CLK_HZ
Value of the external crystal or oscillator clock frequency in Hz.
Definition: config-clocks.h:48
#define SIM
Peripheral SIM base pointer.
Definition: MK60D10.h:7650
#define CONFIG_CLOCK_K60_FB_DIV
Flexbus clock divider setting, the actual hardware register value, see reference manual for details...
Definition: config-clocks.h:67
#define SCB_CPUID_REVISION_Msk
Definition: core_cm0.h:352
void rtc_init(void)
Initialize the RTC hardware.
Definition: rtc.c:47
K60 hardware register header wrapper.
#define CPU_INT_FAST_CLK_HZ
Value of the fast internal oscillator clock frequency in Hz.
Definition: config-clocks.h:51
#define DEBUGGER_BREAK(sig)
Make the CPU signal to the debugger and break execution by issuing a bkpt instruction.
Definition: K60.h:164
#define CONFIG_CLOCK_K60_FLASH_DIV
Flash clock divider setting, the actual hardware register value, see reference manual for details...
Definition: config-clocks.h:72
#define CONFIG_CLOCK_K60_FLL_MCG_C4_DMX32
FLL parameter DMX32 in MCG register C4, see reference manual for details.
Definition: config-clocks.h:82
#define CONFIG_CLOCK_K60_FLL_MCG_C4_DRST_DRS
FLL parameter DRST DRS in MCG register C4, see reference manual for details.
Definition: config-clocks.h:77
uint32_t SystemCoreClock
Current core clock frequency.
#define CPU_INT_SLOW_CLK_HZ
Value of the slow internal oscillator clock frequency in Hz.
Definition: config-clocks.h:50
#define CPU_XTAL32k_CLK_HZ
Value of the external 32k crystal or oscillator clock frequency in Hz.
Definition: config-clocks.h:49
#define MCG
Peripheral MCG base pointer.
Definition: MK60D10.h:5566
void SystemCoreClockUpdate(void)
Update internal SystemCoreClock variable.
uint32_t SystemSysClock
Current system clock frequency.
uint32_t SystemBusClock
Current bus clock frequency.