//***************************************************************************** // // am_hal_clkgen.c //! @file //! //! @brief Functions for interfacing with the CLKGEN. //! //! @addtogroup clkgen2 Clock Generator (CLKGEN) //! @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" //***************************************************************************** // // CLKGEN HFADJ register // //***************************************************************************** #define AM_REG_CLKGEN_HFADJ_HFXTADJ_DEFAULT 0x5B8 //***************************************************************************** // //! @brief Select the clock divisor for the main system clock. //! //! @param ui32ClockSetting - The divisor value for the system clock. //! //! This function can be used to select the frequency of the main system clock. //! The \e ui32ClockSetting parameter should be set to one of the following //! values: //! //! AM_HAL_CLKGEN_SYSCLK_MAX //! AM_HAL_CLKGEN_SYSCLK_48MHZ //! //! @return None. // //***************************************************************************** void am_hal_clkgen_sysclk_select(uint32_t ui32ClockSetting) { am_hal_debug_assert_msg(ui32ClockSetting == AM_HAL_CLKGEN_SYSCLK_48MHZ, "am_hal_clkgen_sysclk_select(): invalid clock setting."); // // Unlock the clock control register. // AM_REG(CLKGEN, CLKKEY) = AM_REG_CLKGEN_CLKKEY_KEYVAL; // // Set the HFRC divisor to the required operating value. // AM_REG(CLKGEN, CCTRL) = ui32ClockSetting; // // Lock the clock configuration registers. // AM_REG(CLKGEN, CLKKEY) = 0; } //***************************************************************************** // //! @brief Get the current system clock frequency. //! //! This function can be used to determine the frequency of the main system //! clock. The return value is the system clock frequency measured in hertz. //! //! @return System clock frequency in Hz // //***************************************************************************** uint32_t am_hal_clkgen_sysclk_get(void) { uint32_t ui32ClockSetting; uint32_t ui32ClockFreq; // // Read the value of the clock divider. // ui32ClockSetting = AM_REG(CLKGEN, CCTRL) & AM_REG_CLKGEN_CCTRL_CORESEL_M; switch ( ui32ClockSetting ) { case AM_REG_CLKGEN_CCTRL_CORESEL_HFRC: ui32ClockFreq = 48000000; break; case AM_REG_CLKGEN_CCTRL_CORESEL_HFRC_DIV2: ui32ClockFreq = 24000000; break; } return ui32ClockFreq; } //***************************************************************************** // //! @brief Enable selected CLKGEN Interrupts. //! //! Use this function to enable the interrupts. //! //! @param ui32Interrupt - Use the macro bit fields provided in am_hal_clkgen.h //! //! @return None // //***************************************************************************** void am_hal_clkgen_int_enable(uint32_t ui32Interrupt) { // // Enable the interrupts. // AM_REG(CLKGEN, INTEN) |= ui32Interrupt; } //***************************************************************************** // //! @brief Return enabled CLKGEN Interrupts. //! //! Use this function to get all enabled CLKGEN interrupts. //! //! @return enabled CLKGEN interrupts. // //***************************************************************************** uint32_t am_hal_clkgen_int_enable_get(void) { // // Return the enabled interrupts. // return AM_REG(CLKGEN, INTEN); } //***************************************************************************** // //! @brief Disable selected CLKGEN Interrupts. //! //! Use this function to disable the CLKGEN interrupts. //! //! @param ui32Interrupt - Use the macro bit fields provided in am_hal_clkgen.h //! //! @return None // //***************************************************************************** void am_hal_clkgen_int_disable(uint32_t ui32Interrupt) { // // Disable the interrupts. // AM_REG(CLKGEN, INTEN) &= ~ui32Interrupt; } //***************************************************************************** // //! @brief Sets the interrupt status. //! //! @param ui32IntFlags interrupts to be enabled. //! //! This function sets the interrupts. //! //! Valid values for ui32IntFlags are: //! //! AM_HAL_CLKGEN_INT_RTC_ALARM //! AM_HAL_CLKGEN_INT_XT_FAIL //! AM_HAL_CLKGEN_INT_AUTOCAL_COMPLETE //! AM_HAL_CLKGEN_INT AUTOCAL_FAIL //! //! @return None. // //***************************************************************************** void am_hal_clkgen_int_set(uint32_t ui32Interrupt) { // // Set the interrupt status. // AM_REG(CLKGEN, INTSET) = ui32Interrupt; } //***************************************************************************** // //! @brief Gets the interrupt configuration. //! //! @param bEnabledOnly - return the status of only the enabled interrupts. //! //! This function gets the currently configured interrupts. //! //! @return the configured interrupts. //! //! Possible values for the return are: //! //! AM_HAL_CLKGEN_INT_RTC_ALARM //! AM_HAL_CLKGEN_INT_XT_FAIL //! AM_HAL_CLKGEN_INT_AUTOCAL_COMPLETE //! AM_HAL_CLKGEN_INT AUTOCAL_FAIL // //***************************************************************************** uint32_t am_hal_clkgen_int_status_get(bool bEnabledOnly) { // // Return the status. // if ( bEnabledOnly ) { uint32_t u32RetVal = AM_REG(CLKGEN, INTSTAT); u32RetVal &= AM_REG(CLKGEN, INTEN); return u32RetVal; } else { return AM_REG(CLKGEN, INTSTAT); } } //***************************************************************************** // //! @brief Clears the interrupts. //! //! @param ui32IntFlags interrupts to be cleared. //! //! This function clears the interrupts. //! //! Valid values for ui32IntFlags are: //! //! AM_HAL_CLKGEN_INT_RTC_ALARM //! AM_HAL_CLKGEN_INT_XT_FAIL //! AM_HAL_CLKGEN_INT_AUTOCAL_COMPLETE //! AM_HAL_CLKGEN_INT AUTOCAL_FAIL //! //! @return None. // //***************************************************************************** void am_hal_clkgen_int_clear(uint32_t ui32Interrupt) { // // Clear the interrupts. // AM_REG(CLKGEN, INTCLR) = ui32Interrupt; } //***************************************************************************** // //! @brief Starts the desired oscillator(s) (OSC). //! //! @param ui32OscFlags oscillator(s) to start. //! //! This function starts the desired oscillator(s) (OSC). //! //! Valid values for ui32OscFlags are: //! //! AM_HAL_CLKGEN_OSC_LFRC //! AM_HAL_CLKGEN_OSC_XT //! //! @return None. // //***************************************************************************** void am_hal_clkgen_osc_start(uint32_t ui32OscFlags) { if ( ui32OscFlags & (AM_HAL_CLKGEN_OSC_LFRC | AM_HAL_CLKGEN_OSC_XT) ) { // // Start the oscillator(s). // Note that these bits are cleared in order to enable the oscillator. // AM_REG(CLKGEN, OCTRL) &= ~ui32OscFlags; } } //***************************************************************************** // //! @brief Stops the desired oscillator(s) (OSC). //! //! @param ui32OscFlags oscillator(s) to stop. //! //! This function stops the desired oscillator(s) (OSC). //! //! Valid values for ui32OscFlags are: //! //! AM_HAL_CLKGEN_OSC_LFRC //! AM_HAL_CLKGEN_OSC_XT //! //! @return None. // //***************************************************************************** void am_hal_clkgen_osc_stop(uint32_t ui32OscFlags) { if ( ui32OscFlags & (AM_HAL_CLKGEN_OSC_LFRC | AM_HAL_CLKGEN_OSC_XT) ) { // // Stop the oscillator(s). // Note that these bits are set in order to stop the oscillator. // AM_REG(CLKGEN, OCTRL) |= ui32OscFlags; } } //***************************************************************************** // //! @brief Enables the clock out signal. //! //! @param ui32Signal desired location for the clock out signal. //! //! This function enables the clock out signal. See am_hal_clkgen.h for //! available signals. //! //! e.g. AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC //! AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV4 //! AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRC //! //! @return None. // //***************************************************************************** void am_hal_clkgen_clkout_enable(uint32_t ui32Signal) { // // Enable the clock out on desired signal. // AM_REG(CLKGEN, CLKOUT) = AM_REG_CLKGEN_CLKOUT_CKEN_M | ui32Signal; } //***************************************************************************** // //! @brief Disables the clock out signal. //! //! This function disables the clock out signal. //! //! @return None. // //***************************************************************************** void am_hal_clkgen_clkout_disable(void) { // // Disable the clock out. // AM_REG(CLKGEN, CLKOUT) = 0; } //***************************************************************************** // //! @brief Enable UART system clock. //! //! This function enables or disables the UART system clock. //! //! @param ui32Module is 0 or 1 for Apollo2. //! @param ui32UartEn is one of the following. //! AM_HAL_CLKGEN_UARTEN_DIS //! AM_HAL_CLKGEN_UARTEN_EN //! AM_HAL_CLKGEN_UARTEN_REDUCE_FREQ //! AM_HAL_CLKGEN_UARTEN_EN_POWER_SAV //! //! @return None. // //***************************************************************************** void am_hal_clkgen_uarten_set(uint32_t ui32Module, uint32_t ui32UartEn) { uint32_t ui32Mask; if ( (ui32Module >= AM_REG_UART_NUM_MODULES) || (ui32UartEn > AM_HAL_CLKGEN_UARTEN_EN_POWER_SAV) ) { return; } ui32UartEn <<= (ui32Module * AM_HAL_CLKGEN_UARTEN_UARTENn_S(ui32Module)); ui32Mask = ~(AM_HAL_CLKGEN_UARTEN_UARTENn_M(ui32Module)); // // Begin critical section. // AM_CRITICAL_BEGIN // // Set the UART clock // AM_REG(CLKGEN, UARTEN) &= ui32Mask; AM_REG(CLKGEN, UARTEN) |= ui32UartEn; // // Begin critical section. // AM_CRITICAL_END } //***************************************************************************** // //! @brief Enables HFRC auto-adjustment at the specified interval. //! //! @param ui32Warmup - How long to give the HFRC to stabilize during each //! calibration attempt. //! @param ui32Frequency - How often the auto-adjustment should happen. //! //! This function enables HFRC auto-adjustment from an external crystal //! oscillator even when the crystal is not normally being used. //! //! ui32Warmup should be one of the following values: //! //! AM_REG_CLKGEN_HFADJ_HFWARMUP_1SEC //! AM_REG_CLKGEN_HFADJ_HFWARMUP_2SEC //! //! ui32Frequency should be one of the following values: //! //! AM_REG_CLKGEN_HFADJ_HFADJCK_4SEC //! AM_REG_CLKGEN_HFADJ_HFADJCK_16SEC //! AM_REG_CLKGEN_HFADJ_HFADJCK_32SEC //! AM_REG_CLKGEN_HFADJ_HFADJCK_64SEC //! AM_REG_CLKGEN_HFADJ_HFADJCK_128SEC //! AM_REG_CLKGEN_HFADJ_HFADJCK_256SEC //! AM_REG_CLKGEN_HFADJ_HFADJCK_512SEC //! AM_REG_CLKGEN_HFADJ_HFADJCK_1024SEC //! //! @return None. // //***************************************************************************** void am_hal_clkgen_hfrc_adjust_enable(uint32_t ui32Warmup, uint32_t ui32Frequency) { // // Set the HFRC Auto-adjust register for the user's chosen settings. Assume // that the HFRC should be calibrated to 48 MHz and that the crystal is // running at 32.768 kHz. // AM_REG(CLKGEN, HFADJ) = AM_REG_CLKGEN_HFADJ_HFADJ_GAIN_Gain_of_1_in_2 | ui32Warmup | AM_REG_CLKGEN_HFADJ_HFXTADJ(AM_REG_CLKGEN_HFADJ_HFXTADJ_DEFAULT) | ui32Frequency | AM_REG_CLKGEN_HFADJ_HFADJEN_EN; } //***************************************************************************** // //! @brief Disables HFRC auto-adjustment. //! //! This function disables HFRC auto-adjustment. //! //! @return None. // //***************************************************************************** void am_hal_clkgen_hfrc_adjust_disable(void) { // // Disable the clock out. // AM_REG(CLKGEN, HFADJ) = AM_REG_CLKGEN_HFADJ_HFADJ_GAIN_Gain_of_1_in_2 | AM_REG_CLKGEN_HFADJ_HFWARMUP_1SEC | AM_REG_CLKGEN_HFADJ_HFXTADJ(AM_REG_CLKGEN_HFADJ_HFXTADJ_DEFAULT) | AM_REG_CLKGEN_HFADJ_HFADJCK_4SEC | AM_REG_CLKGEN_HFADJ_HFADJEN_DIS; } //***************************************************************************** // // End Doxygen group. //! @} // //*****************************************************************************