1 //*****************************************************************************
2 //
3 //! @file am_hal_stimer.c
4 //!
5 //! @brief Functions for interfacing with the system timer (STIMER).
6 //!
7 //! @addtogroup stimer4_4p STIMER - System Timer
8 //! @ingroup apollo4p_hal
9 //! @{
10 //
11 //*****************************************************************************
12
13 //*****************************************************************************
14 //
15 // Copyright (c) 2024, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision stable-5d223aedc3 of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51
52 //
53 //! Timer Currently Configured
54 //
55 static bool bStimerConfigured = false;
56
57 //
58 //! Time at which last delta was set
59 //
60 static uint32_t g_lastStimer[8] =
61 {
62 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFE,
63 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFE
64 };
65
66 //*****************************************************************************
67 //
68 // Set up the stimer.
69 //
70 // This function should be used to perform the initial set-up of the
71 // stimer.
72 //
73 //*****************************************************************************
74 uint32_t
am_hal_stimer_config(uint32_t ui32STimerConfig)75 am_hal_stimer_config(uint32_t ui32STimerConfig)
76 {
77 uint32_t ui32CurrVal;
78
79 //
80 // Read the current config
81 //
82 ui32CurrVal = STIMER->STCFG;
83
84 //
85 // Write our configuration value.
86 //
87 STIMER->STCFG = ui32STimerConfig;
88
89 //
90 // Indication that the STIMER has been configured.
91 //
92 bStimerConfigured = true;
93
94 return ui32CurrVal;
95 }
96
97 //*****************************************************************************
98 //
99 // Check if the STIMER is running.
100 //
101 // This function should be used to perform the initial set-up of the
102 // stimer.
103 //
104 //*****************************************************************************
105 bool
am_hal_stimer_is_running(void)106 am_hal_stimer_is_running(void)
107 {
108 //
109 // Check the STIMER has been configured and is currently counting
110 //
111 return (bStimerConfigured &&
112 (STIMER_STCFG_CLKSEL_NOCLK != STIMER->STCFG_b.CLKSEL) &&
113 (STIMER_STCFG_FREEZE_THAW == STIMER->STCFG_b.FREEZE) &&
114 (STIMER_STCFG_CLEAR_RUN == STIMER->STCFG_b.CLEAR));
115 }
116 //*****************************************************************************
117 //
118 // Reset the current stimer block to power-up state.
119 //
120 //*****************************************************************************
121 void
am_hal_stimer_reset_config(void)122 am_hal_stimer_reset_config(void)
123 {
124 STIMER->STCFG = _VAL2FLD(STIMER_STCFG_FREEZE, 1);
125 STIMER->SCAPCTRL0 = _VAL2FLD(STIMER_SCAPCTRL0_STSEL0, 0x7F);
126 STIMER->SCAPCTRL1 = _VAL2FLD(STIMER_SCAPCTRL1_STSEL1, 0x7F);
127 STIMER->SCAPCTRL2 = _VAL2FLD(STIMER_SCAPCTRL2_STSEL2, 0x7F);
128 STIMER->SCAPCTRL3 = _VAL2FLD(STIMER_SCAPCTRL3_STSEL3, 0x7F);
129 STIMER->SCMPR0 = 0;
130 STIMER->SCMPR1 = 0;
131 STIMER->SCMPR2 = 0;
132 STIMER->SCMPR3 = 0;
133 STIMER->SCMPR4 = 0;
134 STIMER->SCMPR5 = 0;
135 STIMER->SCMPR6 = 0;
136 STIMER->SCMPR7 = 0;
137 STIMER->SCAPT0 = 0;
138 STIMER->SCAPT1 = 0;
139 STIMER->SCAPT2 = 0;
140 STIMER->SCAPT3 = 0;
141 STIMER->SNVR0 = 0;
142 STIMER->SNVR1 = 0;
143 STIMER->SNVR2 = 0;
144 STIMER->STMINTEN = 0;
145 STIMER->STMINTSTAT = 0;
146 STIMER->STMINTCLR = 0xFFF;
147 }
148
149 //*****************************************************************************
150 //
151 // Get the current stimer value.
152 //
153 // This function can be used to read, uninvasively, the value in the stimer.
154 //
155 //*****************************************************************************
156 uint32_t
am_hal_stimer_counter_get(void)157 am_hal_stimer_counter_get(void)
158 {
159 uint32_t ui32TimerAddr = (uint32_t)&STIMER->STTMR;
160 uint32_t ui32TimerVals[3];
161
162 //
163 // Read the register into ui32TimerVals[].
164 //
165 am_hal_triple_read(ui32TimerAddr, ui32TimerVals);
166
167 //
168 // Now determine which of the three values is the correct value.
169 // If the first 2 match, then the values are both correct and we're done.
170 // Otherwise, the third value is taken to be the correct value.
171 //
172 if ( ui32TimerVals[0] == ui32TimerVals[1] )
173 {
174 //
175 // If the first two values match, then neither one was a bad read.
176 // We'll take this as the current time.
177 //
178 return ui32TimerVals[1];
179 }
180 else
181 {
182 return ui32TimerVals[2];
183 }
184 }
185
186 //*****************************************************************************
187 //
188 // Clear the stimer counter.
189 //
190 // This function clears the STimer Counter and leaves the stimer running.
191 //
192 //*****************************************************************************
193 void
am_hal_stimer_counter_clear(void)194 am_hal_stimer_counter_clear(void)
195 {
196 //
197 // Set the clear bit
198 //
199 STIMER->STCFG |= STIMER_STCFG_CLEAR_Msk;
200
201 //
202 // Reset the clear bit
203 //
204 STIMER->STCFG &= ~STIMER_STCFG_CLEAR_Msk;
205 }
206
207 //*****************************************************************************
208 //
209 // Check if the compare value can be set without blocking.
210 //
211 //*****************************************************************************
212 bool
am_hal_stimer_check_compare_delta_set(uint32_t ui32CmprInstance)213 am_hal_stimer_check_compare_delta_set(uint32_t ui32CmprInstance)
214 {
215 uint32_t curTimer;
216 #ifndef AM_HAL_DISABLE_API_VALIDATION
217 if ( ui32CmprInstance > 7 )
218 {
219 return AM_HAL_STATUS_OUT_OF_RANGE;
220 }
221 #endif
222 // Take a snapshot of STIMER
223 curTimer = am_hal_stimer_counter_get();
224 // We cannot set COMPARE back to back
225 // Need to wait for previous write to complete, which takes 2 cycles
226 if ((curTimer != g_lastStimer[ui32CmprInstance]) &&
227 (curTimer != (g_lastStimer[ui32CmprInstance] + 1)))
228 {
229 return true;
230 }
231 else
232 {
233 return false;
234 }
235 }
236
237 //*****************************************************************************
238 //
239 // Set the compare value.
240 //
241 //*****************************************************************************
242 uint32_t
am_hal_stimer_compare_delta_set(uint32_t ui32CmprInstance,uint32_t ui32Delta)243 am_hal_stimer_compare_delta_set(uint32_t ui32CmprInstance, uint32_t ui32Delta)
244 {
245 uint32_t curTimer, curTimer0;
246 uint32_t ui32Ret = AM_HAL_STATUS_SUCCESS;
247
248 // Take a snapshot of STIMER at the beginning of the function
249 curTimer = curTimer0 = am_hal_stimer_counter_get();
250
251 #ifndef AM_HAL_DISABLE_API_VALIDATION
252 if ( ui32CmprInstance > 7 )
253 {
254 return AM_HAL_STATUS_OUT_OF_RANGE;
255 }
256 #endif
257 //
258 //! @note Due to latency in write to COMPARE register to take effect, it is
259 //! possible that the application could get a stale interrupt even after
260 //! this API returns (a result of previous value of COMPARE).
261 //!
262 //! The application needs to handle these cases gracefully.
263 //
264
265 do
266 {
267 // We cannot set COMPARE back to back
268 // Need to wait for previous write to complete, which takes 2 cycles
269 if ((curTimer != g_lastStimer[ui32CmprInstance]) &&
270 (curTimer != (g_lastStimer[ui32CmprInstance] + 1)))
271 {
272 //
273 // Start a critical section.
274 //
275 AM_CRITICAL_BEGIN
276 curTimer = am_hal_stimer_counter_get();
277 // Adjust Delta
278 // It takes 2 STIMER clock cycles for writes to COMPARE to be effective
279 // Also the interrupt itself is delayed by a cycle
280 // This effectively means we need to adjust the delta by 3
281 // Also adjust for the delay since we entered the function
282 if (ui32Delta > (3 + (curTimer - curTimer0)))
283 {
284 ui32Delta -= 3 + (curTimer - curTimer0);
285 }
286 else
287 {
288 // Need to floor delta to 1
289 ui32Delta = 1;
290 ui32Ret = AM_HAL_STIMER_DELTA_TOO_SMALL;
291 }
292 //
293 // Set the delta
294 //
295 AM_REGVAL(AM_REG_STIMER_COMPARE(0, ui32CmprInstance)) = ui32Delta;
296 //
297 // Get a snapshot when we set COMPARE
298 //
299 g_lastStimer[ui32CmprInstance] = am_hal_stimer_counter_get();
300 //
301 // End the critical section.
302 //
303 AM_CRITICAL_END
304 break;
305 }
306 curTimer = am_hal_stimer_counter_get();
307 } while (1);
308
309 return ui32Ret;
310 }
311
312 //*****************************************************************************
313 //
314 // Get the current stimer compare register value.
315 //
316 // This function can be used to read the value in an stimer compare register.
317 //
318 //*****************************************************************************
319 uint32_t
am_hal_stimer_compare_get(uint32_t ui32CmprInstance)320 am_hal_stimer_compare_get(uint32_t ui32CmprInstance)
321 {
322 uint32_t curTimer;
323 #ifndef AM_HAL_DISABLE_API_VALIDATION
324 if ( ui32CmprInstance > 7 )
325 {
326 return 0;
327 }
328 #endif
329 //
330 // Need to wait at least 3 cycle after setting the compare to read it
331 // reliably
332 //
333 do
334 {
335 curTimer = am_hal_stimer_counter_get();
336 if ((curTimer != g_lastStimer[ui32CmprInstance]) &&
337 (curTimer != (g_lastStimer[ui32CmprInstance] + 1)) &&
338 (curTimer != (g_lastStimer[ui32CmprInstance] + 2)))
339 {
340 return AM_REGVAL(AM_REG_STIMER_COMPARE(0, ui32CmprInstance));
341 }
342 } while (1);
343 }
344
345 //*****************************************************************************
346 //
347 // Start capturing data with the specified capture register.
348 //
349 // Use this function to start capturing.
350 //
351 //*****************************************************************************
352 void
am_hal_stimer_capture_start(uint32_t ui32CaptureNum,uint32_t ui32GPIONumber,bool bPolarity)353 am_hal_stimer_capture_start(uint32_t ui32CaptureNum,
354 uint32_t ui32GPIONumber,
355 bool bPolarity)
356 {
357 #ifndef AM_HAL_DISABLE_API_VALIDATION
358 if ( ui32GPIONumber > (AM_HAL_GPIO_MAX_PADS-1) )
359 {
360 return;
361 }
362 #endif
363
364 //
365 // Set the polarity and pin selection in the GPIO block.
366 //
367 switch (ui32CaptureNum)
368 {
369 case 0:
370 STIMER->SCAPCTRL0_b.STPOL0 = bPolarity;
371 STIMER->SCAPCTRL0_b.STSEL0 = ui32GPIONumber;
372 STIMER->SCAPCTRL0_b.CAPTURE0 = STIMER_SCAPCTRL0_CAPTURE0_ENABLE;
373 break;
374 case 1:
375 STIMER->SCAPCTRL1_b.STPOL1 = bPolarity;
376 STIMER->SCAPCTRL1_b.STSEL1 = ui32GPIONumber;
377 STIMER->SCAPCTRL1_b.CAPTURE1 = STIMER_SCAPCTRL1_CAPTURE1_ENABLE;
378 break;
379 case 2:
380 STIMER->SCAPCTRL2_b.STPOL2 = bPolarity;
381 STIMER->SCAPCTRL2_b.STSEL2 = ui32GPIONumber;
382 STIMER->SCAPCTRL2_b.CAPTURE2 = STIMER_SCAPCTRL2_CAPTURE2_ENABLE;
383 break;
384 case 3:
385 STIMER->SCAPCTRL3_b.STPOL3 = bPolarity;
386 STIMER->SCAPCTRL3_b.STSEL3 = ui32GPIONumber;
387 STIMER->SCAPCTRL3_b.CAPTURE3 = STIMER_SCAPCTRL3_CAPTURE3_ENABLE;
388 break;
389 default:
390 return; // error concealment.
391 }
392
393 //
394 // Set TIMER Global Enable for GPIO inputs.
395 //
396 TIMER->GLOBEN_b.ENABLEALLINPUTS = 1;
397
398 }
399
400 //*****************************************************************************
401 //
402 // Stop capturing data with the specified capture register.
403 //
404 // Use this function to stop capturing.
405 //
406 //*****************************************************************************
407 void
am_hal_stimer_capture_stop(uint32_t ui32CaptureNum)408 am_hal_stimer_capture_stop(uint32_t ui32CaptureNum)
409 {
410 //
411 // Disable it in the STIMER block.
412 //
413 switch (ui32CaptureNum)
414 {
415 case 0:
416 STIMER->SCAPCTRL0_b.CAPTURE0 = STIMER_SCAPCTRL0_CAPTURE0_DISABLE;
417 break;
418 case 1:
419 STIMER->SCAPCTRL1_b.CAPTURE1 = STIMER_SCAPCTRL1_CAPTURE1_DISABLE;
420 break;
421 case 2:
422 STIMER->SCAPCTRL2_b.CAPTURE2 = STIMER_SCAPCTRL2_CAPTURE2_DISABLE;
423 break;
424 case 3:
425 STIMER->SCAPCTRL3_b.CAPTURE3 = STIMER_SCAPCTRL3_CAPTURE3_DISABLE;
426 break;
427 default:
428 return; // error concealment.
429 }
430
431 //
432 // Start a critical section.
433 //
434 AM_CRITICAL_BEGIN
435
436 //
437 // Set TIMER Global Disable for GPIO inputs if all are DISABLED.
438 //
439 if ((STIMER->SCAPCTRL0_b.CAPTURE0 == STIMER_SCAPCTRL0_CAPTURE0_DISABLE) &&
440 (STIMER->SCAPCTRL1_b.CAPTURE1 == STIMER_SCAPCTRL1_CAPTURE1_DISABLE) &&
441 (STIMER->SCAPCTRL2_b.CAPTURE2 == STIMER_SCAPCTRL2_CAPTURE2_DISABLE) &&
442 (STIMER->SCAPCTRL3_b.CAPTURE3 == STIMER_SCAPCTRL3_CAPTURE3_DISABLE))
443 {
444 TIMER->GLOBEN_b.ENABLEALLINPUTS = 0;
445 }
446
447 AM_CRITICAL_END
448 }
449
450 //*****************************************************************************
451 //
452 // Set the current stimer nvram register value.
453 //
454 // This function can be used to read the value in an stimer NVRAM register.
455 //
456 //*****************************************************************************
457 void
am_hal_stimer_nvram_set(uint32_t ui32NvramNum,uint32_t ui32NvramVal)458 am_hal_stimer_nvram_set(uint32_t ui32NvramNum, uint32_t ui32NvramVal)
459 {
460 #ifndef AM_HAL_DISABLE_API_VALIDATION
461 if ( ui32NvramNum > 3 )
462 {
463 return;
464 }
465 #endif
466
467 AM_REGVAL(AM_REG_STIMER_NVRAM(0, ui32NvramNum)) = ui32NvramVal;
468 }
469
470 //*****************************************************************************
471 //
472 // Get the current stimer nvram register value.
473 //
474 // This function can be used to read the value in an stimer NVRAM register.
475 //
476 //*****************************************************************************
am_hal_stimer_nvram_get(uint32_t ui32NvramNum)477 uint32_t am_hal_stimer_nvram_get(uint32_t ui32NvramNum)
478 {
479 #ifndef AM_HAL_DISABLE_API_VALIDATION
480 if ( ui32NvramNum > 3 )
481 {
482 return 0;
483 }
484 #endif
485
486 return AM_REGVAL(AM_REG_STIMER_NVRAM(0, ui32NvramNum));
487 }
488
489 //*****************************************************************************
490 //
491 // Get the current stimer capture register value.
492 //
493 // This function can be used to read the value in an stimer capture register.
494 //
495 //*****************************************************************************
am_hal_stimer_capture_get(uint32_t ui32CaptureNum)496 uint32_t am_hal_stimer_capture_get(uint32_t ui32CaptureNum)
497 {
498 #ifndef AM_HAL_DISABLE_API_VALIDATION
499 if ( ui32CaptureNum > 3 )
500 {
501 return 0;
502 }
503 #endif
504
505 return AM_REGVAL(AM_REG_STIMER_CAPTURE(0, ui32CaptureNum));
506 }
507
508 //*****************************************************************************
509 //
510 // Enables the selected system timer interrupt.
511 //
512 // This function will enable the selected interrupts in the STIMER interrupt
513 // enable register. In order to receive an interrupt from an stimer component,
514 // you will need to enable the interrupt for that component in this main
515 // register, as well as in the stimer configuration register (accessible though
516 // am_hal_stimer_config()), and in the NVIC.
517 //
518 //*****************************************************************************
519 void
am_hal_stimer_int_enable(uint32_t ui32Interrupt)520 am_hal_stimer_int_enable(uint32_t ui32Interrupt)
521 {
522 //
523 // Enable the interrupt at the module level.
524 //
525 STIMER->STMINTEN |= ui32Interrupt;
526 }
527
528 //*****************************************************************************
529 //
530 // Return the enabled stimer interrupts.
531 //
532 // This function will return all enabled interrupts in the STIMER
533 // interrupt enable register.
534 //
535 //*****************************************************************************
536 uint32_t
am_hal_stimer_int_enable_get(void)537 am_hal_stimer_int_enable_get(void)
538 {
539 //
540 // Return enabled interrupts.
541 //
542 return STIMER->STMINTEN;
543 }
544
545 //*****************************************************************************
546 //
547 // Disables the selected stimer interrupt.
548 //
549 // This function will disable the selected interrupts in the STIMER
550 // interrupt register.
551 //
552 //*****************************************************************************
553 void
am_hal_stimer_int_disable(uint32_t ui32Interrupt)554 am_hal_stimer_int_disable(uint32_t ui32Interrupt)
555 {
556 //
557 // Disable the interrupt at the module level.
558 //
559 STIMER->STMINTEN &= ~ui32Interrupt;
560 }
561
562 //*****************************************************************************
563 //
564 // Sets the selected stimer interrupt.
565 //
566 // This function will set the selected interrupts in the STIMER
567 // interrupt register.
568 //
569 //*****************************************************************************
570 void
am_hal_stimer_int_set(uint32_t ui32Interrupt)571 am_hal_stimer_int_set(uint32_t ui32Interrupt)
572 {
573 //
574 // Set the interrupts.
575 //
576 STIMER->STMINTSET = ui32Interrupt;
577 }
578
579 //*****************************************************************************
580 //
581 // Clears the selected stimer interrupt.
582 //
583 // This function will clear the selected interrupts in the STIMER
584 // interrupt register.
585 //
586 //*****************************************************************************
587 void
am_hal_stimer_int_clear(uint32_t ui32Interrupt)588 am_hal_stimer_int_clear(uint32_t ui32Interrupt)
589 {
590 //
591 // Disable the interrupt at the module level.
592 //
593 STIMER->STMINTCLR = ui32Interrupt;
594 }
595
596 //*****************************************************************************
597 //
598 // Returns either the enabled or raw stimer interrupt status.
599 //
600 // This function will return the stimer interrupt status.
601 //
602 //*****************************************************************************
603 uint32_t
am_hal_stimer_int_status_get(bool bEnabledOnly)604 am_hal_stimer_int_status_get(bool bEnabledOnly)
605 {
606 //
607 // Return the desired status.
608 //
609 uint32_t ui32RetVal = STIMER->STMINTSTAT;
610
611 if ( bEnabledOnly )
612 {
613 ui32RetVal &= STIMER->STMINTEN;
614 }
615
616 return ui32RetVal;
617 }
618
619 //*****************************************************************************
620 //
621 // End Doxygen group.
622 //! @}
623 //
624 //*****************************************************************************
625