1 //*****************************************************************************
2 //
3 //! @file am_hal_timer.c
4 //!
5 //! @brief Functions for interfacing with the timer (TIMER).
6 //!
7 //! @addtogroup timer_4p Timer Functionality
8 //! @ingroup apollo4p_hal
9 //! @{
10 //
11 //*****************************************************************************
12
13 //*****************************************************************************
14 //
15 // Copyright (c) 2023, 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_4_4_0-3c5977e664 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 // Not declared as static as this function can be used from within HAL
54 //
55 uint32_t
internal_timer_config(uint32_t ui32TimerNumber,am_hal_timer_config_t * psTimerConfig)56 internal_timer_config(uint32_t ui32TimerNumber,
57 am_hal_timer_config_t *psTimerConfig)
58 {
59 uint32_t ui32ConfigCtrl, ui32ConfigMode;
60 uint32_t ui32TimerLimit = psTimerConfig->ui32PatternLimit;
61 uint32_t ui32Compare0 = psTimerConfig->ui32Compare0;
62 uint32_t ui32Compare1 = psTimerConfig->ui32Compare1;
63
64 //
65 // Mode/function specific error checking.
66 //
67 switch ( psTimerConfig->eFunction )
68 {
69 case AM_HAL_TIMER_FN_EDGE:
70 //
71 // If Compare1 is used, then compare0 must be set to a higher value than compare1.
72 //
73 if ((ui32Compare1 != 0xFFFFFFFF) && (ui32Compare0 <= ui32Compare1))
74 {
75 return AM_HAL_STATUS_INVALID_OPERATION;
76 }
77 break;
78
79 case AM_HAL_TIMER_FN_PWM:
80 break;
81
82 case AM_HAL_TIMER_FN_UPCOUNT:
83 break;
84
85 case AM_HAL_TIMER_FN_SINGLEPATTERN:
86 case AM_HAL_TIMER_FN_REPEATPATTERN:
87 //
88 // Check that requested pattern is not too long.
89 //
90 if (psTimerConfig->ui32PatternLimit > 63)
91 {
92 return AM_HAL_STATUS_INVALID_OPERATION;
93 }
94
95 break;
96
97 default:
98 return AM_HAL_STATUS_INVALID_OPERATION;
99 }
100
101 //
102 //
103 // Build up a value in SRAM before we start writing to the timer control
104 // registers.
105 //
106 ui32ConfigCtrl = _VAL2FLD(TIMER_CTRL0_TMR0CLK, psTimerConfig->eInputClock);
107 ui32ConfigCtrl |= _VAL2FLD(TIMER_CTRL0_TMR0FN, psTimerConfig->eFunction);
108 ui32ConfigCtrl |= _VAL2FLD(TIMER_CTRL0_TMR0POL1, psTimerConfig->bInvertOutput1);
109 ui32ConfigCtrl |= _VAL2FLD(TIMER_CTRL0_TMR0POL0, psTimerConfig->bInvertOutput0);
110 ui32ConfigCtrl |= _VAL2FLD(TIMER_CTRL0_TMR0TMODE, psTimerConfig->eTriggerType);
111 ui32ConfigCtrl |= _VAL2FLD(TIMER_CTRL0_TMR0LMT, ui32TimerLimit);
112 ui32ConfigCtrl |= _VAL2FLD(TIMER_CTRL0_TMR0EN, 0);
113
114 ui32ConfigMode = _VAL2FLD(TIMER_MODE0_TMR0TRIGSEL, psTimerConfig->eTriggerSource);
115
116 //
117 // Disable the timer.
118 //
119 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0EN = 0;
120
121 //
122 // Apply the settings from the configuration structure.
123 //
124 TIMERn(ui32TimerNumber)->CTRL0 = ui32ConfigCtrl;
125 TIMERn(ui32TimerNumber)->MODE0 = ui32ConfigMode;
126 TIMERn(ui32TimerNumber)->TMR0CMP0 = ui32Compare0;
127 TIMERn(ui32TimerNumber)->TMR0CMP1 = ui32Compare1;
128
129 //
130 // Clear the timer to make sure it has the appropriate starting value.
131 //
132 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0CLR = 1;
133
134 return AM_HAL_STATUS_SUCCESS;
135
136 } // internal_timer_config()
137
138 uint32_t
am_hal_timer_config(uint32_t ui32TimerNumber,am_hal_timer_config_t * psTimerConfig)139 am_hal_timer_config(uint32_t ui32TimerNumber,
140 am_hal_timer_config_t *psTimerConfig)
141 {
142 #if defined(AM_HAL_PWRCTL_HPLP_WA)
143 //
144 // Check for internal timers which we don't want the customer to use.
145 //
146 if ( AM_HAL_WRITE_WAIT_TIMER == ui32TimerNumber )
147 {
148 return AM_HAL_STATUS_INVALID_ARG;
149 }
150 #endif // defined(AM_HAL_PWRCTL_HPLP_WA)
151 return internal_timer_config(ui32TimerNumber, psTimerConfig);
152 }
153
154 //
155 // Initialize a timer configuration structure with default values.
156 //
157 uint32_t
am_hal_timer_default_config_set(am_hal_timer_config_t * psTimerConfig)158 am_hal_timer_default_config_set(am_hal_timer_config_t *psTimerConfig)
159 {
160
161 psTimerConfig->eInputClock = AM_HAL_TIMER_CLOCK_HFRC_DIV16;
162 psTimerConfig->eFunction = AM_HAL_TIMER_FN_EDGE;
163 psTimerConfig->ui32Compare0 = 0xFFFFFFFF;
164 psTimerConfig->ui32Compare1 = 0xFFFFFFFF;
165 psTimerConfig->bInvertOutput0 = false;
166 psTimerConfig->bInvertOutput1 = false;
167 psTimerConfig->eTriggerType = AM_HAL_TIMER_TRIGGER_DIS;
168 psTimerConfig->eTriggerSource = AM_HAL_TIMER_TRIGGER_TMR0_OUT1;
169 psTimerConfig->ui32PatternLimit = 0;
170
171 return AM_HAL_STATUS_SUCCESS;
172 }
173
174 //
175 // Reset the timer to the default state.
176 //
177 uint32_t
am_hal_timer_reset_config(uint32_t ui32TimerNumber)178 am_hal_timer_reset_config(uint32_t ui32TimerNumber)
179 {
180 //
181 // Disable Interrupts.
182 //
183 am_hal_timer_interrupt_disable(3 << (ui32TimerNumber * 2));
184
185 //
186 // Enable the Global enable.
187 //
188 am_hal_timer_enable_sync(1 << ui32TimerNumber);
189
190 //
191 // Disable the Timer.
192 //
193 am_hal_timer_disable(ui32TimerNumber);
194
195 //
196 // Reset the Timer specific registers.
197 //
198 TIMERn(ui32TimerNumber)->CTRL0 = 0;
199 TIMERn(ui32TimerNumber)->TIMER0 = 0;
200 TIMERn(ui32TimerNumber)->TMR0CMP0 = 0;
201 TIMERn(ui32TimerNumber)->TMR0CMP1 = 0;
202 TIMERn(ui32TimerNumber)->MODE0 = 0;
203
204 am_hal_timer_interrupt_clear(3 << (ui32TimerNumber *2));
205
206 return AM_HAL_STATUS_SUCCESS;
207 }
208
209 //
210 // Enable a single TIMER
211 //
212 uint32_t
am_hal_timer_enable(uint32_t ui32TimerNumber)213 am_hal_timer_enable(uint32_t ui32TimerNumber)
214 {
215 AM_CRITICAL_BEGIN;
216 //
217 // Enable the timer in both the individual enable register and the global
218 // sync register.
219 //
220 TIMER->GLOBEN |= 1 << ui32TimerNumber;
221
222 //
223 // Toggle the clear bit (required by the hardware), and then enable the timer.
224 //
225 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0CLR = 1;
226 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0CLR = 0;
227 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0EN = 1;
228
229 AM_CRITICAL_END;
230
231 return AM_HAL_STATUS_SUCCESS;
232 }
233
234 //
235 // Disable a single TIMER
236 //
237 uint32_t
am_hal_timer_disable(uint32_t ui32TimerNumber)238 am_hal_timer_disable(uint32_t ui32TimerNumber)
239 {
240
241 AM_CRITICAL_BEGIN;
242
243 //
244 // Disable the timer.
245 //
246 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0EN = 0;
247
248 AM_CRITICAL_END;
249
250 return AM_HAL_STATUS_SUCCESS;
251 }
252
253 //
254 // Enable a group of TIMERS all at once
255 //
256 uint32_t
am_hal_timer_enable_sync(uint32_t ui32TimerMask)257 am_hal_timer_enable_sync(uint32_t ui32TimerMask)
258 {
259 //
260 // Disable the timers in the global sync register, make sure they are all
261 // individually enabled, and then re-enable them in the global sync
262 // register.
263 //
264 AM_CRITICAL_BEGIN;
265
266 TIMER->GLOBEN &= ~(ui32TimerMask);
267
268 for (uint32_t i = 0; i < AM_REG_NUM_TIMERS; i++)
269 {
270 if ((1 << i) & ui32TimerMask)
271 {
272 //
273 // Toggle the clear bit (required by the hardware), and then enable the timer.
274 //
275 TIMERn(i)->CTRL0_b.TMR0CLR = 1;
276 TIMERn(i)->CTRL0_b.TMR0CLR = 0;
277 //
278 // Enable the timer.
279 //
280 TIMERn(i)->CTRL0_b.TMR0EN = 1;
281 }
282 }
283
284 TIMER->GLOBEN |= ui32TimerMask;
285
286 AM_CRITICAL_END;
287
288 return AM_HAL_STATUS_SUCCESS;
289 }
290
291 //
292 // Disable a group of TIMERS all at once
293 //
294 uint32_t
am_hal_timer_disable_sync(uint32_t ui32TimerMask)295 am_hal_timer_disable_sync(uint32_t ui32TimerMask)
296 {
297 //
298 // Disable the timers in the global sync register, make sure they are all
299 // individually disabled, and then re-enable them in the global sync
300 // register.
301 //
302 AM_CRITICAL_BEGIN;
303
304 TIMER->GLOBEN &= ~(ui32TimerMask);
305
306 for (uint32_t i = 0; i < AM_REG_NUM_TIMERS; i++)
307 {
308 if ((1 << i) & ui32TimerMask)
309 {
310 //
311 // Disable the timer.
312 //
313 TIMERn(i)->CTRL0_b.TMR0EN = 0;
314 }
315 }
316
317 AM_CRITICAL_END;
318
319 return AM_HAL_STATUS_SUCCESS;
320 }
321
322 //
323 // Clear a single TIMER and start the timer.
324 //
325 uint32_t
am_hal_timer_clear(uint32_t ui32TimerNumber)326 am_hal_timer_clear(uint32_t ui32TimerNumber)
327 {
328 AM_CRITICAL_BEGIN;
329
330 //
331 // Disable the timer.
332 //
333 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0EN = 0;
334
335 //
336 // Clear the timer.
337 //
338 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0CLR = 1;
339 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0CLR = 0;
340
341 //
342 // Enable the timer.
343 //
344 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0EN = 1;
345
346 AM_CRITICAL_END;
347
348 return AM_HAL_STATUS_SUCCESS;
349 }
350
351 //
352 // Clear a single TIMER but don't start it.
353 //
354 uint32_t
am_hal_timer_clear_stop(uint32_t ui32TimerNumber)355 am_hal_timer_clear_stop(uint32_t ui32TimerNumber)
356 {
357 AM_CRITICAL_BEGIN;
358
359 //
360 // Disable the timer.
361 //
362 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0EN = 0;
363
364 //
365 // Clear the timer.
366 //
367 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0CLR = 1;
368
369 TIMERn(ui32TimerNumber)->CTRL0_b.TMR0CLR = 0;
370
371 AM_CRITICAL_END;
372
373 return AM_HAL_STATUS_SUCCESS;
374 }
375
376 //
377 // Read the current value of a timer.
378 //
379 uint32_t
am_hal_timer_read(uint32_t ui32TimerNumber)380 am_hal_timer_read(uint32_t ui32TimerNumber)
381 {
382 uint32_t ui32TimerAddr = (uint32_t)&TIMERn(ui32TimerNumber)->TIMER0;
383 uint32_t ui32TimerVals[3];
384
385 //
386 // Read the register into ui32TimerVals[].
387 //
388 am_hal_triple_read(ui32TimerAddr, ui32TimerVals);
389
390 //
391 // Now determine which of the three values is the correct value.
392 // If the first 2 match, then the values are both correct and we're done.
393 // Otherwise, the third value is taken to be the correct value.
394 //
395 if ( ui32TimerVals[0] == ui32TimerVals[1] )
396 {
397 //
398 // If the first two values match, then neither one was a bad read.
399 // We'll take this as the current time.
400 //
401 return ui32TimerVals[1];
402 }
403 else
404 {
405 return ui32TimerVals[2];
406 }
407 }
408
409 //
410 // Configure timer pin output.
411 //
412 uint32_t
am_hal_timer_output_config(uint32_t ui32PadNum,uint32_t eOutputType)413 am_hal_timer_output_config(uint32_t ui32PadNum,
414 uint32_t eOutputType)
415 {
416 uint32_t volatile *outcfg;
417 uint32_t ui32OutcfgValue, ui32OutcfgMsk, ui32CfgShf, ui32OutcfgFnc;
418
419 #ifndef AM_HAL_DISABLE_API_VALIDATION
420 if ( (ui32PadNum >= AM_HAL_GPIO_MAX_PADS) || (eOutputType > AM_HAL_TIMER_OUTPUT_STIMER7) )
421 {
422 return AM_HAL_STATUS_INVALID_ARG;
423 }
424 #endif
425
426 ui32CfgShf = ui32PadNum % 4 * 8;
427 ui32OutcfgMsk = 0x7F << ui32CfgShf;
428 ui32OutcfgFnc = eOutputType << ui32CfgShf;
429
430 //
431 // Begin critical section.
432 //
433 AM_CRITICAL_BEGIN
434
435 outcfg = &(TIMER->OUTCFG0) + (ui32PadNum >> 2);
436 ui32OutcfgValue = *outcfg;
437 ui32OutcfgValue &= ~ui32OutcfgMsk;
438 ui32OutcfgValue |= ui32OutcfgFnc;
439 *outcfg = ui32OutcfgValue;
440
441 //
442 // Done with critical section.
443 //
444 AM_CRITICAL_END
445
446 return AM_HAL_STATUS_SUCCESS;
447 } // am_hal_timer_output_config()
448
449 //
450 // Set the COMPARE0 value for a single timer.
451 //
452 uint32_t
am_hal_timer_compare0_set(uint32_t ui32TimerNumber,uint32_t ui32CompareValue)453 am_hal_timer_compare0_set(uint32_t ui32TimerNumber,
454 uint32_t ui32CompareValue)
455 {
456 //
457 // Apply the Compare0 value without disabling the timer.
458 //
459 TIMERn(ui32TimerNumber)->TMR0CMP0 = ui32CompareValue;
460
461 return AM_HAL_STATUS_SUCCESS;
462 }
463
464 //
465 // Set the COMPARE1 value for a single timer.
466 //
467 uint32_t
am_hal_timer_compare1_set(uint32_t ui32TimerNumber,uint32_t ui32CompareValue)468 am_hal_timer_compare1_set(uint32_t ui32TimerNumber,
469 uint32_t ui32CompareValue)
470 {
471 //
472 // Apply the Compare1 value without disabling the timer.
473 //
474 TIMERn(ui32TimerNumber)->TMR0CMP1 = ui32CompareValue;
475
476 return AM_HAL_STATUS_SUCCESS;
477 }
478
479 //
480 // Enable timer interrupts.
481 //
482 uint32_t
am_hal_timer_interrupt_enable(uint32_t ui32InterruptMask)483 am_hal_timer_interrupt_enable(uint32_t ui32InterruptMask)
484 {
485 TIMER->INTEN |= ui32InterruptMask;
486
487 return AM_HAL_STATUS_SUCCESS;
488 }
489
490 //
491 // Disable timer interrupts.
492 //
493 uint32_t
am_hal_timer_interrupt_disable(uint32_t ui32InterruptMask)494 am_hal_timer_interrupt_disable(uint32_t ui32InterruptMask)
495 {
496 TIMER->INTEN &= ~(ui32InterruptMask);
497
498 return AM_HAL_STATUS_SUCCESS;
499 }
500
501 //
502 // Get the timer interrupt status.
503 //
504 uint32_t
am_hal_timer_interrupt_status_get(bool bEnabledOnly,uint32_t * pui32IntStatus)505 am_hal_timer_interrupt_status_get(bool bEnabledOnly, uint32_t *pui32IntStatus)
506 {
507 DIAG_SUPPRESS_VOLATILE_ORDER()
508
509 if (bEnabledOnly)
510 {
511 *pui32IntStatus = TIMER->INTSTAT & TIMER->INTEN;
512 }
513 else
514 {
515 *pui32IntStatus = TIMER->INTSTAT;
516 }
517
518 return AM_HAL_STATUS_SUCCESS;
519
520 DIAG_DEFAULT_VOLATILE_ORDER()
521 }
522
523 //
524 // Clear timer interrupts.
525 //
526 uint32_t
am_hal_timer_interrupt_clear(uint32_t ui32InterruptMask)527 am_hal_timer_interrupt_clear(uint32_t ui32InterruptMask)
528 {
529 TIMER->INTCLR = ui32InterruptMask;
530 return AM_HAL_STATUS_SUCCESS;
531 }
532
533 //*****************************************************************************
534 //
535 // End Doxygen group.
536 //! @}
537 //
538 //*****************************************************************************
539