1 //*****************************************************************************
2 //
3 //! @file am_hal_stimer.c
4 //!
5 //! @brief Functions for interfacing with the system timer (STIMER).
6 //!
7 //! @addtogroup stimer3 STIMER - System Timer
8 //! @ingroup apollo3_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 release_sdk_3_2_0-dd5f40c14b 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 //
54 // @brief Set up the stimer.
55 //
56 // @param ui32STimerConfig is the value to load into the configuration reg.
57 //
58 // This function should be used to perform the initial set-up of the
59 // stimer.
60 //
61 // @return The 32-bit current config of the STimer Config register
62 //
63 //*****************************************************************************
64 uint32_t
am_hal_stimer_config(uint32_t ui32STimerConfig)65 am_hal_stimer_config(uint32_t ui32STimerConfig)
66 {
67 uint32_t ui32CurrVal;
68
69 //
70 // Read the current config
71 //
72 ui32CurrVal = CTIMER->STCFG;
73
74 //
75 // Write our configuration value.
76 //
77 CTIMER->STCFG = ui32STimerConfig;
78
79 #if AM_PART_APOLLO2
80 //
81 // If all of the clock sources are not HFRC, disable LDO when sleeping if timers are enabled.
82 //
83 if ( (CTIMER->STCFG_b.CLKSELCTIMER->STCFG_b.CLKSEL == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV16) ||
84 (CTIMER->STCFG_b.CLKSELCTIMER->STCFG_b.CLKSEL == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV256) )
85 {
86 PWRCTRL->MISC_b.FORCEMEMVRLPTIMERS = 0;
87 }
88 else
89 {
90 PWRCTRL->MISC_b.FORCEMEMVRLPTIMERS = 1;
91 }
92 #endif
93
94 return ui32CurrVal;
95 }
96
97 //*****************************************************************************
98 //
99 // @brief Get the current stimer value.
100 //
101 // This function can be used to read, uninvasively, the value in the stimer.
102 //
103 // @return The 32-bit value from the STimer counter register.
104 //
105 //*****************************************************************************
106 uint32_t
am_hal_stimer_counter_get(void)107 am_hal_stimer_counter_get(void)
108 {
109 uint32_t ui32TmrAddr = AM_REGADDR(CTIMER, STTMR);
110 uint32_t ui32Values[3];
111 uint32_t ui32RetVal;
112
113 //
114 // Read the register into ui32Values[].
115 //
116 am_hal_triple_read(ui32TmrAddr, ui32Values);
117
118 //
119 // Now determine which of the three values is the correct value.
120 // If the first 2 match, then the values are both correct and we're done.
121 // Otherwise, the third value is taken to be the correct value.
122 //
123 if ( ui32Values[0] == ui32Values[1] )
124 {
125 //
126 // If the first two values match, then neither one was a bad read.
127 // We'll take this as the current time.
128 //
129 ui32RetVal = ui32Values[1];
130 }
131 else
132 {
133 ui32RetVal = ui32Values[2];
134 }
135 return ui32RetVal;
136 }
137
138 //*****************************************************************************
139 //
140 // @brief Clear the stimer counter.
141 //
142 // This function clears the STimer Counter and leaves the stimer running.
143 //
144 //*****************************************************************************
145 void
am_hal_stimer_counter_clear(void)146 am_hal_stimer_counter_clear(void)
147 {
148 //
149 // Set the clear bit
150 //
151 CTIMER->STCFG |= CTIMER_STCFG_CLEAR_Msk;
152
153 //
154 // Reset the clear bit
155 //
156 CTIMER->STCFG &= ~CTIMER_STCFG_CLEAR_Msk;
157 }
158
159 //*****************************************************************************
160 //
161 // @brief Set the compare value.
162 //
163 // @param ui32CmprInstance is the compare register instance number (0-7).
164 // @param ui32Delta is the value to add to the STimer counter and load into
165 // the comparator register.
166 //
167 // NOTE: There is no way to set an absolute value into a comparator register.
168 // Only deltas added to the STimer counter can be written to the compare
169 // registers.
170 //
171 //*****************************************************************************
172 void
am_hal_stimer_compare_delta_set(uint32_t ui32CmprInstance,uint32_t ui32Delta)173 am_hal_stimer_compare_delta_set(uint32_t ui32CmprInstance, uint32_t ui32Delta)
174 {
175 uint32_t cfgVal;
176 uint32_t numTries = 0;
177
178 if ( ui32CmprInstance > 7 )
179 {
180 return;
181 }
182
183 // We need to disable the compare temporarily while setting the delta value
184 // That leaves a corner case where we could miss the trigger if setting a very
185 // small delta. To avoid this, we take critical section, and we should ensure
186 // that delta value is at least > 1
187
188 //
189 // Start a critical section.
190 //
191 AM_CRITICAL_BEGIN
192
193 //
194 // Get current CFG value
195 //
196 cfgVal = CTIMER->STCFG;
197
198 //
199 // Disable the compare if already enabled, when setting the new value
200 //
201 CTIMER->STCFG &= ~((AM_HAL_STIMER_CFG_COMPARE_A_ENABLE << ui32CmprInstance));
202
203 // In rare case the delta might not be effective
204 // We retry if that is the case.
205 // Allow for some variability in the value owing to execution latency
206 while (numTries++ < 4)
207 {
208 uint32_t expVal;
209 uint32_t expMax;
210 uint32_t cmpVal;
211
212 // Expected value
213 expVal = CTIMER->STTMR + ui32Delta;
214
215 // Max allowed - taking care of latency
216 expMax = expVal + 10;
217
218 //
219 // Set the delta
220 //
221 AM_REGVAL(AM_REG_STIMER_COMPARE(0, ui32CmprInstance)) = ui32Delta;
222
223 // Read back the compare value
224 cmpVal = AM_REGVAL(AM_REG_STIMER_COMPARE(0, ui32CmprInstance));
225
226 // Make sure the value is in expected range
227 if (!AM_HAL_U32_SMALLER(cmpVal, expVal) && !AM_HAL_U32_GREATER(cmpVal, expMax))
228 {
229 break;
230 }
231 }
232
233
234 //
235 // Restore Compare Enable bit
236 //
237 CTIMER->STCFG |= cfgVal & (AM_HAL_STIMER_CFG_COMPARE_A_ENABLE << ui32CmprInstance);
238
239 //
240 // End the critical section.
241 //
242 AM_CRITICAL_END
243 }
244
245 //*****************************************************************************
246 //
247 // @brief Get the current stimer compare register value.
248 //
249 // @param ui32CmprInstance is the compare register instance number (0-7).
250 //
251 // This function can be used to read the value in an stimer compare register.
252 //
253 //*****************************************************************************
254 uint32_t
am_hal_stimer_compare_get(uint32_t ui32CmprInstance)255 am_hal_stimer_compare_get(uint32_t ui32CmprInstance)
256 {
257 if ( ui32CmprInstance > 7 )
258 {
259 return 0;
260 }
261
262 return AM_REGVAL(AM_REG_STIMER_COMPARE(0, ui32CmprInstance));
263 }
264
265 //*****************************************************************************
266 //
267 // @brief Start capturing data with the specified capture register.
268 //
269 // @param ui32CaptureNum is the Capture Register Number to read (0-3).
270 // @param ui32GPIONumber is the pin number.
271 // @param bPolarity: false (0) = Capture on low to high transition.
272 // true (1) = Capture on high to low transition.
273 //
274 // Use this function to start capturing.
275 //
276 //*****************************************************************************
277 void
am_hal_stimer_capture_start(uint32_t ui32CaptureNum,uint32_t ui32GPIONumber,bool bPolarity)278 am_hal_stimer_capture_start(uint32_t ui32CaptureNum,
279 uint32_t ui32GPIONumber,
280 bool bPolarity)
281 {
282 uint32_t ui32CapCtrl;
283
284 if ( ui32GPIONumber > (AM_HAL_GPIO_MAX_PADS-1) )
285 {
286 return;
287 }
288
289 //
290 // Set the polarity and pin selection in the GPIO block.
291 //
292 switch (ui32CaptureNum)
293 {
294 case 0:
295 GPIO->STMRCAP_b.STPOL0 = bPolarity;
296 GPIO->STMRCAP_b.STSEL0 = ui32GPIONumber;
297 ui32CapCtrl = CTIMER_CAPTURECONTROL_CAPTURE0_Msk;
298 break;
299 case 1:
300 GPIO->STMRCAP_b.STPOL1 = bPolarity;
301 GPIO->STMRCAP_b.STSEL1 = ui32GPIONumber;
302 ui32CapCtrl = CTIMER_CAPTURECONTROL_CAPTURE1_Msk;
303 break;
304 case 2:
305 GPIO->STMRCAP_b.STPOL2 = bPolarity;
306 GPIO->STMRCAP_b.STSEL2 = ui32GPIONumber;
307 ui32CapCtrl = CTIMER_CAPTURECONTROL_CAPTURE2_Msk;
308 break;
309 case 3:
310 GPIO->STMRCAP_b.STPOL3 = bPolarity;
311 GPIO->STMRCAP_b.STSEL3 = ui32GPIONumber;
312 ui32CapCtrl = CTIMER_CAPTURECONTROL_CAPTURE3_Msk;
313 break;
314 default:
315 return; // error concealment.
316 }
317
318 //
319 // Enable it in the CTIMER Block
320 //
321 CTIMER->CAPTURECONTROL |= ui32CapCtrl;
322 }
323
324 //*****************************************************************************
325 //
326 // @brief Start capturing data with the specified capture register.
327 //
328 // @param ui32CaptureNum is the Capture Register Number to read.
329 //
330 // Use this function to start capturing.
331 //
332 //*****************************************************************************
am_hal_stimer_capture_stop(uint32_t ui32CaptureNum)333 void am_hal_stimer_capture_stop(uint32_t ui32CaptureNum)
334 {
335 //
336 // Disable it in the CTIMER block.
337 //
338 CTIMER->CAPTURECONTROL &=
339 ~(CTIMER_CAPTURECONTROL_CAPTURE0_Msk <<
340 ((CTIMER_CAPTURECONTROL_CAPTURE1_Pos -
341 CTIMER_CAPTURECONTROL_CAPTURE0_Pos) * ui32CaptureNum));
342 }
343
344 //*****************************************************************************
345 //
346 // @brief Get the current stimer nvram register value.
347 //
348 // @param ui32NvramNum is the NVRAM Register Number to read.
349 // @param ui32NvramVal is the value to write to NVRAM.
350 //
351 // This function can be used to read the value in an stimer NVRAM register.
352 //
353 //*****************************************************************************
354 void
am_hal_stimer_nvram_set(uint32_t ui32NvramNum,uint32_t ui32NvramVal)355 am_hal_stimer_nvram_set(uint32_t ui32NvramNum, uint32_t ui32NvramVal)
356 {
357 if ( ui32NvramNum > 3 )
358 {
359 return;
360 }
361
362 //AM_REGn(CTIMER, 0, SNVR)
363 //AM_REG_STIMER_NVRAM(0, ui32NvramNum) = ui32NvramVal;
364 }
365
366 //*****************************************************************************
367 //
368 // @brief Get the current stimer nvram register value.
369 //
370 // @param ui32NvramNum is the NVRAM Register Number to read.
371 //
372 // This function can be used to read the value in an stimer NVRAM register.
373 //
374 // @return NVRAM Register Value
375 //
376 //
377 //*****************************************************************************
am_hal_stimer_nvram_get(uint32_t ui32NvramNum)378 uint32_t am_hal_stimer_nvram_get(uint32_t ui32NvramNum)
379 {
380 if ( ui32NvramNum > 3 )
381 {
382 return 0;
383 }
384
385 return AM_REGVAL(AM_REG_STIMER_NVRAM(0, ui32NvramNum));
386 }
387
388 //*****************************************************************************
389 //
390 // @brief Get the current stimer capture register value.
391 //
392 // @param ui32CaptureNum is the Capture Register Number to read.
393 //
394 // This function can be used to read the value in an stimer capture register.
395 //
396 // @return Stimer Capture Register Value.
397 //
398 //*****************************************************************************
am_hal_stimer_capture_get(uint32_t ui32CaptureNum)399 uint32_t am_hal_stimer_capture_get(uint32_t ui32CaptureNum)
400 {
401 if ( ui32CaptureNum > 3 )
402 {
403 return 0;
404 }
405
406 return AM_REGVAL(AM_REG_STIMER_CAPTURE(0, ui32CaptureNum));
407 }
408
409 //*****************************************************************************
410 //
411 // @brief Enables the selected system timer interrupt.
412 //
413 // @param ui32Interrupt is the interrupt to be used.
414 //
415 // This function will enable the selected interrupts in the STIMER interrupt
416 // enable register. In order to receive an interrupt from an stimer component,
417 // you will need to enable the interrupt for that component in this main
418 // register, as well as in the stimer configuration register (accessible though
419 // am_hal_stimer_config()), and in the NVIC.
420 //
421 // ui32Interrupt should be the logical OR of one or more of the following
422 // values:
423 //
424 // AM_HAL_STIMER_INT_COMPAREA
425 // AM_HAL_STIMER_INT_COMPAREB
426 // AM_HAL_STIMER_INT_COMPAREC
427 // AM_HAL_STIMER_INT_COMPARED
428 // AM_HAL_STIMER_INT_COMPAREE
429 // AM_HAL_STIMER_INT_COMPAREF
430 // AM_HAL_STIMER_INT_COMPAREG
431 // AM_HAL_STIMER_INT_COMPAREH
432 //
433 // AM_HAL_STIMER_INT_OVERFLOW
434 //
435 // AM_HAL_STIMER_INT_CAPTUREA
436 // AM_HAL_STIMER_INT_CAPTUREB
437 // AM_HAL_STIMER_INT_CAPTUREC
438 // AM_HAL_STIMER_INT_CAPTURED
439 //
440 //*****************************************************************************
441 void
am_hal_stimer_int_enable(uint32_t ui32Interrupt)442 am_hal_stimer_int_enable(uint32_t ui32Interrupt)
443 {
444 //
445 // Enable the interrupt at the module level.
446 //
447 CTIMERn(0)->STMINTEN |= ui32Interrupt;
448 }
449
450 //*****************************************************************************
451 //
452 // @brief Return the enabled stimer interrupts.
453 //
454 // This function will return all enabled interrupts in the STIMER
455 // interrupt enable register.
456 //
457 // @return return enabled interrupts. This will be a logical or of:
458 //
459 // AM_HAL_STIMER_INT_COMPAREA
460 // AM_HAL_STIMER_INT_COMPAREB
461 // AM_HAL_STIMER_INT_COMPAREC
462 // AM_HAL_STIMER_INT_COMPARED
463 // AM_HAL_STIMER_INT_COMPAREE
464 // AM_HAL_STIMER_INT_COMPAREF
465 // AM_HAL_STIMER_INT_COMPAREG
466 // AM_HAL_STIMER_INT_COMPAREH
467 //
468 // AM_HAL_STIMER_INT_OVERFLOW
469 //
470 // AM_HAL_STIMER_INT_CAPTUREA
471 // AM_HAL_STIMER_INT_CAPTUREB
472 // AM_HAL_STIMER_INT_CAPTUREC
473 // AM_HAL_STIMER_INT_CAPTURED
474 //
475 // @return Return the enabled timer interrupts.
476 //
477 //*****************************************************************************
478 uint32_t
am_hal_stimer_int_enable_get(void)479 am_hal_stimer_int_enable_get(void)
480 {
481 //
482 // Return enabled interrupts.
483 //
484 return CTIMERn(0)->STMINTEN;
485 }
486
487 //*****************************************************************************
488 //
489 // @brief Disables the selected stimer interrupt.
490 //
491 // @param ui32Interrupt is the interrupt to be used.
492 //
493 // This function will disable the selected interrupts in the STIMER
494 // interrupt register.
495 //
496 // ui32Interrupt should be the logical OR of one or more of the following
497 // values:
498 //
499 // AM_HAL_STIMER_INT_COMPAREA
500 // AM_HAL_STIMER_INT_COMPAREB
501 // AM_HAL_STIMER_INT_COMPAREC
502 // AM_HAL_STIMER_INT_COMPARED
503 // AM_HAL_STIMER_INT_COMPAREE
504 // AM_HAL_STIMER_INT_COMPAREF
505 // AM_HAL_STIMER_INT_COMPAREG
506 // AM_HAL_STIMER_INT_COMPAREH
507 //
508 // AM_HAL_STIMER_INT_OVERFLOW
509 //
510 // AM_HAL_STIMER_INT_CAPTUREA
511 // AM_HAL_STIMER_INT_CAPTUREB
512 // AM_HAL_STIMER_INT_CAPTUREC
513 // AM_HAL_STIMER_INT_CAPTURED
514 //
515 //*****************************************************************************
516 void
am_hal_stimer_int_disable(uint32_t ui32Interrupt)517 am_hal_stimer_int_disable(uint32_t ui32Interrupt)
518 {
519 //
520 // Disable the interrupt at the module level.
521 //
522 CTIMERn(0)->STMINTEN &= ~ui32Interrupt;
523 }
524
525 //*****************************************************************************
526 //
527 // @brief Sets the selected stimer interrupt.
528 //
529 // @param ui32Interrupt is the interrupt to be used.
530 //
531 // This function will set the selected interrupts in the STIMER
532 // interrupt register.
533 //
534 // ui32Interrupt should be the logical OR of one or more of the following
535 // values:
536 //
537 // AM_HAL_STIMER_INT_COMPAREA
538 // AM_HAL_STIMER_INT_COMPAREB
539 // AM_HAL_STIMER_INT_COMPAREC
540 // AM_HAL_STIMER_INT_COMPARED
541 // AM_HAL_STIMER_INT_COMPAREE
542 // AM_HAL_STIMER_INT_COMPAREF
543 // AM_HAL_STIMER_INT_COMPAREG
544 // AM_HAL_STIMER_INT_COMPAREH
545 //
546 // AM_HAL_STIMER_INT_OVERFLOW
547 //
548 // AM_HAL_STIMER_INT_CAPTUREA
549 // AM_HAL_STIMER_INT_CAPTUREB
550 // AM_HAL_STIMER_INT_CAPTUREC
551 // AM_HAL_STIMER_INT_CAPTURED
552 //
553 //*****************************************************************************
554 void
am_hal_stimer_int_set(uint32_t ui32Interrupt)555 am_hal_stimer_int_set(uint32_t ui32Interrupt)
556 {
557 //
558 // Set the interrupts.
559 //
560 CTIMERn(0)->STMINTSET = ui32Interrupt;
561 }
562
563 //*****************************************************************************
564 //
565 // @brief Clears the selected stimer interrupt.
566 //
567 // @param ui32Interrupt is the interrupt to be used.
568 //
569 // This function will clear the selected interrupts in the STIMER
570 // interrupt register.
571 //
572 // ui32Interrupt should be the logical OR of one or more of the following
573 // values:
574 //
575 // AM_HAL_STIMER_INT_COMPAREA
576 // AM_HAL_STIMER_INT_COMPAREB
577 // AM_HAL_STIMER_INT_COMPAREC
578 // AM_HAL_STIMER_INT_COMPARED
579 // AM_HAL_STIMER_INT_COMPAREE
580 // AM_HAL_STIMER_INT_COMPAREF
581 // AM_HAL_STIMER_INT_COMPAREG
582 // AM_HAL_STIMER_INT_COMPAREH
583 //
584 // AM_HAL_STIMER_INT_OVERFLOW
585 //
586 // AM_HAL_STIMER_INT_CAPTUREA
587 // AM_HAL_STIMER_INT_CAPTUREB
588 // AM_HAL_STIMER_INT_CAPTUREC
589 // AM_HAL_STIMER_INT_CAPTURED
590 //
591 //*****************************************************************************
592 void
am_hal_stimer_int_clear(uint32_t ui32Interrupt)593 am_hal_stimer_int_clear(uint32_t ui32Interrupt)
594 {
595 //
596 // Disable the interrupt at the module level.
597 //
598 CTIMERn(0)->STMINTCLR = ui32Interrupt;
599 }
600
601
602 //*****************************************************************************
603 //
604 // @brief Returns either the enabled or raw stimer interrupt status.
605 //
606 // This function will return the stimer interrupt status.
607 //
608 // @param bEnabledOnly if true returns the status of the enabled interrupts
609 // only.
610 //
611 // The return value will be the logical OR of one or more of the following
612 // values:
613 //
614 // @return Returns the stimer interrupt status.
615 //
616 //*****************************************************************************
617 uint32_t
am_hal_stimer_int_status_get(bool bEnabledOnly)618 am_hal_stimer_int_status_get(bool bEnabledOnly)
619 {
620 //
621 // Return the desired status.
622 //
623 uint32_t ui32RetVal = CTIMERn(0)->STMINTSTAT;
624
625 if ( bEnabledOnly )
626 {
627 ui32RetVal &= CTIMERn(0)->STMINTEN;
628 }
629
630 return ui32RetVal;
631 }
632
633 //*****************************************************************************
634 //
635 // End Doxygen group.
636 //! @}
637 //
638 //*****************************************************************************
639