1 //*****************************************************************************
2 //
3 // am_hal_systick.c
4 //! @file
5 //!
6 //! @brief Functions for interfacing with the SYSTICK
7 //!
8 //! @addtogroup systick2 System Timer (SYSTICK)
9 //! @ingroup apollo2hal
10 //! @{
11 //
12 //*****************************************************************************
13
14 //*****************************************************************************
15 //
16 // Copyright (c) 2017, Ambiq Micro
17 // All rights reserved.
18 //
19 // Redistribution and use in source and binary forms, with or without
20 // modification, are permitted provided that the following conditions are met:
21 //
22 // 1. Redistributions of source code must retain the above copyright notice,
23 // this list of conditions and the following disclaimer.
24 //
25 // 2. Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // 3. Neither the name of the copyright holder nor the names of its
30 // contributors may be used to endorse or promote products derived from this
31 // software without specific prior written permission.
32 //
33 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
37 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 // POSSIBILITY OF SUCH DAMAGE.
44 //
45 // This is part of revision 1.2.11 of the AmbiqSuite Development Package.
46 //
47 //*****************************************************************************
48
49 #include <stdint.h>
50 #include <stdbool.h>
51 #include "am_mcu_apollo.h"
52
53
54 //*****************************************************************************
55 //
56 // Macro definitions
57 //
58 //*****************************************************************************
59 #define SYSTICK_MAX_TICKS ((1 << 24)-1)
60 #define MAX_U32 (0xffffffff)
61
62 //*****************************************************************************
63 //
64 //! @brief Start the SYSTICK.
65 //!
66 //! This function starts the systick timer.
67 //!
68 //! @note This timer does not run in deep-sleep mode as it runs from the core
69 //! clock, which is gated in deep-sleep. If a timer is needed in deep-sleep use
70 //! one of the ctimers instead. Also to note is this timer will consume higher
71 //! power than the ctimers.
72 //!
73 //! @return None.
74 //
75 //*****************************************************************************
76 void
am_hal_systick_start(void)77 am_hal_systick_start(void)
78 {
79 //
80 // Start the systick timer.
81 //
82 AM_REG(SYSTICK, SYSTCSR) |= AM_REG_SYSTICK_SYSTCSR_ENABLE_M;
83 }
84
85 //*****************************************************************************
86 //
87 //! @brief Stop the SYSTICK.
88 //!
89 //! This function stops the systick timer.
90 //!
91 //! @note This timer does not run in deep-sleep mode as it runs from the core
92 //! clock, which is gated in deep-sleep. If a timer is needed in deep-sleep use
93 //! one of the ctimers instead. Also to note is this timer will consume higher
94 //! power than the ctimers.
95 //!
96 //! @return None.
97 //
98 //*****************************************************************************
99 void
am_hal_systick_stop(void)100 am_hal_systick_stop(void)
101 {
102 //
103 // Stop the systick timer.
104 //
105 AM_REG(SYSTICK, SYSTCSR) &= ~AM_REG_SYSTICK_SYSTCSR_ENABLE_M;
106 }
107
108 //*****************************************************************************
109 //
110 //! @brief Enable the interrupt in the SYSTICK.
111 //!
112 //! This function enables the interupt in the systick timer.
113 //!
114 //! @return None.
115 //
116 //*****************************************************************************
117 void
am_hal_systick_int_enable(void)118 am_hal_systick_int_enable(void)
119 {
120 //
121 // Enable the systick timer interrupt.
122 //
123 AM_REG(SYSTICK, SYSTCSR) |= AM_REG_SYSTICK_SYSTCSR_TICKINT_M;
124 }
125
126 //*****************************************************************************
127 //
128 //! @brief Disable the interrupt in the SYSTICK.
129 //!
130 //! This function disables the interupt in the systick timer.
131 //!
132 //! @return None.
133 //
134 //*****************************************************************************
135 void
am_hal_systick_int_disable(void)136 am_hal_systick_int_disable(void)
137 {
138 //
139 // Disable the systick timer interrupt.
140 //
141 AM_REG(SYSTICK, SYSTCSR) &= ~AM_REG_SYSTICK_SYSTCSR_TICKINT_M;
142 }
143
144 //*****************************************************************************
145 //
146 //! @brief Reads the interrupt status.
147 //!
148 //! This function reads the interrupt status in the systick timer.
149 //!
150 //! @return the interrupt status.
151 //
152 //*****************************************************************************
153 uint32_t
am_hal_systick_int_status_get(void)154 am_hal_systick_int_status_get(void)
155 {
156 //
157 // Return the systick timer interrupt status.
158 //
159 return AM_REG(SYSTICK, SYSTCSR) & AM_REG_SYSTICK_SYSTCSR_COUNTFLAG_M;
160 }
161
162 //*****************************************************************************
163 //
164 //! @brief Reset the interrupt in the SYSTICK.
165 //!
166 //! This function resets the systick timer by clearing out the configuration
167 //! register.
168 //!
169 //! @return None.
170 //
171 //*****************************************************************************
172 void
am_hal_systick_reset(void)173 am_hal_systick_reset(void)
174 {
175 //
176 // Reset the systick timer interrupt.
177 //
178 AM_REG(SYSTICK, SYSTCSR) = 0x0;
179 }
180
181 //*****************************************************************************
182 //
183 //! @brief Load the value into the SYSTICK.
184 //!
185 //! @param ui32LoadVal the desired load value for the systick. Maximum value is
186 //! 0x00FF.FFFF.
187 //!
188 //! This function loads the desired value into the systick timer.
189 //!
190 //! @return None.
191 //
192 //*****************************************************************************
193 void
am_hal_systick_load(uint32_t ui32LoadVal)194 am_hal_systick_load(uint32_t ui32LoadVal)
195 {
196 //
197 // Write the reload register.
198 //
199 AM_REG(SYSTICK, SYSTRVR) = ui32LoadVal;
200 }
201
202 //*****************************************************************************
203 //
204 //! @brief Get the current count value in the SYSTICK.
205 //!
206 //! This function gets the current count value in the systick timer.
207 //!
208 //! @return Current count value.
209 //
210 //*****************************************************************************
211 uint32_t
am_hal_systick_count(void)212 am_hal_systick_count(void)
213 {
214 //
215 // Return the current systick timer count value.
216 //
217 return AM_REG(SYSTICK, SYSTCVR);
218 }
219
220 //*****************************************************************************
221 //
222 //! @brief Wait the specified number of ticks.
223 //!
224 //! This function delays for the given number of SysTick ticks.
225 //!
226 //! @note If the SysTick timer is being used elsewhere, it will be corrupted
227 //! by calling this function.
228 //!
229 //! @return 0 if successful.
230 //
231 //*****************************************************************************
232 uint32_t
am_hal_systick_wait_ticks(uint32_t u32Ticks)233 am_hal_systick_wait_ticks(uint32_t u32Ticks)
234 {
235
236 if ( u32Ticks == 0 )
237 {
238 u32Ticks++; // Make sure we get the COUNTFLAG
239 }
240
241 //
242 // The proper SysTick initialization sequence is: (p 4-36 of the M4 UG).
243 // 1. Program reload value
244 // 2. Clear current value
245 // 3. Program CSR
246 //
247 // Set the reload value to the required number of ticks.
248 //
249 AM_REG(SYSTICK, SYSTRVR) = u32Ticks;
250
251 //
252 // Clear the current count.
253 //
254 AM_REG(SYSTICK, SYSTCVR) = 0x0;
255
256 //
257 // Set to use the processor clock, but don't cause an exception (we'll poll).
258 //
259 AM_REG(SYSTICK, SYSTCSR) = AM_REG_SYSTICK_SYSTCSR_ENABLE_M;
260
261 //
262 // Poll till done
263 //
264 while ( !(AM_REG(SYSTICK, SYSTCSR) & AM_REG_SYSTICK_SYSTCSR_COUNTFLAG_M) );
265
266 //
267 // And disable systick before exiting.
268 //
269 AM_REG(SYSTICK, SYSTCSR) = 0;
270
271 return 0;
272 }
273
274 //*****************************************************************************
275 //
276 //! @brief Delay the specified number of microseconds.
277 //!
278 //! This function will use the SysTick timer to delay until the specified
279 //! number of microseconds have elapsed. It uses the processor clocks and
280 //! takes into account the current CORESEL setting.
281 //!
282 //! @note If the SysTick timer is being used elsewhere, it will be corrupted
283 //! by calling this function.
284 //!
285 //! @return Total number of SysTick ticks delayed.
286 //
287 //*****************************************************************************
288 uint32_t
am_hal_systick_delay_us(uint32_t u32NumUs)289 am_hal_systick_delay_us(uint32_t u32NumUs)
290 {
291 uint32_t u32ClkFreq, u32nLoops, u32Ticks, uRet;
292 uint32_t u32CoreSel = AM_BFR(CLKGEN, CCTRL, CORESEL);
293
294 u32nLoops = 1;
295 switch (u32CoreSel)
296 {
297 //
298 // We need to compute the required number of ticks. To do so and to
299 // minimize divide operations, we'll use the following equation:
300 // u32Ticks = (u32NumUs * HFCR_EXACT)/1000000
301 // = (u32NumUs * (HFCR_EXACT * 1024)/1000000) / 1024
302 // The values for the variable u32ClkFreq are computed as follows:
303 // u32ClkFreq = (24390200 * 1024) / ((clksel+1)*1000000);
304 // (and we'll do the remaining divide by 1024, using a shift, later).
305 //
306 case 0:
307 u32ClkFreq = 24975;
308 if ( u32NumUs > ((SYSTICK_MAX_TICKS / 24975)*1024) )
309 {
310 u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 24975)*1024)) + 1;
311 u32NumUs /= u32nLoops;
312 }
313 if ( u32NumUs > (MAX_U32 / 24975) )
314 {
315 u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
316 }
317 else
318 {
319 u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
320 }
321 break;
322 case 1:
323 u32ClkFreq = 12487;
324 if ( u32NumUs > ((SYSTICK_MAX_TICKS / 12487)*1024) )
325 {
326 u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 12487)*1024)) + 1;
327 u32NumUs /= u32nLoops;
328 }
329 if ( u32NumUs > (MAX_U32 / 12487) )
330 {
331 u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
332 }
333 else
334 {
335 u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
336 }
337 break;
338 case 2:
339 u32ClkFreq = 8325;
340 if ( u32NumUs > ((SYSTICK_MAX_TICKS / 8325)*1024) )
341 {
342 u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 8325)*1024)) + 1;
343 u32NumUs /= u32nLoops;
344 }
345 if ( u32NumUs > (MAX_U32 / 8325) )
346 {
347 u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
348 }
349 else
350 {
351 u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
352 }
353 break;
354 case 3:
355 u32ClkFreq = 6243;
356 if ( u32NumUs > ((SYSTICK_MAX_TICKS / 6243)*1024) )
357 {
358 u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 6243)*1024)) + 1;
359 u32NumUs /= u32nLoops;
360 }
361 if ( u32NumUs > (MAX_U32 / 6243) )
362 {
363 u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
364 }
365 else
366 {
367 u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
368 }
369 break;
370 case 4:
371 u32ClkFreq = 4995;
372 if ( u32NumUs > ((SYSTICK_MAX_TICKS / 4995)*1024) )
373 {
374 u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 4995)*1024)) + 1;
375 u32NumUs /= u32nLoops;
376 }
377 if ( u32NumUs > (MAX_U32 / 4995) )
378 {
379 u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
380 }
381 else
382 {
383 u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
384 }
385 break;
386 case 5:
387 u32ClkFreq = 4162;
388 if ( u32NumUs > ((SYSTICK_MAX_TICKS / 4162)*1024) )
389 {
390 u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 4162)*1024)) + 1;
391 u32NumUs /= u32nLoops;
392 }
393 if ( u32NumUs > (MAX_U32 / 4162) )
394 {
395 u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
396 }
397 else
398 {
399 u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
400 }
401 break;
402 case 6:
403 u32ClkFreq = 3567;
404 if ( u32NumUs > ((SYSTICK_MAX_TICKS / 3567)*1024) )
405 {
406 u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 3567)*1024)) + 1;
407 u32NumUs /= u32nLoops;
408 }
409 if ( u32NumUs > (MAX_U32 / 3567) )
410 {
411 u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
412 }
413 else
414 {
415 u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
416 }
417 break;
418 case 7:
419 u32ClkFreq = 3121;
420 if ( u32NumUs > ((SYSTICK_MAX_TICKS / 3121)*1024) )
421 {
422 u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 3121)*1024)) + 1;
423 u32NumUs /= u32nLoops;
424 }
425 if ( u32NumUs > (MAX_U32 / 3121) )
426 {
427 u32Ticks = (u32NumUs >> 10) * u32ClkFreq;
428 }
429 else
430 {
431 u32Ticks = (u32NumUs * u32ClkFreq) >> 10;
432 }
433 break;
434 default:
435 u32Ticks = 1;
436 break;
437 } // switch()
438
439 uRet = u32Ticks * u32nLoops;
440 while ( u32nLoops-- )
441 {
442 am_hal_systick_wait_ticks(u32Ticks);
443 }
444
445 return uRet;
446 }
447
448 //*****************************************************************************
449 //
450 // End Doxygen group.
451 //! @}
452 //
453 //*****************************************************************************
454