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