852 lines
27 KiB
C
852 lines
27 KiB
C
|
//*****************************************************************************
|
||
|
//
|
||
|
// 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.
|
||
|
//! @}
|
||
|
//
|
||
|
//*****************************************************************************
|