diff options
Diffstat (limited to 'lib/chibios/os/hal/ports/SPC5/SPC560Pxx/hal_lld.c')
-rw-r--r-- | lib/chibios/os/hal/ports/SPC5/SPC560Pxx/hal_lld.c | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/lib/chibios/os/hal/ports/SPC5/SPC560Pxx/hal_lld.c b/lib/chibios/os/hal/ports/SPC5/SPC560Pxx/hal_lld.c new file mode 100644 index 000000000..4bcfe8a46 --- /dev/null +++ b/lib/chibios/os/hal/ports/SPC5/SPC560Pxx/hal_lld.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | SPC5 HAL - Copyright (C) 2013 STMicroelectronics | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * @file SPC560Pxx/hal_lld.c | ||
19 | * @brief SPC560Pxx HAL subsystem low level driver source. | ||
20 | * | ||
21 | * @addtogroup HAL | ||
22 | * @{ | ||
23 | */ | ||
24 | |||
25 | #include "hal.h" | ||
26 | |||
27 | /*===========================================================================*/ | ||
28 | /* Driver exported variables. */ | ||
29 | /*===========================================================================*/ | ||
30 | |||
31 | /*===========================================================================*/ | ||
32 | /* Driver local variables and types. */ | ||
33 | /*===========================================================================*/ | ||
34 | |||
35 | /*===========================================================================*/ | ||
36 | /* Driver local functions. */ | ||
37 | /*===========================================================================*/ | ||
38 | |||
39 | /*===========================================================================*/ | ||
40 | /* Driver interrupt handlers. */ | ||
41 | /*===========================================================================*/ | ||
42 | |||
43 | /** | ||
44 | * @brief PIT channel 0 interrupt handler. | ||
45 | * | ||
46 | * @isr | ||
47 | */ | ||
48 | OSAL_IRQ_HANDLER(vector59) { | ||
49 | |||
50 | OSAL_IRQ_PROLOGUE(); | ||
51 | |||
52 | osalSysLockFromISR(); | ||
53 | osalOsTimerHandlerI(); | ||
54 | osalSysUnlockFromISR(); | ||
55 | |||
56 | /* Resets the PIT channel 0 IRQ flag.*/ | ||
57 | PIT.CH[0].TFLG.R = 1; | ||
58 | |||
59 | OSAL_IRQ_EPILOGUE(); | ||
60 | } | ||
61 | |||
62 | /*===========================================================================*/ | ||
63 | /* Driver exported functions. */ | ||
64 | /*===========================================================================*/ | ||
65 | |||
66 | /** | ||
67 | * @brief Low level HAL driver initialization. | ||
68 | * | ||
69 | * @notapi | ||
70 | */ | ||
71 | void hal_lld_init(void) { | ||
72 | uint32_t reg; | ||
73 | |||
74 | /* The system is switched to the RUN0 mode, the default for normal | ||
75 | operations.*/ | ||
76 | if (halSPCSetRunMode(SPC5_FINAL_RUNMODE) == OSAL_FAILED) { | ||
77 | SPC5_CLOCK_FAILURE_HOOK(); | ||
78 | } | ||
79 | |||
80 | /* PIT channel 0 initialization for Kernel ticks, the PIT is configured | ||
81 | to run in DRUN,RUN0...RUN3 and HALT0 modes, the clock is gated in other | ||
82 | modes.*/ | ||
83 | INTC.PSR[59].R = SPC5_PIT0_IRQ_PRIORITY; | ||
84 | halSPCSetPeripheralClockMode(92, | ||
85 | SPC5_ME_PCTL_RUN(2) | SPC5_ME_PCTL_LP(2)); | ||
86 | reg = halSPCGetSystemClock() / OSAL_ST_FREQUENCY - 1; | ||
87 | PIT.PITMCR.R = 1; /* PIT clock enabled, stop while debugging. */ | ||
88 | PIT.CH[0].LDVAL.R = reg; | ||
89 | PIT.CH[0].CVAL.R = reg; | ||
90 | PIT.CH[0].TFLG.R = 1; /* Interrupt flag cleared. */ | ||
91 | PIT.CH[0].TCTRL.R = 3; /* Timer active, interrupt enabled. */ | ||
92 | |||
93 | /* EDMA initialization.*/ | ||
94 | edmaInit(); | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * @brief SPC560Pxx clocks and PLL initialization. | ||
99 | * @note All the involved constants come from the file @p board.h and | ||
100 | * @p hal_lld.h | ||
101 | * @note This function must be invoked only after the system reset. | ||
102 | * | ||
103 | * @special | ||
104 | */ | ||
105 | void spc_clock_init(void) { | ||
106 | |||
107 | /* Waiting for IRC stabilization before attempting anything else.*/ | ||
108 | while (!ME.GS.B.S_RC) | ||
109 | ; | ||
110 | |||
111 | #if !SPC5_NO_INIT | ||
112 | |||
113 | /* CMUs initialization.*/ | ||
114 | CGM.CMU_0_HFREFR_A.R = SPC5_CMU0_HFREFR_INIT; | ||
115 | CGM.CMU_0_LFREFR_A.R = SPC5_CMU0_LFREFR_INIT; | ||
116 | CGM.CMU_0_MDR.R = SPC5_CMU0_MDR_INIT; | ||
117 | CGM.CMU_0_CSR.R = SPC5_CMU0_CSR_INIT; | ||
118 | #if SPC5_HAS_CMU1 | ||
119 | CGM.CMU_1_HFREFR_A.R = SPC5_CMU1_HFREFR_INIT; | ||
120 | CGM.CMU_1_LFREFR_A.R = SPC5_CMU1_LFREFR_INIT; | ||
121 | CGM.CMU_1_CSR.R = SPC5_CMU1_CSR_INIT; | ||
122 | #endif | ||
123 | |||
124 | #if SPC5_DISABLE_WATCHDOG | ||
125 | /* SWT disabled.*/ | ||
126 | SWT.SR.R = 0xC520; | ||
127 | SWT.SR.R = 0xD928; | ||
128 | SWT.CR.R = 0xFF00000A; | ||
129 | #endif | ||
130 | |||
131 | /* SSCM initialization. Setting up the most restrictive handling of | ||
132 | invalid accesses to peripherals.*/ | ||
133 | SSCM.ERROR.R = 3; /* PAE and RAE bits. */ | ||
134 | |||
135 | /* RGM errors clearing.*/ | ||
136 | RGM.FES.R = 0xFFFF; | ||
137 | RGM.DES.R = 0xFFFF; | ||
138 | |||
139 | /* The system must be in DRUN mode on entry, if this is not the case then | ||
140 | it is considered a serious anomaly.*/ | ||
141 | if (ME.GS.B.S_CURRENTMODE != SPC5_RUNMODE_DRUN) { | ||
142 | SPC5_CLOCK_FAILURE_HOOK(); | ||
143 | } | ||
144 | |||
145 | #if defined(SPC5_OSC_BYPASS) | ||
146 | /* If the board is equipped with an oscillator instead of a xtal then the | ||
147 | bypass must be activated.*/ | ||
148 | CGM.OSC_CTL.B.OSCBYP = TRUE; | ||
149 | #endif /* SPC5_OSC_BYPASS */ | ||
150 | |||
151 | /* Setting the various dividers and source selectors.*/ | ||
152 | #if SPC5_HAS_AC0 | ||
153 | CGM.AC0DC.R = SPC5_CGM_AC0_DC0; | ||
154 | CGM.AC0SC.R = SPC5_AUX0CLK_SRC; | ||
155 | #endif | ||
156 | #if SPC5_HAS_AC1 | ||
157 | CGM.AC1DC.R = SPC5_CGM_AC1_DC0; | ||
158 | CGM.AC1SC.R = SPC5_AUX1CLK_SRC; | ||
159 | #endif | ||
160 | #if SPC5_HAS_AC2 | ||
161 | CGM.AC2DC.R = SPC5_CGM_AC2_DC0; | ||
162 | CGM.AC2SC.R = SPC5_AUX2CLK_SRC; | ||
163 | #endif | ||
164 | #if SPC5_HAS_AC3 | ||
165 | CGM.AC3DC.R = SPC5_CGM_AC3_DC0; | ||
166 | CGM.AC3SC.R = SPC5_AUX3CLK_SRC; | ||
167 | #endif | ||
168 | |||
169 | /* Enables the XOSC in order to check its functionality before proceeding | ||
170 | with the initialization.*/ | ||
171 | ME.DRUN.R = SPC5_ME_MC_SYSCLK_IRC | SPC5_ME_MC_IRCON | \ | ||
172 | SPC5_ME_MC_XOSC0ON | SPC5_ME_MC_CFLAON_NORMAL | \ | ||
173 | SPC5_ME_MC_DFLAON_NORMAL | SPC5_ME_MC_MVRON; | ||
174 | if (halSPCSetRunMode(SPC5_RUNMODE_DRUN) == OSAL_FAILED) { | ||
175 | SPC5_CLOCK_FAILURE_HOOK(); | ||
176 | } | ||
177 | |||
178 | /* Initialization of the FMPLLs settings.*/ | ||
179 | CGM.FMPLL[0].CR.R = SPC5_FMPLL0_ODF | | ||
180 | SPC5_FMPLL_IDF(SPC5_FMPLL0_IDF_VALUE) | | ||
181 | SPC5_FMPLL_NDIV(SPC5_FMPLL0_NDIV_VALUE) | | ||
182 | SPC5_FMPLL0_OPTIONS; | ||
183 | CGM.FMPLL[0].MR.R = SPC5_FMPLL0_MR_INIT; | ||
184 | #if SPC5_HAS_FMPLL1 | ||
185 | CGM.FMPLL[1].CR.R = SPC5_FMPLL1_ODF | | ||
186 | SPC5_FMPLL_IDF(SPC5_FMPLL1_IDF_VALUE) | | ||
187 | SPC5_FMPLL_NDIV(SPC5_FMPLL1_NDIV_VALUE) | | ||
188 | SPC5_FMPLL1_OPTIONS; | ||
189 | CGM.FMPLL[1].MR.R = SPC5_FMPLL1_MR_INIT; | ||
190 | #endif | ||
191 | |||
192 | /* Run modes initialization.*/ | ||
193 | ME.IS.R = 8; /* Resetting I_ICONF status.*/ | ||
194 | ME.MER.R = SPC5_ME_ME_BITS; /* Enabled run modes. */ | ||
195 | ME.TEST.R = SPC5_ME_TEST_MC_BITS; /* TEST run mode. */ | ||
196 | ME.SAFE.R = SPC5_ME_SAFE_MC_BITS; /* SAFE run mode. */ | ||
197 | ME.DRUN.R = SPC5_ME_DRUN_MC_BITS; /* DRUN run mode. */ | ||
198 | ME.RUN[0].R = SPC5_ME_RUN0_MC_BITS; /* RUN0 run mode. */ | ||
199 | ME.RUN[1].R = SPC5_ME_RUN1_MC_BITS; /* RUN1 run mode. */ | ||
200 | ME.RUN[2].R = SPC5_ME_RUN2_MC_BITS; /* RUN2 run mode. */ | ||
201 | ME.RUN[3].R = SPC5_ME_RUN3_MC_BITS; /* RUN0 run mode. */ | ||
202 | ME.HALT0.R = SPC5_ME_HALT0_MC_BITS; /* HALT0 run mode. */ | ||
203 | ME.STOP0.R = SPC5_ME_STOP0_MC_BITS; /* STOP0 run mode. */ | ||
204 | if (ME.IS.B.I_CONF) { | ||
205 | /* Configuration rejected.*/ | ||
206 | SPC5_CLOCK_FAILURE_HOOK(); | ||
207 | } | ||
208 | |||
209 | /* Peripherals run and low power modes initialization.*/ | ||
210 | ME.RUNPC[0].R = SPC5_ME_RUN_PC0_BITS; | ||
211 | ME.RUNPC[1].R = SPC5_ME_RUN_PC1_BITS; | ||
212 | ME.RUNPC[2].R = SPC5_ME_RUN_PC2_BITS; | ||
213 | ME.RUNPC[3].R = SPC5_ME_RUN_PC3_BITS; | ||
214 | ME.RUNPC[4].R = SPC5_ME_RUN_PC4_BITS; | ||
215 | ME.RUNPC[5].R = SPC5_ME_RUN_PC5_BITS; | ||
216 | ME.RUNPC[6].R = SPC5_ME_RUN_PC6_BITS; | ||
217 | ME.RUNPC[7].R = SPC5_ME_RUN_PC7_BITS; | ||
218 | ME.LPPC[0].R = SPC5_ME_LP_PC0_BITS; | ||
219 | ME.LPPC[1].R = SPC5_ME_LP_PC1_BITS; | ||
220 | ME.LPPC[2].R = SPC5_ME_LP_PC2_BITS; | ||
221 | ME.LPPC[3].R = SPC5_ME_LP_PC3_BITS; | ||
222 | ME.LPPC[4].R = SPC5_ME_LP_PC4_BITS; | ||
223 | ME.LPPC[5].R = SPC5_ME_LP_PC5_BITS; | ||
224 | ME.LPPC[6].R = SPC5_ME_LP_PC6_BITS; | ||
225 | ME.LPPC[7].R = SPC5_ME_LP_PC7_BITS; | ||
226 | |||
227 | /* CFLASH settings calculated for a maximum clock of 64MHz.*/ | ||
228 | CFLASH.PFCR0.B.BK0_APC = 2; | ||
229 | CFLASH.PFCR0.B.BK0_RWSC = 2; | ||
230 | |||
231 | /* Switches again to DRUN mode (current mode) in order to update the | ||
232 | settings.*/ | ||
233 | if (halSPCSetRunMode(SPC5_RUNMODE_DRUN) == OSAL_FAILED) { | ||
234 | SPC5_CLOCK_FAILURE_HOOK(); | ||
235 | } | ||
236 | |||
237 | /* Clock Out selection after all the other configurations.*/ | ||
238 | CGM.OCDSSC.R = SPC5_CLKOUT_SRC | SPC5_CGM_OCDS_SELDIV; | ||
239 | #endif /* !SPC5_NO_INIT */ | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * @brief Switches the system to the specified run mode. | ||
244 | * | ||
245 | * @param[in] mode one of the possible run modes | ||
246 | * | ||
247 | * @return The operation status. | ||
248 | * @retval OSAL_SUCCESS if the switch operation has been completed. | ||
249 | * @retval OSAL_FAILED if the switch operation failed. | ||
250 | */ | ||
251 | bool halSPCSetRunMode(spc5_runmode_t mode) { | ||
252 | |||
253 | /* Clearing status register bits I_IMODE(4) and I_IMTC(1).*/ | ||
254 | ME.IS.R = 5; | ||
255 | |||
256 | /* Starts a transition process.*/ | ||
257 | ME.MCTL.R = SPC5_ME_MCTL_MODE(mode) | SPC5_ME_MCTL_KEY; | ||
258 | ME.MCTL.R = SPC5_ME_MCTL_MODE(mode) | SPC5_ME_MCTL_KEY_INV; | ||
259 | |||
260 | /* Waits for the mode switch or an error condition.*/ | ||
261 | while (TRUE) { | ||
262 | uint32_t r = ME.IS.R; | ||
263 | if (r & 1) | ||
264 | return OSAL_SUCCESS; | ||
265 | if (r & 4) | ||
266 | return OSAL_FAILED; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | /** | ||
271 | * @brief Changes the clock mode of a peripheral. | ||
272 | * | ||
273 | * @param[in] n index of the @p PCTL register | ||
274 | * @param[in] pctl new value for the @p PCTL register | ||
275 | * | ||
276 | * @notapi | ||
277 | */ | ||
278 | void halSPCSetPeripheralClockMode(uint32_t n, uint32_t pctl) { | ||
279 | uint32_t mode; | ||
280 | |||
281 | ME.PCTL[n].R = pctl; | ||
282 | mode = ME.MCTL.B.TARGET_MODE; | ||
283 | ME.MCTL.R = SPC5_ME_MCTL_MODE(mode) | SPC5_ME_MCTL_KEY; | ||
284 | ME.MCTL.R = SPC5_ME_MCTL_MODE(mode) | SPC5_ME_MCTL_KEY_INV; | ||
285 | } | ||
286 | |||
287 | #if !SPC5_NO_INIT || defined(__DOXYGEN__) | ||
288 | /** | ||
289 | * @brief Returns the system clock under the current run mode. | ||
290 | * | ||
291 | * @return The system clock in Hertz. | ||
292 | */ | ||
293 | uint32_t halSPCGetSystemClock(void) { | ||
294 | uint32_t sysclk; | ||
295 | |||
296 | sysclk = ME.GS.B.S_SYSCLK; | ||
297 | switch (sysclk) { | ||
298 | case SPC5_ME_GS_SYSCLK_IRC: | ||
299 | return SPC5_IRC_CLK; | ||
300 | case SPC5_ME_GS_SYSCLK_XOSC: | ||
301 | return SPC5_XOSC_CLK; | ||
302 | case SPC5_ME_GS_SYSCLK_FMPLL0: | ||
303 | return SPC5_FMPLL0_CLK; | ||
304 | #if SPC5_HAS_FMPLL1 | ||
305 | case SPC5_ME_GS_SYSCLK_FMPLL1: | ||
306 | return SPC5_FMPLL1_CLK; | ||
307 | #endif | ||
308 | default: | ||
309 | return 0; | ||
310 | } | ||
311 | } | ||
312 | #endif /* !SPC5_NO_INIT */ | ||
313 | |||
314 | /** @} */ | ||