summaryrefslogtreecommitdiff
path: root/bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c')
-rw-r--r--bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c851
1 files changed, 851 insertions, 0 deletions
diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c b/bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c
new file mode 100644
index 0000000000..50e0b67915
--- /dev/null
+++ b/bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c
@@ -0,0 +1,851 @@
+//*****************************************************************************
+//
+// am_hal_sysctrl.c
+//! @file
+//!
+//! @brief Functions for interfacing with the M4F system control registers
+//!
+//! @addtogroup sysctrl2 System Control (SYSCTRL)
+//! @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.9 of the AmbiqSuite Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "am_mcu_apollo.h"
+
+//*****************************************************************************
+//
+// Local macro constants
+//
+//*****************************************************************************
+//
+// Define ZX workaround values.
+// These values are defined by the factory.
+//
+#define COREZXVALUE 0x07
+#define MEMZXVALUE 0x07
+
+//
+// Define values for g_ui32CoreBuck, which indicates which timer carries
+// the signal for the CORE Buck, and which also implies that the other timer
+// carries the signal for the MEM buck.
+//
+#define COREBUCK_TIMERA 1 // Core buck signal comes in on timer A
+#define COREBUCK_TIMERB 2 // Core buck signal comes in on timer B
+
+//
+// Define the bit values for static function g_buckZX_chk;
+//
+#define CHKBUCKZX_BUCKS 0x01 // The bucks are enabled
+#define CHKBUCKZX_REV 0x02 // This chip rev needs the workaround
+#define CHKBUCKZX_TIMER 0x04 // A valid timer has been allocated
+#define CHKBUCKZX_DEVEN 0x08 // Devices are powered up and enabled
+
+//*****************************************************************************
+//
+// Prototypes
+//
+//*****************************************************************************
+static void am_hal_sysctrl_buckA_ctimer_isr(void);
+static void am_hal_sysctrl_buckB_ctimer_isr(void);
+
+//*****************************************************************************
+//
+// Globals
+//
+//*****************************************************************************
+static volatile uint32_t g_ui32BuckTimer = 0;
+static volatile uint32_t g_ui32BuckInputs = 0;
+static volatile bool g_bBuckRestoreComplete = false;
+static volatile bool g_bBuckTimed = false;
+static uint32_t g_ui32SaveCoreBuckZX, g_ui32SaveMemBuckZX;
+static uint32_t g_buckZX_chk = 0;
+static volatile uint32_t g_ui32CoreBuck;
+
+//
+// Timer configuration for BUCK inputs.
+//
+static const am_hal_ctimer_config_t g_sBuckTimer =
+{
+ // Don't link timers.
+ 0,
+
+ // Set up Timer0A.
+ (AM_HAL_CTIMER_FN_ONCE |
+ AM_HAL_CTIMER_INT_ENABLE |
+ AM_HAL_CTIMER_BUCK),
+
+ // Set up Timer0B.
+ (AM_HAL_CTIMER_FN_ONCE |
+ AM_HAL_CTIMER_INT_ENABLE |
+ AM_HAL_CTIMER_BUCK),
+};
+
+//*****************************************************************************
+//
+// Determine if we need to do the zero cross workaround on this device.
+// Three criteria are used. All three must be true.
+// 1. Are the bucks enabled?
+// 2. Is the chip rev appropriate for the workaround?
+// 3. Has a timer been allocated to do the workaround?
+// 4. Are certain peripherals powered up?
+//
+// Saves the bitmask to the global g_buckZX_chk.
+// Bitmask bits are defined as: CHKBUCKZX_BUCKS, CHKBUCKZX_REV, CHKBUCKZX_TIMER.
+//
+// Returns true if all criteria are met, false otherwise.
+// g_buckZX_chk can be probed to determine which criteria passed or failed.
+//
+//*****************************************************************************
+static bool
+buckZX_chk(void)
+{
+ uint32_t ui32SupplySrc;
+
+ //
+ // Is this chip rev appropriate to do the workaround?
+ //
+ g_buckZX_chk = AM_BFM(MCUCTRL, CHIPREV, REVMAJ) == AM_REG_MCUCTRL_CHIPREV_REVMAJ_B ?
+ CHKBUCKZX_REV : 0x0;
+
+ //
+ // Has a timer been configured to handle the workaround?
+ //
+ g_buckZX_chk |= ( g_ui32BuckTimer - 1 ) <= BUCK_TIMER_MAX ?
+ CHKBUCKZX_TIMER : 0x0;
+
+ //
+ // Are either or both of the bucks actually enabled?
+ //
+ ui32SupplySrc = AM_REG(PWRCTRL, SUPPLYSRC);
+
+ g_buckZX_chk |= (ui32SupplySrc &
+ (AM_REG_PWRCTRL_SUPPLYSRC_COREBUCKEN_M |
+ AM_REG_PWRCTRL_SUPPLYSRC_MEMBUCKEN_M) ) ?
+ CHKBUCKZX_BUCKS : 0x0;
+
+ //
+ // Finally, if any peripheral is already powered up, we don't need to do the
+ // ZX workaround because in this case the bucks remain in active mode.
+ //
+ ui32SupplySrc = AM_REG(PWRCTRL, DEVICEEN);
+
+ g_buckZX_chk |= ( ui32SupplySrc &
+ (AM_REG_PWRCTRL_DEVICEEN_PDM_M |
+ AM_REG_PWRCTRL_DEVICEEN_UART1_M |
+ AM_REG_PWRCTRL_DEVICEEN_UART0_M |
+ AM_REG_PWRCTRL_DEVICEEN_IO_MASTER5_M |
+ AM_REG_PWRCTRL_DEVICEEN_IO_MASTER4_M |
+ AM_REG_PWRCTRL_DEVICEEN_IO_MASTER3_M |
+ AM_REG_PWRCTRL_DEVICEEN_IO_MASTER2_M |
+ AM_REG_PWRCTRL_DEVICEEN_IO_MASTER1_M |
+ AM_REG_PWRCTRL_DEVICEEN_IO_MASTER0_M |
+ AM_REG_PWRCTRL_DEVICEEN_IO_SLAVE_M) ) ?
+ 0x0 : CHKBUCKZX_DEVEN;
+
+ //
+ // If all 4 criteria were met, we're good to do the workaround.
+ //
+ return ( g_buckZX_chk ==
+ (CHKBUCKZX_BUCKS | CHKBUCKZX_REV |
+ CHKBUCKZX_TIMER | CHKBUCKZX_DEVEN) ) ? true : false;
+}
+
+//*****************************************************************************
+//
+// Set the buck zero cross settings to the values given.
+//
+// ui32Flags, one or more of the following:
+// SETBUCKZX_USE_PROVIDED_SETTINGS - Use the values provided in the parameters
+// to set the trim value(s).
+// SETBUCKZX_USE_SAVED_SETTINGS - Use the values that were previously saved
+// to set the trim value(s).
+// SETBUCKZX_SAVE_CURR_SETTINGS - Save the current trim values before
+// setting the new ones.
+// SETBUCKZX_RESTORE_CORE_ONLY - Restore the Core trim and save the current
+// value of the core buck trim iff
+// SETBUCKZX_SAVE_CURR_SETTINGS is set.
+// SETBUCKZX_RESTORE_MEM_ONLY - Restore the Mem trim and save the current
+// value of the mem buck trim iff
+// SETBUCKZX_SAVE_CURR_SETTINGS is set.
+// SETBUCKZX_RESTORE_BOTH - Restore both buck trims and save the
+// current value of both iff
+// SETBUCKZX_SAVE_CURR_SETTINGS is set.
+//
+//*****************************************************************************
+#define SETBUCKZX_USE_PROVIDED_SETTINGS 0x01
+#define SETBUCKZX_USE_SAVED_SETTINGS 0x02
+#define SETBUCKZX_SAVE_CURR_SETTINGS 0x04
+#define SETBUCKZX_RESTORE_CORE_ONLY 0x10
+#define SETBUCKZX_RESTORE_MEM_ONLY 0x20
+#define SETBUCKZX_RESTORE_BOTH ( SETBUCKZX_RESTORE_CORE_ONLY | \
+ SETBUCKZX_RESTORE_MEM_ONLY )
+static void
+setBuckZX(uint32_t ui32CoreBuckZX, uint32_t ui32MemBuckZX, uint32_t ui32Flags)
+{
+ uint32_t ui32SaveCore, ui32SaveMem, ui32NewCore, ui32NewMem;
+ bool bDoRestore = false;
+
+ //
+ // Begin critical section.
+ //
+ AM_CRITICAL_BEGIN_ASM
+
+ //
+ // Get the current zero cross trim values.
+ //
+ ui32SaveCore = AM_BFR(MCUCTRL, BUCK3, COREBUCKZXTRIM);
+ ui32SaveMem = AM_BFR(MCUCTRL, BUCK3, MEMBUCKZXTRIM);
+
+ //
+ // Determine which values will be restored.
+ //
+ if ( ui32Flags & SETBUCKZX_USE_SAVED_SETTINGS )
+ {
+ //
+ // Use saved settings
+ //
+ ui32NewCore = g_ui32SaveCoreBuckZX;
+ ui32NewMem = g_ui32SaveMemBuckZX;
+ bDoRestore = true;
+ }
+ else if ( ui32Flags & SETBUCKZX_USE_PROVIDED_SETTINGS )
+ {
+ //
+ // Use settings provided in the call parameters
+ //
+ ui32NewCore = ui32CoreBuckZX;
+ ui32NewMem = ui32MemBuckZX;
+ bDoRestore = true;
+ }
+
+ //
+ // Restore the buck Core and Mem trim registers.
+ //
+ if ( bDoRestore )
+ {
+ if ( ui32Flags & SETBUCKZX_RESTORE_CORE_ONLY )
+ {
+ AM_BFW(MCUCTRL, BUCK3, COREBUCKZXTRIM, ui32NewCore);
+ }
+
+ if ( ui32Flags & SETBUCKZX_RESTORE_MEM_ONLY )
+ {
+ AM_BFW(MCUCTRL, BUCK3, MEMBUCKZXTRIM, ui32NewMem);
+ }
+ }
+
+ if ( ui32Flags & SETBUCKZX_SAVE_CURR_SETTINGS )
+ {
+ //
+ // Save off the zero cross values as read on entry to the function.
+ //
+ if ( ui32Flags & SETBUCKZX_RESTORE_CORE_ONLY )
+ {
+ g_ui32SaveCoreBuckZX = ui32SaveCore;
+ }
+
+ if ( ui32Flags & SETBUCKZX_RESTORE_MEM_ONLY )
+ {
+ g_ui32SaveMemBuckZX = ui32SaveMem;
+ }
+ }
+
+ //
+ // Done with critical section.
+ //
+ AM_CRITICAL_END_ASM
+}
+
+//*****************************************************************************
+//
+//! @brief Place the core into sleep or deepsleep.
+//!
+//! @param bSleepDeep - False for Normal or True Deep sleep.
+//!
+//! This function puts the MCU to sleep or deepsleep depending on bSleepDeep.
+//!
+//! Valid values for bSleepDeep are:
+//!
+//! AM_HAL_SYSCTRL_SLEEP_NORMAL
+//! AM_HAL_SYSCTRL_SLEEP_DEEP
+//!
+//! @return None.
+//
+//*****************************************************************************
+void
+am_hal_sysctrl_sleep(bool bSleepDeep)
+{
+ uint32_t ui32Critical;
+// uint32_t ui32DebugGpioSleep = g_ui32DebugGpioSleep - 1;
+ bool bBuckZX_chk;
+ volatile uint32_t ui32BuckTimer;
+
+ //
+ // Disable interrupts and save the previous interrupt state.
+ //
+ ui32Critical = am_hal_interrupt_master_disable();
+
+ //
+ // If the user selected DEEPSLEEP and the TPIU is off, attempt to enter
+ // DEEP SLEEP.
+ //
+ if ((bSleepDeep == AM_HAL_SYSCTRL_SLEEP_DEEP) &&
+ (AM_BFM(MCUCTRL, TPIUCTRL, ENABLE) == AM_REG_MCUCTRL_TPIUCTRL_ENABLE_DIS))
+ {
+ //
+ // Prepare the core for deepsleep (write 1 to the DEEPSLEEP bit).
+ //
+ AM_BFW(SYSCTRL, SCR, SLEEPDEEP, 1);
+
+ //
+ // Check if special buck handling is needed
+ //
+ bBuckZX_chk = buckZX_chk();
+
+ if ( bBuckZX_chk )
+ {
+ ui32BuckTimer = g_ui32BuckTimer - 1;
+
+ //
+ // Before going to sleep, clear the buck timers.
+ // This will also handle the case where we're going back to
+ // sleep before the buck sequence has even completed.
+ //
+ am_hal_ctimer_clear(ui32BuckTimer, AM_HAL_CTIMER_BOTH);
+
+ //
+ // Set CMPR0 of both timerA and timerB to the period value
+ //
+ #define TIMER_PERIOD_BUCKS 1
+ am_hal_ctimer_period_set(ui32BuckTimer,
+ AM_HAL_CTIMER_BOTH,
+ TIMER_PERIOD_BUCKS |
+ (TIMER_PERIOD_BUCKS << 16),
+ 0);
+
+ //
+ // Disable bucks before going to sleep.
+ //
+ am_hal_pwrctrl_bucks_disable();
+ }
+
+ //
+ // Execute the sleep instruction.
+ //
+ AM_ASM_WFI;
+
+ //
+ // Return from sleep
+ //
+ if ( bBuckZX_chk )
+ {
+ //
+ // Adjust the core and mem trims
+ //
+ setBuckZX(COREZXVALUE, MEMZXVALUE,
+ SETBUCKZX_USE_PROVIDED_SETTINGS |
+ SETBUCKZX_RESTORE_BOTH );
+
+ //
+ // Delay for 2us before enabling bucks.
+ //
+ am_hal_flash_delay( FLASH_CYCLES_US(2) );
+
+ //
+ // Turn on the bucks
+ //
+ am_hal_pwrctrl_bucks_enable();
+
+ //
+ // Get the actual timer number
+ //
+ ui32BuckTimer = g_ui32BuckTimer - 1;
+
+ //
+ // Initialize the complete flag
+ //
+ g_bBuckRestoreComplete = false;
+
+ //
+ // Initialize the input flags
+ //
+ g_ui32BuckInputs = 0;
+
+ //
+ // Delay for 5us to make sure we're receiving clean buck signals.
+ //
+ am_hal_flash_delay( FLASH_CYCLES_US(5) );
+
+ //
+ // Start timers (set the enable bit, clear the clear bit)
+ //
+ am_hal_ctimer_start(ui32BuckTimer, AM_HAL_CTIMER_BOTH);
+ }
+ else
+ {
+ //
+ // Since we're not doing anything, we're done, so set the done flag.
+ //
+ g_bBuckRestoreComplete = true;
+ }
+ }
+ else
+ {
+ //
+ // Prepare the core for normal sleep (write 0 to the DEEPSLEEP bit).
+ //
+ AM_BFW(SYSCTRL, SCR, SLEEPDEEP, 0);
+
+ //
+ // Go to sleep.
+ //
+ AM_ASM_WFI;
+ }
+
+ //
+ // Restore the interrupt state.
+ //
+ am_hal_interrupt_master_set(ui32Critical);
+}
+
+//*****************************************************************************
+//
+//! @brief Enable the floating point module.
+//!
+//! Call this function to enable the ARM hardware floating point module.
+//!
+//! @return None.
+//
+//*****************************************************************************
+void
+am_hal_sysctrl_fpu_enable(void)
+{
+ //
+ // Enable access to the FPU in both privileged and user modes.
+ // NOTE: Write 0s to all reserved fields in this register.
+ //
+ AM_REG(SYSCTRL, CPACR) = (AM_REG_SYSCTRL_CPACR_CP11(0x3) |
+ AM_REG_SYSCTRL_CPACR_CP10(0x3));
+}
+
+//*****************************************************************************
+//
+//! @brief Disable the floating point module.
+//!
+//! Call this function to disable the ARM hardware floating point module.
+//!
+//! @return None.
+//
+//*****************************************************************************
+void
+am_hal_sysctrl_fpu_disable(void)
+{
+ //
+ // Disable access to the FPU in both privileged and user modes.
+ // NOTE: Write 0s to all reserved fields in this register.
+ //
+ AM_REG(SYSCTRL, CPACR) = 0x00000000 &
+ ~(AM_REG_SYSCTRL_CPACR_CP11(0x3) |
+ AM_REG_SYSCTRL_CPACR_CP10(0x3));
+}
+
+//*****************************************************************************
+//
+//! @brief Enable stacking of FPU registers on exception entry.
+//!
+//! @param bLazy - Set to "true" to enable "lazy stacking".
+//!
+//! This function allows the core to save floating-point information to the
+//! stack on exception entry. Setting the bLazy option enables "lazy stacking"
+//! for interrupt handlers. Normally, mixing floating-point code and interrupt
+//! driven routines causes increased interrupt latency, because the core must
+//! save extra information to the stack upon exception entry. With the lazy
+//! stacking option enabled, the core will skip the saving of floating-point
+//! registers when possible, reducing average interrupt latency.
+//!
+//! @note This function should be called before the floating-point module is
+//! used in interrupt-driven code. If it is not called, the core will not have
+//! any way to save context information for floating-point variables on
+//! exception entry.
+//!
+//! @return None.
+//
+//*****************************************************************************
+void
+am_hal_sysctrl_fpu_stacking_enable(bool bLazy)
+{
+ if ( bLazy )
+ {
+ //
+ // Enable automatic saving of FPU registers on exception entry, using lazy
+ // context saving.
+ //
+ AM_REG(SYSCTRL, FPCCR) |= (AM_REG_SYSCTRL_FPCCR_ASPEN(0x1) |
+ AM_REG_SYSCTRL_FPCCR_LSPEN(0x1));
+ }
+ else
+ {
+ //
+ // Enable automatic saving of FPU registers on exception entry.
+ //
+ AM_REG(SYSCTRL, FPCCR) |= AM_REG_SYSCTRL_FPCCR_ASPEN(0x1);
+ }
+}
+
+//*****************************************************************************
+//
+//! @brief Disable FPU register stacking on exception entry.
+//!
+//! This function disables all stacking of floating point registers for
+//! interrupt handlers.
+//!
+//! @return None.
+//
+//*****************************************************************************
+void
+am_hal_sysctrl_fpu_stacking_disable(void)
+{
+ //
+ // Enable automatic saving of FPU registers on exception entry, using lazy
+ // context saving.
+ //
+ AM_REG(SYSCTRL, FPCCR) &= ~(AM_REG_SYSCTRL_FPCCR_ASPEN(0x1) |
+ AM_REG_SYSCTRL_FPCCR_LSPEN(0x1));
+}
+
+//*****************************************************************************
+//
+//! @brief Issue a system wide reset using the AIRCR bit in the M4 system ctrl.
+//!
+//! This function issues a system wide reset (Apollo POR level reset).
+//!
+//! @return None.
+//
+//*****************************************************************************
+void
+am_hal_sysctrl_aircr_reset(void)
+{
+ //
+ // Set the system reset bit in the AIRCR register
+ //
+ AM_REG(SYSCTRL, AIRCR) = AM_REG_SYSCTRL_AIRCR_VECTKEY(0x5FA) |
+ AM_REG_SYSCTRL_AIRCR_SYSRESETREQ(1);
+}
+
+//*****************************************************************************
+//
+//! @brief Buck CTimer ISR initializer.
+//!
+//! @param ui32BuckTimerNumber - Timer number to be used for handling the buck.
+//! Must be 0-3.
+//!
+//! If called with an invalid timer (that is, not 0 - 3, or greater than
+//! BUCK_TIMER_MAX), then the workaround will not be enabled.
+//!
+//! Instead, the bucks will be initialized with a value that will avoid the
+//! issues described in the Errata (ERR019). However, this will cause a
+//! less efficient energy usage condtion.
+//!
+//! @return 0.
+//
+//*****************************************************************************
+uint32_t
+am_hal_sysctrl_buck_ctimer_isr_init(uint32_t ui32BuckTimerNumber)
+{
+ uint32_t ui32RetVal = 0;
+
+ //
+ // Initialize the input flags
+ //
+ g_ui32BuckInputs = 0;
+
+ //
+ // Initialize operation complete flag
+ //
+ g_bBuckRestoreComplete = false;
+
+ //
+ // Initialize to assume there is no valid timer.
+ //
+ g_ui32BuckTimer = 0;
+
+ if ( ui32BuckTimerNumber > BUCK_TIMER_MAX )
+ {
+ if ( ( ui32BuckTimerNumber & 0xFFFF0000 ) ==
+ AM_HAL_SYSCTRL_BUCK_CTIMER_ZX_CONSTANT )
+ {
+ //
+ // The caller is asking for the hard option, which changes the
+ // settings to the more noise-immune, if less efficient, settings.
+ // While we're at it, go ahead and save off the current settings.
+ //
+ if ( (ui32BuckTimerNumber & 0x0000FFFF) == 0 )
+ {
+ setBuckZX(COREZXVALUE, MEMZXVALUE,
+ SETBUCKZX_USE_PROVIDED_SETTINGS |
+ SETBUCKZX_SAVE_CURR_SETTINGS |
+ SETBUCKZX_RESTORE_BOTH );
+ }
+ else
+ {
+ uint32_t ui32Core, ui32Mem;
+
+ //
+ // Use the setting provided in the parameter.
+ //
+ ui32Core = (((ui32BuckTimerNumber & 0x001F) >> 0) - 1) & 0xF;
+ ui32Mem = (((ui32BuckTimerNumber & 0x1F00) >> 8) - 1) & 0xF;
+
+ setBuckZX(ui32Core, ui32Mem,
+ SETBUCKZX_USE_PROVIDED_SETTINGS |
+ SETBUCKZX_SAVE_CURR_SETTINGS |
+ SETBUCKZX_RESTORE_BOTH );
+ }
+ }
+ }
+ else
+ {
+ //
+ // Save off the current trim settings (but don't change any settings).
+ //
+ setBuckZX(0, 0, SETBUCKZX_SAVE_CURR_SETTINGS | SETBUCKZX_RESTORE_BOTH);
+
+ //
+ // The timer number will be maintained as (n + 1). Therefore, a value
+ // of 0 saved in the global is an invalid timer. 1=timer0, 2=timer1...
+ //
+ g_ui32BuckTimer = ui32BuckTimerNumber + 1;
+
+ //
+ // Register the timer ISRs
+ //
+ am_hal_ctimer_int_register( AM_HAL_CTIMER_INT_TIMERA0C0 <<
+ (ui32BuckTimerNumber * 2),
+ am_hal_sysctrl_buckA_ctimer_isr );
+
+ am_hal_ctimer_int_register( AM_HAL_CTIMER_INT_TIMERB0C0 <<
+ (ui32BuckTimerNumber * 2),
+ am_hal_sysctrl_buckB_ctimer_isr );
+
+ //
+ // Determine which timer input (A or B) is core buck and which is mem
+ // buck based on the timer number.
+ // For CTIMER 0 & 1: Timer A is mem buck, Timer B is core buck
+ // For CTIMER 2 & 3: Timer A is core buck, Timer B is mem buck
+ //
+ if ( (ui32BuckTimerNumber == 0) || (ui32BuckTimerNumber == 1) )
+ {
+ //
+ // Indicate that TimerB is core buck.
+ //
+ g_ui32CoreBuck = COREBUCK_TIMERB;
+ }
+ else
+ {
+ //
+ // Indicate that TimerA is core buck
+ //
+ g_ui32CoreBuck = COREBUCK_TIMERA;
+ }
+
+ //
+ // Clear and configure the timers
+ //
+ am_hal_ctimer_clear(ui32BuckTimerNumber, AM_HAL_CTIMER_BOTH);
+
+ am_hal_ctimer_config(ui32BuckTimerNumber,
+ (am_hal_ctimer_config_t*)&g_sBuckTimer);
+
+ //
+ // Enable the interrupts for timers A and B
+ //
+ am_hal_ctimer_int_enable( (AM_HAL_CTIMER_INT_TIMERA0C0 |
+ AM_HAL_CTIMER_INT_TIMERB0C0 ) <<
+ (ui32BuckTimerNumber * 2) );
+
+ //
+ // Enable the timer interrupt in the NVIC.
+ //
+ am_hal_interrupt_enable(AM_HAL_INTERRUPT_CTIMER);
+ }
+
+ return ui32RetVal;
+}
+
+//*****************************************************************************
+//
+// Get buck update complete status.
+//
+//*****************************************************************************
+bool
+am_hal_sysctrl_buck_update_complete(void)
+{
+ return g_bBuckRestoreComplete;
+}
+
+//*****************************************************************************
+//
+// Buck CTIMER ISR (for handling buck switching via TimerA).
+//
+// Note: This handler assumes that the interrupt is cleared in am_ctimer_isr().
+//
+//*****************************************************************************
+static void
+am_hal_sysctrl_buckA_ctimer_isr(void)
+{
+ volatile uint32_t ui32BuckTimer = g_ui32BuckTimer - 1;
+
+ //
+ // Begin critical section.
+ // Although a relatively long time, the following 2us delay is critically
+ // timed for re-trimming the buck and thus cannot be extended. Therefore,
+ // we must keep it inside the critical section.
+ //
+ AM_CRITICAL_BEGIN_ASM
+
+ //
+ // Delay for 2us.
+ //
+ am_hal_flash_delay( FLASH_CYCLES_US(2) );
+
+ //
+ // Determine which buck (core or mem) needs to be updated.
+ //
+ if ( g_ui32CoreBuck == COREBUCK_TIMERA )
+ {
+ //
+ // Timer A buck signal is the CORE buck.
+ // Restore the core buck.
+ //
+ setBuckZX(0, 0, SETBUCKZX_RESTORE_CORE_ONLY |
+ SETBUCKZX_USE_SAVED_SETTINGS );
+ }
+ else
+ {
+ //
+ // Timer A buck signal is the MEM buck.
+ // Restore the mem buck.
+ //
+ setBuckZX(0, 0, SETBUCKZX_RESTORE_MEM_ONLY |
+ SETBUCKZX_USE_SAVED_SETTINGS );
+ }
+
+ g_ui32BuckInputs |= 0x1;
+
+ if ( g_ui32BuckInputs == 0x3 )
+ {
+ g_bBuckRestoreComplete = true;
+ g_ui32BuckInputs = 0;
+ }
+
+ //
+ // End critical section.
+ //
+ AM_CRITICAL_END_ASM
+}
+
+//*****************************************************************************
+//
+// Buck CTIMER ISR (for handling buck switching via TimerB).
+//
+// Note: This handler assumes that the interrupt is cleared in am_ctimer_isr().
+//
+//*****************************************************************************
+static void
+am_hal_sysctrl_buckB_ctimer_isr(void)
+{
+ volatile uint32_t ui32BuckTimer = g_ui32BuckTimer - 1;
+
+ //
+ // Begin critical section.
+ // Although a relatively long time, the following 2us delay is critically
+ // timed for re-trimming the buck and thus cannot be extended. Therefore,
+ // we must keep it inside the critical section.
+ //
+ AM_CRITICAL_BEGIN_ASM
+
+ //
+ // Delay for 2us.
+ //
+ am_hal_flash_delay( FLASH_CYCLES_US(2) );
+
+ //
+ // Determine which buck (core or mem) needs to be updated.
+ //
+ if ( g_ui32CoreBuck == COREBUCK_TIMERB )
+ {
+ //
+ // Timer B buck signal is the CORE buck.
+ // Restore the core buck.
+ //
+ setBuckZX(0, 0, SETBUCKZX_RESTORE_CORE_ONLY |
+ SETBUCKZX_USE_SAVED_SETTINGS );
+ }
+ else
+ {
+ //
+ // Timer B buck signal is the MEM buck.
+ // Restore the mem buck.
+ //
+ setBuckZX(0, 0, SETBUCKZX_RESTORE_MEM_ONLY |
+ SETBUCKZX_USE_SAVED_SETTINGS );
+ }
+
+ g_ui32BuckInputs |= 0x2;
+
+ if ( g_ui32BuckInputs == 0x3 )
+ {
+ g_bBuckRestoreComplete = true;
+ g_ui32BuckInputs = 0;
+ }
+
+ //
+ // End critical section.
+ //
+ AM_CRITICAL_END_ASM
+}
+
+//*****************************************************************************
+//
+// End Doxygen group.
+//! @}
+//
+//*****************************************************************************