vos/ambiq-hal-sys/ambiq-sparkfun-sdk/mcu/apollo2/hal/am_hal_clkgen.c
2022-10-23 23:45:43 -07:00

507 lines
15 KiB
C

//*****************************************************************************
//
// 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 <stdint.h>
#include <stdbool.h>
#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.
//! @}
//
//*****************************************************************************