//***************************************************************************** // // am_hal_stimer.c //! @file //! //! @brief Functions for interfacing with the system timer (STIMER). //! //! @addtogroup stimer2 System Timer (STIMER) //! @ingroup apollo2hal //! @{ // //***************************************************************************** //***************************************************************************** // // Copyright (c) 2020, 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. // // Third party software included in this distribution is subject to the // additional license terms as defined in the /docs/licenses directory. // // 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 2.4.2 of the AmbiqSuite Development Package. // //***************************************************************************** #include #include #include "am_mcu_apollo.h" //***************************************************************************** // //! @brief Set up the stimer. //! //! @param ui32STimerConfig is the value to load into the configuration reg. //! //! This function should be used to perform the initial set-up of the //! stimer. //! //! @return The 32-bit current config of the STimer Config register // //***************************************************************************** uint32_t am_hal_stimer_config(uint32_t ui32STimerConfig) { uint32_t ui32CurrVal; // // Read the current config // ui32CurrVal = AM_REG(CTIMER, STCFG); // // Write our configuration value. // AM_REG(CTIMER, STCFG) = ui32STimerConfig; // // If all of the clock sources are not HFRC, disable LDO when sleeping if timers are enabled. // if ( (AM_BFR(CTIMER, STCFG, CLKSEL) == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV16) || (AM_BFR(CTIMER, STCFG, CLKSEL) == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV256) ) { AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 0); } else { AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 1); } return ui32CurrVal; } //***************************************************************************** // //! @brief Get the current stimer value. //! //! This function can be used to read, uninvasively, the value in the stimer. //! //! @return The 32-bit value from the STimer counter register. // //***************************************************************************** uint32_t am_hal_stimer_counter_get(void) { return AM_REG(CTIMER, STTMR); } //***************************************************************************** // //! @brief Clear the stimer counter. //! //! This function clears the STimer Counter and leaves the stimer running. //! //! @return None. // //***************************************************************************** void am_hal_stimer_counter_clear(void) { // // Set the clear bit // AM_REG(CTIMER, STCFG) |= AM_REG_CTIMER_STCFG_CLEAR_M; // // Reset the clear bit // AM_REG(CTIMER, STCFG) &= ~AM_REG_CTIMER_STCFG_CLEAR_M; } //***************************************************************************** // //! @brief Set the compare value. //! //! @param ui32CmprInstance is the compare register instance number (0-7). //! @param ui32Delta is the value to add to the STimer counter and load into //! the comparator register. It should be > 1 //! //! NOTE: There is no way to set an absolute value into a comparator register. //! Only deltas added to the STimer counter can be written to the compare //! registers. //! CAUTION: The HAL implementation requires temporarily disabling the //! comparison. To avoid the remote possibility of losing an interrupt //! during that time, delta should always be set to a value greater than 1 //! //! @return None. // //***************************************************************************** void am_hal_stimer_compare_delta_set(uint32_t ui32CmprInstance, uint32_t ui32Delta) { uint32_t cfgVal; uint32_t ui32Critical = 0; if ( ui32CmprInstance > 7 ) { return; } // // Start a critical section. // ui32Critical = am_hal_interrupt_master_disable(); cfgVal = AM_REG(CTIMER, STCFG); // We need to disable the compare temporarily while setting the delta value // That leaves a corner case where we could miss the trigger if setting a very // small delta. To avoid this, we take critical section, and we should ensure // that delta value is at least > 1 // Disable the compare if already enabled, when setting the new value AM_REG(CTIMER, STCFG) &= ~((AM_HAL_STIMER_CFG_COMPARE_A_ENABLE << ui32CmprInstance)); AM_REGVAL(AM_REG_STIMER_COMPARE(0, ui32CmprInstance)) = ui32Delta; // Restore Compare Enable bit AM_REG(CTIMER, STCFG) |= cfgVal & (AM_HAL_STIMER_CFG_COMPARE_A_ENABLE << ui32CmprInstance); // // End the critical section. // am_hal_interrupt_master_set(ui32Critical); } //***************************************************************************** // //! @brief Get the current stimer compare register value. //! //! @param ui32CmprInstance is the compare register instance number (0-7). //! //! This function can be used to read the value in an stimer compare register. //! //! //! @return None. // //***************************************************************************** uint32_t am_hal_stimer_compare_get(uint32_t ui32CmprInstance) { if ( ui32CmprInstance > 7 ) { return 0; } return AM_REGVAL(AM_REG_STIMER_COMPARE(0, ui32CmprInstance)); } //***************************************************************************** // //! @brief Start capturing data with the specified capture register. //! //! @param ui32CaptureNum is the Capture Register Number to read (0-3). //! ui32GPIONumber is the pin number. //! bPolarity: false (0) = Capture on low to high transition. //! true (1) = Capture on high to low transition. //! //! Use this function to start capturing. //! //! @return None. // //***************************************************************************** void am_hal_stimer_capture_start(uint32_t ui32CaptureNum, uint32_t ui32GPIONumber, bool bPolarity) { uint32_t ui32CapCtrl; if ( ui32GPIONumber > (AM_HAL_GPIO_MAX_PADS-1) ) { return; } // // Set the polarity and pin selection in the GPIO block. // switch (ui32CaptureNum) { case 0: AM_BFW(GPIO, STMRCAP, STPOL0, bPolarity); AM_BFW(GPIO, STMRCAP, STSEL0, ui32GPIONumber); ui32CapCtrl = AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_A_M; break; case 1: AM_BFW(GPIO, STMRCAP, STPOL1, bPolarity); AM_BFW(GPIO, STMRCAP, STSEL1, ui32GPIONumber); ui32CapCtrl = AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_B_M; break; case 2: AM_BFW(GPIO, STMRCAP, STPOL2, bPolarity); AM_BFW(GPIO, STMRCAP, STSEL2, ui32GPIONumber); ui32CapCtrl = AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_C_M; break; case 3: AM_BFW(GPIO, STMRCAP, STPOL3, bPolarity); AM_BFW(GPIO, STMRCAP, STSEL3, ui32GPIONumber); ui32CapCtrl = AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_D_M; break; default: return; // error concealment. } // // Enable it in the CTIMER Block // AM_REG(CTIMER, CAPTURE_CONTROL) |= ui32CapCtrl; } //***************************************************************************** // //! @brief Start capturing data with the specified capture register. //! //! @param ui32CaptureNum is the Capture Register Number to read. //! //! Use this function to start capturing. //! //! @return None. // //***************************************************************************** void am_hal_stimer_capture_stop(uint32_t ui32CaptureNum) { // // Disable it in the CTIMER block. // AM_REG(CTIMER, CAPTURE_CONTROL) &= ~(AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_A_M << ((AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_B_S - AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_A_S) * ui32CaptureNum)); } //***************************************************************************** // //! @brief Get the current stimer capture register value. //! //! @param ui32CaptureNum is the Capture Register Number to read. //! //! This function can be used to read the value in an stimer capture register. //! //! //! @return None. // //***************************************************************************** uint32_t am_hal_stimer_capture_get(uint32_t ui32CaptureNum) { if ( ui32CaptureNum > 7 ) { return 0; } return AM_REGVAL(AM_REG_STIMER_CAPTURE(0, ui32CaptureNum)); } //***************************************************************************** // //! @brief Enables the selected system timer interrupt. //! //! @param ui32Interrupt is the interrupt to be used. //! //! This function will enable the selected interrupts in the STIMER interrupt //! enable register. In order to receive an interrupt from an stimer component, //! you will need to enable the interrupt for that component in this main //! register, as well as in the stimer configuration register (accessible though //! am_hal_stimer_config()), and in the NVIC. //! //! ui32Interrupt should be the logical OR of one or more of the following //! values: //! //! AM_HAL_STIMER_INT_COMPAREA //! AM_HAL_STIMER_INT_COMPAREB //! AM_HAL_STIMER_INT_COMPAREC //! AM_HAL_STIMER_INT_COMPARED //! AM_HAL_STIMER_INT_COMPAREE //! AM_HAL_STIMER_INT_COMPAREF //! AM_HAL_STIMER_INT_COMPAREG //! AM_HAL_STIMER_INT_COMPAREH //! //! AM_HAL_STIMER_INT_OVERFLOW //! //! AM_HAL_STIMER_INT_CAPTUREA //! AM_HAL_STIMER_INT_CAPTUREB //! AM_HAL_STIMER_INT_CAPTUREC //! AM_HAL_STIMER_INT_CAPTURED //! //! @return None. // //***************************************************************************** void am_hal_stimer_int_enable(uint32_t ui32Interrupt) { // // Enable the interrupt at the module level. // AM_REGn(CTIMER, 0, STMINTEN) |= ui32Interrupt; } //***************************************************************************** // //! @brief Return the enabled stimer interrupts. //! //! This function will return all enabled interrupts in the STIMER //! interrupt enable register. //! //! @return return enabled interrupts. This will be a logical or of: //! //! AM_HAL_STIMER_INT_COMPAREA //! AM_HAL_STIMER_INT_COMPAREB //! AM_HAL_STIMER_INT_COMPAREC //! AM_HAL_STIMER_INT_COMPARED //! AM_HAL_STIMER_INT_COMPAREE //! AM_HAL_STIMER_INT_COMPAREF //! AM_HAL_STIMER_INT_COMPAREG //! AM_HAL_STIMER_INT_COMPAREH //! //! AM_HAL_STIMER_INT_OVERFLOW //! //! AM_HAL_STIMER_INT_CAPTUREA //! AM_HAL_STIMER_INT_CAPTUREB //! AM_HAL_STIMER_INT_CAPTUREC //! AM_HAL_STIMER_INT_CAPTURED //! //! @return Return the enabled timer interrupts. // //***************************************************************************** uint32_t am_hal_stimer_int_enable_get(void) { // // Return enabled interrupts. // return AM_REGn(CTIMER, 0, STMINTEN); } //***************************************************************************** // //! @brief Disables the selected stimer interrupt. //! //! @param ui32Interrupt is the interrupt to be used. //! //! This function will disable the selected interrupts in the STIMER //! interrupt register. //! //! ui32Interrupt should be the logical OR of one or more of the following //! values: //! //! AM_HAL_STIMER_INT_COMPAREA //! AM_HAL_STIMER_INT_COMPAREB //! AM_HAL_STIMER_INT_COMPAREC //! AM_HAL_STIMER_INT_COMPARED //! AM_HAL_STIMER_INT_COMPAREE //! AM_HAL_STIMER_INT_COMPAREF //! AM_HAL_STIMER_INT_COMPAREG //! AM_HAL_STIMER_INT_COMPAREH //! //! AM_HAL_STIMER_INT_OVERFLOW //! //! AM_HAL_STIMER_INT_CAPTUREA //! AM_HAL_STIMER_INT_CAPTUREB //! AM_HAL_STIMER_INT_CAPTUREC //! AM_HAL_STIMER_INT_CAPTURED //! //! @return None. // //***************************************************************************** void am_hal_stimer_int_disable(uint32_t ui32Interrupt) { // // Disable the interrupt at the module level. // AM_REGn(CTIMER, 0, STMINTEN) &= ~ui32Interrupt; } //***************************************************************************** // //! @brief Sets the selected stimer interrupt. //! //! @param ui32Interrupt is the interrupt to be used. //! //! This function will set the selected interrupts in the STIMER //! interrupt register. //! //! ui32Interrupt should be the logical OR of one or more of the following //! values: //! //! AM_HAL_STIMER_INT_COMPAREA //! AM_HAL_STIMER_INT_COMPAREB //! AM_HAL_STIMER_INT_COMPAREC //! AM_HAL_STIMER_INT_COMPARED //! AM_HAL_STIMER_INT_COMPAREE //! AM_HAL_STIMER_INT_COMPAREF //! AM_HAL_STIMER_INT_COMPAREG //! AM_HAL_STIMER_INT_COMPAREH //! //! AM_HAL_STIMER_INT_OVERFLOW //! //! AM_HAL_STIMER_INT_CAPTUREA //! AM_HAL_STIMER_INT_CAPTUREB //! AM_HAL_STIMER_INT_CAPTUREC //! AM_HAL_STIMER_INT_CAPTURED //! //! @return None. // //***************************************************************************** void am_hal_stimer_int_set(uint32_t ui32Interrupt) { // // Set the interrupts. // AM_REGn(CTIMER, 0, STMINTSET) = ui32Interrupt; } //***************************************************************************** // //! @brief Clears the selected stimer interrupt. //! //! @param ui32Interrupt is the interrupt to be used. //! //! This function will clear the selected interrupts in the STIMER //! interrupt register. //! //! ui32Interrupt should be the logical OR of one or more of the following //! values: //! //! AM_HAL_STIMER_INT_COMPAREA //! AM_HAL_STIMER_INT_COMPAREB //! AM_HAL_STIMER_INT_COMPAREC //! AM_HAL_STIMER_INT_COMPARED //! AM_HAL_STIMER_INT_COMPAREE //! AM_HAL_STIMER_INT_COMPAREF //! AM_HAL_STIMER_INT_COMPAREG //! AM_HAL_STIMER_INT_COMPAREH //! //! AM_HAL_STIMER_INT_OVERFLOW //! //! AM_HAL_STIMER_INT_CAPTUREA //! AM_HAL_STIMER_INT_CAPTUREB //! AM_HAL_STIMER_INT_CAPTUREC //! AM_HAL_STIMER_INT_CAPTURED //! //! @return None. // //***************************************************************************** void am_hal_stimer_int_clear(uint32_t ui32Interrupt) { // // Disable the interrupt at the module level. // AM_REGn(CTIMER, 0, STMINTCLR) = ui32Interrupt; } //***************************************************************************** // //! @brief Returns either the enabled or raw stimer interrupt status. //! //! This function will return the stimer interrupt status. //! //! @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: //! //! //! @return Returns the stimer interrupt status. // //***************************************************************************** uint32_t am_hal_stimer_int_status_get(bool bEnabledOnly) { // // Return the desired status. // uint32_t ui32RetVal = AM_REGn(CTIMER, 0, STMINTSTAT); if ( bEnabledOnly ) { ui32RetVal &= AM_REGn(CTIMER, 0, STMINTEN); } return ui32RetVal; } //***************************************************************************** // // End Doxygen group. //! @} // //*****************************************************************************