12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688 |
- //*****************************************************************************
- //
- // am_hal_ctimer.c
- //! @file
- //!
- //! @brief Functions for interfacing with the Counter/Timer module.
- //!
- //! @addtogroup ctimer2 Counter/Timer (CTIMER)
- //! @ingroup apollo2hal
- //! @{
- //
- //*****************************************************************************
- //*****************************************************************************
- //
- // Copyright (c) 2017, Ambiq Micro
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are met:
- //
- // 1. Redistributions of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- //
- // 2. Redistributions in binary form must reproduce the above copyright
- // notice, this list of conditions and the following disclaimer in the
- // documentation and/or other materials provided with the distribution.
- //
- // 3. Neither the name of the copyright holder nor the names of its
- // contributors may be used to endorse or promote products derived from this
- // software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- // POSSIBILITY OF SUCH DAMAGE.
- //
- // This is part of revision 1.2.11 of the AmbiqSuite Development Package.
- //
- //*****************************************************************************
- #include <stdint.h>
- #include <stdbool.h>
- #include "am_mcu_apollo.h"
- //*****************************************************************************
- //
- // Address space distance between timer configuration registers.
- //
- //*****************************************************************************
- #define MAX_CTIMERS 4
- #define TIMER_OFFSET (AM_REG_CTIMER_TMR1_O - AM_REG_CTIMER_TMR0_O)
- #define CTIMER_CMPR_OFFSET (AM_REG_CTIMER_CMPRB0_O - AM_REG_CTIMER_CMPRA0_O)
- //*****************************************************************************
- //
- // Adjacency check
- //
- // This is related to the timer read workaround. This macro checks to see if
- // the two supplied count values are within one "tick" of eachother. It should
- // still pass in the event of a timer rollover.
- //
- //*****************************************************************************
- //! Timer read workaround: Do count values differ by one tick or less.
- #define adjacent(A, B) (((A) == (B)) || (((A) + 1) == (B)) || ((B) == 0))
- //*****************************************************************************
- //
- //! Array of function pointers for handling CTimer interrupts.
- //
- //*****************************************************************************
- am_hal_ctimer_handler_t am_hal_ctimer_ppfnHandlers[16];
- //*****************************************************************************
- //
- // Static function for reading the timer value.
- //
- //*****************************************************************************
- #if defined(__GNUC_STDC_INLINE__)
- __attribute__((naked))
- static
- void
- back2back_reads(uint32_t u32TimerAddr, uint32_t u32Data[])
- {
- // u32TimerAddr = address of the timer to be read.
- // u32Data[] is a pointer to a 3 word data array provided by the caller.
- __asm
- (
- // Do 3 back-to-back reads of the register
- " push {r4}\n" // Save r4
- " push {r1}\n" // Save the data array ptr for later
- " mov r2, r0\n" // Get Timer Addr
- " mrs r4, PRIMASK\n" // Save PRIMASK
- " cpsid i\n" // __disable_irq()
- " nop\n" // Give the disable a cycle to take affect (but almost certainly not really needed)
- " ldr r0, [r2, #0]\n" // Get TMRn register value
- " ldr r1, [r2, #0]\n" // Get TMRn register value again
- " ldr r3, [r2, #0]\n" // Get TMRn register value for a third time
- " msr PRIMASK, r4\n" // Restore PRIMASK
- " pop {r2}\n" // Get the array ptr
- " str r0, [r2, #0]\n" // Store register value to variable
- " str r1, [r2, #4]\n" // Store register value to variable
- " str r3, [r2, #8]\n" // Store register value to variable
- " pop {r4}\n" // restore r4
- " bx lr\n"
- );
- }
- #elif defined(__ARMCC_VERSION)
- __asm static uint32_t
- back2back_reads( uint32_t u32TimerAddr, uint32_t u32Data[])
- {
- push {r4} // Save r4
- push {r1} // Save the data array ptr for later
- mov r2, r0 // Get Timer Addr
- mrs r4, PRIMASK // Save PRIMASK
- cpsid i // __disable_irq()
- nop // Give the disable a cycle to take affect (but almost certainly not really needed)
- ldr r0, [r2, #0] // Get TMRn register value
- ldr r1, [r2, #0] // Get TMRn register value again
- ldr r3, [r2, #0] // Get TMRn register value for a third time
- msr PRIMASK, r4 // Restore PRIMASK
- pop {r2} // Get the array ptr
- str r0, [r2, #0] // Store register value to variable
- str r1, [r2, #4] // Store register value to variable
- str r3, [r2, #8] // Store register value to variable
- pop {r4} // Restore r4
- bx lr
- }
- #elif defined(__IAR_SYSTEMS_ICC__)
- #pragma diag_suppress = Pe940 // Suppress IAR compiler warning about missing
- // return statement on a non-void function
- __stackless static uint32_t
- back2back_reads( uint32_t u32TimerAddr, uint32_t u32Data[])
- {
- __asm(" push {r4}"); // Save r4
- __asm(" push {r1}"); // Save the data array ptr for later
- __asm(" mov r2, r0"); // Get Timer Addr
- __asm(" mrs r4, PRIMASK"); // Save PRIMASK"
- __asm(" cpsid i"); // __disable_irq()
- __asm(" nop"); // Give the disable a cycle to take affect (but almost certainly not really needed)
- __asm(" ldr r0, [r2, #0]"); // Get TMRn register value
- __asm(" ldr r1, [r2, #0]"); // Get TMRn register value again
- __asm(" ldr r3, [r2, #0]"); // Get TMRn register value for a third time
- __asm(" msr PRIMASK, r4"); // Restore PRIMASK
- __asm(" pop {r2}"); // Get the array ptr
- __asm(" str r0, [r2, #0]"); // Store register value to variable
- __asm(" str r1, [r2, #4]"); // Store register value to variable
- __asm(" str r3, [r2, #8]"); // Store register value to variable
- __asm(" pop {r4}"); // Restore r4
- __asm(" bx lr");
- }
- #pragma diag_default = Pe940 // Restore IAR compiler warning
- #endif
- //*****************************************************************************
- //
- //! @brief Check to see if the given CTimer is using the HFRC
- //!
- //! @note Calls to this function should be from inside a critical section.
- //!
- //! @return None.
- //
- //*****************************************************************************
- static bool
- ctimer_source_hfrc(uint32_t ui32CtimerNum)
- {
- uint32_t *pui32ConfigReg;
- uint32_t ui32TimerASrc, ui32TimerBSrc;
- //
- // Find the correct register to write.
- //
- pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
- (ui32CtimerNum * TIMER_OFFSET));
- //
- // Determine if this timer is using HFRC as the clock source.
- // The value we are looking for is HFRC_DIV4 to HFRC_DIV4K.
- // Get the clock sources and 0-base the extracted value.
- //
- ui32TimerASrc = AM_BFX(CTIMER, CTRL0, TMRA0CLK, *pui32ConfigReg) -
- AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4);
- ui32TimerBSrc = AM_BFX(CTIMER, CTRL0, TMRB0CLK, *pui32ConfigReg) -
- AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4);
- //
- // If the source value is 0 to (HFRC_DIV4K - HFRC_DIV4), then it's HFRC.
- //
- if ( (ui32TimerASrc <= (AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4K) -
- AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4))) ||
- (ui32TimerBSrc <= (AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4K) -
- AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4))) )
- {
- return true;
- }
- else
- {
- return false;
- }
- } // ctimer_source_hfrc()
- //*****************************************************************************
- //
- // @brief Check to see if any of the CTimers or STimer are using the HFRC.
- //
- // This function should be used to check if the HFRC is being used in order
- // to correctly establish power related settings.
- //
- // Note - Calls to this function should be from inside a critical section.
- //
- //! @return None.
- //
- //*****************************************************************************
- static bool
- timers_use_hfrc(void)
- {
- uint32_t ui32TimerASrc, ui32CtimerNum;
- //
- // Check STimer to see if it is using HFRC.
- //
- ui32TimerASrc = AM_BFR(CTIMER, STCFG, CLKSEL);
- if ( (ui32TimerASrc == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV16) ||
- (ui32TimerASrc == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV256) )
- {
- return true;
- }
- //
- // Check the CTimers to see if any are using HFRC as their clock source.
- //
- for ( ui32CtimerNum = 0; ui32CtimerNum < MAX_CTIMERS; ui32CtimerNum++ )
- {
- if ( ctimer_source_hfrc(ui32CtimerNum) )
- {
- return true;
- }
- }
- return false;
- } // timers_use_hfrc()
- //*****************************************************************************
- //
- //! @brief Convenience function for responding to CTimer interrupts.
- //!
- //! @param ui32Status is the interrupt status as returned by
- //! am_hal_ctimer_int_status_get()
- //!
- //! This function may be called from am_ctimer_isr() to read the status of
- //! the CTimer interrupts, determine which source caused the most recent
- //! interrupt, and call an interrupt handler function to respond. The interrupt
- //! handler to be called must be first registered with the
- //! am_hal_ctimer_int_register() function.
- //!
- //! In the event that multiple sources are active, the corresponding
- //! interrupt handlers will be called in numerical order based on interrupt def.
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_int_service(uint32_t ui32Status)
- {
- uint32_t ui32Clz;
- am_hal_ctimer_handler_t pfnHandler;
- ui32Status &= 0xFFFF;
- while ( ui32Status )
- {
- //
- // Pick one of any remaining active interrupt bits
- //
- #ifdef __IAR_SYSTEMS_ICC__
- ui32Clz = __CLZ(ui32Status);
- #else
- ui32Clz = __builtin_clz(ui32Status);
- #endif
- //
- // Turn off the bit we picked in the working copy
- //
- ui32Status &= ~(0x80000000 >> ui32Clz);
- //
- // Check the bit handler table to see if there is an interrupt handler
- // registered for this particular bit.
- //
- pfnHandler = am_hal_ctimer_ppfnHandlers[31 - ui32Clz];
- if ( pfnHandler )
- {
- //
- // If we found an interrupt handler routine, call it now.
- //
- pfnHandler();
- }
- }
- } // am_hal_ctimer_int_service()
- //*****************************************************************************
- //
- //! @brief Register an interrupt handler for CTimer.
- //!
- //! @param ui32Interrupt - interrupt number to assign this interrupt handler to.
- //! @param pfnHandler - Function to call when this interrupt is received.
- //!
- //! This function allows the caller to specify a function that should be called
- //! any time a Ctimer interrupt is received. Registering an
- //! interrupt handler using this function adds the function pointer to an array
- //! in SRAM. This interrupt handler will be called by am_hal_ctimer_int_service()
- //! whenever the ui32Status parameter indicates that the corresponding interrupt.
- //!
- //! To remove an interrupt handler that has already been registered, the
- //! pfnHandler parameter may be set to zero.
- //!
- //! @note This function will not have any effect unless the
- //! am_hal_ctimer_int_service() function is being used.
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_int_register(uint32_t ui32Interrupt,
- am_hal_ctimer_handler_t pfnHandler)
- {
- uint32_t intIdx = 0;
- //
- // Check to make sure the interrupt number is valid. (Debug builds only)
- //
- switch (ui32Interrupt)
- {
- case AM_REG_CTIMER_INTEN_CTMRA0C0INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRA0C0INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRB0C0INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRB0C0INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRA1C0INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRA1C0INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRB1C0INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRB1C0INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRA2C0INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRA2C0INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRB2C0INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRB2C0INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRA3C0INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRA3C0INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRB3C0INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRB3C0INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRA0C1INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRA0C1INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRB0C1INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRB0C1INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRA1C1INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRA1C1INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRB1C1INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRB1C1INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRA2C1INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRA2C1INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRB2C1INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRB2C1INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRA3C1INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRA3C1INT_S;
- break;
- case AM_REG_CTIMER_INTEN_CTMRB3C1INT_M:
- intIdx = AM_REG_CTIMER_INTEN_CTMRB3C1INT_S;
- break;
- default:
- am_hal_debug_assert_msg(false, "CTimer interrupt number out of range.");
- }
- am_hal_ctimer_ppfnHandlers[intIdx] = pfnHandler;
- } // am_hal_ctimer_int_register()
- //*****************************************************************************
- //
- //! @brief Set up the counter/timer.
- //!
- //! @param ui32TimerNumber is the number of the Timer that should be
- //! configured.
- //!
- //! @param psConfig is a pointer to a structure that holds important settings
- //! for the timer.
- //!
- //! This function should be used to perform the initial set-up of the
- //! counter-timer.
- //!
- //! @note This function will eventually be replaced by
- //! am_hal_ctimer_config_single(), which performs the same configuration
- //! without requiring a structure. Please use am_hal_ctimer_config_single() for
- //! new development.
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_config(uint32_t ui32TimerNumber,
- am_hal_ctimer_config_t *psConfig)
- {
- uint32_t *pui32ConfigReg;
- uint32_t ui32ConfigVal;
- //
- // Start preparing the configuration word for this timer. The configuration
- // values for Timer A and Timer B provided in the config structure should
- // match the register definitions already, so we will mostly just need to
- // OR them together.
- //
- ui32ConfigVal = ( (psConfig->ui32TimerAConfig) |
- (psConfig->ui32TimerBConfig << 16) );
- //
- // OR in the Link bit if the timers need to be linked.
- //
- ui32ConfigVal |= psConfig->ui32Link ? AM_HAL_CTIMER_LINK : 0;
- //
- // Begin critical section while config registers are read and modified.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Find the correct register to write.
- //
- pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- //
- // Write our configuration value.
- //
- AM_REGVAL(pui32ConfigReg) = ui32ConfigVal;
- //
- // If all of the clock sources are not HRFC disable LDO when sleeping if timers are enabled.
- //
- if ( timers_use_hfrc() )
- {
- AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 0);
- }
- else
- {
- AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 1);
- }
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_config()
- //*****************************************************************************
- //
- //! @brief Set up the counter/timer.
- //!
- //! @param ui32TimerNumber is the number of the Timer that should be
- //! configured.
- //!
- //! @param ui32TimerSegment specifies which segment of the timer should be
- //! enabled.
- //!
- //! @param ui32ConfigVal specifies the configuration options for the selected
- //! timer.
- //!
- //! This function should be used to perform the initial set-up of the
- //! counter-timer. It can be used to configure either a 16-bit timer (A or B) or a
- //! 32-bit timer using the BOTH option.
- //!
- //! Valid values for ui32TimerSegment are:
- //!
- //! AM_HAL_CTIMER_TIMERA
- //! AM_HAL_CTIMER_TIMERB
- //! AM_HAL_CTIMER_BOTH
- //!
- //! The timer's clock source, mode, interrupt, and external pin behavior are
- //! all controlled through the \e ui32Configval parameter. The valid options
- //! for ui32ConfigVal include any ORed together combination of the following:
- //!
- //! Clock configuration macros:
- //!
- //! AM_HAL_CTIMER_HFRC_24MHZ
- //! AM_HAL_CTIMER_LFRC_512HZ
- //! ... etc. (See am_hal_ctimer.h for the full set of options.)
- //!
- //! Mode selection macros:
- //!
- //! AM_HAL_CTIMER_FN_ONCE
- //! AM_HAL_CTIMER_FN_REPEAT
- //! AM_HAL_CTIMER_FN_PWM_ONCE
- //! AM_HAL_CTIMER_FN_PWM_REPEAT
- //! AM_HAL_CTIMER_FN_CONTINUOUS
- //!
- //! Interrupt control:
- //!
- //! AM_HAL_CTIMER_INT_ENABLE
- //!
- //! Pin control:
- //!
- //! AM_HAL_CTIMER_PIN_ENABLE
- //! AM_HAL_CTIMER_PIN_INVERT
- //!
- //! ADC trigger (Timer 3 only):
- //!
- //! AM_HAL_CTIMER_ADC_TRIG
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_config_single(uint32_t ui32TimerNumber,
- uint32_t ui32TimerSegment,
- uint32_t ui32ConfigVal)
- {
- volatile uint32_t *pui32ConfigReg;
- uint32_t ui32WriteVal;
- //
- // Find the correct register to write based on the timer number.
- //
- pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- //
- // Begin critical section while config registers are read and modified.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Save the value that's already in the register.
- //
- ui32WriteVal = AM_REGVAL(pui32ConfigReg);
- //
- // If we're working with TIMERB, we need to shift our configuration value
- // up by 16 bits.
- //
- if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
- {
- ui32ConfigVal = ((ui32ConfigVal & 0xFFFF) << 16);
- }
- //
- // Replace part of the saved register value with the configuration value
- // from the caller.
- //
- ui32WriteVal = (ui32WriteVal & ~(ui32TimerSegment)) | ui32ConfigVal;
- //
- // If we're configuring both timers, we need to set the "link" bit.
- //
- if ( ui32TimerSegment == AM_HAL_CTIMER_BOTH )
- {
- ui32WriteVal |= AM_HAL_CTIMER_LINK;
- }
- //
- // Write our completed configuration value.
- //
- AM_REGVAL(pui32ConfigReg) = ui32WriteVal;
- //
- // If all of the clock sources are not HRFC disable LDO when sleeping if timers are enabled.
- //
- if ( timers_use_hfrc() )
- {
- AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 0);
- }
- else
- {
- AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 1);
- }
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_config_single()
- //*****************************************************************************
- //
- //! @brief Start a timer
- //!
- //! @param ui32TimerNumber is the number of the timer to enable
- //!
- //! @param ui32TimerSegment specifies which segment of the timer should be
- //! enabled. Valid values for ui32TimerSegment are:
- //! AM_HAL_CTIMER_TIMERA
- //! AM_HAL_CTIMER_TIMERB
- //! AM_HAL_CTIMER_BOTH
- //!
- //! This function will enable a timer to begin incrementing. The \e
- //! ui32TimerNumber parameter selects the timer that should be enabled, for
- //! example, a 0 would target TIMER0. The \e ui32TimerSegment parameter allows
- //! the caller to individually select a segment within a timer to be enabled,
- //! such as TIMER0A, TIMER0B, or both.
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_start(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
- {
- volatile uint32_t *pui32ConfigReg;
- uint32_t ui32ConfigVal;
- //
- // Find the correct control register.
- //
- pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- //
- // Begin critical section while config registers are read and modified.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Read the current value.
- //
- ui32ConfigVal = *pui32ConfigReg;
- //
- // Clear out the "clear" bit.
- //
- ui32ConfigVal &= ~(ui32TimerSegment & (AM_REG_CTIMER_CTRL0_TMRA0CLR_M |
- AM_REG_CTIMER_CTRL0_TMRB0CLR_M));
- //
- // Set the "enable bit"
- //
- ui32ConfigVal |= (ui32TimerSegment & (AM_REG_CTIMER_CTRL0_TMRA0EN_M |
- AM_REG_CTIMER_CTRL0_TMRB0EN_M));
- //
- // Write the value back to the register.
- //
- AM_REGVAL(pui32ConfigReg) = ui32ConfigVal;
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_start()
- //*****************************************************************************
- //
- //! @brief Stop a timer
- //!
- //! @param ui32TimerNumber is the number of the timer to disable.
- //!
- //! @param ui32TimerSegment specifies which segment of the timer should be
- //! disabled.
- //!
- //! This function will stop the selected timer from incrementing. The \e
- //! ui32TimerNumber parameter selects the timer that should be disabled, for
- //! example, a 0 would target TIMER0. The \e ui32TimerSegment parameter allows
- //! the caller to individually select a segment within a timer to be disabled,
- //! such as TIMER0A, TIMER0B, or both.
- //!
- //! This function will stop a counter/timer from counting, but does not return
- //! the count value to 'zero'. If you would like to reset the counter back to
- //! zero, try the am_hal_ctimer_clear() function instead.
- //!
- //! Valid values for ui32TimerSegment are:
- //!
- //! AM_HAL_CTIMER_TIMERA
- //! AM_HAL_CTIMER_TIMERB
- //! AM_HAL_CTIMER_BOTH
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_stop(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
- {
- volatile uint32_t *pui32ConfigReg;
- //
- // Find the correct control register.
- //
- pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Clear the "enable" bit
- //
- AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment &
- (AM_REG_CTIMER_CTRL0_TMRA0EN_M |
- AM_REG_CTIMER_CTRL0_TMRB0EN_M));
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_stop()
- //*****************************************************************************
- //
- //! @brief Stops a timer and resets its value back to zero.
- //!
- //! @param ui32TimerNumber is the number of the timer to clear.
- //!
- //! @param ui32TimerSegment specifies which segment of the timer should be
- //! cleared.
- //!
- //! This function will stop a free-running counter-timer, reset its value to
- //! zero, and leave the timer disabled. When you would like to restart the
- //! counter, you will need to call am_hal_ctimer_start().
- //!
- //! The \e ui32TimerSegment parameter allows the caller to individually select
- //! a segment within, such as TIMER0A, TIMER0B, or both.
- //!
- //! Valid values for ui32TimerSegment are:
- //!
- //! AM_HAL_CTIMER_TIMERA
- //! AM_HAL_CTIMER_TIMERB
- //! AM_HAL_CTIMER_BOTH
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_clear(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
- {
- volatile uint32_t *pui32ConfigReg;
- //
- // Find the correct control register.
- //
- pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Set the "clear" bit
- //
- AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment &
- (AM_REG_CTIMER_CTRL0_TMRA0CLR_M |
- AM_REG_CTIMER_CTRL0_TMRB0CLR_M));
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_clear()
- //*****************************************************************************
- //
- //! @brief Returns the current free-running value of the selected timer.
- //!
- //! @param ui32TimerNumber is the number of the timer to read.
- //! @param ui32TimerSegment specifies which segment of the timer should be
- //! read.
- //!
- //! This function returns the current free-running value of the selected timer.
- //!
- //! @note When reading from a linked timer, be sure to use AM_HAL_CTIMER both
- //! for the segment argument.
- //!
- //! Valid values for ui32TimerSegment are:
- //!
- //! AM_HAL_CTIMER_TIMERA
- //! AM_HAL_CTIMER_TIMERB
- //! AM_HAL_CTIMER_BOTH
- //!
- //! @return Current timer value.
- //
- //*****************************************************************************
- uint32_t
- am_hal_ctimer_read(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
- {
- volatile uint32_t ui32Value = 0;
- uint32_t ui32Values[4] = {0, };
- uint32_t ui32TimerAddrTbl[4] =
- {
- REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR0_O,
- REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR1_O,
- REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR2_O,
- REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR3_O
- };
- //
- // Read the timer with back2back reads. This is a workaround for a clock
- // domain synchronization issue. Some timer bits may be slow to increment,
- // which means that the value in the timer register will sometimes be
- // wrong.
- //
- // The architecture guarantees that:
- //
- // 1) If the timer is running at a speed close to the core frequency, the
- // core and timer clock domains will be synchronized, and no "bad" reads
- // will happen.
- //
- // 2) Bad reads will only happen if the core reads the timer register while
- // the timer value is transitioning from one count to the next.
- //
- // 3) The timer will resolve to the correct value within one 24 MHz clock
- // cycle.
- //
- // If we read the timer three times in a row with back-to-back load
- // instructions, then we can guarantee that the timer will only have time
- // to increment once, and that only one of the three reads can be wrong.
- // This routine will perform the back-to-back reads and return all three
- // values. The rest of this fuction determines which value we should
- // actually use.
- //
- back2back_reads(ui32TimerAddrTbl[ui32TimerNumber], ui32Values);
- //
- // Shift or mask the values based on the given timer segment.
- //
- if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
- {
- ui32Values[0] >>= 16;
- ui32Values[1] >>= 16;
- ui32Values[2] >>= 16;
- }
- else if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERA )
- {
- ui32Values[0] &= 0xFFFF;
- ui32Values[1] &= 0xFFFF;
- ui32Values[2] &= 0xFFFF;
- }
- //
- // Now, we'll figure out which of the three values is the correct time.
- //
- if (ui32Values[0] == ui32Values[1])
- {
- //
- // If the first two values match, then neither one was a bad read.
- // We'll take this as the current time.
- //
- ui32Value = ui32Values[1];
- }
- else
- {
- //
- // If the first two values didn't match, then one of them might be bad.
- // If one of the first two values is bad, then the third one should
- // always be correct. We'll take the third value as the correct time.
- //
- ui32Value = ui32Values[2];
- //
- // If all of the statements about the architecture are true, the third
- // value should be correct, and it should always be within one count of
- // either the first or the second value.
- //
- // Just in case, we'll check against the previous two values to make
- // sure that our final answer was reasonable. If it isn't, we will
- // flag it as a "bad read", and fail this assert statement.
- //
- // This shouldn't ever happen, and it hasn't ever happened in any of
- // our tests so far.
- //
- am_hal_debug_assert_msg((adjacent(ui32Values[1], ui32Values[2]) ||
- adjacent(ui32Values[0], ui32Values[2])),
- "Bad CTIMER read");
- }
- return ui32Value;
- } // am_hal_ctimer_read()
- //*****************************************************************************
- //
- //! @brief Enable output to the timer pin
- //!
- //! @param ui32TimerNumber is the number of the timer to configure.
- //!
- //! @param ui32TimerSegment specifies which segment of the timer to use.
- //!
- //! This function will enable the output pin for the selected timer. The \e
- //! ui32TimerSegment parameter allows the caller to individually select a
- //! segment within, such as TIMER0A, TIMER0B, or both.
- //!
- //! Valid values for ui32TimerSegment are:
- //!
- //! AM_HAL_CTIMER_TIMERA
- //! AM_HAL_CTIMER_TIMERB
- //! AM_HAL_CTIMER_BOTH
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_pin_enable(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
- {
- volatile uint32_t *pui32ConfigReg;
- //
- // Find the correct control register.
- //
- pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Set the pin enable bit
- //
- AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment &
- (AM_REG_CTIMER_CTRL0_TMRA0PE_M |
- AM_REG_CTIMER_CTRL0_TMRB0PE_M));
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_pin_enable()
- //*****************************************************************************
- //
- //! @brief Disable the output pin.
- //!
- //! @param ui32TimerNumber is the number of the timer to configure.
- //!
- //! @param ui32TimerSegment specifies which segment of the timer to use.
- //!
- //! This function will disable the output pin for the selected timer. The \e
- //! ui32TimerSegment parameter allows the caller to individually select a
- //! segment within, such as TIMER0A, TIMER0B, or both.
- //!
- //! Valid values for ui32TimerSegment are:
- //!
- //! AM_HAL_CTIMER_TIMERA
- //! AM_HAL_CTIMER_TIMERB
- //! AM_HAL_CTIMER_BOTH
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_pin_disable(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment)
- {
- volatile uint32_t *pui32ConfigReg;
- //
- // Find the correct control register.
- //
- pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Clear the pin enable bit
- //
- AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment &
- (AM_REG_CTIMER_CTRL0_TMRA0PE_M |
- AM_REG_CTIMER_CTRL0_TMRB0PE_M));
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_pin_disable()
- //*****************************************************************************
- //
- //! @brief Set the polarity of the output pin.
- //!
- //! @param ui32TimerNumber is the number of the timer to configure.
- //!
- //! @param ui32TimerSegment specifies which segment of the timer to use.
- //!
- //! @param bInvertOutput determines whether the output should be inverted. If
- //! true, the timer output pin for the selected timer segment will be
- //! inverted.
- //!
- //! This function will set the polarity of the the output pin for the selected
- //! timer. The \e ui32TimerSegment parameter allows the caller to individually
- //! select a segment within, such as TIMER0A, TIMER0B, or both.
- //!
- //! Valid values for ui32TimerSegment are:
- //!
- //! AM_HAL_CTIMER_TIMERA
- //! AM_HAL_CTIMER_TIMERB
- //! AM_HAL_CTIMER_BOTH
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_pin_invert(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment,
- bool bInvertOutput)
- {
- volatile uint32_t *pui32ConfigReg;
- //
- // Find the correct control register.
- //
- pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Figure out if we're supposed to be setting or clearing the polarity bit.
- //
- if ( bInvertOutput )
- {
- //
- // Set the polarity bit to invert the output.
- //
- AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment &
- (AM_REG_CTIMER_CTRL0_TMRA0POL_M |
- AM_REG_CTIMER_CTRL0_TMRB0POL_M));
- }
- else
- {
- //
- // Clear the polarity bit.
- //
- AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment &
- (AM_REG_CTIMER_CTRL0_TMRA0POL_M |
- AM_REG_CTIMER_CTRL0_TMRB0POL_M));
- }
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_pin_invert()
- //*****************************************************************************
- //
- //! @brief Set a compare register.
- //!
- //! @param ui32TimerNumber is the number of the timer to configure.
- //!
- //! @param ui32TimerSegment specifies which segment of the timer to use.
- //! Valid values for ui32TimerSegment are:
- //!
- //! AM_HAL_CTIMER_TIMERA
- //! AM_HAL_CTIMER_TIMERB
- //! AM_HAL_CTIMER_BOTH
- //!
- //! @param ui32CompareReg specifies which compare register should be set
- //! (either 0 or 1)
- //!
- //! @param ui32Value is the value that should be written to the compare
- //! register.
- //!
- //! This function allows the caller to set the values in the compare registers
- //! for a timer. These registers control the period and duty cycle of the
- //! timers and their associated output pins. Please see the datasheet for
- //! further information on the operation of the compare registers. The \e
- //! ui32TimerSegment parameter allows the caller to individually select a
- //! segment within, such as TIMER0A, TIMER0B, or both.
- //!
- //! @note For simple manipulations of period or duty cycle for timers and PWMs,
- //! you may find it easier to use the am_hal_ctimer_period_set() function.
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_compare_set(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment,
- uint32_t ui32CompareReg, uint32_t ui32Value)
- {
- volatile uint32_t *pui32CmprRegA, *pui32CmprRegB;
- uint32_t ui32CmprRegA, ui32CmprRegB;
- //
- // Find the correct compare register to write.
- // Assume A or BOTH. We'll change later if B.
- //
- pui32CmprRegA = (uint32_t *)(AM_REG_CTIMERn(0) +
- AM_REG_CTIMER_CMPRA0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- pui32CmprRegB = pui32CmprRegA + CTIMER_CMPR_OFFSET / 4;
- //
- // Write the compare register with the selected value.
- // Begin critical section while CMPR registers are modified.
- //
- AM_CRITICAL_BEGIN_ASM
- ui32CmprRegA = *pui32CmprRegA;
- ui32CmprRegB = *pui32CmprRegB;
- if ( ui32CompareReg == 1 )
- {
- //
- // CMPR reg 1
- // Get the lower 16b (but may not be used if TIMERB).
- //
- ui32CmprRegA = ( (ui32CmprRegA & AM_REG_CTIMER_CMPRA0_CMPR0A0_M) |
- AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Value & 0xFFFF) );
- //
- // Get the upper 16b (but may not be used if TIMERA)
- //
- ui32CmprRegB = ( (ui32CmprRegB & AM_REG_CTIMER_CMPRA0_CMPR0A0_M) |
- AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Value >> 16) );
- }
- else
- {
- //
- // CMPR reg 0
- // Get the lower 16b (but may not be used if TIMERB)
- //
- ui32CmprRegA = ( (ui32CmprRegA & AM_REG_CTIMER_CMPRA0_CMPR1A0_M) |
- AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Value & 0xFFFF) );
- //
- // Set the upper 16b (but may not be used if TIMERA)
- //
- ui32CmprRegB = ( (ui32CmprRegB & AM_REG_CTIMER_CMPRA0_CMPR1A0_M) |
- AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Value >> 16) );
- }
- if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
- {
- *pui32CmprRegB = ui32CmprRegB;
- }
- else
- {
- //
- // It's TIMERA or BOTH.
- //
- *pui32CmprRegA = ui32CmprRegA;
- if ( ui32TimerSegment == AM_HAL_CTIMER_BOTH )
- {
- *pui32CmprRegB = ui32CmprRegB;
- }
- }
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_compare_set()
- //*****************************************************************************
- //
- //! @brief Set the period and duty cycle of a timer.
- //!
- //! @param ui32TimerNumber is the number of the timer to configure.
- //!
- //! @param ui32TimerSegment specifies which segment of the timer to use.
- //!
- //! @param ui32Period specifies the desired period. This parameter effectively
- //! specifies the CTIMER CMPR field(s). The CMPR fields are handled in hardware
- //! as (n+1) values, therefore ui32Period is actually specified as 1 less than
- //! the desired period. Finally, as mentioned in the data sheet, the CMPR fields
- //! cannot be 0 (a value of 1), so neither can ui32Period be 0.
- //!
- //! @param ui32OnTime set the number of clocks where the output signal is high.
- //!
- //! This function should be used for simple manipulations of the period and
- //! duty cycle of a counter/timer. To set the period and/or duty cycle of a
- //! linked timer pair, use AM_HAL_CTIMER_BOTH as the timer segment argument. If
- //! you would like to set the period and/or duty cycle for both TIMERA and
- //! TIMERB you will need to call this function twice: once for TIMERA, and once
- //! for TIMERB.
- //!
- //! Valid values for ui32TimerSegment are:
- //!
- //! AM_HAL_CTIMER_TIMERA
- //! AM_HAL_CTIMER_TIMERB
- //! AM_HAL_CTIMER_BOTH
- //!
- //! @note The ui32OnTime parameter will only work if the timer is currently
- //! operating in one of the PWM modes.
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_period_set(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment,
- uint32_t ui32Period, uint32_t ui32OnTime)
- {
- volatile uint32_t *pui32ControlReg;
- volatile uint32_t *pui32CompareRegA;
- volatile uint32_t *pui32CompareRegB;
- uint32_t ui32Mode, ui32Comp0, ui32Comp1;
- //
- // Find the correct control register to pull the function select field
- // from.
- //
- pui32ControlReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- //
- // Find the correct compare registers to write.
- //
- pui32CompareRegA = (uint32_t *)(AM_REG_CTIMERn(0) +
- AM_REG_CTIMER_CMPRA0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- pui32CompareRegB = (uint32_t *)(AM_REG_CTIMERn(0) +
- AM_REG_CTIMER_CMPRB0_O +
- (ui32TimerNumber * TIMER_OFFSET));
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Extract the timer mode from the register based on the ui32TimerSegment
- // selected by the user.
- //
- ui32Mode = *pui32ControlReg;
- if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
- {
- ui32Mode = ui32Mode >> 16;
- }
- //
- // Mask to get to the bits we're interested in.
- //
- ui32Mode = ui32Mode & AM_REG_CTIMER_CTRL0_TMRA0FN_M;
- //
- // If the mode is a PWM mode, we'll need to calculate the correct CMPR0 and
- // CMPR1 values here.
- //
- if (ui32Mode == AM_HAL_CTIMER_FN_PWM_ONCE ||
- ui32Mode == AM_HAL_CTIMER_FN_PWM_REPEAT)
- {
- ui32Comp0 = ui32Period - ui32OnTime;
- ui32Comp1 = ui32Period;
- }
- else
- {
- ui32Comp0 = ui32Period;
- ui32Comp1 = 0;
- }
- //
- // Based on the timer segment argument, write the calculated Compare 0 and
- // Compare 1 values to the correct halves of the correct registers.
- //
- if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERA )
- {
- //
- // For timer A, write the values to the TIMERA compare register.
- //
- *pui32CompareRegA = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) |
- AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1));
- }
- else if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB )
- {
- //
- // For timer B, write the values to the TIMERA compare register.
- //
- *pui32CompareRegB = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) |
- AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1));
- }
- else
- {
- //
- // For the linked case, write the lower halves of the values to the
- // TIMERA compare register, and the upper halves to the TIMERB compare
- // register.
- //
- *pui32CompareRegA = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) |
- AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1));
- *pui32CompareRegB = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0 >> 16) |
- AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1 >> 16));
- }
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_period_set()
- //*****************************************************************************
- //
- //! @brief Enable the TIMERA3 ADC trigger
- //!
- //! This function enables the ADC trigger within TIMERA3.
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_adc_trigger_enable(void)
- {
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Enable the ADC trigger.
- //
- AM_REGn(CTIMER, 0, CTRL3) |= AM_REG_CTIMER_CTRL3_ADCEN_M;
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_adc_trigger_enable()
- //*****************************************************************************
- //
- //! @brief Disable the TIMERA3 ADC trigger
- //!
- //! This function disables the ADC trigger within TIMERA3.
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_adc_trigger_disable(void)
- {
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Disable the ADC trigger.
- //
- AM_REGn(CTIMER, 0, CTRL3) &= ~AM_REG_CTIMER_CTRL3_ADCEN_M;
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_adc_trigger_disable()
- //*****************************************************************************
- //
- //! @brief Enables the selected timer interrupt.
- //!
- //! @param ui32Interrupt is the interrupt to be used.
- //!
- //! This function will enable the selected interrupts in the main CTIMER
- //! interrupt enable register. In order to receive an interrupt from a timer,
- //! you will need to enable the interrupt for that timer in this main register,
- //! as well as in the timer control register (accessible though
- //! am_hal_ctimer_config()), and in the NVIC.
- //!
- //! ui32Interrupt should be the logical OR of one or more of the following
- //! values:
- //!
- //! AM_HAL_CTIMER_INT_TIMERA0C0
- //! AM_HAL_CTIMER_INT_TIMERA0C1
- //! AM_HAL_CTIMER_INT_TIMERB0C0
- //! AM_HAL_CTIMER_INT_TIMERB0C1
- //! AM_HAL_CTIMER_INT_TIMERA1C0
- //! AM_HAL_CTIMER_INT_TIMERA1C1
- //! AM_HAL_CTIMER_INT_TIMERB1C0
- //! AM_HAL_CTIMER_INT_TIMERB1C1
- //! AM_HAL_CTIMER_INT_TIMERA2C0
- //! AM_HAL_CTIMER_INT_TIMERA2C1
- //! AM_HAL_CTIMER_INT_TIMERB2C0
- //! AM_HAL_CTIMER_INT_TIMERB2C1
- //! AM_HAL_CTIMER_INT_TIMERA3C0
- //! AM_HAL_CTIMER_INT_TIMERA3C1
- //! AM_HAL_CTIMER_INT_TIMERB3C0
- //! AM_HAL_CTIMER_INT_TIMERB3C1
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_int_enable(uint32_t ui32Interrupt)
- {
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Enable the interrupt at the module level.
- //
- AM_REGn(CTIMER, 0, INTEN) |= ui32Interrupt;
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_int_enable()
- //*****************************************************************************
- //
- //! @brief Return the enabled timer interrupts.
- //!
- //! This function will return all enabled interrupts in the main CTIMER
- //! interrupt enable register.
- //!
- //! @return return enabled interrupts. This will be a logical or of:
- //!
- //! AM_HAL_CTIMER_INT_TIMERA0C0
- //! AM_HAL_CTIMER_INT_TIMERA0C1
- //! AM_HAL_CTIMER_INT_TIMERB0C0
- //! AM_HAL_CTIMER_INT_TIMERB0C1
- //! AM_HAL_CTIMER_INT_TIMERA1C0
- //! AM_HAL_CTIMER_INT_TIMERA1C1
- //! AM_HAL_CTIMER_INT_TIMERB1C0
- //! AM_HAL_CTIMER_INT_TIMERB1C1
- //! AM_HAL_CTIMER_INT_TIMERA2C0
- //! AM_HAL_CTIMER_INT_TIMERA2C1
- //! AM_HAL_CTIMER_INT_TIMERB2C0
- //! AM_HAL_CTIMER_INT_TIMERB2C1
- //! AM_HAL_CTIMER_INT_TIMERA3C0
- //! AM_HAL_CTIMER_INT_TIMERA3C1
- //! AM_HAL_CTIMER_INT_TIMERB3C0
- //! AM_HAL_CTIMER_INT_TIMERB3C1
- //!
- //! @return Return the enabled timer interrupts.
- //
- //*****************************************************************************
- uint32_t
- am_hal_ctimer_int_enable_get(void)
- {
- //
- // Return enabled interrupts.
- //
- return AM_REGn(CTIMER, 0, INTEN);
- } // am_hal_ctimer_int_enable_get()
- //*****************************************************************************
- //
- //! @brief Disables the selected timer interrupt.
- //!
- //! @param ui32Interrupt is the interrupt to be used.
- //!
- //! This function will disable the selected interrupts in the main CTIMER
- //! interrupt register.
- //!
- //! ui32Interrupt should be the logical OR of one or more of the following
- //! values:
- //!
- //! AM_HAL_CTIMER_INT_TIMERA0C0
- //! AM_HAL_CTIMER_INT_TIMERA0C1
- //! AM_HAL_CTIMER_INT_TIMERB0C0
- //! AM_HAL_CTIMER_INT_TIMERB0C1
- //! AM_HAL_CTIMER_INT_TIMERA1C0
- //! AM_HAL_CTIMER_INT_TIMERA1C1
- //! AM_HAL_CTIMER_INT_TIMERB1C0
- //! AM_HAL_CTIMER_INT_TIMERB1C1
- //! AM_HAL_CTIMER_INT_TIMERA2C0
- //! AM_HAL_CTIMER_INT_TIMERA2C1
- //! AM_HAL_CTIMER_INT_TIMERB2C0
- //! AM_HAL_CTIMER_INT_TIMERB2C1
- //! AM_HAL_CTIMER_INT_TIMERA3C0
- //! AM_HAL_CTIMER_INT_TIMERA3C1
- //! AM_HAL_CTIMER_INT_TIMERB3C0
- //! AM_HAL_CTIMER_INT_TIMERB3C1
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_int_disable(uint32_t ui32Interrupt)
- {
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- //
- // Disable the interrupt at the module level.
- //
- AM_REGn(CTIMER, 0, INTEN) &= ~ui32Interrupt;
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- } // am_hal_ctimer_int_disable()
- //*****************************************************************************
- //
- //! @brief Clears the selected timer interrupt.
- //!
- //! @param ui32Interrupt is the interrupt to be used.
- //!
- //! This function will clear the selected interrupts in the main CTIMER
- //! interrupt register.
- //!
- //! ui32Interrupt should be the logical OR of one or more of the following
- //! values:
- //!
- //! AM_HAL_CTIMER_INT_TIMERA0C0
- //! AM_HAL_CTIMER_INT_TIMERA0C1
- //! AM_HAL_CTIMER_INT_TIMERB0C0
- //! AM_HAL_CTIMER_INT_TIMERB0C1
- //! AM_HAL_CTIMER_INT_TIMERA1C0
- //! AM_HAL_CTIMER_INT_TIMERA1C1
- //! AM_HAL_CTIMER_INT_TIMERB1C0
- //! AM_HAL_CTIMER_INT_TIMERB1C1
- //! AM_HAL_CTIMER_INT_TIMERA2C0
- //! AM_HAL_CTIMER_INT_TIMERA2C1
- //! AM_HAL_CTIMER_INT_TIMERB2C0
- //! AM_HAL_CTIMER_INT_TIMERB2C1
- //! AM_HAL_CTIMER_INT_TIMERA3C0
- //! AM_HAL_CTIMER_INT_TIMERA3C1
- //! AM_HAL_CTIMER_INT_TIMERB3C0
- //! AM_HAL_CTIMER_INT_TIMERB3C1
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_int_clear(uint32_t ui32Interrupt)
- {
- //
- // Disable the interrupt at the module level.
- //
- AM_REGn(CTIMER, 0, INTCLR) = ui32Interrupt;
- } // am_hal_ctimer_int_clear()
- //*****************************************************************************
- //
- //! @brief Sets the selected timer interrupt.
- //!
- //! @param ui32Interrupt is the interrupt to be used.
- //!
- //! This function will set the selected interrupts in the main CTIMER
- //! interrupt register.
- //!
- //! ui32Interrupt should be the logical OR of one or more of the following
- //! values:
- //!
- //! AM_HAL_CTIMER_INT_TIMERA0C0
- //! AM_HAL_CTIMER_INT_TIMERA0C1
- //! AM_HAL_CTIMER_INT_TIMERB0C0
- //! AM_HAL_CTIMER_INT_TIMERB0C1
- //! AM_HAL_CTIMER_INT_TIMERA1C0
- //! AM_HAL_CTIMER_INT_TIMERA1C1
- //! AM_HAL_CTIMER_INT_TIMERB1C0
- //! AM_HAL_CTIMER_INT_TIMERB1C1
- //! AM_HAL_CTIMER_INT_TIMERA2C0
- //! AM_HAL_CTIMER_INT_TIMERA2C1
- //! AM_HAL_CTIMER_INT_TIMERB2C0
- //! AM_HAL_CTIMER_INT_TIMERB2C1
- //! AM_HAL_CTIMER_INT_TIMERA3C0
- //! AM_HAL_CTIMER_INT_TIMERA3C1
- //! AM_HAL_CTIMER_INT_TIMERB3C0
- //! AM_HAL_CTIMER_INT_TIMERB3C1
- //!
- //! @return None.
- //
- //*****************************************************************************
- void
- am_hal_ctimer_int_set(uint32_t ui32Interrupt)
- {
- //
- // Set the interrupts.
- //
- AM_REGn(CTIMER, 0, INTSET) = ui32Interrupt;
- } // am_hal_ctimer_int_set()
- //*****************************************************************************
- //
- //! @brief Returns either the enabled or raw timer interrupt status.
- //!
- //! This function will return the timer interrupt status.
- //!
- //! @return bEnabledOnly if true returns the status of the enabled interrupts
- //! only.
- //!
- //! The return value will be the logical OR of one or more of the following
- //! values:
- //!
- //! AM_HAL_CTIMER_INT_TIMERA0C0
- //! AM_HAL_CTIMER_INT_TIMERA0C1
- //! AM_HAL_CTIMER_INT_TIMERB0C0
- //! AM_HAL_CTIMER_INT_TIMERB0C1
- //! AM_HAL_CTIMER_INT_TIMERA1C0
- //! AM_HAL_CTIMER_INT_TIMERA1C1
- //! AM_HAL_CTIMER_INT_TIMERB1C0
- //! AM_HAL_CTIMER_INT_TIMERB1C1
- //! AM_HAL_CTIMER_INT_TIMERA2C0
- //! AM_HAL_CTIMER_INT_TIMERA2C1
- //! AM_HAL_CTIMER_INT_TIMERB2C0
- //! AM_HAL_CTIMER_INT_TIMERB2C1
- //! AM_HAL_CTIMER_INT_TIMERA3C0
- //! AM_HAL_CTIMER_INT_TIMERA3C1
- //! AM_HAL_CTIMER_INT_TIMERB3C0
- //! AM_HAL_CTIMER_INT_TIMERB3C1
- //!
- //! @return Returns either the timer interrupt status.
- //
- //*****************************************************************************
- uint32_t
- am_hal_ctimer_int_status_get(bool bEnabledOnly)
- {
- //
- // Return the desired status.
- //
- if ( bEnabledOnly )
- {
- uint32_t u32RetVal;
- //
- // Begin critical section.
- //
- AM_CRITICAL_BEGIN_ASM
- u32RetVal = AM_REGn(CTIMER, 0, INTSTAT);
- u32RetVal &= AM_REGn(CTIMER, 0, INTEN);
- //
- // Done with critical section.
- //
- AM_CRITICAL_END_ASM
- return u32RetVal;
- }
- else
- {
- return AM_REGn(CTIMER, 0, INTSTAT);
- }
- } // am_hal_ctimer_int_status_get()
- //*****************************************************************************
- //
- // End Doxygen group.
- //! @}
- //
- //*****************************************************************************
|