1 //*****************************************************************************
2 //
3 //  am_hal_ctimer.c
4 //! @file
5 //!
6 //! @brief Functions for interfacing with the Counter/Timer module.
7 //!
8 //! @addtogroup ctimer2 Counter/Timer (CTIMER)
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 // Address space distance between timer configuration registers.
56 //
57 //*****************************************************************************
58 #define MAX_CTIMERS         4
59 #define TIMER_OFFSET        (AM_REG_CTIMER_TMR1_O - AM_REG_CTIMER_TMR0_O)
60 #define CTIMER_CMPR_OFFSET  (AM_REG_CTIMER_CMPRB0_O - AM_REG_CTIMER_CMPRA0_O)
61 
62 //*****************************************************************************
63 //
64 // Adjacency check
65 //
66 // This is related to the timer read workaround. This macro checks to see if
67 // the two supplied count values are within one "tick" of eachother. It should
68 // still pass in the event of a timer rollover.
69 //
70 //*****************************************************************************
71 //! Timer read workaround: Do count values differ by one tick or less.
72 #define adjacent(A, B)      (((A) == (B)) || (((A) + 1) == (B)) || ((B) == 0))
73 
74 //*****************************************************************************
75 //
76 //! Array of function pointers for handling CTimer interrupts.
77 //
78 //*****************************************************************************
79 am_hal_ctimer_handler_t am_hal_ctimer_ppfnHandlers[16];
80 
81 //*****************************************************************************
82 //
83 // Static function for reading the timer value.
84 //
85 //*****************************************************************************
86 #if defined(__GNUC_STDC_INLINE__)
87 __attribute__((naked))
88 static
89 void
back2back_reads(uint32_t u32TimerAddr,uint32_t u32Data[])90 back2back_reads(uint32_t u32TimerAddr, uint32_t u32Data[])
91 {
92     // u32TimerAddr = address of the timer to be read.
93     // u32Data[] is a pointer to a 3 word data array provided by the caller.
94     __asm
95     (
96         // Do 3 back-to-back reads of the register
97         "   push    {r4}\n"                     // Save r4
98         "   push    {r1}\n"                     // Save the data array ptr for later
99         "   mov     r2, r0\n"                   // Get Timer Addr
100         "   mrs     r4, PRIMASK\n"              // Save PRIMASK
101         "   cpsid   i\n"                        // __disable_irq()
102         "   nop\n"                              // Give the disable a cycle to take affect (but almost certainly not really needed)
103         "   ldr     r0, [r2, #0]\n"             // Get TMRn register value
104         "   ldr     r1, [r2, #0]\n"             // Get TMRn register value again
105         "   ldr     r3, [r2, #0]\n"             // Get TMRn register value for a third time
106         "   msr     PRIMASK, r4\n"              // Restore PRIMASK
107         "   pop     {r2}\n"                     // Get the array ptr
108         "   str     r0, [r2, #0]\n"             // Store register value to variable
109         "   str     r1, [r2, #4]\n"             // Store register value to variable
110         "   str     r3, [r2, #8]\n"             // Store register value to variable
111         "   pop     {r4}\n"                     // restore r4
112         "   bx      lr\n"
113     );
114 }
115 
116 #elif defined(__ARMCC_VERSION)
117 __asm static uint32_t
back2back_reads(uint32_t u32TimerAddr,uint32_t u32Data[])118 back2back_reads( uint32_t u32TimerAddr, uint32_t u32Data[])
119 {
120     push    {r4}                     // Save r4
121     push    {r1}                     // Save the data array ptr for later
122     mov     r2, r0                   // Get Timer Addr
123     mrs     r4, PRIMASK              // Save PRIMASK
124     cpsid   i                        // __disable_irq()
125     nop                              // Give the disable a cycle to take affect (but almost certainly not really needed)
126     ldr     r0, [r2, #0]             // Get TMRn register value
127     ldr     r1, [r2, #0]             // Get TMRn register value again
128     ldr     r3, [r2, #0]             // Get TMRn register value for a third time
129     msr     PRIMASK, r4              // Restore PRIMASK
130     pop     {r2}                     // Get the array ptr
131     str     r0, [r2, #0]             // Store register value to variable
132     str     r1, [r2, #4]             // Store register value to variable
133     str     r3, [r2, #8]             // Store register value to variable
134     pop     {r4}                     // Restore r4
135     bx      lr
136 }
137 
138 #elif defined(__IAR_SYSTEMS_ICC__)
139 #pragma diag_suppress = Pe940   // Suppress IAR compiler warning about missing
140                                 // return statement on a non-void function
141 __stackless static uint32_t
back2back_reads(uint32_t u32TimerAddr,uint32_t u32Data[])142 back2back_reads( uint32_t u32TimerAddr, uint32_t u32Data[])
143 {
144     __asm("    push    {r4}");          // Save r4
145     __asm("    push    {r1}");          // Save the data array ptr for later
146     __asm("    mov     r2, r0");        // Get Timer Addr
147     __asm("    mrs     r4, PRIMASK");   // Save PRIMASK"
148     __asm("    cpsid   i");             // __disable_irq()
149     __asm("    nop");                   // Give the disable a cycle to take affect (but almost certainly not really needed)
150     __asm("    ldr     r0, [r2, #0]");  // Get TMRn register value
151     __asm("    ldr     r1, [r2, #0]");  // Get TMRn register value again
152     __asm("    ldr     r3, [r2, #0]");  // Get TMRn register value for a third time
153     __asm("    msr     PRIMASK, r4");   // Restore PRIMASK
154     __asm("    pop     {r2}");          // Get the array ptr
155     __asm("    str     r0, [r2, #0]");  // Store register value to variable
156     __asm("    str     r1, [r2, #4]");  // Store register value to variable
157     __asm("    str     r3, [r2, #8]");  // Store register value to variable
158     __asm("    pop     {r4}");          // Restore r4
159     __asm("    bx      lr");
160 }
161 #pragma diag_default = Pe940    // Restore IAR compiler warning
162 #endif
163 
164 //*****************************************************************************
165 //
166 //! @brief Check to see if the given CTimer is using the HFRC
167 //!
168 //! @note Calls to this function should be from inside a critical section.
169 //!
170 //! @return None.
171 //
172 //*****************************************************************************
173 static bool
ctimer_source_hfrc(uint32_t ui32CtimerNum)174 ctimer_source_hfrc(uint32_t ui32CtimerNum)
175 {
176     uint32_t *pui32ConfigReg;
177     uint32_t ui32TimerASrc, ui32TimerBSrc;
178 
179     //
180     // Find the correct register to write.
181     //
182     pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
183                                   (ui32CtimerNum * TIMER_OFFSET));
184 
185     //
186     // Determine if this timer is using HFRC as the clock source.
187     // The value we are looking for is HFRC_DIV4 to HFRC_DIV4K.
188     // Get the clock sources and 0-base the extracted value.
189     //
190     ui32TimerASrc = AM_BFX(CTIMER, CTRL0, TMRA0CLK, *pui32ConfigReg) -
191                     AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4);
192     ui32TimerBSrc = AM_BFX(CTIMER, CTRL0, TMRB0CLK, *pui32ConfigReg) -
193                     AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4);
194 
195     //
196     // If the source value is 0 to (HFRC_DIV4K - HFRC_DIV4), then it's HFRC.
197     //
198     if ( (ui32TimerASrc <= (AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4K) -
199                             AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4)))  ||
200          (ui32TimerBSrc <= (AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4K) -
201                             AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4))) )
202     {
203         return true;
204     }
205     else
206     {
207         return false;
208     }
209 
210 } // ctimer_source_hfrc()
211 
212 //*****************************************************************************
213 //
214 // @brief Check to see if any of the CTimers or STimer are using the HFRC.
215 //
216 //  This function should be used to check if the HFRC is being used in order
217 //  to correctly establish power related settings.
218 //
219 //  Note - Calls to this function should be from inside a critical section.
220 //
221 //! @return None.
222 //
223 //*****************************************************************************
224 static bool
timers_use_hfrc(void)225 timers_use_hfrc(void)
226 {
227     uint32_t ui32TimerASrc, ui32CtimerNum;
228 
229     //
230     // Check STimer to see if it is using HFRC.
231     //
232     ui32TimerASrc = AM_BFR(CTIMER, STCFG, CLKSEL);
233     if ( (ui32TimerASrc == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV16)   ||
234          (ui32TimerASrc == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV256) )
235     {
236         return true;
237     }
238 
239     //
240     // Check the CTimers to see if any are using HFRC as their clock source.
241     //
242     for ( ui32CtimerNum = 0; ui32CtimerNum < MAX_CTIMERS; ui32CtimerNum++ )
243     {
244         if ( ctimer_source_hfrc(ui32CtimerNum) )
245         {
246             return true;
247         }
248     }
249 
250     return false;
251 
252 } // timers_use_hfrc()
253 
254 //*****************************************************************************
255 //
256 //! @brief Convenience function for responding to CTimer interrupts.
257 //!
258 //! @param ui32Status is the interrupt status as returned by
259 //! am_hal_ctimer_int_status_get()
260 //!
261 //! This function may be called from am_ctimer_isr() to read the status of
262 //! the CTimer interrupts, determine which source caused the most recent
263 //! interrupt, and call an interrupt handler function to respond. The interrupt
264 //! handler to be called must be first registered with the
265 //! am_hal_ctimer_int_register() function.
266 //!
267 //! In the event that multiple sources are active, the corresponding
268 //! interrupt handlers will be called in numerical order based on interrupt def.
269 //!
270 //! @return None.
271 //
272 //*****************************************************************************
273 void
am_hal_ctimer_int_service(uint32_t ui32Status)274 am_hal_ctimer_int_service(uint32_t ui32Status)
275 {
276     uint32_t ui32Clz;
277 
278     am_hal_ctimer_handler_t pfnHandler;
279 
280     ui32Status &= 0xFFFF;
281 
282     while ( ui32Status )
283     {
284         //
285         // Pick one of any remaining active interrupt bits
286         //
287 #ifdef __IAR_SYSTEMS_ICC__
288         ui32Clz = __CLZ(ui32Status);
289 #else
290         ui32Clz = __builtin_clz(ui32Status);
291 #endif
292 
293         //
294         // Turn off the bit we picked in the working copy
295         //
296         ui32Status &= ~(0x80000000 >> ui32Clz);
297 
298         //
299         // Check the bit handler table to see if there is an interrupt handler
300         // registered for this particular bit.
301         //
302         pfnHandler = am_hal_ctimer_ppfnHandlers[31 - ui32Clz];
303         if ( pfnHandler )
304         {
305             //
306             // If we found an interrupt handler routine, call it now.
307             //
308             pfnHandler();
309         }
310     }
311 } // am_hal_ctimer_int_service()
312 
313 //*****************************************************************************
314 //
315 //! @brief Register an interrupt handler for CTimer.
316 //!
317 //! @param ui32Interrupt - interrupt number to assign this interrupt handler to.
318 //! @param pfnHandler - Function to call when this interrupt is received.
319 //!
320 //! This function allows the caller to specify a function that should be called
321 //! any time a Ctimer interrupt is received. Registering an
322 //! interrupt handler using this function adds the function pointer to an array
323 //! in SRAM. This interrupt handler will be called by am_hal_ctimer_int_service()
324 //! whenever the ui32Status parameter indicates that the corresponding interrupt.
325 //!
326 //! To remove an interrupt handler that has already been registered, the
327 //! pfnHandler parameter may be set to zero.
328 //!
329 //! @note This function will not have any effect unless the
330 //! am_hal_ctimer_int_service() function is being used.
331 //!
332 //! @return None.
333 //
334 //*****************************************************************************
335 void
am_hal_ctimer_int_register(uint32_t ui32Interrupt,am_hal_ctimer_handler_t pfnHandler)336 am_hal_ctimer_int_register(uint32_t ui32Interrupt,
337                            am_hal_ctimer_handler_t pfnHandler)
338 {
339     uint32_t intIdx = 0;
340 
341     //
342     // Check to make sure the interrupt number is valid. (Debug builds only)
343     //
344     switch (ui32Interrupt)
345     {
346         case AM_REG_CTIMER_INTEN_CTMRA0C0INT_M:
347             intIdx = AM_REG_CTIMER_INTEN_CTMRA0C0INT_S;
348             break;
349 
350         case AM_REG_CTIMER_INTEN_CTMRB0C0INT_M:
351             intIdx = AM_REG_CTIMER_INTEN_CTMRB0C0INT_S;
352             break;
353 
354         case AM_REG_CTIMER_INTEN_CTMRA1C0INT_M:
355             intIdx = AM_REG_CTIMER_INTEN_CTMRA1C0INT_S;
356             break;
357 
358         case AM_REG_CTIMER_INTEN_CTMRB1C0INT_M:
359             intIdx = AM_REG_CTIMER_INTEN_CTMRB1C0INT_S;
360             break;
361 
362         case AM_REG_CTIMER_INTEN_CTMRA2C0INT_M:
363             intIdx = AM_REG_CTIMER_INTEN_CTMRA2C0INT_S;
364             break;
365 
366         case AM_REG_CTIMER_INTEN_CTMRB2C0INT_M:
367             intIdx = AM_REG_CTIMER_INTEN_CTMRB2C0INT_S;
368             break;
369 
370         case AM_REG_CTIMER_INTEN_CTMRA3C0INT_M:
371             intIdx = AM_REG_CTIMER_INTEN_CTMRA3C0INT_S;
372             break;
373 
374         case AM_REG_CTIMER_INTEN_CTMRB3C0INT_M:
375             intIdx = AM_REG_CTIMER_INTEN_CTMRB3C0INT_S;
376             break;
377 
378         case AM_REG_CTIMER_INTEN_CTMRA0C1INT_M:
379             intIdx = AM_REG_CTIMER_INTEN_CTMRA0C1INT_S;
380             break;
381 
382         case AM_REG_CTIMER_INTEN_CTMRB0C1INT_M:
383             intIdx = AM_REG_CTIMER_INTEN_CTMRB0C1INT_S;
384             break;
385 
386         case AM_REG_CTIMER_INTEN_CTMRA1C1INT_M:
387             intIdx = AM_REG_CTIMER_INTEN_CTMRA1C1INT_S;
388             break;
389 
390         case AM_REG_CTIMER_INTEN_CTMRB1C1INT_M:
391             intIdx = AM_REG_CTIMER_INTEN_CTMRB1C1INT_S;
392             break;
393 
394         case AM_REG_CTIMER_INTEN_CTMRA2C1INT_M:
395             intIdx = AM_REG_CTIMER_INTEN_CTMRA2C1INT_S;
396             break;
397 
398         case AM_REG_CTIMER_INTEN_CTMRB2C1INT_M:
399             intIdx = AM_REG_CTIMER_INTEN_CTMRB2C1INT_S;
400             break;
401 
402         case AM_REG_CTIMER_INTEN_CTMRA3C1INT_M:
403             intIdx = AM_REG_CTIMER_INTEN_CTMRA3C1INT_S;
404             break;
405 
406         case AM_REG_CTIMER_INTEN_CTMRB3C1INT_M:
407             intIdx = AM_REG_CTIMER_INTEN_CTMRB3C1INT_S;
408             break;
409 
410         default:
411             am_hal_debug_assert_msg(false, "CTimer interrupt number out of range.");
412     }
413 
414     am_hal_ctimer_ppfnHandlers[intIdx] = pfnHandler;
415 
416 } // am_hal_ctimer_int_register()
417 
418 //*****************************************************************************
419 //
420 //! @brief Set up the counter/timer.
421 //!
422 //! @param ui32TimerNumber is the number of the Timer that should be
423 //! configured.
424 //!
425 //! @param psConfig is a pointer to a structure that holds important settings
426 //! for the timer.
427 //!
428 //! This function should be used to perform the initial set-up of the
429 //! counter-timer.
430 //!
431 //! @note This function will eventually be replaced by
432 //! am_hal_ctimer_config_single(), which performs the same configuration
433 //! without requiring a structure. Please use am_hal_ctimer_config_single() for
434 //! new development.
435 //!
436 //! @return None.
437 //
438 //*****************************************************************************
439 void
am_hal_ctimer_config(uint32_t ui32TimerNumber,am_hal_ctimer_config_t * psConfig)440 am_hal_ctimer_config(uint32_t ui32TimerNumber,
441                      am_hal_ctimer_config_t *psConfig)
442 {
443     uint32_t *pui32ConfigReg;
444     uint32_t ui32ConfigVal;
445 
446     //
447     // Start preparing the configuration word for this timer. The configuration
448     // values for Timer A and Timer B provided in the config structure should
449     // match the register definitions already, so we will mostly just need to
450     // OR them together.
451     //
452     ui32ConfigVal = ( (psConfig->ui32TimerAConfig)  |
453                       (psConfig->ui32TimerBConfig << 16) );
454 
455     //
456     // OR in the Link bit if the timers need to be linked.
457     //
458     ui32ConfigVal |= psConfig->ui32Link ? AM_HAL_CTIMER_LINK : 0;
459 
460     //
461     // Begin critical section while config registers are read and modified.
462     //
463     AM_CRITICAL_BEGIN_ASM
464 
465     //
466     // Find the correct register to write.
467     //
468     pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
469                                   (ui32TimerNumber * TIMER_OFFSET));
470 
471     //
472     // Write our configuration value.
473     //
474     AM_REGVAL(pui32ConfigReg) = ui32ConfigVal;
475 
476     //
477     // If all of the clock sources are not HRFC disable LDO when sleeping if timers are enabled.
478     //
479     if ( timers_use_hfrc() )
480     {
481         AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 0);
482     }
483     else
484     {
485         AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 1);
486     }
487 
488     //
489     // Done with critical section.
490     //
491     AM_CRITICAL_END_ASM
492 
493 } // am_hal_ctimer_config()
494 
495 //*****************************************************************************
496 //
497 //! @brief Set up the counter/timer.
498 //!
499 //! @param ui32TimerNumber is the number of the Timer that should be
500 //! configured.
501 //!
502 //! @param ui32TimerSegment specifies which segment of the timer should be
503 //! enabled.
504 //!
505 //! @param ui32ConfigVal specifies the configuration options for the selected
506 //! timer.
507 //!
508 //! This function should be used to perform the initial set-up of the
509 //! counter-timer. It can be used to configure either a 16-bit timer (A or B) or a
510 //! 32-bit timer using the BOTH option.
511 //!
512 //! Valid values for ui32TimerSegment are:
513 //!
514 //!     AM_HAL_CTIMER_TIMERA
515 //!     AM_HAL_CTIMER_TIMERB
516 //!     AM_HAL_CTIMER_BOTH
517 //!
518 //! The timer's clock source, mode, interrupt, and external pin behavior are
519 //! all controlled through the \e ui32Configval parameter. The valid options
520 //! for ui32ConfigVal include any ORed together combination of the following:
521 //!
522 //! Clock configuration macros:
523 //!
524 //!     AM_HAL_CTIMER_HFRC_24MHZ
525 //!     AM_HAL_CTIMER_LFRC_512HZ
526 //!     ... etc. (See am_hal_ctimer.h for the full set of options.)
527 //!
528 //! Mode selection macros:
529 //!
530 //!     AM_HAL_CTIMER_FN_ONCE
531 //!     AM_HAL_CTIMER_FN_REPEAT
532 //!     AM_HAL_CTIMER_FN_PWM_ONCE
533 //!     AM_HAL_CTIMER_FN_PWM_REPEAT
534 //!     AM_HAL_CTIMER_FN_CONTINUOUS
535 //!
536 //! Interrupt control:
537 //!
538 //!     AM_HAL_CTIMER_INT_ENABLE
539 //!
540 //! Pin control:
541 //!
542 //!     AM_HAL_CTIMER_PIN_ENABLE
543 //!     AM_HAL_CTIMER_PIN_INVERT
544 //!
545 //! ADC trigger (Timer 3 only):
546 //!
547 //!     AM_HAL_CTIMER_ADC_TRIG
548 //!
549 //! @return None.
550 //
551 //*****************************************************************************
552 void
am_hal_ctimer_config_single(uint32_t ui32TimerNumber,uint32_t ui32TimerSegment,uint32_t ui32ConfigVal)553 am_hal_ctimer_config_single(uint32_t ui32TimerNumber,
554                             uint32_t ui32TimerSegment,
555                             uint32_t ui32ConfigVal)
556 {
557     volatile uint32_t *pui32ConfigReg;
558     uint32_t ui32WriteVal;
559 
560     //
561     // Find the correct register to write based on the timer number.
562     //
563     pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
564                                   (ui32TimerNumber * TIMER_OFFSET));
565 
566     //
567     // Begin critical section while config registers are read and modified.
568     //
569     AM_CRITICAL_BEGIN_ASM
570 
571     //
572     // Save the value that's already in the register.
573     //
574     ui32WriteVal = AM_REGVAL(pui32ConfigReg);
575 
576     //
577     // If we're working with TIMERB, we need to shift our configuration value
578     // up by 16 bits.
579     //
580 
581     if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
582     {
583         ui32ConfigVal = ((ui32ConfigVal & 0xFFFF) << 16);
584     }
585 
586     //
587     // Replace part of the saved register value with the configuration value
588     // from the caller.
589     //
590     ui32WriteVal = (ui32WriteVal & ~(ui32TimerSegment)) | ui32ConfigVal;
591 
592     //
593     // If we're configuring both timers, we need to set the "link" bit.
594     //
595     if ( ui32TimerSegment == AM_HAL_CTIMER_BOTH )
596     {
597         ui32WriteVal |= AM_HAL_CTIMER_LINK;
598     }
599 
600     //
601     // Write our completed configuration value.
602     //
603     AM_REGVAL(pui32ConfigReg) = ui32WriteVal;
604 
605     //
606     // If all of the clock sources are not HRFC disable LDO when sleeping if timers are enabled.
607     //
608     if ( timers_use_hfrc() )
609     {
610         AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 0);
611     }
612     else
613     {
614         AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 1);
615     }
616 
617     //
618     // Done with critical section.
619     //
620     AM_CRITICAL_END_ASM
621 
622 } // am_hal_ctimer_config_single()
623 
624 //*****************************************************************************
625 //
626 //! @brief Start a timer
627 //!
628 //! @param ui32TimerNumber is the number of the timer to enable
629 //!
630 //! @param ui32TimerSegment specifies which segment of the timer should be
631 //! enabled.  Valid values for ui32TimerSegment are:
632 //!     AM_HAL_CTIMER_TIMERA
633 //!     AM_HAL_CTIMER_TIMERB
634 //!     AM_HAL_CTIMER_BOTH
635 //!
636 //! This function will enable a timer to begin incrementing. The \e
637 //! ui32TimerNumber parameter selects the timer that should be enabled, for
638 //! example, a 0 would target TIMER0. The \e ui32TimerSegment parameter allows
639 //! the caller to individually select a segment within a timer to be enabled,
640 //! such as TIMER0A, TIMER0B, or both.
641 //!
642 //! @return None.
643 //
644 //*****************************************************************************
645 void
am_hal_ctimer_start(uint32_t ui32TimerNumber,uint32_t ui32TimerSegment)646 am_hal_ctimer_start(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
647 {
648     volatile uint32_t *pui32ConfigReg;
649     uint32_t ui32ConfigVal;
650 
651     //
652     // Find the correct control register.
653     //
654     pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
655                                   (ui32TimerNumber * TIMER_OFFSET));
656 
657     //
658     // Begin critical section while config registers are read and modified.
659     //
660     AM_CRITICAL_BEGIN_ASM
661 
662     //
663     // Read the current value.
664     //
665     ui32ConfigVal = *pui32ConfigReg;
666 
667     //
668     // Clear out the "clear" bit.
669     //
670     ui32ConfigVal &= ~(ui32TimerSegment & (AM_REG_CTIMER_CTRL0_TMRA0CLR_M |
671                                            AM_REG_CTIMER_CTRL0_TMRB0CLR_M));
672 
673     //
674     // Set the "enable bit"
675     //
676     ui32ConfigVal |= (ui32TimerSegment & (AM_REG_CTIMER_CTRL0_TMRA0EN_M |
677                                           AM_REG_CTIMER_CTRL0_TMRB0EN_M));
678 
679     //
680     // Write the value back to the register.
681     //
682     AM_REGVAL(pui32ConfigReg) = ui32ConfigVal;
683 
684     //
685     // Done with critical section.
686     //
687     AM_CRITICAL_END_ASM
688 } // am_hal_ctimer_start()
689 
690 //*****************************************************************************
691 //
692 //! @brief Stop a timer
693 //!
694 //! @param ui32TimerNumber is the number of the timer to disable.
695 //!
696 //! @param ui32TimerSegment specifies which segment of the timer should be
697 //! disabled.
698 //!
699 //! This function will stop the selected timer from incrementing. The \e
700 //! ui32TimerNumber parameter selects the timer that should be disabled, for
701 //! example, a 0 would target TIMER0. The \e ui32TimerSegment parameter allows
702 //! the caller to individually select a segment within a timer to be disabled,
703 //! such as TIMER0A, TIMER0B, or both.
704 //!
705 //! This function will stop a counter/timer from counting, but does not return
706 //! the count value to 'zero'. If you would like to reset the counter back to
707 //! zero, try the am_hal_ctimer_clear() function instead.
708 //!
709 //! Valid values for ui32TimerSegment are:
710 //!
711 //!     AM_HAL_CTIMER_TIMERA
712 //!     AM_HAL_CTIMER_TIMERB
713 //!     AM_HAL_CTIMER_BOTH
714 //!
715 //! @return None.
716 //
717 //*****************************************************************************
718 void
am_hal_ctimer_stop(uint32_t ui32TimerNumber,uint32_t ui32TimerSegment)719 am_hal_ctimer_stop(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
720 {
721     volatile uint32_t *pui32ConfigReg;
722 
723     //
724     // Find the correct control register.
725     //
726     pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
727                                   (ui32TimerNumber * TIMER_OFFSET));
728 
729     //
730     // Begin critical section.
731     //
732     AM_CRITICAL_BEGIN_ASM
733 
734     //
735     // Clear the "enable" bit
736     //
737     AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment &
738                                    (AM_REG_CTIMER_CTRL0_TMRA0EN_M |
739                                     AM_REG_CTIMER_CTRL0_TMRB0EN_M));
740 
741     //
742     // Done with critical section.
743     //
744     AM_CRITICAL_END_ASM
745 } // am_hal_ctimer_stop()
746 
747 //*****************************************************************************
748 //
749 //! @brief Stops a timer and resets its value back to zero.
750 //!
751 //! @param ui32TimerNumber is the number of the timer to clear.
752 //!
753 //! @param ui32TimerSegment specifies which segment of the timer should be
754 //! cleared.
755 //!
756 //! This function will stop a free-running counter-timer, reset its value to
757 //! zero, and leave the timer disabled. When you would like to restart the
758 //! counter, you will need to call am_hal_ctimer_start().
759 //!
760 //! The \e ui32TimerSegment parameter allows the caller to individually select
761 //! a segment within, such as TIMER0A, TIMER0B, or both.
762 //!
763 //! Valid values for ui32TimerSegment are:
764 //!
765 //!     AM_HAL_CTIMER_TIMERA
766 //!     AM_HAL_CTIMER_TIMERB
767 //!     AM_HAL_CTIMER_BOTH
768 //!
769 //! @return None.
770 //
771 //*****************************************************************************
772 void
am_hal_ctimer_clear(uint32_t ui32TimerNumber,uint32_t ui32TimerSegment)773 am_hal_ctimer_clear(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
774 {
775     volatile uint32_t *pui32ConfigReg;
776 
777     //
778     // Find the correct control register.
779     //
780     pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
781                                   (ui32TimerNumber * TIMER_OFFSET));
782 
783     //
784     // Begin critical section.
785     //
786     AM_CRITICAL_BEGIN_ASM
787 
788     //
789     // Set the "clear" bit
790     //
791     AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment &
792                                   (AM_REG_CTIMER_CTRL0_TMRA0CLR_M |
793                                    AM_REG_CTIMER_CTRL0_TMRB0CLR_M));
794 
795     //
796     // Done with critical section.
797     //
798     AM_CRITICAL_END_ASM
799 } // am_hal_ctimer_clear()
800 
801 //*****************************************************************************
802 //
803 //! @brief Returns the current free-running value of the selected timer.
804 //!
805 //! @param ui32TimerNumber is the number of the timer to read.
806 //! @param ui32TimerSegment specifies which segment of the timer should be
807 //! read.
808 //!
809 //! This function returns the current free-running value of the selected timer.
810 //!
811 //! @note When reading from a linked timer, be sure to use AM_HAL_CTIMER both
812 //! for the segment argument.
813 //!
814 //! Valid values for ui32TimerSegment are:
815 //!
816 //!     AM_HAL_CTIMER_TIMERA
817 //!     AM_HAL_CTIMER_TIMERB
818 //!     AM_HAL_CTIMER_BOTH
819 //!
820 //! @return Current timer value.
821 //
822 //*****************************************************************************
823 uint32_t
am_hal_ctimer_read(uint32_t ui32TimerNumber,uint32_t ui32TimerSegment)824 am_hal_ctimer_read(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
825 {
826     volatile uint32_t ui32Value = 0;
827     uint32_t ui32Values[4] = {0, };
828     uint32_t ui32TimerAddrTbl[4] =
829     {
830         REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR0_O,
831         REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR1_O,
832         REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR2_O,
833         REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR3_O
834     };
835 
836     //
837     // Read the timer with back2back reads. This is a workaround for a clock
838     // domain synchronization issue. Some timer bits may be slow to increment,
839     // which means that the value in the timer register will sometimes be
840     // wrong.
841     //
842     // The architecture guarantees that:
843     //
844     // 1) If the timer is running at a speed close to the core frequency, the
845     // core and timer clock domains will be synchronized, and no "bad" reads
846     // will happen.
847     //
848     // 2) Bad reads will only happen if the core reads the timer register while
849     // the timer value is transitioning from one count to the next.
850     //
851     // 3) The timer will resolve to the correct value within one 24 MHz clock
852     // cycle.
853     //
854     // If we read the timer three times in a row with back-to-back load
855     // instructions, then we can guarantee that the timer will only have time
856     // to increment once, and that only one of the three reads can be wrong.
857     // This routine will perform the back-to-back reads and return all three
858     // values. The rest of this fuction determines which value we should
859     // actually use.
860     //
861     back2back_reads(ui32TimerAddrTbl[ui32TimerNumber], ui32Values);
862 
863     //
864     // Shift or mask the values based on the given timer segment.
865     //
866     if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
867     {
868         ui32Values[0] >>= 16;
869         ui32Values[1] >>= 16;
870         ui32Values[2] >>= 16;
871     }
872     else if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERA )
873     {
874         ui32Values[0] &= 0xFFFF;
875         ui32Values[1] &= 0xFFFF;
876         ui32Values[2] &= 0xFFFF;
877     }
878 
879     //
880     // Now, we'll figure out which of the three values is the correct time.
881     //
882     if (ui32Values[0] == ui32Values[1])
883     {
884         //
885         // If the first two values match, then neither one was a bad read.
886         // We'll take this as the current time.
887         //
888         ui32Value = ui32Values[1];
889     }
890     else
891     {
892         //
893         // If the first two values didn't match, then one of them might be bad.
894         // If one of the first two values is bad, then the third one should
895         // always be correct. We'll take the third value as the correct time.
896         //
897         ui32Value = ui32Values[2];
898 
899         //
900         // If all of the statements about the architecture are true, the third
901         // value should be correct, and it should always be within one count of
902         // either the first or the second value.
903         //
904         // Just in case, we'll check against the previous two values to make
905         // sure that our final answer was reasonable. If it isn't, we will
906         // flag it as a "bad read", and fail this assert statement.
907         //
908         // This shouldn't ever happen, and it hasn't ever happened in any of
909         // our tests so far.
910         //
911         am_hal_debug_assert_msg((adjacent(ui32Values[1], ui32Values[2]) ||
912                                  adjacent(ui32Values[0], ui32Values[2])),
913                                 "Bad CTIMER read");
914     }
915 
916     return ui32Value;
917 } // am_hal_ctimer_read()
918 
919 //*****************************************************************************
920 //
921 //! @brief Enable output to the timer pin
922 //!
923 //! @param ui32TimerNumber is the number of the timer to configure.
924 //!
925 //! @param ui32TimerSegment specifies which segment of the timer to use.
926 //!
927 //! This function will enable the output pin for the selected timer. The \e
928 //! ui32TimerSegment parameter allows the caller to individually select a
929 //! segment within, such as TIMER0A, TIMER0B, or both.
930 //!
931 //! Valid values for ui32TimerSegment are:
932 //!
933 //!     AM_HAL_CTIMER_TIMERA
934 //!     AM_HAL_CTIMER_TIMERB
935 //!     AM_HAL_CTIMER_BOTH
936 //!
937 //! @return None.
938 //
939 //*****************************************************************************
940 void
am_hal_ctimer_pin_enable(uint32_t ui32TimerNumber,uint32_t ui32TimerSegment)941 am_hal_ctimer_pin_enable(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
942 {
943     volatile uint32_t *pui32ConfigReg;
944 
945     //
946     // Find the correct control register.
947     //
948     pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
949                                   (ui32TimerNumber * TIMER_OFFSET));
950 
951     //
952     // Begin critical section.
953     //
954     AM_CRITICAL_BEGIN_ASM
955 
956     //
957     // Set the pin enable bit
958     //
959     AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment &
960                                   (AM_REG_CTIMER_CTRL0_TMRA0PE_M |
961                                    AM_REG_CTIMER_CTRL0_TMRB0PE_M));
962 
963     //
964     // Done with critical section.
965     //
966     AM_CRITICAL_END_ASM
967 } // am_hal_ctimer_pin_enable()
968 
969 //*****************************************************************************
970 //
971 //! @brief Disable the output pin.
972 //!
973 //! @param ui32TimerNumber is the number of the timer to configure.
974 //!
975 //! @param ui32TimerSegment specifies which segment of the timer to use.
976 //!
977 //! This function will disable the output pin for the selected timer. The \e
978 //! ui32TimerSegment parameter allows the caller to individually select a
979 //! segment within, such as TIMER0A, TIMER0B, or both.
980 //!
981 //! Valid values for ui32TimerSegment are:
982 //!
983 //!     AM_HAL_CTIMER_TIMERA
984 //!     AM_HAL_CTIMER_TIMERB
985 //!     AM_HAL_CTIMER_BOTH
986 //!
987 //! @return None.
988 //
989 //*****************************************************************************
990 void
am_hal_ctimer_pin_disable(uint32_t ui32TimerNumber,uint32_t ui32TimerSegment)991 am_hal_ctimer_pin_disable(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
992 {
993     volatile uint32_t *pui32ConfigReg;
994 
995     //
996     // Find the correct control register.
997     //
998     pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
999                                   (ui32TimerNumber * TIMER_OFFSET));
1000 
1001     //
1002     // Begin critical section.
1003     //
1004     AM_CRITICAL_BEGIN_ASM
1005 
1006     //
1007     // Clear the pin enable bit
1008     //
1009     AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment &
1010                                    (AM_REG_CTIMER_CTRL0_TMRA0PE_M |
1011                                     AM_REG_CTIMER_CTRL0_TMRB0PE_M));
1012 
1013     //
1014     // Done with critical section.
1015     //
1016     AM_CRITICAL_END_ASM
1017 } // am_hal_ctimer_pin_disable()
1018 
1019 //*****************************************************************************
1020 //
1021 //! @brief Set the polarity of the output pin.
1022 //!
1023 //! @param ui32TimerNumber is the number of the timer to configure.
1024 //!
1025 //! @param ui32TimerSegment specifies which segment of the timer to use.
1026 //!
1027 //! @param bInvertOutput determines whether the output should be inverted. If
1028 //! true, the timer output pin for the selected timer segment will be
1029 //! inverted.
1030 //!
1031 //! This function will set the polarity of the the output pin for the selected
1032 //! timer. The \e ui32TimerSegment parameter allows the caller to individually
1033 //! select a segment within, such as TIMER0A, TIMER0B, or both.
1034 //!
1035 //! Valid values for ui32TimerSegment are:
1036 //!
1037 //!     AM_HAL_CTIMER_TIMERA
1038 //!     AM_HAL_CTIMER_TIMERB
1039 //!     AM_HAL_CTIMER_BOTH
1040 //!
1041 //! @return None.
1042 //
1043 //*****************************************************************************
1044 void
am_hal_ctimer_pin_invert(uint32_t ui32TimerNumber,uint32_t ui32TimerSegment,bool bInvertOutput)1045 am_hal_ctimer_pin_invert(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment,
1046                          bool bInvertOutput)
1047 {
1048     volatile uint32_t *pui32ConfigReg;
1049 
1050     //
1051     // Find the correct control register.
1052     //
1053     pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
1054                                   (ui32TimerNumber * TIMER_OFFSET));
1055 
1056     //
1057     // Begin critical section.
1058     //
1059     AM_CRITICAL_BEGIN_ASM
1060 
1061     //
1062     // Figure out if we're supposed to be setting or clearing the polarity bit.
1063     //
1064     if ( bInvertOutput )
1065     {
1066         //
1067         // Set the polarity bit to invert the output.
1068         //
1069         AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment &
1070                                       (AM_REG_CTIMER_CTRL0_TMRA0POL_M |
1071                                        AM_REG_CTIMER_CTRL0_TMRB0POL_M));
1072     }
1073     else
1074     {
1075         //
1076         // Clear the polarity bit.
1077         //
1078         AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment &
1079                                        (AM_REG_CTIMER_CTRL0_TMRA0POL_M |
1080                                         AM_REG_CTIMER_CTRL0_TMRB0POL_M));
1081     }
1082 
1083     //
1084     // Done with critical section.
1085     //
1086     AM_CRITICAL_END_ASM
1087 } // am_hal_ctimer_pin_invert()
1088 
1089 //*****************************************************************************
1090 //
1091 //! @brief Set a compare register.
1092 //!
1093 //! @param ui32TimerNumber is the number of the timer to configure.
1094 //!
1095 //! @param ui32TimerSegment specifies which segment of the timer to use.
1096 //! Valid values for ui32TimerSegment are:
1097 //!
1098 //!     AM_HAL_CTIMER_TIMERA
1099 //!     AM_HAL_CTIMER_TIMERB
1100 //!     AM_HAL_CTIMER_BOTH
1101 //!
1102 //! @param ui32CompareReg specifies which compare register should be set
1103 //! (either 0 or 1)
1104 //!
1105 //! @param ui32Value is the value that should be written to the compare
1106 //! register.
1107 //!
1108 //! This function allows the caller to set the values in the compare registers
1109 //! for a timer. These registers control the period and duty cycle of the
1110 //! timers and their associated output pins. Please see the datasheet for
1111 //! further information on the operation of the compare registers. The \e
1112 //! ui32TimerSegment parameter allows the caller to individually select a
1113 //! segment within, such as TIMER0A, TIMER0B, or both.
1114 //!
1115 //! @note For simple manipulations of period or duty cycle for timers and PWMs,
1116 //! you may find it easier to use the am_hal_ctimer_period_set() function.
1117 //!
1118 //! @return None.
1119 //
1120 //*****************************************************************************
1121 void
am_hal_ctimer_compare_set(uint32_t ui32TimerNumber,uint32_t ui32TimerSegment,uint32_t ui32CompareReg,uint32_t ui32Value)1122 am_hal_ctimer_compare_set(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment,
1123                           uint32_t ui32CompareReg, uint32_t ui32Value)
1124 {
1125     volatile uint32_t *pui32CmprRegA, *pui32CmprRegB;
1126     uint32_t ui32CmprRegA, ui32CmprRegB;
1127 
1128     //
1129     // Find the correct compare register to write.
1130     // Assume A or BOTH.  We'll change later if B.
1131     //
1132     pui32CmprRegA = (uint32_t *)(AM_REG_CTIMERn(0) +
1133                                  AM_REG_CTIMER_CMPRA0_O +
1134                                  (ui32TimerNumber * TIMER_OFFSET));
1135     pui32CmprRegB = pui32CmprRegA + CTIMER_CMPR_OFFSET / 4;
1136 
1137     //
1138     // Write the compare register with the selected value.
1139     // Begin critical section while CMPR registers are modified.
1140     //
1141     AM_CRITICAL_BEGIN_ASM
1142 
1143     ui32CmprRegA = *pui32CmprRegA;
1144     ui32CmprRegB = *pui32CmprRegB;
1145 
1146     if ( ui32CompareReg == 1 )
1147     {
1148         //
1149         // CMPR reg 1
1150         // Get the lower 16b (but may not be used if TIMERB).
1151         //
1152         ui32CmprRegA = ( (ui32CmprRegA & AM_REG_CTIMER_CMPRA0_CMPR0A0_M) |
1153                           AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Value & 0xFFFF) );
1154 
1155         //
1156         // Get the upper 16b (but may not be used if TIMERA)
1157         //
1158         ui32CmprRegB = ( (ui32CmprRegB & AM_REG_CTIMER_CMPRA0_CMPR0A0_M) |
1159                           AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Value >> 16) );
1160     }
1161     else
1162     {
1163         //
1164         // CMPR reg 0
1165         // Get the lower 16b (but may not be used if TIMERB)
1166         //
1167         ui32CmprRegA = ( (ui32CmprRegA & AM_REG_CTIMER_CMPRA0_CMPR1A0_M) |
1168                          AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Value & 0xFFFF) );
1169 
1170         //
1171         // Set the upper 16b (but may not be used if TIMERA)
1172         //
1173         ui32CmprRegB = ( (ui32CmprRegB & AM_REG_CTIMER_CMPRA0_CMPR1A0_M) |
1174                          AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Value >> 16) );
1175     }
1176 
1177     if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
1178     {
1179         *pui32CmprRegB = ui32CmprRegB;
1180     }
1181     else
1182     {
1183         //
1184         // It's TIMERA or BOTH.
1185         //
1186         *pui32CmprRegA = ui32CmprRegA;
1187 
1188         if ( ui32TimerSegment == AM_HAL_CTIMER_BOTH )
1189         {
1190             *pui32CmprRegB = ui32CmprRegB;
1191         }
1192     }
1193 
1194     //
1195     // Done with critical section.
1196     //
1197     AM_CRITICAL_END_ASM
1198 } // am_hal_ctimer_compare_set()
1199 
1200 //*****************************************************************************
1201 //
1202 //! @brief Set the period and duty cycle of a timer.
1203 //!
1204 //! @param ui32TimerNumber is the number of the timer to configure.
1205 //!
1206 //! @param ui32TimerSegment specifies which segment of the timer to use.
1207 //!
1208 //! @param ui32Period specifies the desired period.  This parameter effectively
1209 //! specifies the CTIMER CMPR field(s). The CMPR fields are handled in hardware
1210 //! as (n+1) values, therefore ui32Period is actually specified as 1 less than
1211 //! the desired period. Finally, as mentioned in the data sheet, the CMPR fields
1212 //! cannot be 0 (a value of 1), so neither can ui32Period be 0.
1213 //!
1214 //! @param ui32OnTime set the number of clocks where the output signal is high.
1215 //!
1216 //! This function should be used for simple manipulations of the period and
1217 //! duty cycle of a counter/timer. To set the period and/or duty cycle of a
1218 //! linked timer pair, use AM_HAL_CTIMER_BOTH as the timer segment argument. If
1219 //! you would like to set the period and/or duty cycle for both TIMERA and
1220 //! TIMERB you will need to call this function twice: once for TIMERA, and once
1221 //! for TIMERB.
1222 //!
1223 //! Valid values for ui32TimerSegment are:
1224 //!
1225 //!     AM_HAL_CTIMER_TIMERA
1226 //!     AM_HAL_CTIMER_TIMERB
1227 //!     AM_HAL_CTIMER_BOTH
1228 //!
1229 //! @note The ui32OnTime parameter will only work if the timer is currently
1230 //! operating in one of the PWM modes.
1231 //!
1232 //! @return None.
1233 //
1234 //*****************************************************************************
1235 void
am_hal_ctimer_period_set(uint32_t ui32TimerNumber,uint32_t ui32TimerSegment,uint32_t ui32Period,uint32_t ui32OnTime)1236 am_hal_ctimer_period_set(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment,
1237                          uint32_t ui32Period, uint32_t ui32OnTime)
1238 {
1239     volatile uint32_t *pui32ControlReg;
1240     volatile uint32_t *pui32CompareRegA;
1241     volatile uint32_t *pui32CompareRegB;
1242     uint32_t ui32Mode, ui32Comp0, ui32Comp1;
1243 
1244     //
1245     // Find the correct control register to pull the function select field
1246     // from.
1247     //
1248     pui32ControlReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
1249                                    (ui32TimerNumber * TIMER_OFFSET));
1250 
1251     //
1252     // Find the correct compare registers to write.
1253     //
1254     pui32CompareRegA = (uint32_t *)(AM_REG_CTIMERn(0) +
1255                                     AM_REG_CTIMER_CMPRA0_O +
1256                                     (ui32TimerNumber * TIMER_OFFSET));
1257 
1258     pui32CompareRegB = (uint32_t *)(AM_REG_CTIMERn(0) +
1259                                     AM_REG_CTIMER_CMPRB0_O +
1260                                     (ui32TimerNumber * TIMER_OFFSET));
1261 
1262     //
1263     // Begin critical section.
1264     //
1265     AM_CRITICAL_BEGIN_ASM
1266 
1267     //
1268     // Extract the timer mode from the register based on the ui32TimerSegment
1269     // selected by the user.
1270     //
1271     ui32Mode = *pui32ControlReg;
1272     if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
1273     {
1274         ui32Mode = ui32Mode >> 16;
1275     }
1276 
1277     //
1278     // Mask to get to the bits we're interested in.
1279     //
1280     ui32Mode = ui32Mode & AM_REG_CTIMER_CTRL0_TMRA0FN_M;
1281 
1282     //
1283     // If the mode is a PWM mode, we'll need to calculate the correct CMPR0 and
1284     // CMPR1 values here.
1285     //
1286     if (ui32Mode == AM_HAL_CTIMER_FN_PWM_ONCE   ||
1287         ui32Mode == AM_HAL_CTIMER_FN_PWM_REPEAT)
1288     {
1289         ui32Comp0 = ui32Period - ui32OnTime;
1290         ui32Comp1 = ui32Period;
1291     }
1292     else
1293     {
1294         ui32Comp0 = ui32Period;
1295         ui32Comp1 = 0;
1296     }
1297 
1298     //
1299     // Based on the timer segment argument, write the calculated Compare 0 and
1300     // Compare 1 values to the correct halves of the correct registers.
1301     //
1302     if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERA )
1303     {
1304         //
1305         // For timer A, write the values to the TIMERA compare register.
1306         //
1307         *pui32CompareRegA = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) |
1308                              AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1));
1309     }
1310     else if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
1311     {
1312         //
1313         // For timer B, write the values to the TIMERA compare register.
1314         //
1315         *pui32CompareRegB = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) |
1316                              AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1));
1317     }
1318     else
1319     {
1320         //
1321         // For the linked case, write the lower halves of the values to the
1322         // TIMERA compare register, and the upper halves to the TIMERB compare
1323         // register.
1324         //
1325         *pui32CompareRegA = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) |
1326                              AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1));
1327 
1328         *pui32CompareRegB = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0 >> 16) |
1329                              AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1 >> 16));
1330     }
1331 
1332     //
1333     // Done with critical section.
1334     //
1335     AM_CRITICAL_END_ASM
1336 } // am_hal_ctimer_period_set()
1337 
1338 //*****************************************************************************
1339 //
1340 //! @brief Enable the TIMERA3 ADC trigger
1341 //!
1342 //! This function enables the ADC trigger within TIMERA3.
1343 //!
1344 //! @return None.
1345 //
1346 //*****************************************************************************
1347 void
am_hal_ctimer_adc_trigger_enable(void)1348 am_hal_ctimer_adc_trigger_enable(void)
1349 {
1350     //
1351     // Begin critical section.
1352     //
1353     AM_CRITICAL_BEGIN_ASM
1354 
1355     //
1356     // Enable the ADC trigger.
1357     //
1358     AM_REGn(CTIMER, 0, CTRL3) |= AM_REG_CTIMER_CTRL3_ADCEN_M;
1359 
1360     //
1361     // Done with critical section.
1362     //
1363     AM_CRITICAL_END_ASM
1364 } // am_hal_ctimer_adc_trigger_enable()
1365 
1366 //*****************************************************************************
1367 //
1368 //! @brief Disable the TIMERA3 ADC trigger
1369 //!
1370 //! This function disables the ADC trigger within TIMERA3.
1371 //!
1372 //! @return None.
1373 //
1374 //*****************************************************************************
1375 void
am_hal_ctimer_adc_trigger_disable(void)1376 am_hal_ctimer_adc_trigger_disable(void)
1377 {
1378     //
1379     // Begin critical section.
1380     //
1381     AM_CRITICAL_BEGIN_ASM
1382 
1383     //
1384     // Disable the ADC trigger.
1385     //
1386     AM_REGn(CTIMER, 0, CTRL3) &= ~AM_REG_CTIMER_CTRL3_ADCEN_M;
1387 
1388     //
1389     // Done with critical section.
1390     //
1391     AM_CRITICAL_END_ASM
1392 } // am_hal_ctimer_adc_trigger_disable()
1393 
1394 //*****************************************************************************
1395 //
1396 //! @brief Enables the selected timer interrupt.
1397 //!
1398 //! @param ui32Interrupt is the interrupt to be used.
1399 //!
1400 //! This function will enable the selected interrupts in the main CTIMER
1401 //! interrupt enable register. In order to receive an interrupt from a timer,
1402 //! you will need to enable the interrupt for that timer in this main register,
1403 //! as well as in the timer control register (accessible though
1404 //! am_hal_ctimer_config()), and in the NVIC.
1405 //!
1406 //! ui32Interrupt should be the logical OR of one or more of the following
1407 //! values:
1408 //!
1409 //!     AM_HAL_CTIMER_INT_TIMERA0C0
1410 //!     AM_HAL_CTIMER_INT_TIMERA0C1
1411 //!     AM_HAL_CTIMER_INT_TIMERB0C0
1412 //!     AM_HAL_CTIMER_INT_TIMERB0C1
1413 //!     AM_HAL_CTIMER_INT_TIMERA1C0
1414 //!     AM_HAL_CTIMER_INT_TIMERA1C1
1415 //!     AM_HAL_CTIMER_INT_TIMERB1C0
1416 //!     AM_HAL_CTIMER_INT_TIMERB1C1
1417 //!     AM_HAL_CTIMER_INT_TIMERA2C0
1418 //!     AM_HAL_CTIMER_INT_TIMERA2C1
1419 //!     AM_HAL_CTIMER_INT_TIMERB2C0
1420 //!     AM_HAL_CTIMER_INT_TIMERB2C1
1421 //!     AM_HAL_CTIMER_INT_TIMERA3C0
1422 //!     AM_HAL_CTIMER_INT_TIMERA3C1
1423 //!     AM_HAL_CTIMER_INT_TIMERB3C0
1424 //!     AM_HAL_CTIMER_INT_TIMERB3C1
1425 //!
1426 //! @return None.
1427 //
1428 //*****************************************************************************
1429 void
am_hal_ctimer_int_enable(uint32_t ui32Interrupt)1430 am_hal_ctimer_int_enable(uint32_t ui32Interrupt)
1431 {
1432     //
1433     // Begin critical section.
1434     //
1435     AM_CRITICAL_BEGIN_ASM
1436 
1437     //
1438     // Enable the interrupt at the module level.
1439     //
1440     AM_REGn(CTIMER, 0, INTEN) |= ui32Interrupt;
1441 
1442     //
1443     // Done with critical section.
1444     //
1445     AM_CRITICAL_END_ASM
1446 } // am_hal_ctimer_int_enable()
1447 
1448 //*****************************************************************************
1449 //
1450 //! @brief Return the enabled timer interrupts.
1451 //!
1452 //! This function will return all enabled interrupts in the main CTIMER
1453 //! interrupt enable register.
1454 //!
1455 //! @return return enabled interrupts. This will be a logical or of:
1456 //!
1457 //!     AM_HAL_CTIMER_INT_TIMERA0C0
1458 //!     AM_HAL_CTIMER_INT_TIMERA0C1
1459 //!     AM_HAL_CTIMER_INT_TIMERB0C0
1460 //!     AM_HAL_CTIMER_INT_TIMERB0C1
1461 //!     AM_HAL_CTIMER_INT_TIMERA1C0
1462 //!     AM_HAL_CTIMER_INT_TIMERA1C1
1463 //!     AM_HAL_CTIMER_INT_TIMERB1C0
1464 //!     AM_HAL_CTIMER_INT_TIMERB1C1
1465 //!     AM_HAL_CTIMER_INT_TIMERA2C0
1466 //!     AM_HAL_CTIMER_INT_TIMERA2C1
1467 //!     AM_HAL_CTIMER_INT_TIMERB2C0
1468 //!     AM_HAL_CTIMER_INT_TIMERB2C1
1469 //!     AM_HAL_CTIMER_INT_TIMERA3C0
1470 //!     AM_HAL_CTIMER_INT_TIMERA3C1
1471 //!     AM_HAL_CTIMER_INT_TIMERB3C0
1472 //!     AM_HAL_CTIMER_INT_TIMERB3C1
1473 //!
1474 //! @return Return the enabled timer interrupts.
1475 //
1476 //*****************************************************************************
1477 uint32_t
am_hal_ctimer_int_enable_get(void)1478 am_hal_ctimer_int_enable_get(void)
1479 {
1480     //
1481     // Return enabled interrupts.
1482     //
1483     return AM_REGn(CTIMER, 0, INTEN);
1484 } // am_hal_ctimer_int_enable_get()
1485 
1486 //*****************************************************************************
1487 //
1488 //! @brief Disables the selected timer interrupt.
1489 //!
1490 //! @param ui32Interrupt is the interrupt to be used.
1491 //!
1492 //! This function will disable the selected interrupts in the main CTIMER
1493 //! interrupt register.
1494 //!
1495 //! ui32Interrupt should be the logical OR of one or more of the following
1496 //! values:
1497 //!
1498 //!     AM_HAL_CTIMER_INT_TIMERA0C0
1499 //!     AM_HAL_CTIMER_INT_TIMERA0C1
1500 //!     AM_HAL_CTIMER_INT_TIMERB0C0
1501 //!     AM_HAL_CTIMER_INT_TIMERB0C1
1502 //!     AM_HAL_CTIMER_INT_TIMERA1C0
1503 //!     AM_HAL_CTIMER_INT_TIMERA1C1
1504 //!     AM_HAL_CTIMER_INT_TIMERB1C0
1505 //!     AM_HAL_CTIMER_INT_TIMERB1C1
1506 //!     AM_HAL_CTIMER_INT_TIMERA2C0
1507 //!     AM_HAL_CTIMER_INT_TIMERA2C1
1508 //!     AM_HAL_CTIMER_INT_TIMERB2C0
1509 //!     AM_HAL_CTIMER_INT_TIMERB2C1
1510 //!     AM_HAL_CTIMER_INT_TIMERA3C0
1511 //!     AM_HAL_CTIMER_INT_TIMERA3C1
1512 //!     AM_HAL_CTIMER_INT_TIMERB3C0
1513 //!     AM_HAL_CTIMER_INT_TIMERB3C1
1514 //!
1515 //! @return None.
1516 //
1517 //*****************************************************************************
1518 void
am_hal_ctimer_int_disable(uint32_t ui32Interrupt)1519 am_hal_ctimer_int_disable(uint32_t ui32Interrupt)
1520 {
1521     //
1522     // Begin critical section.
1523     //
1524     AM_CRITICAL_BEGIN_ASM
1525 
1526     //
1527     // Disable the interrupt at the module level.
1528     //
1529     AM_REGn(CTIMER, 0, INTEN) &= ~ui32Interrupt;
1530 
1531     //
1532     // Done with critical section.
1533     //
1534     AM_CRITICAL_END_ASM
1535 } // am_hal_ctimer_int_disable()
1536 
1537 //*****************************************************************************
1538 //
1539 //! @brief Clears the selected timer interrupt.
1540 //!
1541 //! @param ui32Interrupt is the interrupt to be used.
1542 //!
1543 //! This function will clear the selected interrupts in the main CTIMER
1544 //! interrupt register.
1545 //!
1546 //! ui32Interrupt should be the logical OR of one or more of the following
1547 //! values:
1548 //!
1549 //!     AM_HAL_CTIMER_INT_TIMERA0C0
1550 //!     AM_HAL_CTIMER_INT_TIMERA0C1
1551 //!     AM_HAL_CTIMER_INT_TIMERB0C0
1552 //!     AM_HAL_CTIMER_INT_TIMERB0C1
1553 //!     AM_HAL_CTIMER_INT_TIMERA1C0
1554 //!     AM_HAL_CTIMER_INT_TIMERA1C1
1555 //!     AM_HAL_CTIMER_INT_TIMERB1C0
1556 //!     AM_HAL_CTIMER_INT_TIMERB1C1
1557 //!     AM_HAL_CTIMER_INT_TIMERA2C0
1558 //!     AM_HAL_CTIMER_INT_TIMERA2C1
1559 //!     AM_HAL_CTIMER_INT_TIMERB2C0
1560 //!     AM_HAL_CTIMER_INT_TIMERB2C1
1561 //!     AM_HAL_CTIMER_INT_TIMERA3C0
1562 //!     AM_HAL_CTIMER_INT_TIMERA3C1
1563 //!     AM_HAL_CTIMER_INT_TIMERB3C0
1564 //!     AM_HAL_CTIMER_INT_TIMERB3C1
1565 //!
1566 //! @return None.
1567 //
1568 //*****************************************************************************
1569 void
am_hal_ctimer_int_clear(uint32_t ui32Interrupt)1570 am_hal_ctimer_int_clear(uint32_t ui32Interrupt)
1571 {
1572     //
1573     // Disable the interrupt at the module level.
1574     //
1575     AM_REGn(CTIMER, 0, INTCLR) = ui32Interrupt;
1576 } // am_hal_ctimer_int_clear()
1577 
1578 //*****************************************************************************
1579 //
1580 //! @brief Sets the selected timer interrupt.
1581 //!
1582 //! @param ui32Interrupt is the interrupt to be used.
1583 //!
1584 //! This function will set the selected interrupts in the main CTIMER
1585 //! interrupt register.
1586 //!
1587 //! ui32Interrupt should be the logical OR of one or more of the following
1588 //! values:
1589 //!
1590 //!     AM_HAL_CTIMER_INT_TIMERA0C0
1591 //!     AM_HAL_CTIMER_INT_TIMERA0C1
1592 //!     AM_HAL_CTIMER_INT_TIMERB0C0
1593 //!     AM_HAL_CTIMER_INT_TIMERB0C1
1594 //!     AM_HAL_CTIMER_INT_TIMERA1C0
1595 //!     AM_HAL_CTIMER_INT_TIMERA1C1
1596 //!     AM_HAL_CTIMER_INT_TIMERB1C0
1597 //!     AM_HAL_CTIMER_INT_TIMERB1C1
1598 //!     AM_HAL_CTIMER_INT_TIMERA2C0
1599 //!     AM_HAL_CTIMER_INT_TIMERA2C1
1600 //!     AM_HAL_CTIMER_INT_TIMERB2C0
1601 //!     AM_HAL_CTIMER_INT_TIMERB2C1
1602 //!     AM_HAL_CTIMER_INT_TIMERA3C0
1603 //!     AM_HAL_CTIMER_INT_TIMERA3C1
1604 //!     AM_HAL_CTIMER_INT_TIMERB3C0
1605 //!     AM_HAL_CTIMER_INT_TIMERB3C1
1606 //!
1607 //! @return None.
1608 //
1609 //*****************************************************************************
1610 void
am_hal_ctimer_int_set(uint32_t ui32Interrupt)1611 am_hal_ctimer_int_set(uint32_t ui32Interrupt)
1612 {
1613     //
1614     // Set the interrupts.
1615     //
1616     AM_REGn(CTIMER, 0, INTSET) = ui32Interrupt;
1617 } // am_hal_ctimer_int_set()
1618 
1619 //*****************************************************************************
1620 //
1621 //! @brief Returns either the enabled or raw timer interrupt status.
1622 //!
1623 //! This function will return the timer interrupt status.
1624 //!
1625 //! @return bEnabledOnly if true returns the status of the enabled interrupts
1626 //! only.
1627 //!
1628 //! The return value will be the logical OR of one or more of the following
1629 //! values:
1630 //!
1631 //!     AM_HAL_CTIMER_INT_TIMERA0C0
1632 //!     AM_HAL_CTIMER_INT_TIMERA0C1
1633 //!     AM_HAL_CTIMER_INT_TIMERB0C0
1634 //!     AM_HAL_CTIMER_INT_TIMERB0C1
1635 //!     AM_HAL_CTIMER_INT_TIMERA1C0
1636 //!     AM_HAL_CTIMER_INT_TIMERA1C1
1637 //!     AM_HAL_CTIMER_INT_TIMERB1C0
1638 //!     AM_HAL_CTIMER_INT_TIMERB1C1
1639 //!     AM_HAL_CTIMER_INT_TIMERA2C0
1640 //!     AM_HAL_CTIMER_INT_TIMERA2C1
1641 //!     AM_HAL_CTIMER_INT_TIMERB2C0
1642 //!     AM_HAL_CTIMER_INT_TIMERB2C1
1643 //!     AM_HAL_CTIMER_INT_TIMERA3C0
1644 //!     AM_HAL_CTIMER_INT_TIMERA3C1
1645 //!     AM_HAL_CTIMER_INT_TIMERB3C0
1646 //!     AM_HAL_CTIMER_INT_TIMERB3C1
1647 //!
1648 //! @return Returns either the timer interrupt status.
1649 //
1650 //*****************************************************************************
1651 uint32_t
am_hal_ctimer_int_status_get(bool bEnabledOnly)1652 am_hal_ctimer_int_status_get(bool bEnabledOnly)
1653 {
1654     //
1655     // Return the desired status.
1656     //
1657 
1658     if ( bEnabledOnly )
1659     {
1660         uint32_t u32RetVal;
1661 
1662         //
1663         // Begin critical section.
1664         //
1665         AM_CRITICAL_BEGIN_ASM
1666 
1667         u32RetVal  = AM_REGn(CTIMER, 0, INTSTAT);
1668         u32RetVal &= AM_REGn(CTIMER, 0, INTEN);
1669 
1670         //
1671         // Done with critical section.
1672         //
1673         AM_CRITICAL_END_ASM
1674 
1675         return u32RetVal;
1676     }
1677     else
1678     {
1679         return AM_REGn(CTIMER, 0, INTSTAT);
1680     }
1681 } // am_hal_ctimer_int_status_get()
1682 
1683 //*****************************************************************************
1684 //
1685 // End Doxygen group.
1686 //! @}
1687 //
1688 //*****************************************************************************
1689