blob: fb87586f9ae4497cd503c74ac8e33da2655a9846 [file] [log] [blame]
#include "../driverlib/adi.h"
#include "../driverlib/aon_batmon.h"
#include "../driverlib/aon_batmon.h"
#include "../driverlib/aon_batmon.h"
#include "../driverlib/aon_event.h"
#include "../driverlib/aon_ioc.h"
#include "../driverlib/aon_rtc.h"
#include "../driverlib/aon_rtc.h"
#include "../driverlib/aux_adc.h"
#include "../driverlib/aux_ctrl.h"
#include "../driverlib/aux_tdc.h"
#include "../driverlib/chipinfo.h"
#include "../driverlib/cpu.h"
#include "../driverlib/cpu.h"
#include "../driverlib/crypto.h"
#include "../driverlib/ddi.h"
#include "../driverlib/ddi.h"
#include "../driverlib/event.h"
#include "../driverlib/flash.h"
#include "../driverlib/i2c.h"
#include "../driverlib/i2s.h"
#include "../driverlib/interrupt.h"
#include "../driverlib/ioc.h"
#include "../driverlib/ioc.h"
#include "../driverlib/osc.h"
#include "../driverlib/osc.h"
#include "../driverlib/prcm.h"
#include "../driverlib/pwr_ctrl.h"
#include "../driverlib/setup_rom.h"
#include "../driverlib/setup_rom.h"
#include "../driverlib/smph.h"
#include "../driverlib/ssi.h"
#include "../driverlib/sys_ctrl.h"
#include "../driverlib/sys_ctrl.h"
#include "../driverlib/timer.h"
#include "../driverlib/trng.h"
#include "../driverlib/uart.h"
#include "../driverlib/udma.h"
#include "../driverlib/vims.h"
#include "../inc/hw_adi.h"
#include "../inc/hw_adi_2_refsys.h"
#include "../inc/hw_adi_3_refsys.h"
#include "../inc/hw_adi_4_aux.h"
#include "../inc/hw_aon_batmon.h"
#include "../inc/hw_aux_sysif.h"
#include "../inc/hw_aux_sysif.h"
#include "../inc/hw_ccfg.h"
#include "../inc/hw_ccfg.h"
#include "../inc/hw_ccfg.h"
#include "../inc/hw_ccfg.h"
#include "../inc/hw_ddi_0_osc.h"
#include "../inc/hw_fcfg1.h"
#include "../inc/hw_fcfg1.h"
#include "../inc/hw_fcfg1.h"
#include "../inc/hw_fcfg1.h"
#include "../inc/hw_memmap.h"
#include "../inc/hw_memmap.h"
#include "../inc/hw_types.h"
#include "../inc/hw_types.h"
#include "../inc/hw_types.h"
#include "../inc/hw_types.h"
//*****************************************************************************
//
//! Disable all external interrupts
//
//*****************************************************************************
#if defined(__IAR_SYSTEMS_ICC__)
uint32_t
CPUcpsid(void)
{
// Read PRIMASK and disable interrupts.
__asm(" mrs r0, PRIMASK\n"
" cpsid i\n");
// "Warning[Pe940]: missing return statement at end of non-void function"
// is suppressed here to avoid putting a "bx lr" in the inline assembly
// above and a superfluous return statement here.
#pragma diag_suppress=Pe940
}
#pragma diag_default=Pe940
#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
__asm uint32_t
CPUcpsid(void)
{
// Read PRIMASK and disable interrupts.
mrs r0, PRIMASK;
cpsid i;
bx lr
}
#elif defined(__TI_COMPILER_VERSION__) || defined(DOXYGEN)
uint32_t
CPUcpsid(void)
{
// Read PRIMASK and disable interrupts.
__asm(" mrs r0, PRIMASK\n"
" cpsid i\n"
" bx lr\n");
// The following keeps the compiler happy, because it wants to see a
// return value from this function. It will generate code to return
// a zero. However, the real return is the "bx lr" above, so the
// return(0) is never executed and the function returns with the value
// you expect in R0.
return(0);
}
#else
uint32_t __attribute__((naked))
CPUcpsid(void)
{
uint32_t ui32Ret;
// Read PRIMASK and disable interrupts
__asm(" mrs r0, PRIMASK\n"
" cpsid i\n"
" bx lr\n"
: "=r"(ui32Ret));
// The return is handled in the inline assembly, but the compiler will
// still complain if there is not an explicit return here (despite the fact
// that this does not result in any code being produced because of the
// naked attribute).
return(ui32Ret);
}
#endif
//*****************************************************************************
//
//! Enable all external interrupts
//
//*****************************************************************************
#if defined(__IAR_SYSTEMS_ICC__)
uint32_t
CPUcpsie(void)
{
// Read PRIMASK and enable interrupts.
__asm(" mrs r0, PRIMASK\n"
" cpsie i\n");
// "Warning[Pe940]: missing return statement at end of non-void function"
// is suppressed here to avoid putting a "bx lr" in the inline assembly
// above and a superfluous return statement here.
#pragma diag_suppress=Pe940
}
#pragma diag_default=Pe940
#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
__asm uint32_t
CPUcpsie(void)
{
// Read PRIMASK and enable interrupts.
mrs r0, PRIMASK;
cpsie i;
bx lr
}
#elif defined(__TI_COMPILER_VERSION__) || defined(DOXYGEN)
uint32_t
CPUcpsie(void)
{
// Read PRIMASK and enable interrupts.
__asm(" mrs r0, PRIMASK\n"
" cpsie i\n"
" bx lr\n");
// The following keeps the compiler happy, because it wants to see a
// return value from this function. It will generate code to return
// a zero. However, the real return is the "bx lr" above, so the
// return(0) is never executed and the function returns with the value
// you expect in R0.
return(0);
}
#else
uint32_t __attribute__((naked))
CPUcpsie(void)
{
uint32_t ui32Ret;
// Read PRIMASK and enable interrupts.
__asm(" mrs r0, PRIMASK\n"
" cpsie i\n"
" bx lr\n"
: "=r"(ui32Ret));
// The return is handled in the inline assembly, but the compiler will
// still complain if there is not an explicit return here (despite the fact
// that this does not result in any code being produced because of the
// naked attribute).
return(ui32Ret);
}
#endif
//*****************************************************************************
//
//! Provide a small delay
//
//*****************************************************************************
#if defined(__IAR_SYSTEMS_ICC__)
void
CPUdelay(uint32_t ui32Count)
{
// Delay the specified number of times (3 cycles pr. loop)
__asm("CPUdelay:\n"
" subs r0, #1\n"
" bne.n CPUdelay\n"
" bx lr");
#pragma diag_suppress=Pe940
}
#pragma diag_default=Pe940
#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
__asm void
CPUdelay(uint32_t ui32Count)
{
// Delay the specified number of times (3 cycles pr. loop)
CPUdel
subs r0, #1;
bne CPUdel;
bx lr;
}
#elif defined(__TI_COMPILER_VERSION__) || defined(DOXYGEN)
// For CCS implement this function in pure assembly. This prevents the TI
// compiler from doing funny things with the optimizer.
// Delay the specified number of times (3 cycles pr. loop)
__asm(" .sect \".text:CPUdelay\"\n"
" .clink\n"
" .thumbfunc CPUdelay\n"
" .thumb\n"
" .global CPUdelay\n"
"CPUdelay:\n"
" subs r0, #1\n"
" bne.n CPUdelay\n"
" bx lr\n");
#else
void __attribute__((naked))
CPUdelay(uint32_t ui32Count)
{
// Delay the specified number of times (3 cycles pr. loop)
__asm(" subs r0, #1\n"
" bne CPUdelay\n"
" bx lr");
}
#endif
void AONEventMcuWakeUpSet(uint32_t ui32MCUWUEvent, uint32_t ui32EventSrc) {
uint32_t ui32Shift ;
uint32_t ui32Mask ;
uint32_t ui32RegAdr ;
// Check the arguments.
ASSERT(( ui32MCUWUEvent >= AON_EVENT_MCU_WU0 ) && ( ui32MCUWUEvent <= AON_EVENT_MCU_WU7 ))
ASSERT( ui32EventSrc <= AON_EVENT_NONE );
ui32Shift = (( ui32MCUWUEvent & 3 ) << 3 );
ui32Mask = ( 0x3F << ui32Shift );
ui32RegAdr = ( AON_EVENT_BASE + AON_EVENT_O_MCUWUSEL );
if ( ui32MCUWUEvent > 3 ) {
ui32RegAdr += 4;
}
HWREG( ui32RegAdr ) = ( HWREG( ui32RegAdr ) & ( ~ui32Mask )) | ( ui32EventSrc << ui32Shift );
}
uint32_t AONEventMcuWakeUpGet(uint32_t ui32MCUWUEvent) {
uint32_t ui32Shift ;
uint32_t ui32RegAdr ;
// Check the arguments.
ASSERT(( ui32MCUWUEvent >= AON_EVENT_MCU_WU0 ) && ( ui32MCUWUEvent <= AON_EVENT_MCU_WU7 ))
ui32Shift = (( ui32MCUWUEvent & 3 ) << 3 );
ui32RegAdr = ( AON_EVENT_BASE + AON_EVENT_O_MCUWUSEL );
if ( ui32MCUWUEvent > 3 ) {
ui32RegAdr += 4;
}
return (( HWREG( ui32RegAdr ) >> ui32Shift ) & 0x3F );
}
void AONEventMcuSet(uint32_t ui32MCUEvent, uint32_t ui32EventSrc) {
uint32_t ui32Ctrl;
// Check the arguments.
ASSERT((ui32MCUEvent == AON_EVENT_MCU_EVENT0) ||
(ui32MCUEvent == AON_EVENT_MCU_EVENT1) ||
(ui32MCUEvent == AON_EVENT_MCU_EVENT2));
ASSERT(ui32EventSrc <= AON_EVENT_NONE);
ui32Ctrl = HWREG(AON_EVENT_BASE + AON_EVENT_O_EVTOMCUSEL);
if(ui32MCUEvent == AON_EVENT_MCU_EVENT0)
{
ui32Ctrl &= ~(AON_EVENT_EVTOMCUSEL_AON_PROG0_EV_M);
ui32Ctrl |= (ui32EventSrc & 0x3f) << AON_EVENT_EVTOMCUSEL_AON_PROG0_EV_S;
}
else if(ui32MCUEvent == AON_EVENT_MCU_EVENT1)
{
ui32Ctrl &= ~(AON_EVENT_EVTOMCUSEL_AON_PROG1_EV_M);
ui32Ctrl |= (ui32EventSrc & 0x3f) << AON_EVENT_EVTOMCUSEL_AON_PROG1_EV_S;
}
else if(ui32MCUEvent == AON_EVENT_MCU_EVENT2)
{
ui32Ctrl &= ~(AON_EVENT_EVTOMCUSEL_AON_PROG2_EV_M);
ui32Ctrl |= (ui32EventSrc & 0x3f) << AON_EVENT_EVTOMCUSEL_AON_PROG2_EV_S;
}
HWREG(AON_EVENT_BASE + AON_EVENT_O_EVTOMCUSEL) = ui32Ctrl;
}
uint32_t AONEventMcuGet(uint32_t ui32MCUEvent) {
uint32_t ui32EventSrc;
// Check the arguments.
ASSERT((ui32MCUEvent == AON_EVENT_MCU_EVENT0) ||
(ui32MCUEvent == AON_EVENT_MCU_EVENT1) ||
(ui32MCUEvent == AON_EVENT_MCU_EVENT2));
ui32EventSrc = HWREG(AON_EVENT_BASE + AON_EVENT_O_EVTOMCUSEL);
if(ui32MCUEvent == AON_EVENT_MCU_EVENT0)
{
return((ui32EventSrc & AON_EVENT_EVTOMCUSEL_AON_PROG0_EV_M) >>
AON_EVENT_EVTOMCUSEL_AON_PROG0_EV_S);
}
else if(ui32MCUEvent == AON_EVENT_MCU_EVENT1)
{
return((ui32EventSrc & AON_EVENT_EVTOMCUSEL_AON_PROG1_EV_M) >>
AON_EVENT_EVTOMCUSEL_AON_PROG1_EV_S);
}
else if(ui32MCUEvent == AON_EVENT_MCU_EVENT2)
{
return((ui32EventSrc & AON_EVENT_EVTOMCUSEL_AON_PROG2_EV_M) >>
AON_EVENT_EVTOMCUSEL_AON_PROG2_EV_S);
}
// Should never get to this statement, but suppress warning.
ASSERT(0);
return(0);
}
uint64_t AONRTCCurrent64BitValueGet( void ) {
union {
uint64_t returnValue ;
uint32_t secAndSubSec[ 2 ] ;
} currentRtc ;
uint32_t ui32SecondSecRead ;
// Reading SEC both before and after SUBSEC in order to detect if SEC incremented while reading SUBSEC
// If SEC incremented, we can't be sure which SEC the SUBSEC belongs to, so repeating the sequence then.
do {
currentRtc.secAndSubSec[ 1 ] = HWREG( AON_RTC_BASE + AON_RTC_O_SEC );
currentRtc.secAndSubSec[ 0 ] = HWREG( AON_RTC_BASE + AON_RTC_O_SUBSEC );
ui32SecondSecRead = HWREG( AON_RTC_BASE + AON_RTC_O_SEC );
} while ( currentRtc.secAndSubSec[ 1 ] != ui32SecondSecRead );
return ( currentRtc.returnValue );
}
void AUXCTRLImageLoad(uint16_t *pui16Image, uint32_t ui32StartAddr, uint32_t ui32Size) {
uint16_t* pui16Src16;
uint16_t* pui16Dst16;
uint32_t ui32WordCnt;
// Check the arguments.
ASSERT(ui32StartAddr < 512);
ASSERT(ui32Size <= 1024);
ASSERT((ui32Size / 2 + ui32StartAddr) <= 512);
// Copy image to AUX RAM.
ui32WordCnt = (ui32Size >> 1);
pui16Src16 = pui16Image;
pui16Dst16 = (uint16_t*)(AUX_RAM_BASE + (ui32StartAddr << 1));
while(ui32WordCnt--)
{
*pui16Dst16++ = *pui16Src16++;
}
}
void AUXTDCConfigSet(uint32_t ui32Base, uint32_t ui32StartCondition, uint32_t ui32StopCondition) {
// Check the arguments.
ASSERT(AUXTDCBaseValid(ui32Base));
// Make sure the AUX TDC is in the idle state before changing the
// configuration.
while(!((HWREG(ui32Base + AUX_TDC_O_STAT) & AUX_TDC_STAT_STATE_M) ==
AUX_TDC_STAT_STATE_IDLE))
{
}
// Clear previous results.
HWREG(ui32Base + AUX_TDC_O_CTL) = 0x0;
// Change the configuration.
HWREG(ui32Base + AUX_TDC_O_TRIGSRC) = ui32StartCondition | ui32StopCondition;
}
uint32_t AUXTDCMeasurementDone(uint32_t ui32Base) {
uint32_t ui32Reg;
uint32_t ui32Status;
// Check the arguments.
ASSERT(AUXTDCBaseValid(ui32Base));
// Check if the AUX TDC is done measuring.
ui32Reg = HWREG(ui32Base + AUX_TDC_O_STAT);
if(ui32Reg & AUX_TDC_STAT_DONE)
{
ui32Status = AUX_TDC_DONE;
}
else if(ui32Reg & AUX_TDC_STAT_SAT)
{
ui32Status = AUX_TDC_TIMEOUT;
}
else
{
ui32Status = AUX_TDC_BUSY;
}
// Return the status.
return (ui32Status);
}
void DDI32RegWrite(uint32_t ui32Base, uint32_t ui32Reg, uint32_t ui32Val) {
// Check the arguments.
ASSERT(DDIBaseValid(ui32Base));
ASSERT(ui32Reg < DDI_SLAVE_REGS);
// Write the value to the register.
HWREG(ui32Base + ui32Reg) = ui32Val;
}
void DDI16BitWrite(uint32_t ui32Base, uint32_t ui32Reg, uint32_t ui32Mask, uint32_t ui32WrData) {
uint32_t ui32RegAddr;
uint32_t ui32Data;
// Check the arguments.
ASSERT(DDIBaseValid(ui32Base));
ASSERT(!((ui32Mask & 0xFFFF0000) ^ (ui32Mask & 0x0000FFFF)));
ASSERT(!(ui32WrData & 0xFFFF0000));
// DDI 16-bit target is on 32-bit boundary so double offset
ui32RegAddr = ui32Base + (ui32Reg << 1) + DDI_O_MASK16B;
// Adjust for target bit in high half of the word.
if(ui32Mask & 0xFFFF0000)
{
ui32RegAddr += 4;
ui32Mask >>= 16;
}
// Write mask if data is not zero (to set mask bit), else write '0'.
ui32Data = ui32WrData ? ui32Mask : 0x0;
// Update the register.
HWREG(ui32RegAddr) = (ui32Mask << 16) | ui32Data;
}
void DDI16BitfieldWrite(uint32_t ui32Base, uint32_t ui32Reg, uint32_t ui32Mask, uint32_t ui32Shift, uint16_t ui32Data) {
uint32_t ui32RegAddr;
uint32_t ui32WrData;
// Check the arguments.
ASSERT(DDIBaseValid(ui32Base));
// 16-bit target is on 32-bit boundary so double offset.
ui32RegAddr = ui32Base + (ui32Reg << 1) + DDI_O_MASK16B;
// Adjust for target bit in high half of the word.
if(ui32Shift >= 16)
{
ui32Shift = ui32Shift - 16;
ui32RegAddr += 4;
ui32Mask = ui32Mask >> 16;
}
// Shift data in to position.
ui32WrData = ui32Data << ui32Shift;
// Write data.
HWREG(ui32RegAddr) = (ui32Mask << 16) | ui32WrData;
}
uint16_t DDI16BitRead(uint32_t ui32Base, uint32_t ui32Reg, uint32_t ui32Mask) {
uint32_t ui32RegAddr;
uint16_t ui16Data;
// Check the arguments.
ASSERT(DDIBaseValid(ui32Base));
// Calculate the address of the register.
ui32RegAddr = ui32Base + ui32Reg + DDI_O_DIR;
// Adjust for target bit in high half of the word.
if(ui32Mask & 0xFFFF0000)
{
ui32RegAddr += 2;
ui32Mask = ui32Mask >> 16;
}
// Read a halfword on the DDI interface.
ui16Data = HWREGH(ui32RegAddr);
// Mask data.
ui16Data = ui16Data & ui32Mask;
// Return masked data.
return(ui16Data);
}
uint16_t DDI16BitfieldRead(uint32_t ui32Base, uint32_t ui32Reg, uint32_t ui32Mask, uint32_t ui32Shift) {
uint32_t ui32RegAddr;
uint16_t ui16Data;
// Check the arguments.
ASSERT(DDIBaseValid(ui32Base));
// Calculate the register address.
ui32RegAddr = ui32Base + ui32Reg + DDI_O_DIR;
// Adjust for target bit in high half of the word.
if(ui32Shift >= 16)
{
ui32Shift = ui32Shift - 16;
ui32RegAddr += 2;
ui32Mask = ui32Mask >> 16;
}
// Read the register.
ui16Data = HWREGH(ui32RegAddr);
// Mask data and shift into place.
ui16Data &= ui32Mask;
ui16Data >>= ui32Shift;
// Return data.
return(ui16Data);
}
//*****************************************************************************
//
// Defines for accesses to the security control in the customer configuration
// area in flash top sector.
//
//*****************************************************************************
#define CCFG_OFFSET_SECURITY CCFG_O_BL_CONFIG
#define CCFG_OFFSET_SECT_PROT CCFG_O_CCFG_PROT_31_0
#define CCFG_SIZE_SECURITY 0x00000014
#define CCFG_SIZE_SECT_PROT 0x00000004
//*****************************************************************************
//
// Default values for security control in customer configuration area in flash
// top sector.
//
//*****************************************************************************
const uint8_t g_pui8CcfgDefaultSec[] = {0xFF, 0xFF, 0xFF, 0xC5,
0xFF, 0xFF, 0xFF, 0xFF,
0xC5, 0xFF, 0xFF, 0xFF,
0xC5, 0xC5, 0xC5, 0xFF,
0xC5, 0xC5, 0xC5, 0xFF
};
//*****************************************************************************
//
// Function prototypes for static functions
//
//*****************************************************************************
static void IssueFsmCommand(tFlashStateCommandsType eCommand);
static void EnableSectorsForWrite(void);
static uint32_t ScaleCycleValues(uint32_t ui32SpecifiedTiming,
uint32_t ui32ScaleValue);
static void SetWriteMode(void);
static void TrimForWrite(void);
static void SetReadMode(void);
void FlashPowerModeSet(uint32_t ui32PowerMode, uint32_t ui32BankGracePeriode, uint32_t ui32PumpGracePeriode) {
// Check the arguments.
ASSERT(ui32PowerMode == FLASH_PWR_ACTIVE_MODE ||
ui32PowerMode == FLASH_PWR_OFF_MODE ||
ui32PowerMode == FLASH_PWR_DEEP_STDBY_MODE);
ASSERT(ui32BankGracePeriode <= 0xFF);
ASSERT(ui32PumpGracePeriode <= 0xFFFF);
switch(ui32PowerMode)
{
case FLASH_PWR_ACTIVE_MODE:
// Set bank power mode to ACTIVE.
HWREG(FLASH_BASE + FLASH_O_FBFALLBACK) =
(HWREG(FLASH_BASE + FLASH_O_FBFALLBACK) &
~FLASH_FBFALLBACK_BANKPWR0_M) | FBFALLBACK_ACTIVE;
// Set charge pump power mode to ACTIVE mode.
HWREG(FLASH_BASE + FLASH_O_FPAC1) =
(HWREG(FLASH_BASE + FLASH_O_FPAC1) & ~FLASH_FPAC1_PUMPPWR_M) | (1 << FLASH_FPAC1_PUMPPWR_S);
break;
case FLASH_PWR_OFF_MODE:
// Set bank grace periode.
HWREG(FLASH_BASE + FLASH_O_FBAC) =
(HWREG(FLASH_BASE + FLASH_O_FBAC) & (~FLASH_FBAC_BAGP_M)) |
((ui32BankGracePeriode << FLASH_FBAC_BAGP_S) & FLASH_FBAC_BAGP_M);
// Set pump grace periode.
HWREG(FLASH_BASE + FLASH_O_FPAC2) =
(HWREG(FLASH_BASE + FLASH_O_FPAC2) & (~FLASH_FPAC2_PAGP_M)) |
((ui32PumpGracePeriode << FLASH_FPAC2_PAGP_S) & FLASH_FPAC2_PAGP_M);
// Set bank power mode to SLEEP.
HWREG(FLASH_BASE + FLASH_O_FBFALLBACK) &= ~FLASH_FBFALLBACK_BANKPWR0_M;
// Set charge pump power mode to SLEEP mode.
HWREG(FLASH_BASE + FLASH_O_FPAC1) &= ~FLASH_FPAC1_PUMPPWR_M;
break;
case FLASH_PWR_DEEP_STDBY_MODE:
// Set bank grace periode.
HWREG(FLASH_BASE + FLASH_O_FBAC) =
(HWREG(FLASH_BASE + FLASH_O_FBAC) & (~FLASH_FBAC_BAGP_M)) |
((ui32BankGracePeriode << FLASH_FBAC_BAGP_S) & FLASH_FBAC_BAGP_M);
// Set pump grace periode.
HWREG(FLASH_BASE + FLASH_O_FPAC2) =
(HWREG(FLASH_BASE + FLASH_O_FPAC2) & (~FLASH_FPAC2_PAGP_M)) |
((ui32PumpGracePeriode << FLASH_FPAC2_PAGP_S) & FLASH_FPAC2_PAGP_M);
// Set bank power mode to DEEP STANDBY mode.
HWREG(FLASH_BASE + FLASH_O_FBFALLBACK) =
(HWREG(FLASH_BASE + FLASH_O_FBFALLBACK) &
~FLASH_FBFALLBACK_BANKPWR0_M) | FBFALLBACK_DEEP_STDBY;
// Set charge pump power mode to STANDBY mode.
HWREG(FLASH_BASE + FLASH_O_FPAC1) |= FLASH_FPAC1_PUMPPWR_M;
break;
}
}
uint32_t FlashPowerModeGet(void) {
uint32_t ui32PowerMode;
uint32_t ui32BankPwrMode;
ui32BankPwrMode = HWREG(FLASH_BASE + FLASH_O_FBFALLBACK) &
FLASH_FBFALLBACK_BANKPWR0_M;
if(ui32BankPwrMode == FBFALLBACK_SLEEP)
{
ui32PowerMode = FLASH_PWR_OFF_MODE;
}
else if(ui32BankPwrMode == FBFALLBACK_DEEP_STDBY)
{
ui32PowerMode = FLASH_PWR_DEEP_STDBY_MODE;
}
else
{
ui32PowerMode = FLASH_PWR_ACTIVE_MODE;
}
// Return power mode.
return(ui32PowerMode);
}
void FlashProtectionSet(uint32_t ui32SectorAddress, uint32_t ui32ProtectMode) {
uint32_t ui32SectorNumber;
// Check the arguments.
ASSERT(ui32SectorAddress <= (FLASHMEM_BASE + FlashSizeGet() -
FlashSectorSizeGet()));
ASSERT((ui32SectorAddress & (FlashSectorSizeGet() - 1)) == 00);
if(ui32ProtectMode == FLASH_WRITE_PROTECT)
{
ui32SectorNumber = (ui32SectorAddress - FLASHMEM_BASE) /
FlashSectorSizeGet();
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
if(ui32SectorNumber <= 31)
{
HWREG(FLASH_BASE + FLASH_O_FSM_BSLE0) |= (1 << ui32SectorNumber);
HWREG(FLASH_BASE + FLASH_O_FSM_BSLP0) |= (1 << ui32SectorNumber);
}
else if(ui32SectorNumber <= 63)
{
HWREG(FLASH_BASE + FLASH_O_FSM_BSLE1) |=
(1 << (ui32SectorNumber & 0x1F));
HWREG(FLASH_BASE + FLASH_O_FSM_BSLP1) |=
(1 << (ui32SectorNumber & 0x1F));
}
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
}
}
uint32_t FlashProtectionGet(uint32_t ui32SectorAddress) {
uint32_t ui32SectorProtect;
uint32_t ui32SectorNumber;
// Check the arguments.
ASSERT(ui32SectorAddress <= (FLASHMEM_BASE + FlashSizeGet() -
FlashSectorSizeGet()));
ASSERT((ui32SectorAddress & (FlashSectorSizeGet() - 1)) == 00);
ui32SectorProtect = FLASH_NO_PROTECT;
ui32SectorNumber = (ui32SectorAddress - FLASHMEM_BASE) / FlashSectorSizeGet();
if(ui32SectorNumber <= 31)
{
if((HWREG(FLASH_BASE + FLASH_O_FSM_BSLE0) & (1 << ui32SectorNumber)) &&
(HWREG(FLASH_BASE + FLASH_O_FSM_BSLP0) & (1 << ui32SectorNumber)))
{
ui32SectorProtect = FLASH_WRITE_PROTECT;
}
}
else if(ui32SectorNumber <= 63)
{
if((HWREG(FLASH_BASE + FLASH_O_FSM_BSLE1) &
(1 << (ui32SectorNumber & 0x1F))) &&
(HWREG(FLASH_BASE + FLASH_O_FSM_BSLP1) &
(1 << (ui32SectorNumber & 0x1F))))
{
ui32SectorProtect = FLASH_WRITE_PROTECT;
}
}
return(ui32SectorProtect);
}
uint32_t FlashProtectionSave(uint32_t ui32SectorAddress) {
uint32_t ui32ErrorReturn;
uint32_t ui32SectorNumber;
uint32_t ui32CcfgSectorAddr;
uint32_t ui32ProgBuf;
ui32ErrorReturn = FAPI_STATUS_SUCCESS;
// Check the arguments.
ASSERT(ui32SectorAddress <= (FLASHMEM_BASE + FlashSizeGet() -
FlashSectorSizeGet()));
ASSERT((ui32SectorAddress & (FlashSectorSizeGet() - 1)) == 00);
if(FlashProtectionGet(ui32SectorAddress) == FLASH_WRITE_PROTECT)
{
// Find sector number for specified sector.
ui32SectorNumber = (ui32SectorAddress - FLASHMEM_BASE) / FlashSectorSizeGet();
ui32CcfgSectorAddr = FLASHMEM_BASE + FlashSizeGet() - FlashSectorSizeGet();
// Adjust CCFG address to the 32-bit CCFG word holding the
// protect-bit for the specified sector.
ui32CcfgSectorAddr += (((ui32SectorNumber >> 5) * 4) + CCFG_OFFSET_SECT_PROT);
// Find value to program by setting the protect-bit which
// corresponds to specified sector number, to 0.
// Leave other protect-bits unchanged.
ui32ProgBuf = (~(1 << (ui32SectorNumber & 0x1F))) &
*(uint32_t *)ui32CcfgSectorAddr;
ui32ErrorReturn = FlashProgram((uint8_t*)&ui32ProgBuf, ui32CcfgSectorAddr,
CCFG_SIZE_SECT_PROT);
}
// Return status.
return(ui32ErrorReturn);
}
uint32_t FlashSectorErase(uint32_t ui32SectorAddress) {
uint32_t ui32ErrorReturn;
uint32_t ui32Error;
uint32_t ui32SectorBit;
uint32_t ui32SectorNumber;
// Check the arguments.
ASSERT(ui32SectorAddress <= (FLASHMEM_BASE + FlashSizeGet() -
FlashSectorSizeGet()));
ASSERT((ui32SectorAddress & (FlashSectorSizeGet() - 1)) == 00);
// Enable all sectors for erase.
EnableSectorsForWrite();
// Check the arguments.
if((ui32SectorAddress >
(FLASHMEM_BASE + FlashSizeGet() - FlashSectorSizeGet())) ||
((ui32SectorAddress & (FlashSectorSizeGet() - 1)) != 00))
{
// Invalid arguments. Exit function!
FlashDisableSectorsForWrite();
return (FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH);
}
// Clear the Status register.
IssueFsmCommand(FAPI_CLEAR_STATUS);
// Unprotect sector to be erased.
ui32SectorNumber = (ui32SectorAddress - FLASHMEM_BASE) / FlashSectorSizeGet();
ui32SectorBit = 1 << (ui32SectorNumber & 0x1F);
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
if(ui32SectorNumber < 0x20)
{
HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR1) = ~ui32SectorBit;
}
else
{
HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR2) = ~ui32SectorBit;
}
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
// Write the address to the FSM.
HWREG(FLASH_BASE + FLASH_O_FADDR) = ui32SectorAddress + ADDR_OFFSET;
// Issue the sector erase command to the FSM.
IssueFsmCommand(FAPI_ERASE_SECTOR);
// Wait for erase to finish.
while(FlashCheckFsmForReady() == FAPI_STATUS_FSM_BUSY)
{
}
// Update status.
ui32ErrorReturn = FlashCheckFsmForError();
// Disable sectors for erase.
FlashDisableSectorsForWrite();
// Check if flash top sector was erased.
if(ui32SectorAddress == (FLASHMEM_BASE + FlashSizeGet() -
FlashSectorSizeGet()))
{
// Program security data to default values in the customer configuration
// area within the flash top sector.
ui32Error = FlashProgram((uint8_t *)g_pui8CcfgDefaultSec,
(ui32SectorAddress + CCFG_OFFSET_SECURITY),
CCFG_SIZE_SECURITY);
if((ui32Error != FAPI_STATUS_SUCCESS) &&
(ui32ErrorReturn == FAPI_STATUS_SUCCESS))
{
ui32ErrorReturn = ui32Error;
}
}
// Return status of operation.
return(ui32ErrorReturn);
}
uint32_t FlashBankErase(bool bForcePrecondition) {
uint32_t ui32ErrorReturn;
uint32_t ui32SectorAddress;
uint32_t ui32RegVal;
// Enable all sectors for erase.
EnableSectorsForWrite();
// Clear the Status register.
IssueFsmCommand(FAPI_CLEAR_STATUS);
// Enable erase of all sectors and enable precondition if required.
ui32RegVal = HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE);
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR1) = 0x00000000;
HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR2) = 0x00000000;
if(bForcePrecondition)
{
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |=
FLASH_FSM_ST_MACHINE_DO_PRECOND;
}
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
// Issue the bank erase command to the FSM.
IssueFsmCommand(FAPI_ERASE_BANK);
// Wait for erase to finish.
while(FlashCheckFsmForReady() == FAPI_STATUS_FSM_BUSY)
{
}
// Update status.
ui32ErrorReturn = FlashCheckFsmForError();
// Disable sectors for erase.
FlashDisableSectorsForWrite();
// Set configured precondition mode since it may have been forced on.
if(!(ui32RegVal & FLASH_FSM_ST_MACHINE_DO_PRECOND))
{
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &=
~FLASH_FSM_ST_MACHINE_DO_PRECOND;
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
}
// Program security data to default values in the customer configuration
// area within the flash top sector if erase was successful.
if(ui32ErrorReturn == FAPI_STATUS_SUCCESS)
{
ui32SectorAddress = FLASHMEM_BASE + FlashSizeGet() - FlashSectorSizeGet();
ui32ErrorReturn = FlashProgram((uint8_t *)g_pui8CcfgDefaultSec,
(ui32SectorAddress + CCFG_OFFSET_SECURITY),
CCFG_SIZE_SECURITY);
}
// Return status of operation.
return(ui32ErrorReturn);
}
uint32_t FlashhOtpEngrErase(void) {
uint32_t ui32ErrorReturn;
uint32_t ui32RegVal;
// Enable all sectors for erase.
EnableSectorsForWrite();
// Clear the Status register.
IssueFsmCommand(FAPI_CLEAR_STATUS);
// Disable OTP protection.
HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS;
HWREG(FLASH_BASE + FLASH_O_FBAC) |= FLASH_FBAC_OTPPROTDIS;
HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0;
// Enable test commands.
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA;
HWREG(FLASH_BASE + FLASH_O_FTCTL) |= FLASH_FTCTL_TEST_EN;
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA;
// Set address to OTP.
HWREG(FLASH_BASE + FLASH_O_FADDR) = 0xF0000000;
// Enable for FSM test commands and erase precondition.
ui32RegVal = HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE);
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |=
(FLASH_FSM_ST_MACHINE_CMD_EN | FLASH_FSM_ST_MACHINE_DO_PRECOND);
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
// Issue the erase command to the FSM.
IssueFsmCommand(FAPI_ERASE_OTP);
// Wait for erase to finish.
while(FlashCheckFsmForReady() == FAPI_STATUS_FSM_BUSY)
{
}
// Update status.
ui32ErrorReturn = FlashCheckFsmForError();
// Disable sectors for erase.
FlashDisableSectorsForWrite();
// Disable test commands.
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA;
HWREG(FLASH_BASE + FLASH_O_FTCTL) &= ~FLASH_FTCTL_TEST_EN;
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA;
// Renable OTP protection.
HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS;
HWREG(FLASH_BASE + FLASH_O_FBAC) &= ~FLASH_FBAC_OTPPROTDIS;
HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0;
// Disable FSM test command mode.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &= ~FLASH_FSM_ST_MACHINE_CMD_EN;
// Set configured precondition mode since it may have been changed.
if(!(ui32RegVal & FLASH_FSM_ST_MACHINE_DO_PRECOND))
{
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &=
~FLASH_FSM_ST_MACHINE_DO_PRECOND;
}
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
// Return status of operation.
return(ui32ErrorReturn);
}
uint32_t FlashProgram(uint8_t *pui8DataBuffer, uint32_t ui32Address, uint32_t ui32Count) {
uint32_t ui32StartIndex;
uint32_t ui32StopIndex;
uint32_t ui32Index;
uint8_t ui8BankWidth;
uint8_t ui8NoOfBytes;
tFwpWriteByte *oFwpWriteByte;
uint32_t ui32ErrorReturn;
// Check the arguments.
ASSERT((ui32Address + ui32Count) <= (FLASHMEM_BASE + FlashSizeGet()));
// Enable sectors for programming.
EnableSectorsForWrite();
oFwpWriteByte = FWPWRITE_BYTE_ADDRESS;
// Check the arguments.
if((ui32Address + ui32Count) > (FLASHMEM_BASE + FlashSizeGet()))
{
// Invalid arguments. Exit function!
FlashDisableSectorsForWrite();
return (FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH);
}
// Set the status to indicate success.
ui32ErrorReturn = FAPI_STATUS_SUCCESS;
// Find flash bank width in number of bytes.
ui8BankWidth =
(uint8_t)(((HWREG(FLASH_BASE + FLASH_O_FCFG_BANK) &
FLASH_FCFG_BANK_MAIN_BANK_WIDTH_M) >>
FLASH_FCFG_BANK_MAIN_BANK_WIDTH_S) >> 3);
// Loop over the bytes to be programmed.
while(ui32Count)
{
// Setup the start position within the write data registers.
ui32StartIndex = ui32Address & (uint32_t)(ui8BankWidth - 1);
// Setup number of bytes to program.
ui8NoOfBytes = ui8BankWidth - ui32StartIndex;
if(ui8NoOfBytes > ui32Count)
{
ui8NoOfBytes = ui32Count;
}
// Clear the Status register.
IssueFsmCommand(FAPI_CLEAR_STATUS);
// Write address to FADDR register.
HWREG(FLASH_BASE + FLASH_O_FADDR) = ui32Address + ADDR_OFFSET;
// Setup the stop position within the write data registers.
ui32StopIndex = ui32StartIndex + (uint32_t)(ui8NoOfBytes - 1);
// Write each byte to the FWPWrite registers.
for(ui32Index = ui32StartIndex; ui32Index <= ui32StopIndex; ui32Index++)
{
oFwpWriteByte[ui32Index] = *(pui8DataBuffer++);
}
// Issue the Program command to the FSM.
IssueFsmCommand(FAPI_PROGRAM_DATA);
// Wait until the word has been programmed.
while(FlashCheckFsmForReady() == FAPI_STATUS_FSM_BUSY)
{
}
// Exit if an access violation occurred.
ui32ErrorReturn = FlashCheckFsmForError();
if(ui32ErrorReturn != FAPI_STATUS_SUCCESS)
{
break;
}
// Prepare for next data burst.
ui32Count -= ((ui32StopIndex - ui32StartIndex) + 1);
ui32Address += ((ui32StopIndex - ui32StartIndex) + 1);
}
// Disable sectors for programming.
FlashDisableSectorsForWrite();
// Return status of operation.
return(ui32ErrorReturn);
}
uint32_t FlashProgramNowait(uint32_t ui32StartAddress, uint8_t *pui8DataBuffer, uint8_t ui8NoOfBytes) {
uint32_t ui32StartIndex;
uint32_t ui32StopIndex;
uint32_t ui32Index;
uint32_t ui32BankWidth;
uint32_t ui32ErrorReturn;
tFwpWriteByte *oFwpWriteByte;
// Check the arguments.
ASSERT((ui32StartAddress + ui8NoOfBytes) <= (FLASHMEM_BASE + FlashSizeGet()));
// Enable sectors for programming.
EnableSectorsForWrite();
oFwpWriteByte = FWPWRITE_BYTE_ADDRESS;
// Check the arguments.
if((ui32StartAddress + ui8NoOfBytes) > (FLASHMEM_BASE + FlashSizeGet()))
{
// Invalid arguments. Exit function!
FlashDisableSectorsForWrite();
return (FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH);
}
// Set status to indicate success
ui32ErrorReturn = FAPI_STATUS_SUCCESS;
// Find flash bank width in number of bytes.
ui32BankWidth = (((HWREG(FLASH_BASE + FLASH_O_FCFG_BANK) &
FLASH_FCFG_BANK_MAIN_BANK_WIDTH_M) >>
FLASH_FCFG_BANK_MAIN_BANK_WIDTH_S) >> 3);
// Setup the start position within the write data registers.
ui32StartIndex = ui32StartAddress & (ui32BankWidth - 1);
// Check to see if there is more data in the buffer than the register.
// width.
if((ui8NoOfBytes == 0) || ((ui32StartIndex + ui8NoOfBytes) > ui32BankWidth))
{
ui32ErrorReturn = FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH;
}
if(ui32ErrorReturn == FAPI_STATUS_SUCCESS)
{
// Clear the Status register.
IssueFsmCommand(FAPI_CLEAR_STATUS);
// Write address to FADDR register.
HWREG(FLASH_BASE + FLASH_O_FADDR) = ui32StartAddress + ADDR_OFFSET;
// Setup the stop position within the write data registers.
ui32StopIndex = ui32StartIndex + (uint32_t)(ui8NoOfBytes - 1);
// Write each byte to the FWPWrite registers.
for(ui32Index = ui32StartIndex; ui32Index <= ui32StopIndex; ui32Index++)
{
oFwpWriteByte[ui32Index] = *(pui8DataBuffer++);
}
// Issue the Program command to the FSM.
IssueFsmCommand(FAPI_PROGRAM_DATA);
}
// Return the function status.
return(ui32ErrorReturn);
}
bool FlashEfuseReadRow(uint32_t *pui32EfuseData, uint32_t ui32RowAddress) {
bool bStatus;
// Make sure the clock for the efuse is enabled
HWREG(FLASH_BASE + FLASH_O_CFG) &= ~FLASH_CFG_DIS_EFUSECLK;
// Set timing for EFUSE read operations.
HWREG(FLASH_BASE + FLASH_O_EFUSEREAD) |= ((5 << FLASH_EFUSEREAD_READCLOCK_S) &
FLASH_EFUSEREAD_READCLOCK_M);
// Clear status register.
HWREG(FLASH_BASE + FLASH_O_EFUSEERROR) = 0;
// Select the FuseROM block 0.
HWREG(FLASH_BASE + FLASH_O_EFUSEADDR) = 0x00000000;
// Start the read operation.
HWREG(FLASH_BASE + FLASH_O_EFUSE) =
(DUMPWORD_INSTR << FLASH_EFUSE_INSTRUCTION_S) |
(ui32RowAddress & FLASH_EFUSE_DUMPWORD_M);
// Wait for operation to finish.
while(!(HWREG(FLASH_BASE + FLASH_O_EFUSEERROR) & FLASH_EFUSEERROR_DONE))
{
}
// Check if error reported.
if(HWREG(FLASH_BASE + FLASH_O_EFUSEERROR) & FLASH_EFUSEERROR_CODE_M)
{
// Set error status.
bStatus = 1;
// Clear data.
*pui32EfuseData = 0;
}
else
{
// Set ok status.
bStatus = 0;
// No error. Get data from data register.
*pui32EfuseData = HWREG(FLASH_BASE + FLASH_O_DATALOWER);
}
// Disable the efuse clock to conserve power
HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_EFUSECLK;
// Return the data.
return(bStatus);
}
uint32_t FlashProgramPattern(uint32_t ui32SectorAddress, uint32_t ui32DataPattern, bool bInvertData) {
uint8_t ui8Index;
uint8_t ui8BankWidth;
tFwpWriteByte *oFwpWriteByte;
uint32_t ui32ErrorReturn;
// Check the arguments.
ASSERT(ui32SectorAddress <= (FLASHMEM_BASE + FlashSizeGet() -
FlashSectorSizeGet()));
ASSERT((ui32SectorAddress & (FlashSectorSizeGet() - 1)) == 00);
// Enable sectors for programming.
EnableSectorsForWrite();
oFwpWriteByte = FWPWRITE_BYTE_ADDRESS;
// Check the arguments.
if((ui32SectorAddress >
(FLASHMEM_BASE + FlashSizeGet() - FlashSectorSizeGet())) ||
((ui32SectorAddress & (FlashSectorSizeGet() - 1)) != 00))
{
// Invalid arguments. Exit function!
FlashDisableSectorsForWrite();
return (FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH);
}
// Find flash bank width in number of bytes.
ui8BankWidth =
(uint8_t)(((HWREG(FLASH_BASE + FLASH_O_FCFG_BANK) &
FLASH_FCFG_BANK_MAIN_BANK_WIDTH_M) >>
FLASH_FCFG_BANK_MAIN_BANK_WIDTH_S) >> 3);
// Clear the Status register.
IssueFsmCommand(FAPI_CLEAR_STATUS);
// Write address to FADDR register.
HWREG(FLASH_BASE + FLASH_O_FADDR) = ui32SectorAddress + ADDR_OFFSET;
// Write each byte of the pattern to the FWPWrite registers.
for(ui8Index = 0; ui8Index < ui8BankWidth; ui8Index++)
{
oFwpWriteByte[ui8Index] = ui32DataPattern >> ((ui8Index * 8) &
(PATTERN_BITS - 1));
}
// Enable for FSM test command and enable the Invert Data option if
// required.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |= FLASH_FSM_ST_MACHINE_CMD_EN;
if(bInvertData)
{
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |= FLASH_FSM_ST_MACHINE_INV_DATA;
}
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
// Issue the Program command to the FSM.
IssueFsmCommand(FAPI_PROGRAM_SECTOR);
// Wait until the sector has been programmed.
while(FlashCheckFsmForReady() == FAPI_STATUS_FSM_BUSY)
{
}
// Update status of the program operation.
ui32ErrorReturn = FlashCheckFsmForError();
// Disable sectors for programming.
FlashDisableSectorsForWrite();
// Disable FSM test command mode and the Invert Data option.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &= ~FLASH_FSM_ST_MACHINE_CMD_EN;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &= ~FLASH_FSM_ST_MACHINE_INV_DATA;
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
// Return status of operation.
return(ui32ErrorReturn);
}
uint32_t FlashProgramEngr(uint8_t *pui8DataBuffer, uint32_t ui32AddressOffset, uint32_t ui32Count) {
uint32_t ui32StartIndex;
uint32_t ui32StopIndex;
uint32_t ui32Index;
uint8_t ui8BankWidth;
uint8_t ui8NoOfBytes;
tFwpWriteByte *oFwpWriteByte;
uint32_t ui32ErrorReturn;
// Check the arguments.
ASSERT((ui32AddressOffset + ui32Count) <= 2048);
// Enable sectors for programming.
EnableSectorsForWrite();
oFwpWriteByte = FWPWRITE_BYTE_ADDRESS;
// Check the arguments.
if((ui32AddressOffset + ui32Count) > 2048)
{
// Invalid arguments. Exit function!
FlashDisableSectorsForWrite();
return (FAPI_STATUS_INCORRECT_DATABUFFER_LENGTH);
}
// Set the status to indicate success.
ui32ErrorReturn = FAPI_STATUS_SUCCESS;
// Find flash bank width in number of bytes.
ui8BankWidth =
(uint8_t)(((HWREG(FLASH_BASE + FLASH_O_FCFG_BANK) &
FLASH_FCFG_BANK_MAIN_BANK_WIDTH_M) >>
FLASH_FCFG_BANK_MAIN_BANK_WIDTH_S) >> 3);
// Disable OTP protection.
HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS;
HWREG(FLASH_BASE + FLASH_O_FBAC) |= FLASH_FBAC_OTPPROTDIS;
HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0;
// Enable test commands.
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA;
HWREG(FLASH_BASE + FLASH_O_FTCTL) |= FLASH_FTCTL_TEST_EN;
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA;
// Enable for FSM test command.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |= FLASH_FSM_ST_MACHINE_CMD_EN;
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
// Loop over the bytes to be programmed.
while(ui32Count)
{
// Setup the start position within the write data registers.
ui32StartIndex = ui32AddressOffset & (uint32_t)(ui8BankWidth - 1);
// Setup number of bytes to program.
ui8NoOfBytes = ui8BankWidth - ui32StartIndex;
if(ui8NoOfBytes > ui32Count)
{
ui8NoOfBytes = ui32Count;
}
// Clear the Status register.
IssueFsmCommand(FAPI_CLEAR_STATUS);
// Write address to FADDR register.
HWREG(FLASH_BASE + FLASH_O_FADDR) = ui32AddressOffset + 0xF0080000;
// Setup the stop position within the write data registers.
ui32StopIndex = ui32StartIndex + (uint32_t)(ui8NoOfBytes - 1);
// Write each byte to the FWPWrite registers.
for(ui32Index = ui32StartIndex; ui32Index <= ui32StopIndex; ui32Index++)
{
oFwpWriteByte[ui32Index] = *(pui8DataBuffer++);
}
// Issue programming command.
IssueFsmCommand(FAPI_PROGRAM_DATA);
// Wait until the word has been programmed.
while(FlashCheckFsmForReady() == FAPI_STATUS_FSM_BUSY)
{
}
// Update error status and exit if an error occurred.
ui32ErrorReturn = FlashCheckFsmForError();
if(ui32ErrorReturn != FAPI_STATUS_SUCCESS)
{
break;
}
// Prepare for next data burst.
ui32Count -= ((ui32StopIndex - ui32StartIndex) + 1);
ui32AddressOffset += ((ui32StopIndex - ui32StartIndex) + 1);
}
// Disable sectors for programming.
FlashDisableSectorsForWrite();
// Reenable OTP protection.
HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS;
HWREG(FLASH_BASE + FLASH_O_FBAC) &= ~FLASH_FBAC_OTPPROTDIS;
HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0;
// Disable test commands.
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA;
HWREG(FLASH_BASE + FLASH_O_FTCTL) &= ~FLASH_FTCTL_TEST_EN;
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA;
// Disable FSM test command mode.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &= ~FLASH_FSM_ST_MACHINE_CMD_EN;
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
// Return status of operation.
return(ui32ErrorReturn);
}
void FlashOtpProgramEraseSetup(void) {
// Disable OTP protection.
HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS;
HWREG(FLASH_BASE + FLASH_O_FBAC) |= FLASH_FBAC_OTPPROTDIS;
HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0;
// Enable test commands by performing the following steps:
// - Enable SW Interface mode
// - Enable for test commands
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x0000AAAA;
HWREG(FLASH_BASE + FLASH_O_FTCTL) |= FLASH_FTCTL_TEST_EN;
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x000055AA;
// Enable for FSM test commands.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |= FLASH_FSM_ST_MACHINE_CMD_EN;
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
}
void FlashOtpProgramEraseCleanup(void) {
// Reenable OTP protection.
HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS;
HWREG(FLASH_BASE + FLASH_O_FBAC) &= ~FLASH_FBAC_OTPPROTDIS;
HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0;
// Disable test commands and turn off SW interface mode.
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x0000AAAA;
HWREG(FLASH_BASE + FLASH_O_FTCTL) &= ~FLASH_FTCTL_TEST_EN;
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA;
// Disable FSM test command mode.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &= ~FLASH_FSM_ST_MACHINE_CMD_EN;
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
}
void FlashDisableSectorsForWrite(void) {
// Configure flash back to read mode
SetReadMode();
// Disable Level 1 Protection.
HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS;
// Disable all sectors for erase and programming.
HWREG(FLASH_BASE + FLASH_O_FBSE) = 0x0000;
// Enable Level 1 Protection.
HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0;
// Protect sectors from sector erase.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR1) = 0xFFFFFFFF;
HWREG(FLASH_BASE + FLASH_O_FSM_SECTOR2) = 0xFFFFFFFF;
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
}
//*****************************************************************************
//
//! \internal
//! Issues a command to the Flash State Machine.
//!
//! \param eCommand specifies the FSM command.
//!
//! Issues a command to the Flash State Machine.
//!
//! \return None
//
//*****************************************************************************
static void
IssueFsmCommand(tFlashStateCommandsType eCommand)
{
// Check the arguments.
ASSERT(
eCommand == FAPI_ERASE_SECTOR || eCommand == FAPI_ERASE_BANK ||
eCommand == FAPI_VALIDATE_SECTOR || eCommand == FAPI_CLEAR_STATUS ||
eCommand == FAPI_PROGRAM_RESUME || eCommand == FAPI_ERASE_RESUME ||
eCommand == FAPI_CLEAR_MORE || eCommand == FAPI_PROGRAM_SECTOR ||
eCommand == FAPI_PROGRAM_DATA || eCommand == FAPI_ERASE_OTP);
// Enable write to FSM register.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
// Issue FSM command.
HWREG(FLASH_BASE + FLASH_O_FSM_CMD) = eCommand;
// Start command execute.
HWREG(FLASH_BASE + FLASH_O_FSM_EXECUTE) = FLASH_CMD_EXEC;
// Disable write to FSM register.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
}
//*****************************************************************************
//
//! \internal
//! Enables all sectors for erase and programming on the active bank.
//!
//! This function disables the idle reading power reduction mode, selects the
//! flash bank and enables all sectors for erase and programming on the active
//! bank.
//! Sectores may be protected from programming depending on the value of the
//! FLASH_O_FSM_BSLPx registers.
//! Sectores may be protected from erase depending on the value of the
//! FLASH_O_FSM_BSLEx registers. Additional sector erase protection is set by
//! the FLASH_O_FSM_SECTOR1 register.
//!
//! \return None
//
//*****************************************************************************
static void
EnableSectorsForWrite(void)
{
// Trim flash module for program/erase operation.
TrimForWrite();
// Configure flash to write mode
SetWriteMode();
// Select flash bank.
HWREG(FLASH_BASE + FLASH_O_FMAC) = 0x00;
// Disable Level 1 Protection.
HWREG(FLASH_BASE + FLASH_O_FBPROT) = FLASH_FBPROT_PROTL1DIS;
// Enable all sectors for erase and programming.
HWREG(FLASH_BASE + FLASH_O_FBSE) = 0xFFFF;
// Enable Level 1 Protection
HWREG(FLASH_BASE + FLASH_O_FBPROT) = 0;
}
//*****************************************************************************
//
//! \internal
//! Trims the Flash Bank and Flash Pump for program/erase functionality
//!
//! This trimming will make it possible to perform erase and program operations
//! of the flash. Trim values are loaded from factory configuration area
//! (referred to as FCGF1). The trimming done by this function is valid until
//! reset of the flash module.
//!
//! Some registers shall be written with a value that is a number of FCLK
//! cycles. The trim values controlling these registers have a value of
//! number of half us. FCLK = SysClk / ((RWAIT+1) x 2).
//! In order to calculate the register value for these registers the
//! following calculation must be done:
//!
//! OtpValue SysClkMHz
//! -------- us OtpValue x ---------
//! 2 (RWAIT+1)
//! RegValue_in_no_of_clk_cycles = ----------------- = ---------------------
//! 1 4
//! --------------
//! SysClkMHz
//! ------------
//! (RWAIT+1)x 2
//!
//! This is equevivalent to:
//!
//! 16 x SysClkMHz
//! OtpValue x ---------------
//! (RWAIT+1)
//! RegValue_in_no_of_clk_cycles = ----------------------------
//! 64
//!
//! 16 x SysClkMHz
//! A scaling factor is set equal to: ui32FclkScale = --------------
//! (RWAIT+1)
//!
//! which gives:
//! OtpValue x ui32FclkScale
//! RegValue_in_no_of_clk_cycles = ------------------------
//! 64
//!
//! \return None.
//
//*****************************************************************************
static void
TrimForWrite(void)
{
uint32_t ui32Value;
uint32_t ui32TempVal;
uint32_t ui32FclkScale;
uint32_t ui32RWait;
// Return if flash is already trimmed for program/erase operations.
if(HWREG(FLASH_BASE + FLASH_O_FWFLAG) & FW_WRT_TRIMMED)
{
return;
}
//***********************************************************************//
// //
// Configure the FSM registers //
// //
//***********************************************************************//
// Enable access to the FSM registers.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_ENABLE;
// Determine the scaling value to be used on timing related trim values.
// The scaling value is based on the flash module clock frequency and RWAIT
ui32RWait = (HWREG(FLASH_BASE + FLASH_O_FRDCTL) &
FLASH_FRDCTL_RWAIT_M) >> FLASH_FRDCTL_RWAIT_S;
ui32FclkScale = (16 * FLASH_MODULE_CLK_FREQ) / (ui32RWait + 1);
// Configure Program puls width bits 15:0.
// (FCFG1 offset 0x188 bits 15:0).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PROG_EP) &
FCFG1_FLASH_PROG_EP_PROGRAM_PW_M) >>
FCFG1_FLASH_PROG_EP_PROGRAM_PW_S;
ui32Value = ScaleCycleValues(ui32Value, ui32FclkScale);
HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PW) =
(HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PW) &
~FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_M) |
((ui32Value << FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_S) &
FLASH_FSM_PRG_PW_PROG_PUL_WIDTH_M);
// Configure Erase puls width bits 31:0.
// (FCFG1 offset 0x18C bits 31:0).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_ERA_PW) &
FCFG1_FLASH_ERA_PW_ERASE_PW_M) >>
FCFG1_FLASH_ERA_PW_ERASE_PW_S;
ui32Value = ScaleCycleValues(ui32Value, ui32FclkScale);
HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PW) =
(HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PW) &
~FLASH_FSM_ERA_PW_FSM_ERA_PW_M) |
((ui32Value << FLASH_FSM_ERA_PW_FSM_ERA_PW_S) &
FLASH_FSM_ERA_PW_FSM_ERA_PW_M);
// Configure no of flash clock cycles from EXECUTEZ going low to the
// verify data can be read in the program verify mode bits 7:0.
// (FCFG1 offset 0x174 bits 23:16).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) &
FCFG1_FLASH_C_E_P_R_PV_ACCESS_M) >>
FCFG1_FLASH_C_E_P_R_PV_ACCESS_S;
ui32Value = ScaleCycleValues(ui32Value, ui32FclkScale);
HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) =
(HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) &
~FLASH_FSM_EX_VAL_EXE_VALD_M) |
((ui32Value << FLASH_FSM_EX_VAL_EXE_VALD_S) &
FLASH_FSM_EX_VAL_EXE_VALD_M);
// Configure the number of flash clocks from the start of the Read mode at
// the end of the operations until the FSM clears the BUSY bit in FMSTAT.
// (FCFG1 offset 0x178 bits 23:16).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) &
FCFG1_FLASH_P_R_PV_RH_M) >>
FCFG1_FLASH_P_R_PV_RH_S;
HWREG(FLASH_BASE + FLASH_O_FSM_RD_H) =
(HWREG(FLASH_BASE + FLASH_O_FSM_RD_H) &
~FLASH_FSM_RD_H_RD_H_M) |
((ui32Value << FLASH_FSM_RD_H_RD_H_S) &
FLASH_FSM_RD_H_RD_H_M);
// Configure Program hold time
// (FCFG1 offset 0x178 bits 31:24).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) &
FCFG1_FLASH_P_R_PV_PH_M) >>
FCFG1_FLASH_P_R_PV_PH_S;
ui32Value = ScaleCycleValues(ui32Value, ui32FclkScale);
HWREG(FLASH_BASE + FLASH_O_FSM_P_OH) =
(HWREG(FLASH_BASE + FLASH_O_FSM_P_OH) &
~FLASH_FSM_P_OH_PGM_OH_M) |
((ui32Value << FLASH_FSM_P_OH_PGM_OH_S) &
FLASH_FSM_P_OH_PGM_OH_M);
// Configure Erase hold time
// (FCFG1 offset 0x17C bits 31:24).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_EH_SEQ) &
FCFG1_FLASH_EH_SEQ_EH_M) >>
FCFG1_FLASH_EH_SEQ_EH_S;
ui32Value = ScaleCycleValues(ui32Value, ui32FclkScale);
HWREG(FLASH_BASE + FLASH_O_FSM_ERA_OH) =
(HWREG(FLASH_BASE + FLASH_O_FSM_ERA_OH) &
~FLASH_FSM_ERA_OH_ERA_OH_M) |
((ui32Value << FLASH_FSM_ERA_OH_ERA_OH_S) &
FLASH_FSM_ERA_OH_ERA_OH_M);
// Configure Program verify row switch time
// (FCFG1 offset0x178 bits 15:8).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_P_R_PV) &
FCFG1_FLASH_P_R_PV_PVH_M) >>
FCFG1_FLASH_P_R_PV_PVH_S;
ui32Value = ScaleCycleValues(ui32Value, ui32FclkScale);
HWREG(FLASH_BASE + FLASH_O_FSM_PE_VH) =
(HWREG(FLASH_BASE + FLASH_O_FSM_PE_VH) &
~FLASH_FSM_PE_VH_PGM_VH_M) |
((ui32Value << FLASH_FSM_PE_VH_PGM_VH_S) &
FLASH_FSM_PE_VH_PGM_VH_M);
// Configure Program Operation Setup time
// (FCFG1 offset 0x170 bits 31:24).
ui32Value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) &
FCFG1_FLASH_E_P_PSU_M) >>
FCFG1_FLASH_E_P_PSU_S;
HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) =
(HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) &
~FLASH_FSM_PE_OSU_PGM_OSU_M) |
((ui32Value << FLASH_FSM_PE_OSU_PGM_OSU_S) &
FLASH_FSM_PE_OSU_PGM_OSU_M);
// Configure Erase Operation Setup time
// (FCGF1 offset 0x170 bits 23:16).
ui32Value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) &
FCFG1_FLASH_E_P_ESU_M) >>
FCFG1_FLASH_E_P_ESU_S;
HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) =
(HWREG(FLASH_BASE + FLASH_O_FSM_PE_OSU) &
~FLASH_FSM_PE_OSU_ERA_OSU_M) |
((ui32Value << FLASH_FSM_PE_OSU_ERA_OSU_S) &
FLASH_FSM_PE_OSU_ERA_OSU_M);
// Confgure Program Verify Setup time
// (FCFG1 offset 0x170 bits 15:8).
ui32Value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) &
FCFG1_FLASH_E_P_PVSU_M) >>
FCFG1_FLASH_E_P_PVSU_S;
HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) =
(HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) &
~FLASH_FSM_PE_VSU_PGM_VSU_M) |
((ui32Value << FLASH_FSM_PE_VSU_PGM_VSU_S) &
FLASH_FSM_PE_VSU_PGM_VSU_M);
// Configure Erase Verify Setup time
// (FCFG1 offset 0x170 bits 7:0).
ui32Value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_E_P) &
FCFG1_FLASH_E_P_EVSU_M) >>
FCFG1_FLASH_E_P_EVSU_S;
HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) =
(HWREG(FLASH_BASE + FLASH_O_FSM_PE_VSU) &
~FLASH_FSM_PE_VSU_ERA_VSU_M) |
((ui32Value << FLASH_FSM_PE_VSU_ERA_VSU_S) &
FLASH_FSM_PE_VSU_ERA_VSU_M);
// Configure Addr to EXECUTEZ low setup time
// (FCFG1 offset 0x174 bits 15:12).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) &
FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_M) >>
FCFG1_FLASH_C_E_P_R_A_EXEZ_SETUP_S;
HWREG(FLASH_BASE + FLASH_O_FSM_CMP_VSU) =
(HWREG(FLASH_BASE + FLASH_O_FSM_CMP_VSU) &
~FLASH_FSM_CMP_VSU_ADD_EXZ_M) |
((ui32Value << FLASH_FSM_CMP_VSU_ADD_EXZ_S) &
FLASH_FSM_CMP_VSU_ADD_EXZ_M);
// Configure Voltage Status Count
// (FCFG1 offset 0x17C bits 15:12).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_EH_SEQ) &
FCFG1_FLASH_EH_SEQ_VSTAT_M) >>
FCFG1_FLASH_EH_SEQ_VSTAT_S;
HWREG(FLASH_BASE + FLASH_O_FSM_VSTAT) =
(HWREG(FLASH_BASE + FLASH_O_FSM_VSTAT) &
~FLASH_FSM_VSTAT_VSTAT_CNT_M) |
((ui32Value << FLASH_FSM_VSTAT_VSTAT_CNT_S) &
FLASH_FSM_VSTAT_VSTAT_CNT_M);
// Configure Repeat Verify action setup
// (FCFG1 offset 0x174 bits 31:24).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_C_E_P_R) &
FCFG1_FLASH_C_E_P_R_RVSU_M) >>
FCFG1_FLASH_C_E_P_R_RVSU_S;
HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) =
(HWREG(FLASH_BASE + FLASH_O_FSM_EX_VAL) &
~FLASH_FSM_EX_VAL_REP_VSU_M) |
((ui32Value << FLASH_FSM_EX_VAL_REP_VSU_S) &
FLASH_FSM_EX_VAL_REP_VSU_M);
// Configure Maximum Programming Pulses
// (FCFG1 offset 0x184 bits 15:0).
ui32Value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PP) &
FCFG1_FLASH_PP_MAX_PP_M) >>
FCFG1_FLASH_PP_MAX_PP_S;
HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) =
(HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) &
~FLASH_FSM_PRG_PUL_MAX_PRG_PUL_M) |
((ui32Value << FLASH_FSM_PRG_PUL_MAX_PRG_PUL_S) &
FLASH_FSM_PRG_PUL_MAX_PRG_PUL_M);
// Configure Beginning level for VHVCT used during erase modes
// (FCFG1 offset 0x180 bits 31:16).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_E) &
FCFG1_FLASH_VHV_E_VHV_E_START_M) >>
FCFG1_FLASH_VHV_E_VHV_E_START_S;
HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) =
(HWREG(FLASH_BASE + FLASH_O_FSM_PRG_PUL) &
~FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_M) |
((ui32Value << FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_S) &
FLASH_FSM_PRG_PUL_BEG_EC_LEVEL_M);
// Configure Maximum EC Level
// (FCFG1 offset 0x2B0 bits 21:18).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) &
FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_M) >>
FCFG1_FLASH_OTP_DATA3_MAX_EC_LEVEL_S;
HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) =
(HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) &
~FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_M) |
((ui32Value << FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_S) &
FLASH_FSM_ERA_PUL_MAX_EC_LEVEL_M);
// Configure Maximum Erase Pulses
// (FCFG1 offset 0x188 bits 31:16).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_PROG_EP) &
FCFG1_FLASH_PROG_EP_MAX_EP_M) >>
FCFG1_FLASH_PROG_EP_MAX_EP_S;
HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) =
(HWREG(FLASH_BASE + FLASH_O_FSM_ERA_PUL) &
~FLASH_FSM_ERA_PUL_MAX_ERA_PUL_M) |
((ui32Value << FLASH_FSM_ERA_PUL_MAX_ERA_PUL_S) &
FLASH_FSM_ERA_PUL_MAX_ERA_PUL_M);
// Configure the VHVCT Step Size. This is the number of erase pulses that
// must be completed for each level before the FSM increments the
// CUR_EC_LEVEL to the next higher level. Actual erase pulses per level
// equals (EC_STEP_SIZE +1). The stepping is only needed for the VHVCT
// voltage.
// (FCFG1 offset 0x2B0 bits 31:23).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) &
FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_M) >>
FCFG1_FLASH_OTP_DATA3_EC_STEP_SIZE_S;
HWREG(FLASH_BASE + FLASH_O_FSM_STEP_SIZE) =
(HWREG(FLASH_BASE + FLASH_O_FSM_STEP_SIZE) &
~FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_M) |
((ui32Value << FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_S) &
FLASH_FSM_STEP_SIZE_EC_STEP_SIZE_M);
// Configure the hight of each EC step. This is the number of counts that
// the CUR_EC_LEVEL will increment when going to a new level. Actual count
// size equals (EC_STEP_HEIGHT + 1). The stepping applies only to the VHVCT
// voltage.
// The read trim value is decremented by 1 before written to the register
// since actual counts equals (register value + 1).
// (FCFG1 offset 0x180 bits 15:0).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_E) &
FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_M) >>
FCFG1_FLASH_VHV_E_VHV_E_STEP_HIGHT_S;
HWREG(FLASH_BASE + FLASH_O_FSM_EC_STEP_HEIGHT) = ((ui32Value - 1) &
FLASH_FSM_EC_STEP_HEIGHT_EC_STEP_HEIGHT_M);
// Configure Precondition used in erase operations
// (FCFG1 offset 0x2B0 bit 22).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) &
FCFG1_FLASH_OTP_DATA3_DO_PRECOND_M) >>
FCFG1_FLASH_OTP_DATA3_DO_PRECOND_S;
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) =
(HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) &
~FLASH_FSM_ST_MACHINE_DO_PRECOND_M) |
((ui32Value << FLASH_FSM_ST_MACHINE_DO_PRECOND_S) &
FLASH_FSM_ST_MACHINE_DO_PRECOND_M);
// Enable the recommended Good Time function.
HWREG(FLASH_BASE + FLASH_O_FSM_ST_MACHINE) |=
FLASH_FSM_ST_MACHINE_ONE_TIME_GOOD;
// Disable write access to FSM registers.
HWREG(FLASH_BASE + FLASH_O_FSM_WR_ENA) = FSM_REG_WRT_DISABLE;
//***********************************************************************//
// //
// Configure the voltage registers //
// //
//***********************************************************************//
// Unlock voltage registers (0x2080 - 0x2098).
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA;
// Configure voltage level for the specified pump voltage of high
// voltage supply input during erase operation VHVCT_E and the TRIM13_E
// (FCFG1 offset 0x190 bits[3:0] and bits[11:8]).
ui32TempVal = HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV);
ui32Value = ((ui32TempVal & FCFG1_FLASH_VHV_TRIM13_E_M)>>
FCFG1_FLASH_VHV_TRIM13_E_S) << FLASH_FVHVCT1_TRIM13_E_S;
ui32Value |= ((ui32TempVal & FCFG1_FLASH_VHV_VHV_E_M)>>
FCFG1_FLASH_VHV_VHV_E_S) << FLASH_FVHVCT1_VHVCT_E_S;
HWREG(FLASH_BASE + FLASH_O_FVHVCT1) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT1) &
~(FLASH_FVHVCT1_TRIM13_E_M | FLASH_FVHVCT1_VHVCT_E_M)) | ui32Value;
// Configure voltage level for the specified pump voltage of high voltage
// supply input during program verify operation VHVCT_PV and the TRIM13_PV
// (OTP offset 0x194 bits[19:16] and bits[27:24]).
ui32TempVal =
HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_PV);
ui32Value = ((ui32TempVal & FCFG1_FLASH_VHV_PV_TRIM13_PV_M)>>
FCFG1_FLASH_VHV_PV_TRIM13_PV_S) <<
FLASH_FVHVCT1_TRIM13_PV_S;
ui32Value |= ((ui32TempVal & FCFG1_FLASH_VHV_PV_VHV_PV_M)>>
FCFG1_FLASH_VHV_PV_VHV_PV_S) <<
FLASH_FVHVCT1_VHVCT_PV_S;
HWREG(FLASH_BASE + FLASH_O_FVHVCT1) = (HWREG(FLASH_BASE + FLASH_O_FVHVCT1) &
~(FLASH_FVHVCT1_TRIM13_PV_M | FLASH_FVHVCT1_VHVCT_PV_M)) | ui32Value;
// Configure voltage level for the specified pump voltage of high voltage
// supply input during program operation VHVCT_P and TRIM13_P
// (FCFG1 offset 0x190 bits[19:16] and bits[27:24]).
ui32TempVal =
HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV);
ui32Value = ((ui32TempVal & FCFG1_FLASH_VHV_TRIM13_P_M)>>
FCFG1_FLASH_VHV_TRIM13_P_S) << FLASH_FVHVCT2_TRIM13_P_S;
ui32Value |= ((ui32TempVal & FCFG1_FLASH_VHV_VHV_P_M)>>
FCFG1_FLASH_VHV_VHV_P_S) << FLASH_FVHVCT2_VHVCT_P_S;
HWREG(FLASH_BASE + FLASH_O_FVHVCT2) =
(HWREG(FLASH_BASE + FLASH_O_FVHVCT2) &
~(FLASH_FVHVCT2_TRIM13_P_M | FLASH_FVHVCT2_VHVCT_P_M)) | ui32Value;
// Configure voltage level for the specified pump voltage of wordline power
// supply for read mode
// (FCFG1 offset 0x198 Bits 15:8).
ui32Value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) &
FCFG1_FLASH_V_V_READ_M) >>
FCFG1_FLASH_V_V_READ_S;
HWREG(FLASH_BASE + FLASH_O_FVREADCT) =
(HWREG(FLASH_BASE + FLASH_O_FVREADCT) &
~FLASH_FVREADCT_VREADCT_M) |
((ui32Value << FLASH_FVREADCT_VREADCT_S) &
FLASH_FVREADCT_VREADCT_M);
// Configure the voltage level for the VCG 2.5 CT pump voltage
// (FCFG1 offset 0x194 bits 15:8).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_VHV_PV) &
FCFG1_FLASH_VHV_PV_VCG2P5_M) >>
FCFG1_FLASH_VHV_PV_VCG2P5_S;
HWREG(FLASH_BASE + FLASH_O_FVNVCT) =
(HWREG(FLASH_BASE + FLASH_O_FVNVCT) &
~FLASH_FVNVCT_VCG2P5CT_M) |
((ui32Value << FLASH_FVNVCT_VCG2P5CT_S) &
FLASH_FVNVCT_VCG2P5CT_M);
// Configure the voltage level for the specified pump voltage of high
// current power input during program operation
// (FCFG1 offset 0x198 bits 31:24).
ui32Value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) &
FCFG1_FLASH_V_VSL_P_M) >>
FCFG1_FLASH_V_VSL_P_S;
HWREG(FLASH_BASE + FLASH_O_FVSLP) =
(HWREG(FLASH_BASE + FLASH_O_FVSLP) &
~FLASH_FVSLP_VSL_P_M) |
((ui32Value << FLASH_FVSLP_VSL_P_S) &
FLASH_FVSLP_VSL_P_M);
// Configure the voltage level for the specified pump voltage of wordline
// power supply during programming operations
// (OTP offset 0x198 bits 23:16).
ui32Value = (HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_V) &
FCFG1_FLASH_V_VWL_P_M) >>
FCFG1_FLASH_V_VWL_P_S;
HWREG(FLASH_BASE + FLASH_O_FVWLCT) =
(HWREG(FLASH_BASE + FLASH_O_FVWLCT) &
~FLASH_FVWLCT_VWLCT_P_M) |
((ui32Value << FLASH_FVWLCT_VWLCT_P_S) &
FLASH_FVWLCT_VWLCT_P_M);
// Configure the pump's TRIM_1P7 port pins.
// (FCFG1 offset 0x2B0 bits 17:16).
ui32Value =
(HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA3) &
FCFG1_FLASH_OTP_DATA3_TRIM_1P7_M) >>
FCFG1_FLASH_OTP_DATA3_TRIM_1P7_S;
HWREG(FLASH_BASE + FLASH_O_FSEQPMP) =
(HWREG(FLASH_BASE + FLASH_O_FSEQPMP) &
~FLASH_FSEQPMP_TRIM_1P7_M) |
((ui32Value << FLASH_FSEQPMP_TRIM_1P7_S) &
FLASH_FSEQPMP_TRIM_1P7_M);
// Lock the voltage registers.
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA;
// Set trimmed flag.
HWREG(FLASH_BASE + FLASH_O_FWLOCK) = 5;
HWREG(FLASH_BASE + FLASH_O_FWFLAG) |= FW_WRT_TRIMMED;
HWREG(FLASH_BASE + FLASH_O_FWLOCK) = 0;
}
//*****************************************************************************
//
//! \internal
//! Used to scale the TI OTP values based on the FClk scaling value.
//!
//! \param ui32SpecifiedTiming
//! \param ui32ScaleValue
//!
//! Used to scale the TI OTP values based on the FClk scaling value.
//!
//! \return Returns the scaled value
//
//*****************************************************************************
static uint32_t
ScaleCycleValues(uint32_t ui32SpecifiedTiming, uint32_t ui32ScaleValue)
{
return((ui32SpecifiedTiming * ui32ScaleValue) >> 6);
}
//*****************************************************************************
//
//! \internal
//! Used to set flash in read mode.
//!
//! Flash is configured with values loaded from OTP dependent on the current
//! regulator mode.
//!
//! \return None.
//
//*****************************************************************************
static void
SetReadMode(void)
{
uint32_t ui32TrimValue;
uint32_t ui32Value;
// Configure the STANDBY_MODE_SEL, STANDBY_PW_SEL, DIS_STANDBY, DIS_IDLE,
// VIN_AT_X and VIN_BY_PASS for read mode
if(HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) &
AON_PMCTL_PWRCTL_EXT_REG_MODE)
{
// Select trim values for external regulator mode:
// Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 7)
// COnfigure STANDBY_PW_SEL (OTP offset 0x308 bit 6:5)
// Must be done while the register bit field CONFIG.DIS_STANDBY = 1
HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY;
ui32TrimValue =
HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4);
ui32Value = ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_M) >>
FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_RD_S) <<
FLASH_CFG_STANDBY_MODE_SEL_S;
ui32Value |= ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_M) >>
FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_RD_S) <<
FLASH_CFG_STANDBY_PW_SEL_S;
// Configure DIS_STANDBY (OTP offset 0x308 bit 4).
// Configure DIS_IDLE (OTP offset 0x308 bit 3).
ui32Value |= ((ui32TrimValue &
(FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_RD_M |
FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_M)) >>
FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_RD_S) <<
FLASH_CFG_DIS_IDLE_S;
HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) &
~(FLASH_CFG_STANDBY_MODE_SEL_M |
FLASH_CFG_STANDBY_PW_SEL_M |
FLASH_CFG_DIS_STANDBY_M |
FLASH_CFG_DIS_IDLE_M)) | ui32Value;
// Check if sample and hold functionality is disabled.
if(HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE)
{
// Wait for disabled sample and hold functionality to be stable.
while(!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS))
{
}
}
// Configure VIN_AT_X (OTP offset 0x308 bits 2:0)
ui32Value = ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_M) >>
FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_RD_S) <<
FLASH_FSEQPMP_VIN_AT_X_S;
// Configure VIN_BY_PASS which is dependent on the VIN_AT_X value.
// If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise
// VIN_BY_PASS should be 1
if(((ui32Value & FLASH_FSEQPMP_VIN_AT_X_M) >>
FLASH_FSEQPMP_VIN_AT_X_S) != 0x7)
{
ui32Value |= FLASH_FSEQPMP_VIN_BY_PASS;
}
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA;
HWREG(FLASH_BASE + FLASH_O_FSEQPMP) =
(HWREG(FLASH_BASE + FLASH_O_FSEQPMP) &
~(FLASH_FSEQPMP_VIN_BY_PASS_M |
FLASH_FSEQPMP_VIN_AT_X_M)) | ui32Value;
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA;
}
else
{
// Select trim values for internal regulator mode:
// Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 15)
// COnfigure STANDBY_PW_SEL (OTP offset 0x308 bit 14:13)
// Must be done while the register bit field CONFIG.DIS_STANDBY = 1
HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY;
ui32TrimValue =
HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4);
ui32Value = ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_M) >>
FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_RD_S) <<
FLASH_CFG_STANDBY_MODE_SEL_S;
ui32Value |= ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_M) >>
FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_RD_S) <<
FLASH_CFG_STANDBY_PW_SEL_S;
// Configure DIS_STANDBY (OTP offset 0x308 bit 12).
// Configure DIS_IDLE (OTP offset 0x308 bit 11).
ui32Value |= ((ui32TrimValue &
(FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_RD_M |
FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_M)) >>
FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_RD_S) <<
FLASH_CFG_DIS_IDLE_S;
HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) &
~(FLASH_CFG_STANDBY_MODE_SEL_M |
FLASH_CFG_STANDBY_PW_SEL_M |
FLASH_CFG_DIS_STANDBY_M |
FLASH_CFG_DIS_IDLE_M)) | ui32Value;
// Check if sample and hold functionality is disabled.
if(HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE)
{
// Wait for disabled sample and hold functionality to be stable.
while(!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS))
{
}
}
// Configure VIN_AT_X (OTP offset 0x308 bits 10:8)
ui32Value = (((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_M) >>
FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_RD_S) <<
FLASH_FSEQPMP_VIN_AT_X_S);
// Configure VIN_BY_PASS which is dependent on the VIN_AT_X value.
// If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise
// VIN_BY_PASS should be 1
if(((ui32Value & FLASH_FSEQPMP_VIN_AT_X_M) >>
FLASH_FSEQPMP_VIN_AT_X_S) != 0x7)
{
ui32Value |= FLASH_FSEQPMP_VIN_BY_PASS;
}
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA;
HWREG(FLASH_BASE + FLASH_O_FSEQPMP) =
(HWREG(FLASH_BASE + FLASH_O_FSEQPMP) &
~(FLASH_FSEQPMP_VIN_BY_PASS_M |
FLASH_FSEQPMP_VIN_AT_X_M)) | ui32Value;
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA;
}
}
//*****************************************************************************
//
//! \internal
//! Used to set flash in write mode.
//!
//! Flash is configured with values loaded from OTP dependent on the current
//! regulator mode.
//!
//! \return None.
//
//*****************************************************************************
static void
SetWriteMode(void)
{
uint32_t ui32TrimValue;
uint32_t ui32Value;
// Configure the STANDBY_MODE_SEL, STANDBY_PW_SEL, DIS_STANDBY, DIS_IDLE,
// VIN_AT_X and VIN_BY_PASS for program/erase mode
if(HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) &
AON_PMCTL_PWRCTL_EXT_REG_MODE)
{
// Select trim values for external regulator mode:
// Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 23)
// COnfigure STANDBY_PW_SEL (OTP offset 0x308 bit 22:21)
// Must be done while the register bit field CONFIG.DIS_STANDBY = 1
HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY;
ui32TrimValue =
HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4);
ui32Value = ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_M) >>
FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_EXT_WRT_S) <<
FLASH_CFG_STANDBY_MODE_SEL_S;
ui32Value |= ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_M) >>
FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_EXT_WRT_S) <<
FLASH_CFG_STANDBY_PW_SEL_S;
// Configure DIS_STANDBY (OTP offset 0x308 bit 20).
// Configure DIS_IDLE (OTP offset 0x308 bit 19).
ui32Value |= ((ui32TrimValue &
(FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_EXT_WRT_M |
FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_M)) >>
FCFG1_FLASH_OTP_DATA4_DIS_IDLE_EXT_WRT_S) <<
FLASH_CFG_DIS_IDLE_S;
HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) &
~(FLASH_CFG_STANDBY_MODE_SEL_M |
FLASH_CFG_STANDBY_PW_SEL_M |
FLASH_CFG_DIS_STANDBY_M |
FLASH_CFG_DIS_IDLE_M)) | ui32Value;
// Check if sample and hold functionality is disabled.
if(HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE)
{
// Wait for disabled sample and hold functionality to be stable.
while(!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS))
{
}
}
// Configure VIN_AT_X (OTP offset 0x308 bits 18:16)
ui32Value = ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_M) >>
FCFG1_FLASH_OTP_DATA4_VIN_AT_X_EXT_WRT_S) <<
FLASH_FSEQPMP_VIN_AT_X_S;
// Configure VIN_BY_PASS which is dependent on the VIN_AT_X value.
// If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise
// VIN_BY_PASS should be 1
if(((ui32Value & FLASH_FSEQPMP_VIN_AT_X_M) >>
FLASH_FSEQPMP_VIN_AT_X_S) != 0x7)
{
ui32Value |= FLASH_FSEQPMP_VIN_BY_PASS;
}
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA;
HWREG(FLASH_BASE + FLASH_O_FSEQPMP) =
(HWREG(FLASH_BASE + FLASH_O_FSEQPMP) &
~(FLASH_FSEQPMP_VIN_BY_PASS_M |
FLASH_FSEQPMP_VIN_AT_X_M)) | ui32Value;
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA;
}
else
{
// Select trim values for internal regulator mode:
// Configure STANDBY_MODE_SEL (OTP offset 0x308 bit 31)
// COnfigure STANDBY_PW_SEL (OTP offset 0x308 bit 30:29)
// Must be done while the register bit field CONFIG.DIS_STANDBY = 1
HWREG(FLASH_BASE + FLASH_O_CFG) |= FLASH_CFG_DIS_STANDBY;
ui32TrimValue =
HWREG(FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_FLASH_OTP_DATA4);
ui32Value = ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_M) >>
FCFG1_FLASH_OTP_DATA4_STANDBY_MODE_SEL_INT_WRT_S) <<
FLASH_CFG_STANDBY_MODE_SEL_S;
ui32Value |= ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_M) >>
FCFG1_FLASH_OTP_DATA4_STANDBY_PW_SEL_INT_WRT_S) <<
FLASH_CFG_STANDBY_PW_SEL_S;
// Configure DIS_STANDBY (OTP offset 0x308 bit 28).
// Configure DIS_IDLE (OTP offset 0x308 bit 27).
ui32Value |= ((ui32TrimValue &
(FCFG1_FLASH_OTP_DATA4_DIS_STANDBY_INT_WRT_M |
FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_M)) >>
FCFG1_FLASH_OTP_DATA4_DIS_IDLE_INT_WRT_S) <<
FLASH_CFG_DIS_IDLE_S;
HWREG(FLASH_BASE + FLASH_O_CFG) = (HWREG(FLASH_BASE + FLASH_O_CFG) &
~(FLASH_CFG_STANDBY_MODE_SEL_M |
FLASH_CFG_STANDBY_PW_SEL_M |
FLASH_CFG_DIS_STANDBY_M |
FLASH_CFG_DIS_IDLE_M)) | ui32Value;
// Check if sample and hold functionality is disabled.
if(HWREG(FLASH_BASE + FLASH_O_CFG) & FLASH_CFG_DIS_IDLE)
{
// Wait for disabled sample and hold functionality to be stable.
while(!(HWREG(FLASH_BASE + FLASH_O_STAT) & FLASH_STAT_SAMHOLD_DIS))
{
}
}
// Configure VIN_AT_X (OTP offset 0x308 bits 26:24)
ui32Value = ((ui32TrimValue &
FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_M) >>
FCFG1_FLASH_OTP_DATA4_VIN_AT_X_INT_WRT_S) <<
FLASH_FSEQPMP_VIN_AT_X_S;
// Configure VIN_BY_PASS which is dependent on the VIN_AT_X value.
// If VIN_AT_X = 7 then VIN_BY_PASS should be 0 otherwise
// VIN_BY_PASS should be 1
if(((ui32Value & FLASH_FSEQPMP_VIN_AT_X_M) >>
FLASH_FSEQPMP_VIN_AT_X_S) != 0x7)
{
ui32Value |= FLASH_FSEQPMP_VIN_BY_PASS;
}
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0xAAAA;
HWREG(FLASH_BASE + FLASH_O_FSEQPMP) =
(HWREG(FLASH_BASE + FLASH_O_FSEQPMP) &
~(FLASH_FSEQPMP_VIN_BY_PASS_M |
FLASH_FSEQPMP_VIN_AT_X_M)) | ui32Value;
HWREG(FLASH_BASE + FLASH_O_FLOCK) = 0x55AA;
}
}
void I2CMasterInitExpClk(uint32_t ui32Base, uint32_t ui32I2CClk, bool bFast) {
uint32_t ui32SCLFreq;
uint32_t ui32TPR;
// Check the arguments.
ASSERT(I2CBaseValid(ui32Base));
// Must enable the device before doing anything else.
I2CMasterEnable(I2C0_BASE);
// Get the desired SCL speed.
if(bFast == true)
{
ui32SCLFreq = 400000;
}
else
{
ui32SCLFreq = 100000;
}
// Compute the clock divider that achieves the fastest speed less than or
// equal to the desired speed. The numerator is biased to favor a larger
// clock divider so that the resulting clock is always less than or equal
// to the desired clock, never greater.
ui32TPR = ((ui32I2CClk + (2 * 10 * ui32SCLFreq) - 1) / (2 * 10 * ui32SCLFreq)) - 1;
HWREG(I2C0_BASE + I2C_O_MTPR) = ui32TPR;
}
uint32_t I2CMasterErr(uint32_t ui32Base) {
uint32_t ui32Err;
// Check the arguments.
ASSERT(I2CBaseValid(ui32Base));
// Get the raw error state.
ui32Err = HWREG(I2C0_BASE + I2C_O_MSTAT);
// If the I2C master is busy, then all the other status bits are invalid,
// and there is no error to report.
if(ui32Err & I2C_MSTAT_BUSY)
{
return(I2C_MASTER_ERR_NONE);
}
// Check for errors.
if(ui32Err & (I2C_MSTAT_ERR | I2C_MSTAT_ARBLST))
{
return(ui32Err & (I2C_MSTAT_ARBLST | I2C_MSTAT_DATACK_N | I2C_MSTAT_ADRACK_N));
}
else
{
return(I2C_MASTER_ERR_NONE);
}
}
//*****************************************************************************
//
//! This is a mapping between priority grouping encodings and the number of
//! preemption priority bits.
//
//*****************************************************************************
static const uint32_t g_pui32Priority[] =
{
NVIC_APINT_PRIGROUP_0_8, NVIC_APINT_PRIGROUP_1_7, NVIC_APINT_PRIGROUP_2_6,
NVIC_APINT_PRIGROUP_3_5, NVIC_APINT_PRIGROUP_4_4, NVIC_APINT_PRIGROUP_5_3,
NVIC_APINT_PRIGROUP_6_2, NVIC_APINT_PRIGROUP_7_1
};
//*****************************************************************************
//
//! This is a mapping between interrupt number and the register that contains
//! the priority encoding for that interrupt.
//
//*****************************************************************************
static const uint32_t g_pui32Regs[] =
{
0, NVIC_SYS_PRI1, NVIC_SYS_PRI2, NVIC_SYS_PRI3, NVIC_PRI0, NVIC_PRI1,
NVIC_PRI2, NVIC_PRI3, NVIC_PRI4, NVIC_PRI5, NVIC_PRI6, NVIC_PRI7,
NVIC_PRI8, NVIC_PRI9, NVIC_PRI10, NVIC_PRI11, NVIC_PRI12, NVIC_PRI13
};
void IntPriorityGroupingSet(uint32_t ui32Bits) {
// Check the arguments.
ASSERT(ui32Bits < NUM_PRIORITY);
// Set the priority grouping.
HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | g_pui32Priority[ui32Bits];
}
uint32_t IntPriorityGroupingGet(void) {
uint32_t ui32Loop, ui32Value;
// Read the priority grouping.
ui32Value = HWREG(NVIC_APINT) & NVIC_APINT_PRIGROUP_M;
// Loop through the priority grouping values.
for(ui32Loop = 0; ui32Loop < NUM_PRIORITY; ui32Loop++)
{
// Stop looping if this value matches.
if(ui32Value == g_pui32Priority[ui32Loop])
{
break;
}
}
// Return the number of priority bits.
return(ui32Loop);
}
void IntPrioritySet(uint32_t ui32Interrupt, uint8_t ui8Priority) {
uint32_t ui32Temp;
// Check the arguments.
ASSERT((ui32Interrupt >= 4) && (ui32Interrupt < NUM_INTERRUPTS));
ASSERT(ui8Priority <= INT_PRI_LEVEL7);
// Set the interrupt priority.
ui32Temp = HWREG(g_pui32Regs[ui32Interrupt >> 2]);
ui32Temp &= ~(0xFF << (8 * (ui32Interrupt & 3)));
ui32Temp |= ui8Priority << (8 * (ui32Interrupt & 3));
HWREG(g_pui32Regs[ui32Interrupt >> 2]) = ui32Temp;
}
int32_t IntPriorityGet(uint32_t ui32Interrupt) {
// Check the arguments.
ASSERT((ui32Interrupt >= 4) && (ui32Interrupt < NUM_INTERRUPTS));
// Return the interrupt priority.
return((HWREG(g_pui32Regs[ui32Interrupt >> 2]) >> (8 * (ui32Interrupt & 3))) &
0xFF);
}
void IntEnable(uint32_t ui32Interrupt) {
// Check the arguments.
ASSERT(ui32Interrupt < NUM_INTERRUPTS);
// Determine the interrupt to enable.
if(ui32Interrupt == INT_MEMMANAGE_FAULT)
{
// Enable the MemManage interrupt.
HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_MEM;
}
else if(ui32Interrupt == INT_BUS_FAULT)
{
// Enable the bus fault interrupt.
HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_BUS;
}
else if(ui32Interrupt == INT_USAGE_FAULT)
{
// Enable the usage fault interrupt.
HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_USAGE;
}
else if(ui32Interrupt == INT_SYSTICK)
{
// Enable the System Tick interrupt.
HWREG(NVIC_ST_CTRL) |= NVIC_ST_CTRL_INTEN;
}
else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
{
// Enable the general interrupt.
HWREG(NVIC_EN0) = 1 << (ui32Interrupt - 16);
}
else if(ui32Interrupt >= 48)
{
// Enable the general interrupt.
HWREG(NVIC_EN1) = 1 << (ui32Interrupt - 48);
}
}
void IntDisable(uint32_t ui32Interrupt) {
// Check the arguments.
ASSERT(ui32Interrupt < NUM_INTERRUPTS);
// Determine the interrupt to disable.
if(ui32Interrupt == INT_MEMMANAGE_FAULT)
{
// Disable the MemManage interrupt.
HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_MEM);
}
else if(ui32Interrupt == INT_BUS_FAULT)
{
// Disable the bus fault interrupt.
HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_BUS);
}
else if(ui32Interrupt == INT_USAGE_FAULT)
{
// Disable the usage fault interrupt.
HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_USAGE);
}
else if(ui32Interrupt == INT_SYSTICK)
{
// Disable the System Tick interrupt.
HWREG(NVIC_ST_CTRL) &= ~(NVIC_ST_CTRL_INTEN);
}
else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
{
// Disable the general interrupt.
HWREG(NVIC_DIS0) = 1 << (ui32Interrupt - 16);
}
else if(ui32Interrupt >= 48)
{
// Disable the general interrupt.
HWREG(NVIC_DIS1) = 1 << (ui32Interrupt - 48);
}
}
void IntPendSet(uint32_t ui32Interrupt) {
// Check the arguments.
ASSERT(ui32Interrupt < NUM_INTERRUPTS);
// Determine the interrupt to pend.
if(ui32Interrupt == INT_NMI_FAULT)
{
// Pend the NMI interrupt.
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_NMI_SET;
}
else if(ui32Interrupt == INT_PENDSV)
{
// Pend the PendSV interrupt.
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PEND_SV;
}
else if(ui32Interrupt == INT_SYSTICK)
{
// Pend the SysTick interrupt.
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTSET;
}
else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
{
// Pend the general interrupt.
HWREG(NVIC_PEND0) = 1 << (ui32Interrupt - 16);
}
else if(ui32Interrupt >= 48)
{
// Pend the general interrupt.
HWREG(NVIC_PEND1) = 1 << (ui32Interrupt - 48);
}
}
bool IntPendGet(uint32_t ui32Interrupt) {
uint32_t ui32IntPending;
// Check the arguments.
ASSERT(ui32Interrupt < NUM_INTERRUPTS);
// Assume no interrupts are pending.
ui32IntPending = 0;
// The lower 16 IRQ vectors are unsupported by this function
if (ui32Interrupt < 16)
{
return 0;
}
// Subtract lower 16 irq vectors
ui32Interrupt -= 16;
// Check if the interrupt is pending
ui32IntPending = HWREG(NVIC_PEND0 + (ui32Interrupt / 32));
ui32IntPending &= (1 << (ui32Interrupt & 31));
return ui32IntPending ? true : false;
}
void IntPendClear(uint32_t ui32Interrupt) {
// Check the arguments.
ASSERT(ui32Interrupt < NUM_INTERRUPTS);
// Determine the interrupt to unpend.
if(ui32Interrupt == INT_PENDSV)
{
// Unpend the PendSV interrupt.
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_UNPEND_SV;
}
else if(ui32Interrupt == INT_SYSTICK)
{
// Unpend the SysTick interrupt.
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTCLR;
}
else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47))
{
// Unpend the general interrupt.
HWREG(NVIC_UNPEND0) = 1 << (ui32Interrupt - 16);
}
else if(ui32Interrupt >= 48)
{
// Unpend the general interrupt.
HWREG(NVIC_UNPEND1) = 1 << (ui32Interrupt - 48);
}
}
void IOCPortConfigureSet(uint32_t ui32IOId, uint32_t ui32PortId, uint32_t ui32IOConfig) {
uint32_t ui32Reg;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
ASSERT(ui32PortId <= IOC_PORT_RFC_GPI1);
// Get the register address.
ui32Reg = IOC_BASE + ( ui32IOId << 2 );
// Configure the port.
HWREG(ui32Reg) = ui32IOConfig | ui32PortId;
}
uint32_t IOCPortConfigureGet(uint32_t ui32IOId) {
uint32_t ui32Reg;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
// Get the register address.
ui32Reg = IOC_BASE + ( ui32IOId << 2 );
// Return the IO configuration.
return HWREG(ui32Reg);
}
void IOCIOShutdownSet(uint32_t ui32IOId, uint32_t ui32IOShutdown) {
uint32_t ui32Reg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
ASSERT((ui32IOShutdown == IOC_NO_WAKE_UP) ||
(ui32IOShutdown == IOC_WAKE_ON_LOW) ||
(ui32IOShutdown == IOC_WAKE_ON_HIGH));
// Get the register address.
ui32Reg = IOC_BASE + ( ui32IOId << 2 );
// Configure the IO.
ui32Config = HWREG(ui32Reg);
ui32Config &= ~IOC_IOCFG0_WU_CFG_M;
HWREG(ui32Reg) = ui32Config | ui32IOShutdown;
}
void IOCIOJTagSet(uint32_t ui32IOId, uint32_t ui32IOJTag) {
uint32_t ui32Reg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
ASSERT((ui32IOJTag == IOC_JTAG_TDO_ENABLE) ||
(ui32IOJTag == IOC_JTAG_TDI_ENABLE) ||
(ui32IOJTag == IOC_JTAG_DISABLE));
// Get the register address.
ui32Reg = IOC_BASE + ( ui32IOId << 2 );
// Configure the IO.
ui32Config = HWREG(ui32Reg);
ui32Config &= ~(IOC_IOCFG0_TDI | IOC_IOCFG0_TDO);
HWREG(ui32Reg) = ui32Config | ui32IOJTag;
}
void IOCIOModeSet(uint32_t ui32IOId, uint32_t ui32IOMode) {
uint32_t ui32Reg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
ASSERT((ui32IOMode == IOC_IOMODE_NORMAL) ||
(ui32IOMode == IOC_IOMODE_INV) ||
(ui32IOMode == IOC_IOMODE_OPEN_DRAIN_NORMAL) ||
(ui32IOMode == IOC_IOMODE_OPEN_DRAIN_INV) ||
(ui32IOMode == IOC_IOMODE_OPEN_SRC_NORMAL) ||
(ui32IOMode == IOC_IOMODE_OPEN_SRC_INV));
// Get the register address.
ui32Reg = IOC_BASE + ( ui32IOId << 2 );
// Configure the IO.
ui32Config = HWREG(ui32Reg);
ui32Config &= ~IOC_IOCFG0_IOMODE_M;
HWREG(ui32Reg) = ui32Config | ui32IOMode;
}
void IOCIOIntSet(uint32_t ui32IOId, uint32_t ui32Int, uint32_t ui32EdgeDet) {
uint32_t ui32IOReg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
ASSERT((ui32Int == IOC_INT_ENABLE) ||
(ui32Int == IOC_INT_DISABLE));
ASSERT((ui32EdgeDet == IOC_NO_EDGE) ||
(ui32EdgeDet == IOC_FALLING_EDGE) ||
(ui32EdgeDet == IOC_RISING_EDGE) ||
(ui32EdgeDet == IOC_BOTH_EDGES));
// Get the register address.
ui32IOReg = IOC_BASE + ( ui32IOId << 2 );
// Configure the IO.
ui32Config = HWREG(ui32IOReg);
ui32Config &= ~(IOC_IOCFG0_EDGE_IRQ_EN | IOC_IOCFG0_EDGE_DET_M);
HWREG(ui32IOReg) = ui32Config | ((ui32Int ? IOC_IOCFG0_EDGE_IRQ_EN : 0) | ui32EdgeDet);
}
void IOCIOPortPullSet(uint32_t ui32IOId, uint32_t ui32Pull) {
uint32_t ui32IOReg;
uint32_t ui32Config;
// Check the argument.
ASSERT(ui32IOId <= IOID_31);
ASSERT((ui32Pull == IOC_NO_IOPULL) ||
(ui32Pull == IOC_IOPULL_UP) ||
(ui32Pull == IOC_IOPULL_DOWN));
// Get the register address.
ui32IOReg = IOC_BASE + ( ui32IOId << 2 );
// Configure the IO.
ui32Config = HWREG(ui32IOReg);
ui32Config &= ~IOC_IOCFG0_PULL_CTL_M;
HWREG(ui32IOReg) = ui32Config | ui32Pull;
}
void IOCIOHystSet(uint32_t ui32IOId, uint32_t ui32Hysteresis) {
uint32_t ui32IOReg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
ASSERT((ui32Hysteresis == IOC_HYST_ENABLE) ||
(ui32Hysteresis == IOC_HYST_DISABLE));
// Get the register address.
ui32IOReg = IOC_BASE + ( ui32IOId << 2 );
// Configure the IO.
ui32Config = HWREG(ui32IOReg);
ui32Config &= ~IOC_IOCFG0_HYST_EN;
HWREG(ui32IOReg) = ui32Config | ui32Hysteresis;
}
void IOCIOInputSet(uint32_t ui32IOId, uint32_t ui32Input) {
uint32_t ui32IOReg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
ASSERT((ui32Input == IOC_INPUT_ENABLE) ||
(ui32Input == IOC_INPUT_DISABLE));
// Get the register address.
ui32IOReg = IOC_BASE + ( ui32IOId << 2 );
// Configure the IO.
ui32Config = HWREG(ui32IOReg);
ui32Config &= ~IOC_IOCFG0_IE;
HWREG(ui32IOReg) = ui32Config | ui32Input;
}
void IOCIOSlewCtrlSet(uint32_t ui32IOId, uint32_t ui32SlewEnable) {
uint32_t ui32IOReg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
ASSERT((ui32SlewEnable == IOC_SLEW_ENABLE) ||
(ui32SlewEnable == IOC_SLEW_DISABLE));
// Get the register address.
ui32IOReg = IOC_BASE + ( ui32IOId << 2 );
// Configure the IO.
ui32Config = HWREG(ui32IOReg);
ui32Config &= ~IOC_IOCFG0_SLEW_RED;
HWREG(ui32IOReg) = ui32Config | ui32SlewEnable;
}
void IOCIODrvStrengthSet(uint32_t ui32IOId, uint32_t ui32IOCurrent, uint32_t ui32DrvStrength) {
uint32_t ui32IOReg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
ASSERT((ui32IOCurrent == IOC_CURRENT_2MA) ||
(ui32IOCurrent == IOC_CURRENT_4MA) ||
(ui32IOCurrent == IOC_CURRENT_8MA));
ASSERT((ui32DrvStrength == IOC_STRENGTH_MIN) ||
(ui32DrvStrength == IOC_STRENGTH_MAX) ||
(ui32DrvStrength == IOC_STRENGTH_MED) ||
(ui32DrvStrength == IOC_STRENGTH_AUTO));
// Get the register address.
ui32IOReg = IOC_BASE + ( ui32IOId << 2 );
// Configure the IO.
ui32Config = HWREG(ui32IOReg);
ui32Config &= ~(IOC_IOCFG0_IOCURR_M | IOC_IOCFG0_IOSTR_M);
HWREG(ui32IOReg) = ui32Config | (ui32IOCurrent | ui32DrvStrength);
}
void IOCIOPortIdSet(uint32_t ui32IOId, uint32_t ui32PortId) {
uint32_t ui32IOReg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
ASSERT(ui32PortId <= IOC_PORT_RFC_GPI1);
// Get the register address.
ui32IOReg = IOC_BASE + ( ui32IOId << 2 );
// Configure the IO.
ui32Config = HWREG(ui32IOReg);
ui32Config &= ~IOC_IOCFG0_PORT_ID_M;
HWREG(ui32IOReg) = ui32Config | ui32PortId;
}
void IOCIntEnable(uint32_t ui32IOId) {
uint32_t ui32IOReg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
// Get the register address.
ui32IOReg = IOC_BASE + ( ui32IOId << 2 );
// Enable the specified interrupt.
ui32Config = HWREG(ui32IOReg);
ui32Config |= IOC_IOCFG0_EDGE_IRQ_EN;
HWREG(ui32IOReg) = ui32Config;
}
void IOCIntDisable(uint32_t ui32IOId) {
uint32_t ui32IOReg;
uint32_t ui32Config;
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
// Get the register address.
ui32IOReg = IOC_BASE + ( ui32IOId << 2 );
// Disable the specified interrupt.
ui32Config = HWREG(ui32IOReg);
ui32Config &= ~IOC_IOCFG0_EDGE_IRQ_EN;
HWREG(ui32IOReg) = ui32Config;
}
void IOCPinTypeGpioInput(uint32_t ui32IOId) {
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
// Setup the IO for standard input.
IOCPortConfigureSet(ui32IOId, IOC_PORT_GPIO, IOC_STD_INPUT);
// Enable input mode in the GPIO module.
GPIO_setOutputEnableDio(ui32IOId, GPIO_OUTPUT_DISABLE);
}
void IOCPinTypeGpioOutput(uint32_t ui32IOId) {
// Check the arguments.
ASSERT(ui32IOId <= IOID_31);
// Setup the IO for standard input.
IOCPortConfigureSet(ui32IOId, IOC_PORT_GPIO, IOC_STD_OUTPUT);
// Enable output mode in the GPIO module.
GPIO_setOutputEnableDio(ui32IOId, GPIO_OUTPUT_ENABLE);
}
void IOCPinTypeUart(uint32_t ui32Base, uint32_t ui32Rx, uint32_t ui32Tx, uint32_t ui32Cts, uint32_t ui32Rts) {
// Check the arguments.
ASSERT(ui32Base == UART0_BASE);
ASSERT((ui32Rx <= IOID_31) || (ui32Rx == IOID_UNUSED));
ASSERT((ui32Tx <= IOID_31) || (ui32Tx == IOID_UNUSED));
ASSERT((ui32Cts <= IOID_31) || (ui32Cts == IOID_UNUSED));
ASSERT((ui32Rts <= IOID_31) || (ui32Rts == IOID_UNUSED));
// Setup the IOs in the desired configuration.
if(ui32Rx != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Rx, IOC_PORT_MCU_UART0_RX, IOC_STD_INPUT);
}
if(ui32Tx != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Tx, IOC_PORT_MCU_UART0_TX, IOC_STD_OUTPUT);
}
if(ui32Cts != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Cts, IOC_PORT_MCU_UART0_CTS, IOC_STD_INPUT);
}
if(ui32Rts != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Rts, IOC_PORT_MCU_UART0_RTS, IOC_STD_OUTPUT);
}
}
void IOCPinTypeSsiMaster(uint32_t ui32Base, uint32_t ui32Rx, uint32_t ui32Tx, uint32_t ui32Fss, uint32_t ui32Clk) {
// Check the arguments.
ASSERT((ui32Base == SSI0_BASE) || (ui32Base == SSI1_BASE));
ASSERT((ui32Rx <= IOID_31) || (ui32Rx == IOID_UNUSED));
ASSERT((ui32Tx <= IOID_31) || (ui32Tx == IOID_UNUSED));
ASSERT((ui32Fss <= IOID_31) || (ui32Fss == IOID_UNUSED));
ASSERT((ui32Clk <= IOID_31) || (ui32Clk == IOID_UNUSED));
// Setup the IOs in the desired configuration.
if(ui32Base == SSI0_BASE)
{
if(ui32Rx != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Rx, IOC_PORT_MCU_SSI0_RX, IOC_STD_INPUT);
}
if(ui32Tx != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Tx, IOC_PORT_MCU_SSI0_TX, IOC_STD_OUTPUT);
}
if(ui32Fss != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Fss, IOC_PORT_MCU_SSI0_FSS, IOC_STD_OUTPUT);
}
if(ui32Clk != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Clk, IOC_PORT_MCU_SSI0_CLK, IOC_STD_OUTPUT);
}
}
else
{
if(ui32Rx != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Rx, IOC_PORT_MCU_SSI1_RX, IOC_STD_INPUT);
}
if(ui32Tx != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Tx, IOC_PORT_MCU_SSI1_TX, IOC_STD_OUTPUT);
}
if(ui32Fss != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Fss, IOC_PORT_MCU_SSI1_FSS, IOC_STD_OUTPUT);
}
if(ui32Clk != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Clk, IOC_PORT_MCU_SSI1_CLK, IOC_STD_OUTPUT);
}
}
}
void IOCPinTypeSsiSlave(uint32_t ui32Base, uint32_t ui32Rx, uint32_t ui32Tx, uint32_t ui32Fss, uint32_t ui32Clk) {
// Check the arguments.
ASSERT((ui32Base == SSI0_BASE) || (ui32Base == SSI1_BASE));
ASSERT((ui32Rx <= IOID_31) || (ui32Rx == IOID_UNUSED));
ASSERT((ui32Tx <= IOID_31) || (ui32Tx == IOID_UNUSED));
ASSERT((ui32Fss <= IOID_31) || (ui32Fss == IOID_UNUSED));
ASSERT((ui32Clk <= IOID_31) || (ui32Clk == IOID_UNUSED));
// Setup the IOs in the desired configuration.
if(ui32Base == SSI0_BASE)
{
if(ui32Rx != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Rx, IOC_PORT_MCU_SSI0_RX, IOC_STD_INPUT);
}
if(ui32Tx != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Tx, IOC_PORT_MCU_SSI0_TX, IOC_STD_OUTPUT);
}
if(ui32Fss != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Fss, IOC_PORT_MCU_SSI0_FSS, IOC_STD_INPUT);
}
if(ui32Clk != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Clk, IOC_PORT_MCU_SSI0_CLK, IOC_STD_INPUT);
}
}
else
{
if(ui32Rx != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Rx, IOC_PORT_MCU_SSI1_RX, IOC_STD_INPUT);
}
if(ui32Tx != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Tx, IOC_PORT_MCU_SSI1_TX, IOC_STD_OUTPUT);
}
if(ui32Fss != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Fss, IOC_PORT_MCU_SSI1_FSS, IOC_STD_INPUT);
}
if(ui32Clk != IOID_UNUSED)
{
IOCPortConfigureSet(ui32Clk, IOC_PORT_MCU_SSI1_CLK, IOC_STD_INPUT);
}
}
}
void IOCPinTypeI2c(uint32_t ui32Base, uint32_t ui32Data, uint32_t ui32Clk) {
uint32_t ui32IOConfig;
// Check the arguments.
ASSERT((ui32Data <= IOID_31) || (ui32Data == IOID_UNUSED));
ASSERT((ui32Clk <= IOID_31) || (ui32Clk == IOID_UNUSED));
// Define the IO configuration parameters.
ui32IOConfig = IOC_CURRENT_2MA | IOC_STRENGTH_AUTO | IOC_IOPULL_UP |
IOC_SLEW_DISABLE | IOC_HYST_DISABLE | IOC_NO_EDGE |
IOC_INT_DISABLE | IOC_IOMODE_OPEN_DRAIN_NORMAL |
IOC_NO_WAKE_UP | IOC_INPUT_ENABLE;
// Setup the IOs in the desired configuration.
IOCPortConfigureSet(ui32Data, IOC_PORT_MCU_I2C_MSSDA, ui32IOConfig);
IOCPortConfigureSet(ui32Clk, IOC_PORT_MCU_I2C_MSSCL, ui32IOConfig);
}
void IOCPinTypeAux(uint32_t ui32IOId) {
// Check the arguments.
ASSERT((ui32IOId <= IOID_31) || (ui32IOId == IOID_UNUSED));
// Setup the IO.
IOCPortConfigureSet(ui32IOId, IOC_PORT_AUX_IO, IOC_STD_INPUT);
}
//*****************************************************************************
//
// Arrays that maps the "peripheral set" number (which is stored in
// bits[11:8] of the PRCM_PERIPH_* defines) to the PRCM register that
// contains the relevant bit for that peripheral.
//
//*****************************************************************************
// Run mode registers
static const uint32_t g_pui32RCGCRegs[] =
{
PRCM_O_GPTCLKGR , // Index 0
PRCM_O_SSICLKGR , // Index 1
PRCM_O_UARTCLKGR , // Index 2
PRCM_O_I2CCLKGR , // Index 3
PRCM_O_SECDMACLKGR , // Index 4
PRCM_O_GPIOCLKGR , // Index 5
PRCM_O_I2SCLKGR // Index 6
};
// Sleep mode registers
static const uint32_t g_pui32SCGCRegs[] =
{
PRCM_O_GPTCLKGS , // Index 0
PRCM_O_SSICLKGS , // Index 1
PRCM_O_UARTCLKGS , // Index 2
PRCM_O_I2CCLKGS , // Index 3
PRCM_O_SECDMACLKGS , // Index 4
PRCM_O_GPIOCLKGS , // Index 5
PRCM_O_I2SCLKGS // Index 6
};
// Deep sleep mode registers
static const uint32_t g_pui32DCGCRegs[] =
{
PRCM_O_GPTCLKGDS , // Index 0
PRCM_O_SSICLKGDS , // Index 1
PRCM_O_UARTCLKGDS , // Index 2
PRCM_O_I2CCLKGDS , // Index 3
PRCM_O_SECDMACLKGDS , // Index 4
PRCM_O_GPIOCLKGDS , // Index 5
PRCM_O_I2SCLKGDS // Index 6
};
//*****************************************************************************
//
// This macro extracts the array index out of the peripheral number
//
//*****************************************************************************
#define PRCM_PERIPH_INDEX(a) (((a) >> 8) & 0xf)
//*****************************************************************************
//
// This macro extracts the peripheral instance number and generates bit mask
//
//*****************************************************************************
#define PRCM_PERIPH_MASKBIT(a) (0x00000001 << ((a) & 0x1f))
void PRCMInfClockConfigureSet(uint32_t ui32ClkDiv, uint32_t ui32PowerMode) {
uint32_t ui32Divisor;
// Check the arguments.
ASSERT((ui32ClkDiv == PRCM_CLOCK_DIV_1) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_2) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_8) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_32));
ASSERT((ui32PowerMode == PRCM_RUN_MODE) ||
(ui32PowerMode == PRCM_SLEEP_MODE) ||
(ui32PowerMode == PRCM_DEEP_SLEEP_MODE));
ui32Divisor = 0;
// Find the correct division factor.
if(ui32ClkDiv == PRCM_CLOCK_DIV_1)
{
ui32Divisor = 0x0;
}
else if(ui32ClkDiv == PRCM_CLOCK_DIV_2)
{
ui32Divisor = 0x1;
}
else if(ui32ClkDiv == PRCM_CLOCK_DIV_8)
{
ui32Divisor = 0x2;
}
else if(ui32ClkDiv == PRCM_CLOCK_DIV_32)
{
ui32Divisor = 0x3;
}
// Determine the correct power mode set the division factor accordingly.
if(ui32PowerMode == PRCM_RUN_MODE)
{
HWREG(PRCM_BASE + PRCM_O_INFRCLKDIVR) = ui32Divisor;
}
else if(ui32PowerMode == PRCM_SLEEP_MODE)
{
HWREG(PRCM_BASE + PRCM_O_INFRCLKDIVS) = ui32Divisor;
}
else if(ui32PowerMode == PRCM_DEEP_SLEEP_MODE)
{
HWREG(PRCM_BASE + PRCM_O_INFRCLKDIVDS) = ui32Divisor;
}
}
uint32_t PRCMInfClockConfigureGet(uint32_t ui32PowerMode) {
uint32_t ui32ClkDiv;
uint32_t ui32Divisor;
// Check the arguments.
ASSERT((ui32PowerMode == PRCM_RUN_MODE) ||
(ui32PowerMode == PRCM_SLEEP_MODE) ||
(ui32PowerMode == PRCM_DEEP_SLEEP_MODE));
ui32ClkDiv = 0;
ui32Divisor = 0;
// Determine the correct power mode.
if(ui32PowerMode == PRCM_RUN_MODE)
{
ui32ClkDiv = HWREG(PRCM_BASE + PRCM_O_INFRCLKDIVR);
}
else if(ui32PowerMode == PRCM_SLEEP_MODE)
{
ui32ClkDiv = HWREG(PRCM_BASE + PRCM_O_INFRCLKDIVS);
}
else if(ui32PowerMode == PRCM_DEEP_SLEEP_MODE)
{
ui32ClkDiv = HWREG(PRCM_BASE + PRCM_O_INFRCLKDIVDS);
}
// Find the correct division factor.
if(ui32ClkDiv == 0x0)
{
ui32Divisor = PRCM_CLOCK_DIV_1;
}
else if(ui32ClkDiv == 0x1)
{
ui32Divisor = PRCM_CLOCK_DIV_2;
}
else if(ui32ClkDiv == 0x2)
{
ui32Divisor = PRCM_CLOCK_DIV_8;
}
else if(ui32ClkDiv == 0x3)
{
ui32Divisor = PRCM_CLOCK_DIV_32;
}
// Return the clock division factor.
return ui32Divisor;
}
void PRCMClockConfigureSet(uint32_t ui32Domains, uint32_t ui32ClkDiv) {
uint32_t ui32Reg;
// Check the arguments.
ASSERT((ui32Domains & PRCM_DOMAIN_SYSBUS) ||
(ui32Domains & PRCM_DOMAIN_CPU) ||
(ui32Domains & PRCM_DOMAIN_PERIPH) ||
(ui32Domains & PRCM_DOMAIN_TIMER) ||
(ui32Domains & PRCM_DOMAIN_SERIAL));
ASSERT((ui32ClkDiv == PRCM_CLOCK_DIV_1) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_2) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_4) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_8) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_16) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_32) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_64) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_128) ||
(ui32ClkDiv == PRCM_CLOCK_DIV_256));
// Configure the selected clock dividers.
if(ui32Domains & PRCM_DOMAIN_SYSBUS)
{
ui32Reg = PRCM_O_SYSBUSCLKDIV;
HWREG(PRCM_BASE + ui32Reg) = ui32ClkDiv;
}
if(ui32Domains & PRCM_DOMAIN_CPU)
{
ui32Reg = PRCM_O_CPUCLKDIV;
HWREG(PRCM_BASE + ui32Reg) = ui32ClkDiv;
}
if(ui32Domains & PRCM_DOMAIN_PERIPH)
{
ui32Reg = PRCM_O_PERBUSCPUCLKDIV;
HWREG(PRCM_BASE + ui32Reg) = ui32ClkDiv;
}
if(ui32Domains & PRCM_DOMAIN_SERIAL)
{
ui32Reg = PRCM_O_PERDMACLKDIV;
HWREG(PRCM_BASE + ui32Reg) = ui32ClkDiv;
}
if(ui32Domains & PRCM_DOMAIN_TIMER)
{
ui32Reg = PRCM_O_GPTCLKDIV;
HWREG(PRCM_BASE + ui32Reg) = ui32ClkDiv;
}
}
uint32_t PRCMClockConfigureGet(uint32_t ui32Domain) {
uint32_t ui32ClkDiv;
// Check the arguments.
ASSERT((ui32Domain == PRCM_DOMAIN_SYSBUS) ||
(ui32Domain == PRCM_DOMAIN_CPU) ||
(ui32Domain == PRCM_DOMAIN_PERIPH) ||
(ui32Domain == PRCM_DOMAIN_TIMER) ||
(ui32Domain == PRCM_DOMAIN_SERIAL));
ui32ClkDiv = 0;
// Find the correct sub system.
if(ui32Domain == PRCM_DOMAIN_SYSBUS)
{
ui32ClkDiv = HWREG(PRCM_BASE + PRCM_O_SYSBUSCLKDIV);
}
else if(ui32Domain == PRCM_DOMAIN_CPU)
{
ui32ClkDiv = HWREG(PRCM_BASE + PRCM_O_CPUCLKDIV);
}
else if(ui32Domain == PRCM_DOMAIN_PERIPH)
{
ui32ClkDiv = HWREG(PRCM_BASE + PRCM_O_PERBUSCPUCLKDIV);
}
else if(ui32Domain == PRCM_DOMAIN_SERIAL)
{
ui32ClkDiv = HWREG(PRCM_BASE + PRCM_O_PERDMACLKDIV);
}
else if(ui32Domain == PRCM_DOMAIN_TIMER)
{
ui32ClkDiv = HWREG(PRCM_BASE + PRCM_O_GPTCLKDIV);
}
// Return the clock configuration.
return(ui32ClkDiv);
}
void PRCMAudioClockConfigSet(uint32_t ui32ClkConfig, uint32_t ui32SampleRate) {
uint32_t ui32Reg;
uint32_t ui32MstDiv;
uint32_t ui32BitDiv;
uint32_t ui32WordDiv;
// Check the arguments.
ASSERT(!(ui32ClkConfig & (PRCM_I2SCLKCTL_WCLK_PHASE_M | PRCM_I2SCLKCTL_SMPL_ON_POSEDGE_M)));
ASSERT((ui32SampleRate == I2S_SAMPLE_RATE_16K) ||
(ui32SampleRate == I2S_SAMPLE_RATE_24K) ||
(ui32SampleRate == I2S_SAMPLE_RATE_32K) ||
(ui32SampleRate == I2S_SAMPLE_RATE_48K));
ui32MstDiv = 0;
ui32BitDiv = 0;
ui32WordDiv = 0;
// Make sure the audio clock generation is disabled before reconfiguring.
PRCMAudioClockDisable();
// Define the clock division factors for the audio interface.
switch(ui32SampleRate)
{
case I2S_SAMPLE_RATE_16K :
ui32MstDiv = 6;
ui32BitDiv = 60;
ui32WordDiv = 25;
break;
case I2S_SAMPLE_RATE_24K :
ui32MstDiv = 4;
ui32BitDiv = 40;
ui32WordDiv = 25;
break;
case I2S_SAMPLE_RATE_32K :
ui32MstDiv = 3;
ui32BitDiv = 30;
ui32WordDiv = 25;
break;
case I2S_SAMPLE_RATE_48K :
ui32MstDiv = 2;
ui32BitDiv = 20;
ui32WordDiv = 25;
break;
}
// Make sure to compensate the Frame clock division factor if using single
// phase format.
if((ui32ClkConfig & PRCM_I2SCLKCTL_WCLK_PHASE_M) == PRCM_WCLK_SINGLE_PHASE)
{
ui32WordDiv -= 1;
}
// Write the clock division factors.
HWREG(PRCM_BASE + PRCM_O_I2SMCLKDIV) = ui32MstDiv;
HWREG(PRCM_BASE + PRCM_O_I2SBCLKDIV) = ui32BitDiv;
HWREG(PRCM_BASE + PRCM_O_I2SWCLKDIV) = ui32WordDiv;
// Configure the Word clock format and polarity.
ui32Reg = HWREG(PRCM_BASE + PRCM_O_I2SCLKCTL) & ~(PRCM_I2SCLKCTL_WCLK_PHASE_M |
PRCM_I2SCLKCTL_SMPL_ON_POSEDGE_M);
HWREG(PRCM_BASE + PRCM_O_I2SCLKCTL) = ui32Reg | ui32ClkConfig;
}
void PRCMAudioClockConfigSetOverride(uint32_t ui32ClkConfig, uint32_t ui32MstDiv, uint32_t ui32BitDiv, uint32_t ui32WordDiv) {
uint32_t ui32Reg;
// Check the arguments.
ASSERT(!(ui32ClkConfig & (PRCM_I2SCLKCTL_WCLK_PHASE_M | PRCM_I2SCLKCTL_SMPL_ON_POSEDGE_M)));
// Make sure the audio clock generation is disabled before reconfiguring.
PRCMAudioClockDisable();
// Make sure to compensate the Frame clock division factor if using single
// phase format.
if((ui32ClkConfig & PRCM_I2SCLKCTL_WCLK_PHASE_M) == PRCM_WCLK_SINGLE_PHASE)
{
ui32WordDiv -= 1;
}
// Write the clock division factors.
HWREG(PRCM_BASE + PRCM_O_I2SMCLKDIV) = ui32MstDiv;
HWREG(PRCM_BASE + PRCM_O_I2SBCLKDIV) = ui32BitDiv;
HWREG(PRCM_BASE + PRCM_O_I2SWCLKDIV) = ui32WordDiv;
// Configure the Word clock format and polarity.
ui32Reg = HWREG(PRCM_BASE + PRCM_O_I2SCLKCTL) & ~(PRCM_I2SCLKCTL_WCLK_PHASE_M |
PRCM_I2SCLKCTL_SMPL_ON_POSEDGE_M);
HWREG(PRCM_BASE + PRCM_O_I2SCLKCTL) = ui32Reg | ui32ClkConfig;
}
void PRCMPowerDomainOn(uint32_t ui32Domains) {
// Check the arguments.
ASSERT((ui32Domains & PRCM_DOMAIN_RFCORE) ||
(ui32Domains & PRCM_DOMAIN_SERIAL) ||
(ui32Domains & PRCM_DOMAIN_PERIPH) ||
(ui32Domains & PRCM_DOMAIN_CPU) ||
(ui32Domains & PRCM_DOMAIN_VIMS));
// Assert the request to power on the right domains.
if(ui32Domains & PRCM_DOMAIN_RFCORE)
{
HWREG(PRCM_BASE + PRCM_O_PDCTL0RFC ) = 1;
}
if(ui32Domains & PRCM_DOMAIN_SERIAL)
{
HWREG(PRCM_BASE + PRCM_O_PDCTL0SERIAL) = 1;
}
if(ui32Domains & PRCM_DOMAIN_PERIPH)
{
HWREG(PRCM_BASE + PRCM_O_PDCTL0PERIPH) = 1;
}
if(ui32Domains & PRCM_DOMAIN_VIMS)
{
HWREG(PRCM_BASE + PRCM_O_PDCTL1VIMS ) = 1;
}
if(ui32Domains & PRCM_DOMAIN_CPU)
{
HWREG(PRCM_BASE + PRCM_O_PDCTL1CPU ) = 1;
}
}
void PRCMPowerDomainOff(uint32_t ui32Domains) {
// Check the arguments.
ASSERT((ui32Domains & PRCM_DOMAIN_RFCORE) ||
(ui32Domains & PRCM_DOMAIN_SERIAL) ||
(ui32Domains & PRCM_DOMAIN_PERIPH) ||
(ui32Domains & PRCM_DOMAIN_CPU) ||
(ui32Domains & PRCM_DOMAIN_VIMS));
// Assert the request to power off the right domains.
if(ui32Domains & PRCM_DOMAIN_RFCORE)
{
HWREG(PRCM_BASE + PRCM_O_PDCTL0RFC ) = 0;
}
if(ui32Domains & PRCM_DOMAIN_SERIAL)
{
HWREG(PRCM_BASE + PRCM_O_PDCTL0SERIAL) = 0;
}
if(ui32Domains & PRCM_DOMAIN_PERIPH)
{
HWREG(PRCM_BASE + PRCM_O_PDCTL0PERIPH) = 0;
}
if(ui32Domains & PRCM_DOMAIN_VIMS)
{
// Write bits ui32Domains[17:16] to the VIMS_MODE alias register.
// (Legal values are 0b00 and 0b10 (PRCM_DOMAIN_VIMS or PRCM_DOMAIN_VIMS_OFF_NO_WAKUP))
ASSERT(!(ui32Domains & 0x00010000));
HWREG(PRCM_BASE + PRCM_O_PDCTL1VIMS ) = ( ui32Domains >> 16 ) & 3;
}
if(ui32Domains & PRCM_DOMAIN_CPU)
{
HWREG(PRCM_BASE + PRCM_O_PDCTL1CPU ) = 0;
}
}
void PRCMPeripheralRunEnable(uint32_t ui32Peripheral) {
// Check the arguments.
ASSERT(PRCMPeripheralValid(ui32Peripheral));
// Enable module in Run Mode.
HWREG(PRCM_BASE + g_pui32RCGCRegs[PRCM_PERIPH_INDEX(ui32Peripheral)]) |=
PRCM_PERIPH_MASKBIT(ui32Peripheral);
}
void PRCMPeripheralRunDisable(uint32_t ui32Peripheral) {
// Check the arguments.
ASSERT(PRCMPeripheralValid(ui32Peripheral));
// Disable module in Run Mode.
HWREG(PRCM_BASE + g_pui32RCGCRegs[PRCM_PERIPH_INDEX(ui32Peripheral)]) &=
~PRCM_PERIPH_MASKBIT(ui32Peripheral);
}
void PRCMPeripheralSleepEnable(uint32_t ui32Peripheral) {
// Check the arguments.
ASSERT(PRCMPeripheralValid(ui32Peripheral));
// Enable this peripheral in sleep mode.
HWREG(PRCM_BASE + g_pui32SCGCRegs[PRCM_PERIPH_INDEX(ui32Peripheral)]) |=
PRCM_PERIPH_MASKBIT(ui32Peripheral);
}
void PRCMPeripheralSleepDisable(uint32_t ui32Peripheral) {
// Check the arguments.
ASSERT(PRCMPeripheralValid(ui32Peripheral));
// Disable this peripheral in sleep mode
HWREG(PRCM_BASE + g_pui32SCGCRegs[PRCM_PERIPH_INDEX(ui32Peripheral)]) &=
~PRCM_PERIPH_MASKBIT(ui32Peripheral);
}
void PRCMPeripheralDeepSleepEnable(uint32_t ui32Peripheral) {
// Check the arguments.
ASSERT(PRCMPeripheralValid(ui32Peripheral));
// Enable this peripheral in deep-sleep mode.
HWREG(PRCM_BASE + g_pui32DCGCRegs[PRCM_PERIPH_INDEX(ui32Peripheral)]) |=
PRCM_PERIPH_MASKBIT(ui32Peripheral);
}
void PRCMPeripheralDeepSleepDisable(uint32_t ui32Peripheral) {
// Check the arguments.
ASSERT(PRCMPeripheralValid(ui32Peripheral));
// Disable this peripheral in Deep Sleep mode.
HWREG(PRCM_BASE + g_pui32DCGCRegs[PRCM_PERIPH_INDEX(ui32Peripheral)]) &=
~PRCM_PERIPH_MASKBIT(ui32Peripheral);
}
uint32_t PRCMPowerDomainStatus(uint32_t ui32Domains) {
bool bStatus;
uint32_t ui32StatusRegister0;
uint32_t ui32StatusRegister1;
// Check the arguments.
ASSERT((ui32Domains & (PRCM_DOMAIN_RFCORE |
PRCM_DOMAIN_SERIAL |
PRCM_DOMAIN_PERIPH)));
bStatus = true;
ui32StatusRegister0 = HWREG(PRCM_BASE + PRCM_O_PDSTAT0);
ui32StatusRegister1 = HWREG(PRCM_BASE + PRCM_O_PDSTAT1);
// Return the correct power status.
if(ui32Domains & PRCM_DOMAIN_RFCORE)
{
bStatus = bStatus &&
((ui32StatusRegister0 & PRCM_PDSTAT0_RFC_ON) ||
(ui32StatusRegister1 & PRCM_PDSTAT1_RFC_ON));
}
if(ui32Domains & PRCM_DOMAIN_SERIAL)
{
bStatus = bStatus && (ui32StatusRegister0 & PRCM_PDSTAT0_SERIAL_ON);
}
if(ui32Domains & PRCM_DOMAIN_PERIPH)
{
bStatus = bStatus && (ui32StatusRegister0 & PRCM_PDSTAT0_PERIPH_ON);
}
// Return the status.
return (bStatus ? PRCM_DOMAIN_POWER_ON : PRCM_DOMAIN_POWER_OFF);
}
void PRCMDeepSleep(void) {
// Enable deep-sleep.
HWREG(NVIC_SYS_CTRL) |= NVIC_SYS_CTRL_SLEEPDEEP;
// Wait for an interrupt.
CPUwfi();
// Disable deep-sleep so that a future sleep will work correctly.
HWREG(NVIC_SYS_CTRL) &= ~(NVIC_SYS_CTRL_SLEEPDEEP);
}
void PRCMRetentionEnable(uint32_t ui32PowerDomain) {
uint32_t ui32Retention;
// Check the arguments.
ASSERT(PRCM_DOMAIN_CPU & ui32PowerDomain);
// Get the current register values.
ui32Retention = HWREG(PRCM_BASE + PRCM_O_RAMRETEN);
// Enable retention on RF core SRAM.
if(PRCM_DOMAIN_RFCORE & ui32PowerDomain)
{
ui32Retention |= PRCM_RAMRETEN_RFC_M;
}
// Enable retention on VIMS cache.
if(PRCM_DOMAIN_VIMS & ui32PowerDomain)
{
ui32Retention |= PRCM_RAMRETEN_VIMS_M;
}
// Reconfigure retention.
HWREG(PRCM_BASE + PRCM_O_RAMRETEN) = ui32Retention;
}
void PRCMRetentionDisable(uint32_t ui32PowerDomain) {
uint32_t ui32Retention;
// Check the arguments.
ASSERT(PRCM_DOMAIN_CPU & ui32PowerDomain);
// Get the current register values
ui32Retention = HWREG(PRCM_BASE + PRCM_O_RAMRETEN);
// Disable retention on RF core SRAM
if(PRCM_DOMAIN_RFCORE & ui32PowerDomain)
{
ui32Retention &= ~PRCM_RAMRETEN_RFC_M;
}
// Disable retention on VIMS cache
if(PRCM_DOMAIN_VIMS & ui32PowerDomain)
{
ui32Retention &= ~PRCM_RAMRETEN_VIMS_M;
}
// Reconfigure retention.
HWREG(PRCM_BASE + PRCM_O_RAMRETEN) = ui32Retention;
}
void SMPHAcquire(uint32_t ui32Semaphore) {
// Check the arguments.
ASSERT((ui32Semaphore == SMPH_0) ||
(ui32Semaphore == SMPH_1) ||
(ui32Semaphore == SMPH_2) ||
(ui32Semaphore == SMPH_3) ||
(ui32Semaphore == SMPH_4) ||
(ui32Semaphore == SMPH_5) ||
(ui32Semaphore == SMPH_6) ||
(ui32Semaphore == SMPH_7) ||
(ui32Semaphore == SMPH_8) ||
(ui32Semaphore == SMPH_9) ||
(ui32Semaphore == SMPH_10) ||
(ui32Semaphore == SMPH_11) ||
(ui32Semaphore == SMPH_12) ||
(ui32Semaphore == SMPH_13) ||
(ui32Semaphore == SMPH_14) ||
(ui32Semaphore == SMPH_15) ||
(ui32Semaphore == SMPH_16) ||
(ui32Semaphore == SMPH_17) ||
(ui32Semaphore == SMPH_18) ||
(ui32Semaphore == SMPH_19) ||
(ui32Semaphore == SMPH_20) ||
(ui32Semaphore == SMPH_21) ||
(ui32Semaphore == SMPH_22) ||
(ui32Semaphore == SMPH_23) ||
(ui32Semaphore == SMPH_24) ||
(ui32Semaphore == SMPH_25) ||
(ui32Semaphore == SMPH_26) ||
(ui32Semaphore == SMPH_27) ||
(ui32Semaphore == SMPH_28) ||
(ui32Semaphore == SMPH_29) ||
(ui32Semaphore == SMPH_30) ||
(ui32Semaphore == SMPH_31));
// Wait for semaphore to be release such that it can be claimed
// Semaphore register reads 1 when lock was acquired otherwise 0
// (i.e. SMPH_CLAIMED).
while(HWREG(SMPH_BASE + SMPH_O_SMPH0 + 4 * ui32Semaphore) ==
SMPH_CLAIMED)
{
}
}
void SSIConfigSetExpClk(uint32_t ui32Base, uint32_t ui32SSIClk, uint32_t ui32Protocol, uint32_t ui32Mode, uint32_t ui32BitRate, uint32_t ui32DataWidth) {
uint32_t ui32MaxBitRate;
uint32_t ui32RegVal;
uint32_t ui32PreDiv;
uint32_t ui32SCR;
uint32_t ui32SPH_SPO;
// Check the arguments.
ASSERT(SSIBaseValid(ui32Base));
ASSERT((ui32Protocol == SSI_FRF_MOTO_MODE_0) ||
(ui32Protocol == SSI_FRF_MOTO_MODE_1) ||
(ui32Protocol == SSI_FRF_MOTO_MODE_2) ||
(ui32Protocol == SSI_FRF_MOTO_MODE_3) ||
(ui32Protocol == SSI_FRF_TI) ||
(ui32Protocol == SSI_FRF_NMW));
ASSERT((ui32Mode == SSI_MODE_MASTER) ||
(ui32Mode == SSI_MODE_SLAVE) ||
(ui32Mode == SSI_MODE_SLAVE_OD));
ASSERT(((ui32Mode == SSI_MODE_MASTER) && (ui32BitRate <= (ui32SSIClk / 2))) ||
((ui32Mode != SSI_MODE_MASTER) && (ui32BitRate <= (ui32SSIClk / 12))));
ASSERT((ui32SSIClk / ui32BitRate) <= (254 * 256));
ASSERT((ui32DataWidth >= 4) && (ui32DataWidth <= 16));
// Set the mode.
ui32RegVal = (ui32Mode == SSI_MODE_SLAVE_OD) ? SSI_CR1_SOD : 0;
ui32RegVal |= (ui32Mode == SSI_MODE_MASTER) ? 0 : SSI_CR1_MS;
HWREG(ui32Base + SSI_O_CR1) = ui32RegVal;
// Set the clock predivider.
ui32MaxBitRate = ui32SSIClk / ui32BitRate;
ui32PreDiv = 0;
do
{
ui32PreDiv += 2;
ui32SCR = (ui32MaxBitRate / ui32PreDiv) - 1;
}
while(ui32SCR > 255);
HWREG(ui32Base + SSI_O_CPSR) = ui32PreDiv;
// Set protocol and clock rate.
ui32SPH_SPO = (ui32Protocol & 3) << 6;
ui32Protocol &= SSI_CR0_FRF_M;
ui32RegVal = (ui32SCR << 8) | ui32SPH_SPO | ui32Protocol | (ui32DataWidth - 1);
HWREG(ui32Base + SSI_O_CR0) = ui32RegVal;
}
int32_t SSIDataPutNonBlocking(uint32_t ui32Base, uint32_t ui32Data) {
// Check the arguments.
ASSERT(SSIBaseValid(ui32Base));
ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
SSI_CR0_DSS_M))) == 0);
// Check for space to write.
if(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF)
{
HWREG(ui32Base + SSI_O_DR) = ui32Data;
return(1);
}
else
{
return(0);
}
}
void SSIDataPut(uint32_t ui32Base, uint32_t ui32Data) {
// Check the arguments.
ASSERT(SSIBaseValid(ui32Base));
ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
SSI_CR0_DSS_M))) == 0);
// Wait until there is space.
while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF))
{
}
// Write the data to the SSI.
HWREG(ui32Base + SSI_O_DR) = ui32Data;
}
void SSIDataGet(uint32_t ui32Base, uint32_t *pui32Data) {
// Check the arguments.
ASSERT(SSIBaseValid(ui32Base));
// Wait until there is data to be read.
while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_RNE))
{
}
// Read data from SSI.
*pui32Data = HWREG(ui32Base + SSI_O_DR);
}
int32_t SSIDataGetNonBlocking(uint32_t ui32Base, uint32_t *pui32Data) {
// Check the arguments.
ASSERT(SSIBaseValid(ui32Base));
// Check for data to read.
if(HWREG(ui32Base + SSI_O_SR) & SSI_SR_RNE)
{
*pui32Data = HWREG(ui32Base + SSI_O_DR);
return(1);
}
else
{
return(0);
}
}
void TimerConfigure(uint32_t ui32Base, uint32_t ui32Config) {
// Check the arguments.
ASSERT(TimerBaseValid(ui32Base));
ASSERT((ui32Config == TIMER_CFG_ONE_SHOT) ||
(ui32Config == TIMER_CFG_ONE_SHOT_UP) ||
(ui32Config == TIMER_CFG_PERIODIC) ||
(ui32Config == TIMER_CFG_PERIODIC_UP) ||
((ui32Config & 0xFF000000) == TIMER_CFG_SPLIT_PAIR));
ASSERT(((ui32Config & 0xFF000000) != TIMER_CFG_SPLIT_PAIR) ||
((((ui32Config & 0x000000FF) == TIMER_CFG_A_ONE_SHOT) ||
((ui32Config & 0x000000FF) == TIMER_CFG_A_ONE_SHOT_UP) ||
((ui32Config & 0x000000FF) == TIMER_CFG_A_PERIODIC) ||
((ui32Config & 0x000000FF) == TIMER_CFG_A_PERIODIC_UP) ||
((ui32Config & 0x000000FF) == TIMER_CFG_A_CAP_COUNT) ||
((ui32Config & 0x000000FF) == TIMER_CFG_A_CAP_COUNT_UP) ||
((ui32Config & 0x000000FF) == TIMER_CFG_A_CAP_TIME) ||
((ui32Config & 0x000000FF) == TIMER_CFG_A_CAP_TIME_UP) ||
((ui32Config & 0x000000FF) == TIMER_CFG_A_PWM)) &&
(((ui32Config & 0x0000FF00) == TIMER_CFG_B_ONE_SHOT) ||
((ui32Config & 0x0000FF00) == TIMER_CFG_B_ONE_SHOT_UP) ||
((ui32Config & 0x0000FF00) == TIMER_CFG_B_PERIODIC) ||
((ui32Config & 0x0000FF00) == TIMER_CFG_B_PERIODIC_UP) ||
((ui32Config & 0x0000FF00) == TIMER_CFG_B_CAP_COUNT) ||
((ui32Config & 0x0000FF00) == TIMER_CFG_B_CAP_COUNT_UP) ||
((ui32Config & 0x0000FF00) == TIMER_CFG_B_CAP_TIME) ||
((ui32Config & 0x0000FF00) == TIMER_CFG_B_CAP_TIME_UP) ||
((ui32Config & 0x0000FF00) == TIMER_CFG_B_PWM))));
// Disable the timers.
HWREG(ui32Base + GPT_O_CTL) &= ~(GPT_CTL_TAEN | GPT_CTL_TBEN);
// Set the global timer configuration.
HWREG(ui32Base + GPT_O_CFG) = ui32Config >> 24;
// Set the configuration of the A and B timers. Note that the B timer
// configuration is ignored by the hardware in 32-bit modes.
HWREG(ui32Base + GPT_O_TAMR) = (ui32Config & 0xFF) | GPT_TAMR_TAPWMIE;
HWREG(ui32Base + GPT_O_TBMR) =
((ui32Config >> 8) & 0xFF) | GPT_TBMR_TBPWMIE;
}
void TimerLevelControl(uint32_t ui32Base, uint32_t ui32Timer, bool bInvert) {
// Check the arguments.
ASSERT(TimerBaseValid(ui32Base));
ASSERT((ui32Timer == TIMER_A) || (ui32Timer == TIMER_B) ||
(ui32Timer == TIMER_BOTH));
// Set the output levels as requested.
ui32Timer &= GPT_CTL_TAPWML | GPT_CTL_TBPWML;
HWREG(ui32Base + GPT_O_CTL) = (bInvert ?
(HWREG(ui32Base + GPT_O_CTL) | ui32Timer) :
(HWREG(ui32Base + GPT_O_CTL) &
~(ui32Timer)));
}
void TimerStallControl(uint32_t ui32Base, uint32_t ui32Timer, bool bStall) {
// Check the arguments.
ASSERT(TimerBaseValid(ui32Base));
ASSERT((ui32Timer == TIMER_A) || (ui32Timer == TIMER_B) ||
(ui32Timer == TIMER_BOTH));
// Set the stall mode.
ui32Timer &= GPT_CTL_TASTALL | GPT_CTL_TBSTALL;
HWREG(ui32Base + GPT_O_CTL) = (bStall ?
(HWREG(ui32Base + GPT_O_CTL) | ui32Timer) :
(HWREG(ui32Base + GPT_O_CTL) & ~(ui32Timer)));
}
void TimerWaitOnTriggerControl(uint32_t ui32Base, uint32_t ui32Timer, bool bWait) {
// Check the arguments.
ASSERT(TimerBaseValid(ui32Base));
ASSERT((ui32Timer == TIMER_A) || (ui32Timer == TIMER_B) ||
(ui32Timer == TIMER_BOTH));
// Set the wait on trigger mode for timer A.
if(ui32Timer & TIMER_A)
{
if(bWait)
{
HWREG(ui32Base + GPT_O_TAMR) |= GPT_TAMR_TAWOT;
}
else
{
HWREG(ui32Base + GPT_O_TAMR) &= ~(GPT_TAMR_TAWOT);
}
}
// Set the wait on trigger mode for timer B.
if(ui32Timer & TIMER_B)
{
if(bWait)
{
HWREG(ui32Base + GPT_O_TBMR) |= GPT_TBMR_TBWOT;
}
else
{
HWREG(ui32Base + GPT_O_TBMR) &= ~(GPT_TBMR_TBWOT);
}
}
}
void TimerMatchUpdateMode(uint32_t ui32Base, uint32_t ui32Timer, uint32_t ui32Mode) {
// Check the arguments
ASSERT(TimerBaseValid(ui32Base));
ASSERT((ui32Timer == TIMER_A) || (ui32Timer == TIMER_B) || (ui32Timer == TIMER_BOTH));
ASSERT((ui32Mode == TIMER_MATCHUPDATE_NEXTCYCLE) || (ui32Mode == TIMER_MATCHUPDATE_TIMEOUT));
// Set mode for timer A
if(ui32Timer & TIMER_A)
{
if(ui32Mode == TIMER_MATCHUPDATE_NEXTCYCLE)
{
HWREG(ui32Base + GPT_O_TAMR) &= ~(GPT_TAMR_TAMRSU);
}
else
{
HWREG(ui32Base + GPT_O_TAMR) |= GPT_TAMR_TAMRSU;
}
}
// Set mode for timer B
if(ui32Timer & TIMER_B)
{
if(ui32Mode == TIMER_MATCHUPDATE_NEXTCYCLE)
{
HWREG(ui32Base + GPT_O_TBMR) &= ~(GPT_TBMR_TBMRSU);
}
else
{
HWREG(ui32Base + GPT_O_TBMR) |= GPT_TBMR_TBMRSU;
}
}
}
void TimerIntervalLoadMode(uint32_t ui32Base, uint32_t ui32Timer, uint32_t ui32Mode) {
// Check the arguments
ASSERT(TimerBaseValid(ui32Base));
ASSERT((ui32Timer == TIMER_A) || (ui32Timer == TIMER_B) || (ui32Timer == TIMER_BOTH));
ASSERT((ui32Mode == TIMER_INTERVALLOAD_NEXTCYCLE) || (ui32Mode == TIMER_INTERVALLOAD_TIMEOUT));
// Set mode for timer A
if(ui32Timer & TIMER_A)
{
if(ui32Mode == TIMER_INTERVALLOAD_NEXTCYCLE)
{
HWREG(ui32Base + GPT_O_TAMR) &= ~(GPT_TAMR_TAILD);
}
else
{
HWREG(ui32Base + GPT_O_TAMR) |= GPT_TAMR_TAILD;
}
}
// Set mode for timer B
if(ui32Timer & TIMER_B)
{
if(ui32Mode == TIMER_INTERVALLOAD_NEXTCYCLE)
{
HWREG(ui32Base + GPT_O_TBMR) &= ~(GPT_TBMR_TBILD);
}
else
{
HWREG(ui32Base + GPT_O_TBMR) |= GPT_TBMR_TBILD;
}
}
}
void TRNGConfigure(uint32_t ui32MinSamplesPerCycle, uint32_t ui32MaxSamplesPerCycle, uint32_t ui32ClocksPerSample) {
uint32_t ui32Val;
// Make sure the TRNG is disabled.
ui32Val = HWREG(TRNG_BASE + TRNG_O_CTL) & ~TRNG_CTL_TRNG_EN;
HWREG(TRNG_BASE + TRNG_O_CTL) = ui32Val;
// Configure the startup number of samples.
ui32Val &= ~TRNG_CTL_STARTUP_CYCLES_M;
ui32Val |= ((( ui32MaxSamplesPerCycle >> 8 ) << TRNG_CTL_STARTUP_CYCLES_S ) & TRNG_CTL_STARTUP_CYCLES_M );
HWREG(TRNG_BASE + TRNG_O_CTL) = ui32Val;
// Configure the minimum and maximum number of samples pr generated number
// and the number of clocks per sample.
HWREG(TRNG_BASE + TRNG_O_CFG0) = (
((( ui32MaxSamplesPerCycle >> 8 ) << TRNG_CFG0_MAX_REFILL_CYCLES_S ) & TRNG_CFG0_MAX_REFILL_CYCLES_M ) |
((( ui32ClocksPerSample ) << TRNG_CFG0_SMPL_DIV_S ) & TRNG_CFG0_SMPL_DIV_M ) |
((( ui32MinSamplesPerCycle >> 6 ) << TRNG_CFG0_MIN_REFILL_CYCLES_S ) & TRNG_CFG0_MIN_REFILL_CYCLES_M ) );
}
uint32_t TRNGNumberGet(uint32_t ui32Word) {
uint32_t ui32RandomNumber;
// Check the arguments.
ASSERT((ui32Word == TRNG_HI_WORD) ||
(ui32Word == TRNG_LOW_WORD));
// Return the right requested part of the generated number.
if(ui32Word == TRNG_HI_WORD)
{
ui32RandomNumber = HWREG(TRNG_BASE + TRNG_O_OUT1);
}
else
{
ui32RandomNumber = HWREG(TRNG_BASE + TRNG_O_OUT0);
}
// Initiate generation of new number.
HWREG(TRNG_BASE + TRNG_O_IRQFLAGCLR) = 0x1;
// Return the random number.
return ui32RandomNumber;
}
void UARTFIFOLevelGet(uint32_t ui32Base, uint32_t *pui32TxLevel, uint32_t *pui32RxLevel) {
uint32_t ui32Temp;
// Check the arguments.
ASSERT(UARTBaseValid(ui32Base));
// Read the FIFO level register.
ui32Temp = HWREG(ui32Base + UART_O_IFLS);
// Extract the transmit and receive FIFO levels.
*pui32TxLevel = ui32Temp & UART_IFLS_TXSEL_M;
*pui32RxLevel = ui32Temp & UART_IFLS_RXSEL_M;
}
void UARTConfigSetExpClk(uint32_t ui32Base, uint32_t ui32UARTClk, uint32_t ui32Baud, uint32_t ui32Config) {
uint32_t ui32Div;
// Check the arguments.
ASSERT(UARTBaseValid(ui32Base));
ASSERT(ui32Baud != 0);
// Stop the UART.
UARTDisable(ui32Base);
// Compute the fractional baud rate divider.
ui32Div = (((ui32UARTClk * 8) / ui32Baud) + 1) / 2;
// Set the baud rate.
HWREG(ui32Base + UART_O_IBRD) = ui32Div / 64;
HWREG(ui32Base + UART_O_FBRD) = ui32Div % 64;
// Set parity, data length, and number of stop bits.
HWREG(ui32Base + UART_O_LCRH) = ui32Config;
}
void UARTConfigGetExpClk(uint32_t ui32Base, uint32_t ui32UARTClk, uint32_t *pui32Baud, uint32_t *pui32Config) {
uint32_t ui32Int, ui32Frac;
// Check the arguments.
ASSERT(UARTBaseValid(ui32Base));
// Compute the baud rate.
ui32Int = HWREG(ui32Base + UART_O_IBRD);
ui32Frac = HWREG(ui32Base + UART_O_FBRD);
*pui32Baud = (ui32UARTClk * 4) / ((64 * ui32Int) + ui32Frac);
// Get the parity, data length, and number of stop bits.
*pui32Config = (HWREG(ui32Base + UART_O_LCRH) &
(UART_LCRH_SPS | UART_LCRH_WLEN_M | UART_LCRH_STP2 |
UART_LCRH_EPS | UART_LCRH_PEN));
}
void UARTDisable(uint32_t ui32Base) {
// Check the arguments.
ASSERT(UARTBaseValid(ui32Base));
// Wait for end of TX.
while(HWREG(ui32Base + UART_O_FR) & UART_FR_BUSY)
{
}
// Disable the FIFO.
HWREG(ui32Base + UART_O_LCRH) &= ~(UART_LCRH_FEN);
// Disable the UART.
HWREG(ui32Base + UART_O_CTL) &= ~(UART_CTL_UARTEN | UART_CTL_TXE |
UART_CTL_RXE);
}
int32_t UARTCharGetNonBlocking(uint32_t ui32Base) {
// Check the arguments.
ASSERT(UARTBaseValid(ui32Base));
// See if there are any characters in the receive FIFO.
if(!(HWREG(ui32Base + UART_O_FR) & UART_FR_RXFE))
{
// Read and return the next character.
return(HWREG(ui32Base + UART_O_DR));
}
else
{
// There are no characters, so return a failure.
return(-1);
}
}
int32_t UARTCharGet(uint32_t ui32Base) {
// Check the arguments.
ASSERT(UARTBaseValid(ui32Base));
// Wait until a char is available.
while(HWREG(ui32Base + UART_O_FR) & UART_FR_RXFE)
{
}
// Now get the character.
return(HWREG(ui32Base + UART_O_DR));
}
bool UARTCharPutNonBlocking(uint32_t ui32Base, uint8_t ui8Data) {
// Check the arguments.
ASSERT(UARTBaseValid(ui32Base));
// See if there is space in the transmit FIFO.
if(!(HWREG(ui32Base + UART_O_FR) & UART_FR_TXFF))
{
// Write this character to the transmit FIFO.
HWREG(ui32Base + UART_O_DR) = ui8Data;
// Success.
return(true);
}
else
{
// There is no space in the transmit FIFO, so return a failure.
return(false);
}
}
void UARTCharPut(uint32_t ui32Base, uint8_t ui8Data) {
// Check the arguments.
ASSERT(UARTBaseValid(ui32Base));
// Wait until space is available.
while(HWREG(ui32Base + UART_O_FR) & UART_FR_TXFF)
{
}
// Send the char.
HWREG(ui32Base + UART_O_DR) = ui8Data;
}
void uDMAChannelAttributeEnable(uint32_t ui32Base, uint32_t ui32ChannelNum, uint32_t ui32Attr) {
// Check the arguments.
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
ASSERT((ui32Attr & ~(UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)) == 0);
// Set the useburst bit for this channel if set in ui32Attr.
if(ui32Attr & UDMA_ATTR_USEBURST)
{
HWREG(ui32Base + UDMA_O_SETBURST) = 1 << ui32ChannelNum;
}
// Set the alternate control select bit for this channel,
// if set in ui32Attr.
if(ui32Attr & UDMA_ATTR_ALTSELECT)
{
HWREG(ui32Base + UDMA_O_SETCHNLPRIALT) = 1 << ui32ChannelNum;
}
// Set the high priority bit for this channel, if set in ui32Attr.
if(ui32Attr & UDMA_ATTR_HIGH_PRIORITY)
{
HWREG(ui32Base + UDMA_O_SETCHNLPRIORITY) = 1 << ui32ChannelNum;
}
// Set the request mask bit for this channel, if set in ui32Attr.
if(ui32Attr & UDMA_ATTR_REQMASK)
{
HWREG(ui32Base + UDMA_O_SETREQMASK) = 1 << ui32ChannelNum;
}
}
void uDMAChannelAttributeDisable(uint32_t ui32Base, uint32_t ui32ChannelNum, uint32_t ui32Attr) {
// Check the arguments.
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
ASSERT((ui32Attr & ~(UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)) == 0);
// Clear the useburst bit for this channel if set in ui32Attr.
if(ui32Attr & UDMA_ATTR_USEBURST)
{
HWREG(ui32Base + UDMA_O_CLEARBURST) = 1 << ui32ChannelNum;
}
// Clear the alternate control select bit for this channel, if set in
// ululAttr.
if(ui32Attr & UDMA_ATTR_ALTSELECT)
{
HWREG(ui32Base + UDMA_O_CLEARCHNLPRIALT) = 1 << ui32ChannelNum;
}
// Clear the high priority bit for this channel, if set in ui32Attr.
if(ui32Attr & UDMA_ATTR_HIGH_PRIORITY)
{
HWREG(ui32Base + UDMA_O_CLEARCHNLPRIORITY) = 1 << ui32ChannelNum;
}
// Clear the request mask bit for this channel, if set in ui32Attr.
if(ui32Attr & UDMA_ATTR_REQMASK)
{
HWREG(ui32Base + UDMA_O_CLEARREQMASK) = 1 << ui32ChannelNum;
}
}
uint32_t uDMAChannelAttributeGet(uint32_t ui32Base, uint32_t ui32ChannelNum) {
uint32_t ui32Attr = 0;
// Check the arguments.
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
// Check to see if useburst bit is set for this channel.
if(HWREG(ui32Base + UDMA_O_SETBURST) & (1 << ui32ChannelNum))
{
ui32Attr |= UDMA_ATTR_USEBURST;
}
// Check to see if the alternate control bit is set for this channel.
if(HWREG(ui32Base + UDMA_O_SETCHNLPRIALT) & (1 << ui32ChannelNum))
{
ui32Attr |= UDMA_ATTR_ALTSELECT;
}
// Check to see if the high priority bit is set for this channel.
if(HWREG(ui32Base + UDMA_O_SETCHNLPRIORITY) & (1 << ui32ChannelNum))
{
ui32Attr |= UDMA_ATTR_HIGH_PRIORITY;
}
// Check to see if the request mask bit is set for this channel.
if(HWREG(ui32Base + UDMA_O_SETREQMASK) & (1 << ui32ChannelNum))
{
ui32Attr |= UDMA_ATTR_REQMASK;
}
// Return the configuration flags.
return(ui32Attr);
}
void uDMAChannelControlSet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex, uint32_t ui32Control) {
tDMAControlTable *pControlTable;
// Check the arguments.
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
// Get the base address of the control table.
pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
// Get the current control word value and mask off the fields to be
// changed, then OR in the new settings.
pControlTable[ui32ChannelStructIndex].ui32Control =
((pControlTable[ui32ChannelStructIndex].ui32Control &
~(UDMA_DST_INC_M |
UDMA_SRC_INC_M |
UDMA_SIZE_M |
UDMA_ARB_M |
UDMA_NEXT_USEBURST)) |
ui32Control);
}
void uDMAChannelTransferSet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex, uint32_t ui32Mode, void *pvSrcAddr, void *pvDstAddr, uint32_t ui32TransferSize) {
tDMAControlTable *pControlTable;
uint32_t ui32Control;
uint32_t ui32Inc;
uint32_t ui32BufferBytes;
// Check the arguments.
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
ASSERT(ui32Mode <= UDMA_MODE_PER_SCATTER_GATHER);
ASSERT((uint32_t)pvSrcAddr >= SRAM_BASE);
ASSERT((uint32_t)pvDstAddr >= SRAM_BASE);
ASSERT((ui32TransferSize != 0) && (ui32TransferSize <= UDMA_XFER_SIZE_MAX));
// Get the base address of the control table.
pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
// Get the current control word value and mask off the mode and size
// fields.
ui32Control = (pControlTable[ui32ChannelStructIndex].ui32Control &
~(UDMA_XFER_SIZE_M | UDMA_MODE_M));
// Adjust the mode if the alt control structure is selected.
if(ui32ChannelStructIndex & UDMA_ALT_SELECT)
{
if((ui32Mode == UDMA_MODE_MEM_SCATTER_GATHER) ||
(ui32Mode == UDMA_MODE_PER_SCATTER_GATHER))
{
ui32Mode |= UDMA_MODE_ALT_SELECT;
}
}
// Set the transfer size and mode in the control word (but don't write the
// control word yet as it could kick off a transfer).
ui32Control |= ui32Mode | ((ui32TransferSize - 1) << UDMA_XFER_SIZE_S);
// Get the address increment value for the source, from the control word.
ui32Inc = (ui32Control & UDMA_SRC_INC_M);
// Compute the ending source address of the transfer. If the source
// increment is set to none, then the ending address is the same as the
// beginning.
if(ui32Inc != UDMA_SRC_INC_NONE)
{
ui32Inc = ui32Inc >> UDMA_SRC_INC_S;
ui32BufferBytes = ui32TransferSize << ui32Inc;
pvSrcAddr = (void *)((uint32_t)pvSrcAddr + ui32BufferBytes - (1 << ui32Inc));
}
// Load the source ending address into the control block.
pControlTable[ui32ChannelStructIndex].pvSrcEndAddr = pvSrcAddr;
// Get the address increment value for the destination, from the control
// word.
ui32Inc = ui32Control & UDMA_DST_INC_M;
// Compute the ending destination address of the transfer. If the
// destination increment is set to none, then the ending address is the
// same as the beginning.
if(ui32Inc != UDMA_DST_INC_NONE)
{
// There is a special case if this is setting up a scatter-gather
// transfer. The destination pointer needs to point to the end of
// the alternate structure for this channel instead of calculating
// the end of the buffer in the normal way.
if((ui32Mode == UDMA_MODE_MEM_SCATTER_GATHER) ||
(ui32Mode == UDMA_MODE_PER_SCATTER_GATHER))
{
pvDstAddr =
(void *)&pControlTable[ui32ChannelStructIndex |
UDMA_ALT_SELECT].ui32Spare;
}
// Not a scatter-gather transfer, calculate end pointer normally.
else
{
ui32Inc = ui32Inc >> UDMA_DST_INC_S;
ui32BufferBytes = ui32TransferSize << ui32Inc;
pvDstAddr = (void *)((uint32_t)pvDstAddr + ui32BufferBytes - 1);
}
}
// Load the destination ending address into the control block.
pControlTable[ui32ChannelStructIndex].pvDstEndAddr = pvDstAddr;
// Write the new control word value.
pControlTable[ui32ChannelStructIndex].ui32Control = ui32Control;
}
void uDMAChannelScatterGatherSet(uint32_t ui32Base, uint32_t ui32ChannelNum, uint32_t ui32TaskCount, void *pvTaskList, uint32_t ui32IsPeriphSG) {
tDMAControlTable *pControlTable;
tDMAControlTable *pTaskTable;
// Check the parameters.
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelNum < UDMA_NUM_CHANNELS);
ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
ASSERT(pvTaskList != 0);
ASSERT(ui32TaskCount <= UDMA_XFER_SIZE_MAX);
ASSERT(ui32TaskCount != 0);
// Get the base address of the control table.
pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
// Get a handy pointer to the task list.
pTaskTable = (tDMAControlTable *)pvTaskList;
// Compute the ending address for the source pointer. This will be the
// last element of the last task in the task table.
pControlTable[ui32ChannelNum].pvSrcEndAddr =
&pTaskTable[ui32TaskCount - 1].ui32Spare;
// Compute the ending address for the destination pointer. This will be
// the end of the alternate structure for this channel.
pControlTable[ui32ChannelNum].pvDstEndAddr =
&pControlTable[ui32ChannelNum | UDMA_ALT_SELECT].ui32Spare;
// Compute the control word. Most configurable items are fixed for
// scatter-gather. Item and increment sizes are all 32-bit and arb
// size must be 4. The count is the number of items in the task list
// times 4 (4 words per task).
pControlTable[ui32ChannelNum].ui32Control =
(UDMA_DST_INC_32 | UDMA_SRC_INC_32 |
UDMA_SIZE_32 | UDMA_ARB_4 |
(((ui32TaskCount * 4) - 1) << UDMA_XFER_SIZE_S) |
(ui32IsPeriphSG ? UDMA_MODE_PER_SCATTER_GATHER :
UDMA_MODE_MEM_SCATTER_GATHER));
// Scatter-gather operations can leave the alt bit set. So if doing
// back to back scatter-gather transfers, the second attempt may not
// work correctly because the alt bit is set. Therefore, clear the
// alt bit here to ensure that it is always cleared before a new SG
// transfer is started.
HWREG(ui32Base + UDMA_O_CLEARCHNLPRIALT) = 1 << ui32ChannelNum;
}
uint32_t uDMAChannelSizeGet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex) {
tDMAControlTable *pControlTable;
uint32_t ui32Control;
// Check the arguments.
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
// Get the base address of the control table.
pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
// Get the current control word value and mask off all but the size field
// and the mode field.
ui32Control = (pControlTable[ui32ChannelStructIndex].ui32Control &
(UDMA_XFER_SIZE_M | UDMA_MODE_M));
// If the size field and mode field are 0 then the transfer is finished
// and there are no more items to transfer.
if(ui32Control == 0)
{
return(0);
}
// Otherwise, if either the size field or more field is non-zero, then
// not all the items have been transferred.
else
{
// Shift the size field and add one, then return to user.
return((ui32Control >> UDMA_XFER_SIZE_S) + 1);
}
}
uint32_t uDMAChannelModeGet(uint32_t ui32Base, uint32_t ui32ChannelStructIndex) {
tDMAControlTable *pControlTable;
uint32_t ui32Control;
// Check the arguments.
ASSERT(uDMABaseValid(ui32Base));
ASSERT(ui32ChannelStructIndex < (UDMA_NUM_CHANNELS * 2));
ASSERT(HWREG(ui32Base + UDMA_O_CTRL) != 0);
// Get the base address of the control table.
pControlTable = (tDMAControlTable *)HWREG(ui32Base + UDMA_O_CTRL);
// Get the current control word value and mask off all but the mode field.
ui32Control = (pControlTable[ui32ChannelStructIndex].ui32Control &
UDMA_MODE_M);
// Check if scatter/gather mode, and if so, mask off the alt bit.
if(((ui32Control & ~UDMA_MODE_ALT_SELECT) == UDMA_MODE_MEM_SCATTER_GATHER) ||
((ui32Control & ~UDMA_MODE_ALT_SELECT) == UDMA_MODE_PER_SCATTER_GATHER))
{
ui32Control &= ~UDMA_MODE_ALT_SELECT;
}
// Return the mode to the caller.
return(ui32Control);
}
void VIMSConfigure(uint32_t ui32Base, bool bRoundRobin, bool bPrefetch) {
uint32_t ui32Reg;
// Check the arguments.
ASSERT(VIMSBaseValid(ui32Base));
ui32Reg = HWREG(ui32Base + VIMS_O_CTL);
ui32Reg &= ~(VIMS_CTL_PREF_EN | VIMS_CTL_ARB_CFG);
if(bRoundRobin)
{
ui32Reg |= VIMS_CTL_ARB_CFG;
}
if(bPrefetch)
{
ui32Reg |= VIMS_CTL_PREF_EN;
}
// Set the Arbitration and prefetch mode.
HWREG(ui32Base + VIMS_O_CTL) = ui32Reg;
}
void VIMSModeSet(uint32_t ui32Base, uint32_t ui32Mode) {
uint32_t ui32Reg;
// Check the arguments.
ASSERT(VIMSBaseValid(ui32Base));
ASSERT((ui32Mode == VIMS_MODE_DISABLED) ||
(ui32Mode == VIMS_MODE_ENABLED) ||
(ui32Mode == VIMS_MODE_OFF));
// Set the mode.
ui32Reg = HWREG(ui32Base + VIMS_O_CTL);
ui32Reg &= ~VIMS_CTL_MODE_M;
ui32Reg |= (ui32Mode & VIMS_CTL_MODE_M);
HWREG(ui32Base + VIMS_O_CTL) = ui32Reg;
}
uint32_t VIMSModeGet(uint32_t ui32Base) {
uint32_t ui32Reg;
// Check the arguments.
ASSERT(VIMSBaseValid(ui32Base));
ui32Reg = HWREG(ui32Base + VIMS_O_STAT);
if(ui32Reg & VIMS_STAT_MODE_CHANGING)
{
return (VIMS_MODE_CHANGING);
}
else
{
return (ui32Reg & VIMS_STAT_MODE_M);
}
}
void VIMSModeSafeSet( uint32_t ui32Base, uint32_t ui32NewMode, bool blocking ) {
uint32_t currentMode;
// Check the arguments.
ASSERT(VIMSBaseValid(ui32Base));
ASSERT((ui32NewMode == VIMS_MODE_DISABLED) ||
(ui32NewMode == VIMS_MODE_ENABLED) ||
(ui32NewMode == VIMS_MODE_OFF));
// Make sure that only the mode bits are set in the input parameter
// (done just for security since it is critical to the code flow)
ui32NewMode &= VIMS_CTL_MODE_M;
// Wait for any pending change to complete and get current VIMS mode
// (This is a blocking point but will typically only be a blocking point
// only if mode is changed multiple times with blocking=0)
do {
currentMode = VIMSModeGet( ui32Base );
} while ( currentMode == VIMS_MODE_CHANGING );
// First check that it actually is a mode change request
if ( ui32NewMode != currentMode ) {
// Due to a hw-problem it is strongly recommended to go via VIMS_MODE_OFF
// when leaving VIMS_MODE_ENABLED (=VIMS_CTL_MODE_CACHE)
// (And no need to go via OFF, if OFF is the final state and will be set later)
if (( currentMode == VIMS_CTL_MODE_CACHE ) &&
( ui32NewMode != VIMS_CTL_MODE_OFF ) )
{
VIMSModeSet( ui32Base, VIMS_MODE_OFF );
while ( HWREGBITW( VIMS_BASE + VIMS_O_STAT, VIMS_STAT_MODE_CHANGING_BITN )) {
// Do nothing - wait for change to complete.
// (Needed blocking point but it takes only some few cycles)
}
}
// Set new mode
VIMSModeSet( ui32Base, ui32NewMode );
// Wait for final mode change to complete - if blocking is requested
if ( blocking ) {
while ( HWREGBITW( VIMS_BASE + VIMS_O_STAT, VIMS_STAT_MODE_CHANGING_BITN )) {
// Do nothing - wait for change to complete.
}
}
}
}
uint32_t CRYPTOAesLoadKey(uint32_t *pui32AesKey, uint32_t ui32KeyLocation) {
// Check the arguments.
ASSERT((ui32KeyLocation == CRYPTO_KEY_AREA_0) |
(ui32KeyLocation == CRYPTO_KEY_AREA_1) |
(ui32KeyLocation == CRYPTO_KEY_AREA_2) |
(ui32KeyLocation == CRYPTO_KEY_AREA_3) |
(ui32KeyLocation == CRYPTO_KEY_AREA_4) |
(ui32KeyLocation == CRYPTO_KEY_AREA_5) |
(ui32KeyLocation == CRYPTO_KEY_AREA_6) |
(ui32KeyLocation == CRYPTO_KEY_AREA_7));
// Disable the external interrupt to stop the interrupt form propagating
// from the module to the System CPU.
IntDisable(INT_CRYPTO_RESULT_AVAIL_IRQ);
// Enable internal interrupts.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQTYPE) = CRYPTO_IRQTYPE_LEVEL;
HWREG(CRYPTO_BASE + CRYPTO_O_IRQEN) = CRYPTO_IRQEN_DMA_IN_DONE |
CRYPTO_IRQEN_RESULT_AVAIL;
// Configure master control module.
HWREGBITW(CRYPTO_BASE + CRYPTO_O_ALGSEL, CRYPTO_ALGSEL_KEY_STORE_BITN) = 1;
// Clear any outstanding events.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = (CRYPTO_IRQCLR_DMA_IN_DONE |
CRYPTO_IRQCLR_RESULT_AVAIL);
// Configure key store module for 128 bit operation.
HWREG(CRYPTO_BASE + CRYPTO_O_KEYSIZE) &= ~CRYPTO_KEYSIZE_SIZE_M;
HWREG(CRYPTO_BASE + CRYPTO_O_KEYSIZE) |= KEY_STORE_SIZE_128;
// Enable keys to write (e.g. Key 0).
HWREG(CRYPTO_BASE + CRYPTO_O_KEYWRITEAREA) = (0x00000001 << ui32KeyLocation);
// Enable Crypto DMA channel 0.
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH0CTL, CRYPTO_DMACH0CTL_EN_BITN) = 1;
// Base address of the key in ext. memory.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0EXTADDR) = (uint32_t)pui32AesKey;
// Total key length in bytes (e.g. 16 for 1 x 128-bit key).
// Writing the length of the key enables the DMA operation.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0LEN) = KEY_BLENGTH;
// Wait for the DMA operation to complete.
do
{
CPUdelay(1);
}
while(!(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & 0x00000001));
// Check for errors in DMA and key store.
if((HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) &
(CRYPTO_IRQSTAT_DMA_BUS_ERR |
CRYPTO_IRQSTAT_KEY_ST_WR_ERR)) == 0)
{
// Acknowledge/clear the interrupt and disable the master control.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = (CRYPTO_IRQCLR_DMA_IN_DONE |
CRYPTO_IRQCLR_RESULT_AVAIL);
HWREG(CRYPTO_BASE + CRYPTO_O_ALGSEL) = 0x00000000;
// Check status, if error return error code.
if(HWREG(CRYPTO_BASE + CRYPTO_O_KEYWRITTENAREA) != (0x00000001 << ui32KeyLocation))
{
return (AES_KEYSTORE_READ_ERROR);
}
}
// Return success.
return (AES_SUCCESS);
}
uint32_t CRYPTOAesCbc(uint32_t *pui32MsgIn, uint32_t *pui32MsgOut, uint32_t ui32MsgLength, uint32_t *pui32Nonce, uint32_t ui32KeyLocation, bool bEncrypt, bool bIntEnable) {
uint32_t ui32CtrlVal;
// Enable internal interrupts.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQTYPE) = CRYPTO_IRQTYPE_LEVEL;
HWREG(CRYPTO_BASE + CRYPTO_O_IRQEN) = CRYPTO_IRQEN_RESULT_AVAIL;
// Clear any outstanding interrupts.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = (CRYPTO_IRQCLR_DMA_IN_DONE |
CRYPTO_IRQCLR_RESULT_AVAIL);
// Wait for interrupt lines from module to be cleared
while(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & (CRYPTO_IRQSTAT_DMA_IN_DONE | CRYPTO_IRQSTAT_RESULT_AVAIL));
// If using interrupts clear any pending interrupts and enable interrupts
// for the Crypto module.
if(bIntEnable)
{
IntPendClear(INT_CRYPTO_RESULT_AVAIL_IRQ);
IntEnable(INT_CRYPTO_RESULT_AVAIL_IRQ);
}
// Configure Master Control module.
HWREG(CRYPTO_BASE + CRYPTO_O_ALGSEL) = CRYPTO_ALGSEL_AES;
// Enable keys to read (e.g. Key 0).
HWREG(CRYPTO_BASE + CRYPTO_O_KEYREADAREA) = ui32KeyLocation;
//Wait until key is loaded to the AES module.
do
{
CPUdelay(1);
}
while((HWREG(CRYPTO_BASE + CRYPTO_O_KEYREADAREA) & CRYPTO_KEYREADAREA_BUSY));
// Check for Key store Read error.
if((HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT)& CRYPTO_KEY_ST_RD_ERR))
{
return (AES_KEYSTORE_READ_ERROR);
}
// Write initialization vector.
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV0) = pui32Nonce[0];
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV1) = pui32Nonce[1];
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV2) = pui32Nonce[2];
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV3) = pui32Nonce[3];
// Configure AES engine for AES-CBC with 128-bit key size.
ui32CtrlVal = (CRYPTO_AESCTL_SAVE_CONTEXT | CRYPTO_AESCTL_CBC);
if(bEncrypt)
{
ui32CtrlVal |= CRYPTO_AES128_ENCRYPT;
}
else
{
ui32CtrlVal |= CRYPTO_AES128_DECRYPT;
}
HWREG(CRYPTO_BASE + CRYPTO_O_AESCTL) = ui32CtrlVal;
// Write the length of the crypto block (plain text).
// Low and high part (high part is assumed to be always 0).
HWREG(CRYPTO_BASE + CRYPTO_O_AESDATALEN0) = ui32MsgLength;
HWREG(CRYPTO_BASE + CRYPTO_O_AESDATALEN1) = 0;
HWREG(CRYPTO_BASE + CRYPTO_O_AESAUTHLEN) = 0;
// Enable Crypto DMA channel 0.
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH0CTL, CRYPTO_DMACH0CTL_EN_BITN) = 1;
// Base address of the input data in ext. memory.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0EXTADDR) = (uint32_t)pui32MsgIn;
// Input data length in bytes, equal to the message.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0LEN) = ui32MsgLength;
// Enable Crypto DMA channel 1.
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH1CTL, CRYPTO_DMACH1CTL_EN_BITN) = 1;
// Set up the address and length of the output data.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH1EXTADDR) = (uint32_t)pui32MsgOut;
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH1LEN) = ui32MsgLength;
// Return success
return AES_SUCCESS;
}
uint32_t CRYPTOAesCbcStatus(void) {
return(CRYPTOAesEcbStatus());
}
uint32_t CRYPTOAesEcb(uint32_t *pui32MsgIn, uint32_t *pui32MsgOut, uint32_t ui32KeyLocation, bool bEncrypt, bool bIntEnable) {
// Enable internal interrupts.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQTYPE) = CRYPTO_IRQTYPE_LEVEL;
HWREG(CRYPTO_BASE + CRYPTO_O_IRQEN) = CRYPTO_IRQEN_RESULT_AVAIL;
// Clear any outstanding interrupts.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = (CRYPTO_IRQCLR_DMA_IN_DONE |
CRYPTO_IRQCLR_RESULT_AVAIL);
// Wait for interrupt lines from module to be cleared
while(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & (CRYPTO_IRQSTAT_DMA_IN_DONE | CRYPTO_IRQSTAT_RESULT_AVAIL));
// If using interrupts clear any pending interrupts and enable interrupts
// for the Crypto module.
if(bIntEnable)
{
IntPendClear(INT_CRYPTO_RESULT_AVAIL_IRQ);
IntEnable(INT_CRYPTO_RESULT_AVAIL_IRQ);
}
// Configure Master Control module.
HWREG(CRYPTO_BASE + CRYPTO_O_ALGSEL) = CRYPTO_ALGSEL_AES;
// Enable keys to read (e.g. Key 0).
HWREG(CRYPTO_BASE + CRYPTO_O_KEYREADAREA) = ui32KeyLocation;
//Wait until key is loaded to the AES module.
do
{
CPUdelay(1);
}
while((HWREG(CRYPTO_BASE + CRYPTO_O_KEYREADAREA) & CRYPTO_KEYREADAREA_BUSY));
// Check for Key store Read error.
if((HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT)& CRYPTO_KEY_ST_RD_ERR))
{
return (AES_KEYSTORE_READ_ERROR);
}
// Configure AES engine (program AES-ECB-128 encryption and no
// initialization vector - IV).
if(bEncrypt)
{
HWREG(CRYPTO_BASE + CRYPTO_O_AESCTL) = CRYPTO_AES128_ENCRYPT;
}
else
{
HWREG(CRYPTO_BASE + CRYPTO_O_AESCTL) = CRYPTO_AES128_DECRYPT;
}
// Write the length of the data.
HWREG(CRYPTO_BASE + CRYPTO_O_AESDATALEN0) = AES_ECB_LENGTH;
HWREG(CRYPTO_BASE + CRYPTO_O_AESDATALEN1) = 0;
// Enable Crypto DMA channel 0.
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH0CTL, CRYPTO_DMACH0CTL_EN_BITN) = 1;
// Base address of the input data in ext. memory.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0EXTADDR) = (uint32_t)pui32MsgIn;
// Input data length in bytes, equal to the message.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0LEN) = AES_ECB_LENGTH;
// Enable Crypto DMA channel 1.
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH1CTL, CRYPTO_DMACH1CTL_EN_BITN) = 1;
// Set up the address and length of the output data.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH1EXTADDR) = (uint32_t)pui32MsgOut;
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH1LEN) = AES_ECB_LENGTH;
// Return success
return AES_SUCCESS;
}
uint32_t CRYPTOAesEcbStatus(void) {
uint32_t ui32Status;
// Get the current DMA status.
ui32Status = HWREG(CRYPTO_BASE + CRYPTO_O_DMASTAT);
// Check if DMA is still busy.
if(ui32Status & CRYPTO_DMA_BSY)
{
return (AES_DMA_BSY);
}
// Check the status of the DMA operation - return error if not success.
if(ui32Status & CRYPTO_DMA_BUS_ERROR)
{
return (AES_DMA_BUS_ERROR);
}
// Operation successful - disable interrupt and return success.
IntDisable(INT_CRYPTO_RESULT_AVAIL_IRQ);
return (AES_SUCCESS);
}
uint32_t CRYPTOCcmAuthEncrypt(bool bEncrypt, uint32_t ui32AuthLength , uint32_t *pui32Nonce, uint32_t *pui32PlainText, uint32_t ui32PlainTextLength, uint32_t *pui32Header, uint32_t ui32HeaderLength, uint32_t ui32KeyLocation, uint32_t ui32FieldLength, bool bIntEnable) {
uint32_t ui32CtrlVal;
uint32_t i;
uint32_t *pui32CipherText;
union {
uint32_t w[4];
uint8_t b[16];
} ui8InitVec;
// Input address for the encryption engine is the same as the output.
pui32CipherText = pui32PlainText;
// Disable global interrupt, enable local interrupt and clear any pending
// interrupts.
IntDisable(INT_CRYPTO_RESULT_AVAIL_IRQ);
HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = (CRYPTO_IRQCLR_DMA_IN_DONE |
CRYPTO_IRQCLR_RESULT_AVAIL);
// Enable internal interrupts.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQTYPE) = CRYPTO_IRQTYPE_LEVEL;
HWREG(CRYPTO_BASE + CRYPTO_O_IRQEN) = CRYPTO_IRQEN_DMA_IN_DONE |
CRYPTO_IRQEN_RESULT_AVAIL;
// Configure master control module for AES operation.
HWREG(CRYPTO_BASE + CRYPTO_O_ALGSEL) = CRYPTO_ALGSEL_AES;
// Enable keys to read (e.g. Key 0).
HWREG(CRYPTO_BASE + CRYPTO_O_KEYREADAREA) = ui32KeyLocation;
// Wait until key is loaded to the AES module.
do
{
CPUdelay(1);
}
while((HWREG(CRYPTO_BASE + CRYPTO_O_KEYREADAREA) & CRYPTO_KEYREADAREA_BUSY));
// Check for Key store Read error.
if((HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT)& CRYPTO_KEY_ST_RD_ERR))
{
return (AES_KEYSTORE_READ_ERROR);
}
// Prepare the initialization vector (IV),
// Length of Nonce l(n) = 15 - ui32FieldLength.
ui8InitVec.b[0] = ui32FieldLength - 1;
for(i = 0; i < 12; i++)
{
ui8InitVec.b[i + 1] = ((uint8_t*)pui32Nonce)[i];
}
if(ui32FieldLength == 2)
{
ui8InitVec.b[13] = ((uint8_t*)pui32Nonce)[12];
}
else
{
ui8InitVec.b[13] = 0;
}
ui8InitVec.b[14] = 0;
ui8InitVec.b[15] = 0;
// Write initialization vector.
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV0) = ui8InitVec.w[0];
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV1) = ui8InitVec.w[1];
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV2) = ui8InitVec.w[2];
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV3) = ui8InitVec.w[3];
// Configure AES engine.
ui32CtrlVal = ((ui32FieldLength - 1) << CRYPTO_AESCTL_CCM_L_S);
if ( ui32AuthLength >= 2 ) {
ui32CtrlVal |= ((( ui32AuthLength - 2 ) >> 1 ) << CRYPTO_AESCTL_CCM_M_S );
}
ui32CtrlVal |= CRYPTO_AESCTL_CCM;
ui32CtrlVal |= CRYPTO_AESCTL_CTR;
ui32CtrlVal |= CRYPTO_AESCTL_SAVE_CONTEXT;
ui32CtrlVal |= (KEY_STORE_SIZE_128 << CRYPTO_AESCTL_KEY_SIZE_S);
ui32CtrlVal |= (1 << CRYPTO_AESCTL_DIR_S);
ui32CtrlVal |= (CRYPTO_AES_CTR_128 << CRYPTO_AESCTL_CTR_WIDTH_S);
// Write the configuration for 128 bit AES-CCM.
HWREG(CRYPTO_BASE + CRYPTO_O_AESCTL) = ui32CtrlVal;
// Write the length of the crypto block (plain text).
// Low and high part (high part is assumed to be always 0).
HWREG(CRYPTO_BASE + CRYPTO_O_AESDATALEN0) = ui32PlainTextLength;
HWREG(CRYPTO_BASE + CRYPTO_O_AESDATALEN1) = 0;
// Write the length of the header field.
// Also called AAD - Additional Authentication Data.
HWREG(CRYPTO_BASE + CRYPTO_O_AESAUTHLEN) = ui32HeaderLength;
// Check if any header information (AAD).
// If so configure the DMA controller to fetch the header.
if(ui32HeaderLength != 0)
{
// Enable DMA channel 0.
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH0CTL, CRYPTO_DMACH0CTL_EN_BITN) = 1;
// Register the base address of the header (AAD).
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0EXTADDR) = (uint32_t)pui32Header;
// Header length in bytes (may be non-block size aligned).
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0LEN) = ui32HeaderLength;
// Wait for completion of the header data transfer, DMA_IN_DONE.
do
{
CPUdelay(1);
}
while(!(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & CRYPTO_IRQSTAT_DMA_IN_DONE));
// Check for DMA errors.
if(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & CRYPTO_DMA_BUS_ERR)
{
return AES_DMA_BUS_ERROR;
}
}
// Clear interrupt status.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = (CRYPTO_IRQCLR_DMA_IN_DONE |
CRYPTO_IRQCLR_RESULT_AVAIL);
// Wait for interrupt lines from module to be cleared
while(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & (CRYPTO_IRQSTAT_DMA_IN_DONE | CRYPTO_IRQSTAT_RESULT_AVAIL));
// Disable CRYPTO_IRQEN_DMA_IN_DONE interrupt as we only
// want interrupt to trigger once RESULT_AVAIL occurs.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQEN) &= ~CRYPTO_IRQEN_DMA_IN_DONE;
// Is using interrupts enable globally.
if(bIntEnable)
{
IntPendClear(INT_CRYPTO_RESULT_AVAIL_IRQ);
IntEnable(INT_CRYPTO_RESULT_AVAIL_IRQ);
}
// Enable interrupts locally.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQEN) = CRYPTO_IRQEN_RESULT_AVAIL;
// Perform encryption if requested.
if(bEncrypt)
{
// Enable DMA channel 0
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH0CTL, CRYPTO_DMACH0CTL_EN_BITN) = 1;
// base address of the payload data in ext. memory.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0EXTADDR) =
(uint32_t)pui32PlainText;
// Enable DMA channel 1
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH1CTL, CRYPTO_DMACH1CTL_EN_BITN) = 1;
// Base address of the output data buffer.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH1EXTADDR) =
(uint32_t)pui32CipherText;
// Payload data length in bytes, equal to the plaintext length.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0LEN) = ui32PlainTextLength;
// Output data length in bytes, equal to the plaintext length.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH1LEN) = ui32PlainTextLength;
}
return AES_SUCCESS;
}
uint32_t CRYPTOCcmAuthEncryptStatus(void) {
uint32_t ui32Status;
// Get the current DMA status.
ui32Status = HWREG(CRYPTO_BASE + CRYPTO_O_DMASTAT);
// Check if DMA is still busy.
if(ui32Status & CRYPTO_DMA_BSY)
{
return (AES_DMA_BSY);
}
// Check the status of the DMA operation - return error if not success.
if(ui32Status & CRYPTO_DMA_BUS_ERROR)
{
return (AES_DMA_BUS_ERROR);
}
// Operation successful - disable interrupt and return success.
IntDisable(INT_CRYPTO_RESULT_AVAIL_IRQ);
return (AES_SUCCESS);
}
uint32_t CRYPTOCcmAuthEncryptResultGet(uint32_t ui32TagLength, uint32_t *pui32CcmTag) {
uint32_t volatile ui32Tag[4];
uint32_t ui32Idx;
// Result has already been copied to the output buffer by DMA
// Disable master control.
HWREG(CRYPTO_BASE + CRYPTO_O_ALGSEL) = 0x00000000;
// Read tag - wait for the context ready bit.
do
{
CPUdelay(1);
}
while(!(HWREG(CRYPTO_BASE + CRYPTO_O_AESCTL) &
CRYPTO_AESCTL_SAVED_CONTEXT_RDY));
// Read the Tag registers.
ui32Tag[0] = HWREG(CRYPTO_BASE + CRYPTO_O_AESTAGOUT0);
ui32Tag[1] = HWREG(CRYPTO_BASE + CRYPTO_O_AESTAGOUT1);
ui32Tag[2] = HWREG(CRYPTO_BASE + CRYPTO_O_AESTAGOUT2);
ui32Tag[3] = HWREG(CRYPTO_BASE + CRYPTO_O_AESTAGOUT3);
for(ui32Idx = 0; ui32Idx < ui32TagLength ; ui32Idx++)
{
*((uint8_t*)pui32CcmTag + ui32Idx) = *((uint8_t*)ui32Tag + ui32Idx);
}
// Operation successful - clear interrupt status.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = (CRYPTO_IRQCLR_DMA_IN_DONE |
CRYPTO_IRQCLR_RESULT_AVAIL);
return AES_SUCCESS;
}
uint32_t CRYPTOCcmInvAuthDecrypt(bool bDecrypt, uint32_t ui32AuthLength, uint32_t *pui32Nonce, uint32_t *pui32CipherText, uint32_t ui32CipherTextLength, uint32_t *pui32Header, uint32_t ui32HeaderLength, uint32_t ui32KeyLocation, uint32_t ui32FieldLength, bool bIntEnable) {
uint32_t ui32CtrlVal;
uint32_t i;
uint32_t *pui32PlainText;
uint32_t ui32CryptoBlockLength;
union {
uint32_t w[4];
uint8_t b[16];
} ui8InitVec;
// Input address for the encryption engine is the same as the output.
pui32PlainText = pui32CipherText;
// Disable global interrupt, enable local interrupt and clear any pending.
// interrupts.
IntDisable(INT_CRYPTO_RESULT_AVAIL_IRQ);
HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = (CRYPTO_IRQCLR_DMA_IN_DONE |
CRYPTO_IRQCLR_RESULT_AVAIL);
// Enable internal interrupts.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQTYPE) = CRYPTO_IRQTYPE_LEVEL;
HWREG(CRYPTO_BASE + CRYPTO_O_IRQEN) = CRYPTO_IRQEN_DMA_IN_DONE |
CRYPTO_IRQEN_RESULT_AVAIL;
// Configure master control module for AES operation.
HWREG(CRYPTO_BASE + CRYPTO_O_ALGSEL) = CRYPTO_ALGSEL_AES;
// Enable keys to read (e.g. Key 0).
HWREG(CRYPTO_BASE + CRYPTO_O_KEYREADAREA) = ui32KeyLocation;
// Wait until key is loaded to the AES module.
do
{
CPUdelay(1);
}
while((HWREG(CRYPTO_BASE + CRYPTO_O_KEYREADAREA) & CRYPTO_KEYREADAREA_BUSY));
// Check for Key store Read error.
if((HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT)& CRYPTO_KEY_ST_RD_ERR))
{
return (AES_KEYSTORE_READ_ERROR);
}
// Prepare the initialization vector (IV),
// Length of Nonce l(n) = 15 - ui32FieldLength.
ui8InitVec.b[0] = ui32FieldLength - 1;
for(i = 0; i < 12; i++)
{
ui8InitVec.b[i + 1] = ((uint8_t*)pui32Nonce)[i];
}
if(ui32FieldLength == 2)
{
ui8InitVec.b[13] = ((uint8_t*)pui32Nonce)[12];
}
else
{
ui8InitVec.b[13] = 0;
}
ui8InitVec.b[14] = 0;
ui8InitVec.b[15] = 0;
// Write initialization vector.
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV0) = ui8InitVec.w[0];
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV1) = ui8InitVec.w[1];
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV2) = ui8InitVec.w[2];
HWREG(CRYPTO_BASE + CRYPTO_O_AESIV3) = ui8InitVec.w[3];
// Configure AES engine
ui32CryptoBlockLength = ui32CipherTextLength - ui32AuthLength;
ui32CtrlVal = ((ui32FieldLength - 1) << CRYPTO_AESCTL_CCM_L_S);
if ( ui32AuthLength >= 2 ) {
ui32CtrlVal |= ((( ui32AuthLength - 2 ) >> 1 ) << CRYPTO_AESCTL_CCM_M_S );
}
ui32CtrlVal |= CRYPTO_AESCTL_CCM;
ui32CtrlVal |= CRYPTO_AESCTL_CTR;
ui32CtrlVal |= CRYPTO_AESCTL_SAVE_CONTEXT;
ui32CtrlVal |= (KEY_STORE_SIZE_128 << CRYPTO_AESCTL_KEY_SIZE_S);
ui32CtrlVal |= (0 << CRYPTO_AESCTL_DIR_S);
ui32CtrlVal |= (CRYPTO_AES_CTR_128 << CRYPTO_AESCTL_CTR_WIDTH_S);
// Write the configuration for 128 bit AES-CCM.
HWREG(CRYPTO_BASE + CRYPTO_O_AESCTL) = ui32CtrlVal;
// Write the length of the crypto block (plain text).
// Low and high part (high part is assumed to be always 0).
HWREG(CRYPTO_BASE + CRYPTO_O_AESDATALEN0) = ui32CryptoBlockLength;
HWREG(CRYPTO_BASE + CRYPTO_O_AESDATALEN1) = 0;
// Write the length of the header field.
// Also called AAD - Additional Authentication Data.
HWREG(CRYPTO_BASE + CRYPTO_O_AESAUTHLEN) = ui32HeaderLength;
// Check if any header information (AAD).
// If so configure the DMA controller to fetch the header.
if(ui32HeaderLength != 0)
{
// Enable DMA channel 0.
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH0CTL, CRYPTO_DMACH0CTL_EN_BITN) = 1;
// Register the base address of the header (AAD).
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0EXTADDR) = (uint32_t)pui32Header;
// Header length in bytes (may be non-block size aligned).
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0LEN) = ui32HeaderLength;
// Wait for completion of the header data transfer, DMA_IN_DONE.
do
{
CPUdelay(1);
}
while(!(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & CRYPTO_IRQSTAT_DMA_IN_DONE));
// Check for DMA errors.
if(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & CRYPTO_DMA_BUS_ERR)
{
return AES_DMA_BUS_ERROR;
}
}
// Clear interrupt status.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = (CRYPTO_IRQCLR_DMA_IN_DONE |
CRYPTO_IRQCLR_RESULT_AVAIL);
// Wait for interrupt lines from module to be cleared
while(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & (CRYPTO_IRQSTAT_DMA_IN_DONE | CRYPTO_IRQSTAT_RESULT_AVAIL));
// Disable CRYPTO_IRQEN_DMA_IN_DONE interrupt as we only
// want interrupt to trigger once RESULT_AVAIL occurs.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQEN) &= ~CRYPTO_IRQEN_DMA_IN_DONE;
// Is using interrupts - clear and enable globally.
if(bIntEnable)
{
IntPendClear(INT_CRYPTO_RESULT_AVAIL_IRQ);
IntEnable(INT_CRYPTO_RESULT_AVAIL_IRQ);
}
// Enable internal interrupts.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQTYPE) = CRYPTO_IRQTYPE_LEVEL;
HWREG(CRYPTO_BASE + CRYPTO_O_IRQEN) = CRYPTO_IRQEN_RESULT_AVAIL;
// Perform decryption if requested.
if(bDecrypt)
{
// Configure the DMA controller - enable both DMA channels.
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH0CTL, CRYPTO_DMACH0CTL_EN_BITN) = 1;
// Base address of the payload data in ext. memory.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0EXTADDR) =
(uint32_t)pui32CipherText;
// Payload data length in bytes, equal to the cipher text length.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0LEN) = ui32CryptoBlockLength;
// Enable DMA channel 1.
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH1CTL, CRYPTO_DMACH1CTL_EN_BITN) = 1;
// Base address of the output data buffer.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH1EXTADDR) =
(uint32_t)pui32PlainText;
// Output data length in bytes, equal to the cipher text length.
HWREG(CRYPTO_BASE + CRYPTO_O_DMACH1LEN) = ui32CryptoBlockLength;
}
return AES_SUCCESS;
}
uint32_t CRYPTOCcmInvAuthDecryptStatus(void) {
uint32_t ui32Status;
// Get the current DMA status.
ui32Status = HWREG(CRYPTO_BASE + CRYPTO_O_DMASTAT);
// Check if DMA is still busy.
if(ui32Status & CRYPTO_DMA_BSY)
{
return (AES_DMA_BSY);
}
// Check the status of the DMA operation - return error if not success.
if(ui32Status & CRYPTO_DMA_BUS_ERROR)
{
return (AES_DMA_BUS_ERROR);
}
// Operation successful - disable interrupt and return success
IntDisable(INT_CRYPTO_RESULT_AVAIL_IRQ);
return (AES_SUCCESS);
}
uint32_t CRYPTOCcmInvAuthDecryptResultGet(uint32_t ui32AuthLength, uint32_t *pui32CipherText, uint32_t ui32CipherTextLength, uint32_t *pui32CcmTag) {
uint32_t volatile ui32Tag[4];
uint32_t ui32TagIndex;
uint32_t i;
uint32_t ui32Idx;
ui32TagIndex = ui32CipherTextLength - ui32AuthLength;
// Result has already been copied to the output buffer by DMA
// Disable master control.
HWREG(CRYPTO_BASE + CRYPTO_O_ALGSEL) = 0x00000000;
// Read tag - wait for the context ready bit.
do
{
CPUdelay(1);
}
while(!(HWREG(CRYPTO_BASE + CRYPTO_O_AESCTL) &
CRYPTO_AESCTL_SAVED_CONTEXT_RDY));
// Read the Tag registers.
ui32Tag[0] = HWREG(CRYPTO_BASE + CRYPTO_O_AESTAGOUT0);
ui32Tag[1] = HWREG(CRYPTO_BASE + CRYPTO_O_AESTAGOUT1);
ui32Tag[2] = HWREG(CRYPTO_BASE + CRYPTO_O_AESTAGOUT2);
ui32Tag[3] = HWREG(CRYPTO_BASE + CRYPTO_O_AESTAGOUT3);
for(ui32Idx = 0; ui32Idx < ui32AuthLength ; ui32Idx++)
{
*((uint8_t*)pui32CcmTag + ui32Idx) = *((uint8_t*)ui32Tag + ui32Idx);
}
// Operation successful - clear interrupt status.
HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = (CRYPTO_IRQCLR_DMA_IN_DONE |
CRYPTO_IRQCLR_RESULT_AVAIL);
// Verify the Tag.
for(i = 0; i < ui32AuthLength; i++)
{
if(*((uint8_t *)pui32CcmTag + i) !=
(*((uint8_t *)pui32CipherText + ui32TagIndex + i)))
{
return CCM_AUTHENTICATION_FAILED;
}
}
return AES_SUCCESS;
}
void CRYPTODmaEnable(uint32_t ui32Channels) {
// Check the arguments.
ASSERT((ui32Channels & CRYPTO_DMA_CHAN0) |
(ui32Channels & CRYPTO_DMA_CHAN1));
// Enable the selected channels,
if(ui32Channels & CRYPTO_DMA_CHAN0)
{
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH0CTL, CRYPTO_DMACH0CTL_EN_BITN) = 1;
}
if(ui32Channels & CRYPTO_DMA_CHAN1)
{
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH1CTL, CRYPTO_DMACH1CTL_EN_BITN) = 1;
}
}
void CRYPTODmaDisable(uint32_t ui32Channels) {
// Check the arguments.
ASSERT((ui32Channels & CRYPTO_DMA_CHAN0) |
(ui32Channels & CRYPTO_DMA_CHAN1));
// Enable the selected channels.
if(ui32Channels & CRYPTO_DMA_CHAN0)
{
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH0CTL, CRYPTO_DMACH0CTL_EN_BITN) = 0;
}
if(ui32Channels & CRYPTO_DMA_CHAN1)
{
HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH1CTL, CRYPTO_DMACH1CTL_EN_BITN) = 0;
}
}
void OSCClockSourceSet(uint32_t ui32SrcClk, uint32_t ui32Osc) {
// Check the arguments.
ASSERT((ui32SrcClk & OSC_SRC_CLK_LF) ||
(ui32SrcClk & OSC_SRC_CLK_MF) ||
(ui32SrcClk & OSC_SRC_CLK_HF));
ASSERT((ui32Osc == OSC_RCOSC_HF) ||
(ui32Osc == OSC_RCOSC_LF) ||
(ui32Osc == OSC_XOSC_HF) ||
(ui32Osc == OSC_XOSC_LF));
// Request the high frequency source clock (using 24 MHz XTAL)
if(ui32SrcClk & OSC_SRC_CLK_HF)
{
// Enable the HF XTAL as HF clock source
DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL0,
DDI_0_OSC_CTL0_SCLK_HF_SRC_SEL_M,
DDI_0_OSC_CTL0_SCLK_HF_SRC_SEL_S,
ui32Osc);
}
// Configure the medium frequency source clock
if(ui32SrcClk & OSC_SRC_CLK_MF)
{
DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL0,
DDI_0_OSC_CTL0_SCLK_MF_SRC_SEL_M,
DDI_0_OSC_CTL0_SCLK_MF_SRC_SEL_S,
ui32Osc);
}
// Configure the low frequency source clock.
if(ui32SrcClk & OSC_SRC_CLK_LF)
{
// Change the clock source.
DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL0,
DDI_0_OSC_CTL0_SCLK_LF_SRC_SEL_M,
DDI_0_OSC_CTL0_SCLK_LF_SRC_SEL_S,
ui32Osc);
}
}
uint32_t OSCClockSourceGet(uint32_t ui32SrcClk) {
uint32_t ui32ClockSource;
// Check the arguments.
ASSERT((ui32SrcClk & OSC_SRC_CLK_LF) ||
(ui32SrcClk & OSC_SRC_CLK_HF));
// Return the source for the selected clock.
if(ui32SrcClk == OSC_SRC_CLK_LF)
{
ui32ClockSource = DDI16BitfieldRead(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_STAT0,
DDI_0_OSC_STAT0_SCLK_LF_SRC_M,
DDI_0_OSC_STAT0_SCLK_LF_SRC_S);
}
else
{
ui32ClockSource = DDI16BitfieldRead(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_STAT0,
DDI_0_OSC_STAT0_SCLK_HF_SRC_M,
DDI_0_OSC_STAT0_SCLK_HF_SRC_S);
}
return (ui32ClockSource);
}
int32_t OSC_HPOSCRelativeFrequencyOffsetGet( int32_t tempDegC ) {
// Estimate HPOSC frequency, using temperature and curve fitting parameters
uint32_t fitParams = HWREG(FCFG1_BASE + FCFG1_O_FREQ_OFFSET);
// Extract the P0,P1,P2 params, and sign extend them via shifting up/down
int32_t paramP0 = ((((int32_t) fitParams) << (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P0_W - FCFG1_FREQ_OFFSET_HPOSC_COMP_P0_S))
>> (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P0_W));
int32_t paramP1 = ((((int32_t) fitParams) << (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P1_W - FCFG1_FREQ_OFFSET_HPOSC_COMP_P1_S))
>> (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P1_W));
int32_t paramP2 = ((((int32_t) fitParams) << (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P2_W - FCFG1_FREQ_OFFSET_HPOSC_COMP_P2_S))
>> (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P2_W));
int32_t paramP3 = ((((int32_t) HWREG(FCFG1_BASE + FCFG1_O_MISC_CONF_2))
<< (32 - FCFG1_MISC_CONF_2_HPOSC_COMP_P3_W - FCFG1_MISC_CONF_2_HPOSC_COMP_P3_S))
>> (32 - FCFG1_MISC_CONF_2_HPOSC_COMP_P3_W));
// Now we can find the HPOSC freq offset, given as a signed variable d, expressed by:
//
// F_HPOSC = F_nom * (1 + d/(2^22)) , where: F_HPOSC = HPOSC frequency
// F_nom = nominal clock source frequency (e.g. 48.000 MHz)
// d = describes relative freq offset
// We can estimate the d variable, using temperature compensation parameters:
//
// d = P0 + P1*(t - T0) + P2*(t - T0)^2 + P3*(t - T0)^3, where: P0,P1,P2,P3 are curve fitting parameters from FCFG1
// t = current temperature (from temp sensor) in deg C
// T0 = 27 deg C (fixed temperature constant)
int32_t tempDelta = (tempDegC - 27);
int32_t tempDeltaX2 = tempDelta * tempDelta;
int32_t d = paramP0 + ((tempDelta*paramP1)>>3) + ((tempDeltaX2*paramP2)>>10) + ((tempDeltaX2*tempDelta*paramP3)>>18);
return ( d );
}
int16_t OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert( int32_t HPOSC_RelFreqOffset ) {
// The input argument, hereby referred to simply as "d", describes the frequency offset
// of the HPOSC relative to the nominal frequency in this way:
//
// F_HPOSC = F_nom * (1 + d/(2^22))
//
// But for use by the radio, to compensate the frequency error, we need to find the
// frequency offset "rfcFreqOffset" defined in the following format:
//
// F_nom = F_HPOSC * (1 + rfCoreFreqOffset/(2^22))
//
// To derive "rfCoreFreqOffset" from "d" we combine the two above equations and get:
//
// (1 + rfCoreFreqOffset/(2^22)) = (1 + d/(2^22))^-1
//
// Which can be rewritten into:
//
// rfCoreFreqOffset = -d*(2^22) / ((2^22) + d)
//
// = -d * [ 1 / (1 + d/(2^22)) ]
//
// To avoid doing a 64-bit division due to the (1 + d/(2^22))^-1 expression,
// we can use Taylor series (Maclaurin series) to approximate it:
//
// 1 / (1 - x) ~= 1 + x + x^2 + x^3 + x^4 + ... etc (Maclaurin series)
//
// In our case, we have x = - d/(2^22), and we only include up to the first
// order term of the series, as the second order term ((d^2)/(2^44)) is very small:
//
// freqError ~= -d + d^2/(2^22) (+ small approximation error)
//
// The approximation error is negligible for our use.
int32_t rfCoreFreqOffset = -HPOSC_RelFreqOffset + (( HPOSC_RelFreqOffset * HPOSC_RelFreqOffset ) >> 22 );
return ( rfCoreFreqOffset );
}
void AUXADCDisable(void) {
// Disable the ADC reference
ADI8BitsClear(AUX_ADI4_BASE, ADI_4_AUX_O_ADCREF0, ADI_4_AUX_ADCREF0_EN_M | ADI_4_AUX_ADCREF0_REF_ON_IDLE_M | ADI_4_AUX_ADCREF0_SRC_M);
// Assert reset and disable the ADC
ADI8BitsClear(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, ADI_4_AUX_ADC0_EN_M | ADI_4_AUX_ADC0_RESET_N_M | ADI_4_AUX_ADC0_SMPL_MODE_M | ADI_4_AUX_ADC0_SMPL_CYCLE_EXP_M);
// Ensure that scaling is enabled by default before next use of the ADC
ADI8BitsClear(AUX_ADI4_BASE, ADI_4_AUX_O_ADC1, ADI_4_AUX_ADC1_SCALE_DIS_M);
// Disable the ADC clock (no need to wait since IOB_WUC_ADCCLKCTL_ACK goes low immediately)
HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_ADCCLKCTL) = 0;
// Disable the ADC data interface
HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = 0;
}
void AUXADCEnableAsync(uint32_t refSource, uint32_t trigger) {
// Enable the ADC reference, with the following options:
// - SRC: Set when using relative reference
// - REF_ON_IDLE: Always cleared since there is no idle state in asynchronous operation
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADCREF0, refSource | ADI_4_AUX_ADCREF0_EN_M);
// Enable the ADC clock
HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_ADCCLKCTL) = AUX_SYSIF_ADCCLKCTL_REQ_M;
while (!(HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_ADCCLKCTL) & AUX_SYSIF_ADCCLKCTL_ACK_M));
// Enable the ADC data interface
if (trigger == AUXADC_TRIGGER_MANUAL) {
// Manual trigger: No need to configure event routing from GPT
HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_NO_EVENT | AUX_ANAIF_ADCCTL_CMD_EN;
} else {
// GPT trigger: Configure event routing via MCU_EV to the AUX domain
HWREG(EVENT_BASE + EVENT_O_AUXSEL0) = trigger;
HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_MCU_EV | AUX_ANAIF_ADCCTL_CMD_EN;
}
// Configure the ADC
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, ADI_4_AUX_ADC0_SMPL_MODE_M);
// Release reset and enable the ADC
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, ADI_4_AUX_ADC0_EN_M | ADI_4_AUX_ADC0_RESET_N_M);
}
void AUXADCEnableSync(uint32_t refSource, uint32_t sampleTime, uint32_t trigger) {
// Enable the ADC reference, with the following options:
// - SRC: Set when using relative reference
// - REF_ON_IDLE: Set when using fixed reference and sample time < 21.3 us
uint8_t adcref0 = refSource | ADI_4_AUX_ADCREF0_EN_M;
if (!refSource && (sampleTime < AUXADC_SAMPLE_TIME_21P3_US)) {
adcref0 |= ADI_4_AUX_ADCREF0_REF_ON_IDLE_M;
}
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADCREF0, adcref0);
// Enable the ADC clock
HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_ADCCLKCTL) = AUX_SYSIF_ADCCLKCTL_REQ_M;
while (!(HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_ADCCLKCTL) & AUX_SYSIF_ADCCLKCTL_ACK_M));
// Enable the ADC data interface
if (trigger == AUXADC_TRIGGER_MANUAL) {
// Manual trigger: No need to configure event routing from GPT
HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_NO_EVENT | AUX_ANAIF_ADCCTL_CMD_EN;
} else {
// GPT trigger: Configure event routing via MCU_EV to the AUX domain
HWREG(EVENT_BASE + EVENT_O_AUXSEL0) = trigger;
HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_MCU_EV | AUX_ANAIF_ADCCTL_CMD_EN;
}
// Configure the ADC
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, sampleTime << ADI_4_AUX_ADC0_SMPL_CYCLE_EXP_S);
// Release reset and enable the ADC
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, ADI_4_AUX_ADC0_EN_M | ADI_4_AUX_ADC0_RESET_N_M);
}
void AUXADCDisableInputScaling(void) {
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC1, ADI_4_AUX_ADC1_SCALE_DIS_M);
}
void AUXADCFlushFifo(void) {
HWREGBITW(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL, 1) = 1; // CMD: EN(1) -> FLUSH(3)
HWREGBITW(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL, 1) = 0; // CMD: FLUSH(3) -> EN(1)
}
uint32_t AUXADCReadFifo(void) {
// Wait until there is at least one sample in the FIFO
while (HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFOSTAT) & AUX_ANAIF_ADCFIFOSTAT_EMPTY_M);
// Return the first sample from the FIFO
return HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFO);
}
uint32_t AUXADCPopFifo(void) {
// Return the first sample from the FIFO. If the FIFO is empty, this
// generates ADC FIFO underflow
return HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFO);
}
int32_t AUXADCGetAdjustmentGain(uint32_t refSource) {
int32_t gain;
if (refSource == AUXADC_REF_FIXED) {
// AUXADC_REF_FIXED ==> ABS_GAIN
gain = (HWREG(FCFG1_BASE + FCFG1_O_SOC_ADC_ABS_GAIN) & FCFG1_SOC_ADC_ABS_GAIN_SOC_ADC_ABS_GAIN_TEMP1_M) >> FCFG1_SOC_ADC_ABS_GAIN_SOC_ADC_ABS_GAIN_TEMP1_S;
} else {
// AUXADC_REF_VDDS_REL ==> REL_GAIN
gain = (HWREG(FCFG1_BASE + FCFG1_O_SOC_ADC_REL_GAIN) & FCFG1_SOC_ADC_REL_GAIN_SOC_ADC_REL_GAIN_TEMP1_M) >> FCFG1_SOC_ADC_REL_GAIN_SOC_ADC_REL_GAIN_TEMP1_S;
}
return gain;
}
int32_t AUXADCGetAdjustmentOffset(uint32_t refSource) {
int8_t offset;
if ( refSource == AUXADC_REF_FIXED ) {
// AUXADC_REF_FIXED ==> ABS_OFFSET
offset = HWREG(FCFG1_BASE + FCFG1_O_SOC_ADC_OFFSET_INT) >> FCFG1_SOC_ADC_OFFSET_INT_SOC_ADC_ABS_OFFSET_TEMP1_S;
} else {
// AUXADC_REF_VDDS_REL ==> REL_OFFSET
offset = HWREG(FCFG1_BASE + FCFG1_O_SOC_ADC_OFFSET_INT) >> FCFG1_SOC_ADC_OFFSET_INT_SOC_ADC_REL_OFFSET_TEMP1_S;
}
return offset;
}
int32_t AUXADCValueToMicrovolts(int32_t fixedRefVoltage, int32_t adcValue) {
// Chop off 4 bits during calculations to avoid 32-bit overflow
fixedRefVoltage >>= 4;
return (((adcValue * fixedRefVoltage) + 2047) / 4095) << 4;
}
int32_t AUXADCMicrovoltsToValue(int32_t fixedRefVoltage, int32_t microvolts) {
// Chop off 4 bits during calculations to avoid 32-bit overflow
fixedRefVoltage >>= 4;
microvolts >>= 4;
return ((microvolts * 4095) + (fixedRefVoltage / 2)) / fixedRefVoltage;
}
int32_t AUXADCAdjustValueForGainAndOffset(int32_t adcValue, int32_t gain, int32_t offset) {
// Apply gain and offset adjustment
adcValue = (((adcValue + offset) * gain) + 16384) / 32768;
// Saturate
if (adcValue < 0) {
return 0;
} else if (adcValue > 4095) {
return 4095;
} else {
return adcValue;
}
}
int32_t AUXADCUnadjustValueForGainAndOffset(int32_t adcValue, int32_t gain, int32_t offset) {
// Apply inverse gain and offset adjustment
adcValue = (((adcValue * 32768) + (gain / 2)) / gain) - offset;
// Saturate
if (adcValue < 0) {
return 0;
} else if (adcValue > 4095) {
return 4095;
} else {
return adcValue;
}
}
void SysCtrl_DCDC_VoltageConditionalControl( void ) {
uint32_t batThreshold ; // Fractional format with 8 fractional bits.
uint32_t aonBatmonBat ; // Fractional format with 8 fractional bits.
uint32_t ccfg_ModeConfReg ; // Holds a copy of the CCFG_O_MODE_CONF register.
uint32_t aonPmctlPwrctl ; // Reflect whats read/written to the AON_PMCTL_O_PWRCTL register.
// We could potentially call this function before any battery voltage measurement
// is made/available. In that case we must make sure that we do not turn off the DCDC.
// This can be done by doing nothing as long as the battery voltage is 0 (Since the
// reset value of the battery voltage register is 0).
aonBatmonBat = HWREG( AON_BATMON_BASE + AON_BATMON_O_BAT );
if ( aonBatmonBat != 0 ) {
// Check if Voltage Conditional Control is enabled
// It is enabled if all the following are true:
// - DCDC in use (either in active or recharge mode), (in use if one of the corresponding CCFG bits are zero).
// - Alternative DCDC settings are enabled ( DIS_ALT_DCDC_SETTING == 0 )
// - Not in external regulator mode ( EXT_REG_MODE == 0 )
ccfg_ModeConfReg = HWREG( CCFG_BASE + CCFG_O_MODE_CONF );
if (((( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_RECHARGE_M ) == 0 ) ||
(( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_ACTIVE_M ) == 0 ) ) &&
(( HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL ) & AON_PMCTL_PWRCTL_EXT_REG_MODE ) == 0 ) &&
(( HWREG( CCFG_BASE + CCFG_O_SIZE_AND_DIS_FLAGS ) & CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING ) == 0 ) )
{
aonPmctlPwrctl = HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL );
batThreshold = (((( HWREG( CCFG_BASE + CCFG_O_MODE_CONF_1 ) &
CCFG_MODE_CONF_1_ALT_DCDC_VMIN_M ) >>
CCFG_MODE_CONF_1_ALT_DCDC_VMIN_S ) + 28 ) << 4 );
if ( aonPmctlPwrctl & ( AON_PMCTL_PWRCTL_DCDC_EN_M | AON_PMCTL_PWRCTL_DCDC_ACTIVE_M )) {
// DCDC is ON, check if it should be switched off
if ( aonBatmonBat < batThreshold ) {
aonPmctlPwrctl &= ~( AON_PMCTL_PWRCTL_DCDC_EN_M | AON_PMCTL_PWRCTL_DCDC_ACTIVE_M );
HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL ) = aonPmctlPwrctl;
}
} else {
// DCDC is OFF, check if it should be switched on
if ( aonBatmonBat > batThreshold ) {
if (( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_RECHARGE_M ) == 0 ) aonPmctlPwrctl |= AON_PMCTL_PWRCTL_DCDC_EN_M ;
if (( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_ACTIVE_M ) == 0 ) aonPmctlPwrctl |= AON_PMCTL_PWRCTL_DCDC_ACTIVE_M ;
HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL ) = aonPmctlPwrctl;
}
}
}
}
}
uint32_t SysCtrlResetSourceGet( void ) {
if ( HWREG( AON_PMCTL_BASE + AON_PMCTL_O_RESETCTL ) & AON_PMCTL_RESETCTL_WU_FROM_SD_M ) {
return ( RSTSRC_WAKEUP_FROM_SHUTDOWN );
} else {
return (( HWREG( AON_PMCTL_BASE + AON_PMCTL_O_RESETCTL ) &
AON_PMCTL_RESETCTL_RESET_SRC_M ) >>
AON_PMCTL_RESETCTL_RESET_SRC_S ) ;
}
}
int32_t AONBatMonTemperatureGetDegC( void ) {
int32_t signedTemp ; // Signed extended temperature with 8 fractional bits
int32_t tempCorrection ; // Voltage dependent temp correction with 8 fractional bits
int8_t voltageSlope ; // Signed byte value representing the TEMP slope with battery voltage, in degrees C/V, with 4 fractional bits.
// Shift left then right to sign extend the BATMON_TEMP field
signedTemp = ((((int32_t)HWREG( AON_BATMON_BASE + AON_BATMON_O_TEMP ))
<< ( 32 - AON_BATMON_TEMP_INT_W - AON_BATMON_TEMP_INT_S ))
>> ( 32 - AON_BATMON_TEMP_INT_W - AON_BATMON_TEMP_INT_S ));
// Typecasting voltageSlope to int8_t prior to assignment in order to make sure sign extension works properly
// Using byte read (HWREGB) in order to make more efficient code since voltageSlope is assigned to bits[7:0] of FCFG1_O_MISC_TRIM
voltageSlope = ((int8_t)HWREGB( FCFG1_BASE + FCFG1_O_MISC_TRIM ));
tempCorrection = (( voltageSlope * (((int32_t)HWREG( AON_BATMON_BASE + AON_BATMON_O_BAT )) - 0x300 )) >> 4 );
return ((( signedTemp - tempCorrection ) + 0x80 ) >> 8 );
}
// We need intrinsic functions for IAR (if used in source code)
#ifdef __IAR_SYSTEMS_ICC__
#include <intrinsics.h>
#endif
void SetupAfterColdResetWakeupFromShutDownCfg1( uint32_t ccfg_ModeConfReg ) {
int32_t i32VddrSleepTrim;
int32_t i32VddrSleepDelta;
{
i32VddrSleepTrim = SetupSignExtendVddrTrimValue((
HWREG( FCFG1_BASE + FCFG1_O_LDO_TRIM ) &
FCFG1_LDO_TRIM_VDDR_TRIM_SLEEP_M ) >>
FCFG1_LDO_TRIM_VDDR_TRIM_SLEEP_S ) ;
}
// Adjust the VDDR_TRIM_SLEEP value with value adjustable by customer (CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA)
// Read and sign extend VddrSleepDelta (in range -8 to +7)
i32VddrSleepDelta = ((((int32_t)ccfg_ModeConfReg )
<< ( 32 - CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA_W - CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA_S ))
>> ( 32 - CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA_W ));
// Calculate new VDDR sleep trim
i32VddrSleepTrim = ( i32VddrSleepTrim + i32VddrSleepDelta + 1 );
if ( i32VddrSleepTrim > 21 ) i32VddrSleepTrim = 21;
if ( i32VddrSleepTrim < -10 ) i32VddrSleepTrim = -10;
// Write adjusted value using MASKED write (MASK8)
HWREGH( ADI3_BASE + ADI_O_MASK8B + ( ADI_3_REFSYS_O_DCDCCTL1 * 2 )) = (( ADI_3_REFSYS_DCDCCTL1_VDDR_TRIM_SLEEP_M << 8 ) |
(( i32VddrSleepTrim << ADI_3_REFSYS_DCDCCTL1_VDDR_TRIM_SLEEP_S ) & ADI_3_REFSYS_DCDCCTL1_VDDR_TRIM_SLEEP_M ));
// 1.
// Do not allow DCDC to be enabled if in external regulator mode.
// Preventing this by setting both the RECHARGE and the ACTIVE bits bit in the CCFG_MODE_CONF copy register (ccfg_ModeConfReg).
//
// 2.
// Adjusted battery monitor low limit in internal regulator mode.
// This is done by setting AON_BATMON_FLASHPUMPP0_LOWLIM=0 in internal regulator mode.
if ( HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL ) & AON_PMCTL_PWRCTL_EXT_REG_MODE ) {
ccfg_ModeConfReg |= ( CCFG_MODE_CONF_DCDC_RECHARGE_M | CCFG_MODE_CONF_DCDC_ACTIVE_M );
} else {
HWREGBITW( AON_BATMON_BASE + AON_BATMON_O_FLASHPUMPP0, AON_BATMON_FLASHPUMPP0_LOWLIM_BITN ) = 0;
}
// set the RECHARGE source based upon CCFG:MODE_CONF:DCDC_RECHARGE
// Note: Inverse polarity
HWREGBITW( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL, AON_PMCTL_PWRCTL_DCDC_EN_BITN ) =
((( ccfg_ModeConfReg >> CCFG_MODE_CONF_DCDC_RECHARGE_S ) & 1 ) ^ 1 );
// set the ACTIVE source based upon CCFG:MODE_CONF:DCDC_ACTIVE
// Note: Inverse polarity
HWREGBITW( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL, AON_PMCTL_PWRCTL_DCDC_ACTIVE_BITN ) =
((( ccfg_ModeConfReg >> CCFG_MODE_CONF_DCDC_ACTIVE_S ) & 1 ) ^ 1 );
}
void SetupAfterColdResetWakeupFromShutDownCfg2( uint32_t ui32Fcfg1Revision, uint32_t ccfg_ModeConfReg ) {
uint32_t ui32Trim;
// Following sequence is required for using XOSCHF, if not included
// devices crashes when trying to switch to XOSCHF.
//
// Trim CAP settings. Get and set trim value for the ANABYPASS_VALUE1
// register
ui32Trim = SetupGetTrimForAnabypassValue1( ccfg_ModeConfReg );
DDI32RegWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_ANABYPASSVAL1, ui32Trim);
// Trim RCOSC_LF. Get and set trim values for the RCOSCLF_RTUNE_TRIM and
// RCOSCLF_CTUNE_TRIM fields in the XOSCLF_RCOSCLF_CTRL register.
ui32Trim = SetupGetTrimForRcOscLfRtuneCtuneTrim();
DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_LFOSCCTL,
(DDI_0_OSC_LFOSCCTL_RCOSCLF_CTUNE_TRIM_M |
DDI_0_OSC_LFOSCCTL_RCOSCLF_RTUNE_TRIM_M),
DDI_0_OSC_LFOSCCTL_RCOSCLF_CTUNE_TRIM_S,
ui32Trim);
// Trim XOSCHF IBIAS THERM. Get and set trim value for the
// XOSCHF IBIAS THERM bit field in the ANABYPASS_VALUE2 register. Other
// register bit fields are set to 0.
ui32Trim = SetupGetTrimForXoscHfIbiastherm();
DDI32RegWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_ANABYPASSVAL2,
ui32Trim<<DDI_0_OSC_ANABYPASSVAL2_XOSC_HF_IBIASTHERM_S);
// Trim AMPCOMP settings required before switch to XOSCHF
ui32Trim = SetupGetTrimForAmpcompTh2();
DDI32RegWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_AMPCOMPTH2, ui32Trim);
ui32Trim = SetupGetTrimForAmpcompTh1();
DDI32RegWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_AMPCOMPTH1, ui32Trim);
#if ( CCFG_BASE == 0x50003000 )
ui32Trim = SetupGetTrimForAmpcompCtrl( ui32Fcfg1Revision );
#else
ui32Trim = NOROM_SetupGetTrimForAmpcompCtrl( ui32Fcfg1Revision );
#endif
DDI32RegWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_AMPCOMPCTL, ui32Trim);
// Set trim for DDI_0_OSC_ADCDOUBLERNANOAMPCTL_ADC_SH_MODE_EN in accordance to FCFG1 setting
// This is bit[5] in the DDI_0_OSC_O_ADCDOUBLERNANOAMPCTL register
// Using MASK4 write + 1 => writing to bits[7:4]
ui32Trim = SetupGetTrimForAdcShModeEn( ui32Fcfg1Revision );
HWREGB( AUX_DDI0_OSC_BASE + DDI_O_MASK4B + ( DDI_0_OSC_O_ADCDOUBLERNANOAMPCTL * 2 ) + 1 ) =
( 0x20 | ( ui32Trim << 1 ));
// Set trim for DDI_0_OSC_ADCDOUBLERNANOAMPCTL_ADC_SH_VBUF_EN in accordance to FCFG1 setting
// This is bit[4] in the DDI_0_OSC_O_ADCDOUBLERNANOAMPCTL register
// Using MASK4 write + 1 => writing to bits[7:4]
ui32Trim = SetupGetTrimForAdcShVbufEn( ui32Fcfg1Revision );
HWREGB( AUX_DDI0_OSC_BASE + DDI_O_MASK4B + ( DDI_0_OSC_O_ADCDOUBLERNANOAMPCTL * 2 ) + 1 ) =
( 0x10 | ( ui32Trim ));
// Set trim for the PEAK_DET_ITRIM, HP_BUF_ITRIM and LP_BUF_ITRIM bit fields
// in the DDI0_OSC_O_XOSCHFCTL register in accordance to FCFG1 setting.
// Remaining register bit fields are set to their reset values of 0.
ui32Trim = SetupGetTrimForXoscHfCtl(ui32Fcfg1Revision);
DDI32RegWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_XOSCHFCTL, ui32Trim);
// Set trim for DBLR_LOOP_FILTER_RESET_VOLTAGE in accordance to FCFG1 setting
// (This is bits [18:17] in DDI_0_OSC_O_ADCDOUBLERNANOAMPCTL)
// (Using MASK4 write + 4 => writing to bits[19:16] => (4*4))
// (Assuming: DDI_0_OSC_ADCDOUBLERNANOAMPCTL_DBLR_LOOP_FILTER_RESET_VOLTAGE_S = 17 and
// that DDI_0_OSC_ADCDOUBLERNANOAMPCTL_DBLR_LOOP_FILTER_RESET_VOLTAGE_M = 0x00060000)
ui32Trim = SetupGetTrimForDblrLoopFilterResetVoltage( ui32Fcfg1Revision );
HWREGB( AUX_DDI0_OSC_BASE + DDI_O_MASK4B + ( DDI_0_OSC_O_ADCDOUBLERNANOAMPCTL * 2 ) + 4 ) =
( 0x60 | ( ui32Trim << 1 ));
// Update DDI_0_OSC_ATESTCTL_ATESTLF_RCOSCLF_IBIAS_TRIM with data from
// FCFG1_OSC_CONF_ATESTLF_RCOSCLF_IBIAS_TRIM
// This is DDI_0_OSC_O_ATESTCTL bit[7]
// ( DDI_0_OSC_O_ATESTCTL is currently hidden (but=0x00000020))
// Using MASK4 write + 1 => writing to bits[7:4]
ui32Trim = SetupGetTrimForRcOscLfIBiasTrim( ui32Fcfg1Revision );
HWREGB( AUX_DDI0_OSC_BASE + DDI_O_MASK4B + ( 0x00000020 * 2 ) + 1 ) =
( 0x80 | ( ui32Trim << 3 ));
// Update DDI_0_OSC_LFOSCCTL_XOSCLF_REGULATOR_TRIM and
// DDI_0_OSC_LFOSCCTL_XOSCLF_CMIRRWR_RATIO in one write
// This can be simplified since the registers are packed together in the same
// order both in FCFG1 and in the HW register.
// This spans DDI_0_OSC_O_LFOSCCTL bits[23:18]
// Using MASK8 write + 4 => writing to bits[23:16]
ui32Trim = SetupGetTrimForXoscLfRegulatorAndCmirrwrRatio( ui32Fcfg1Revision );
HWREGH( AUX_DDI0_OSC_BASE + DDI_O_MASK8B + ( DDI_0_OSC_O_LFOSCCTL * 2 ) + 4 ) =
( 0xFC00 | ( ui32Trim << 2 ));
// Set trim the HPM_IBIAS_WAIT_CNT, LPM_IBIAS_WAIT_CNT and IDAC_STEP bit
// fields in the DDI0_OSC_O_RADCEXTCFG register in accordance to FCFG1 setting.
// Remaining register bit fields are set to their reset values of 0.
ui32Trim = SetupGetTrimForRadcExtCfg(ui32Fcfg1Revision);
DDI32RegWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_RADCEXTCFG, ui32Trim);
// Setting FORCE_KICKSTART_EN (ref. CC26_V1_BUG00261). Should also be done for PG2
// (This is bit 22 in DDI_0_OSC_O_CTL0)
HWREG( AUX_DDI0_OSC_BASE + DDI_O_SET + DDI_0_OSC_O_CTL0 ) = DDI_0_OSC_CTL0_FORCE_KICKSTART_EN;
}
void SetupAfterColdResetWakeupFromShutDownCfg3( uint32_t ccfg_ModeConfReg ) {
uint32_t fcfg1OscConf;
uint32_t ui32Trim;
uint32_t currentHfClock;
uint32_t ccfgExtLfClk;
// Examin the XOSC_FREQ field to select 0x1=HPOSC, 0x2=48MHz XOSC, 0x3=24MHz XOSC
switch (( ccfg_ModeConfReg & CCFG_MODE_CONF_XOSC_FREQ_M ) >> CCFG_MODE_CONF_XOSC_FREQ_S ) {
case 2 :
// XOSC source is a 48 MHz xtal
// Do nothing (since this is the reset setting)
break;
case 1 :
// XOSC source is HPOSC (trim the HPOSC if this is a chip with HPOSC, otherwise skip trimming and default to 24 MHz XOSC)
fcfg1OscConf = HWREG( FCFG1_BASE + FCFG1_O_OSC_CONF );
if (( fcfg1OscConf & FCFG1_OSC_CONF_HPOSC_OPTION ) == 0 ) {
// This is a HPOSC chip, apply HPOSC settings
// Set bit DDI_0_OSC_CTL0_HPOSC_MODE_EN (this is bit 14 in DDI_0_OSC_O_CTL0)
HWREG( AUX_DDI0_OSC_BASE + DDI_O_SET + DDI_0_OSC_O_CTL0 ) = DDI_0_OSC_CTL0_HPOSC_MODE_EN;
// ADI_2_REFSYS_HPOSCCTL2_BIAS_HOLD_MODE_EN = FCFG1_OSC_CONF_HPOSC_BIAS_HOLD_MODE_EN (1 bit)
// ADI_2_REFSYS_HPOSCCTL2_CURRMIRR_RATIO = FCFG1_OSC_CONF_HPOSC_CURRMIRR_RATIO (4 bits)
// ADI_2_REFSYS_HPOSCCTL1_BIAS_RES_SET = FCFG1_OSC_CONF_HPOSC_BIAS_RES_SET (4 bits)
// ADI_2_REFSYS_HPOSCCTL0_FILTER_EN = FCFG1_OSC_CONF_HPOSC_FILTER_EN (1 bit)
// ADI_2_REFSYS_HPOSCCTL0_BIAS_RECHARGE_DLY = FCFG1_OSC_CONF_HPOSC_BIAS_RECHARGE_DELAY (2 bits)
// ADI_2_REFSYS_HPOSCCTL0_SERIES_CAP = FCFG1_OSC_CONF_HPOSC_SERIES_CAP (2 bits)
// ADI_2_REFSYS_HPOSCCTL0_DIV3_BYPASS = FCFG1_OSC_CONF_HPOSC_DIV3_BYPASS (1 bit)
HWREG( ADI2_BASE + ADI_2_REFSYS_O_HPOSCCTL2 ) = (( HWREG( ADI2_BASE + ADI_2_REFSYS_O_HPOSCCTL2 ) &
~( ADI_2_REFSYS_HPOSCCTL2_BIAS_HOLD_MODE_EN_M | ADI_2_REFSYS_HPOSCCTL2_CURRMIRR_RATIO_M ) ) |
((( fcfg1OscConf & FCFG1_OSC_CONF_HPOSC_BIAS_HOLD_MODE_EN_M ) >> FCFG1_OSC_CONF_HPOSC_BIAS_HOLD_MODE_EN_S ) << ADI_2_REFSYS_HPOSCCTL2_BIAS_HOLD_MODE_EN_S ) |
((( fcfg1OscConf & FCFG1_OSC_CONF_HPOSC_CURRMIRR_RATIO_M ) >> FCFG1_OSC_CONF_HPOSC_CURRMIRR_RATIO_S ) << ADI_2_REFSYS_HPOSCCTL2_CURRMIRR_RATIO_S ) );
HWREG( ADI2_BASE + ADI_2_REFSYS_O_HPOSCCTL1 ) = (( HWREG( ADI2_BASE + ADI_2_REFSYS_O_HPOSCCTL1 ) & ~( ADI_2_REFSYS_HPOSCCTL1_BIAS_RES_SET_M ) ) |
((( fcfg1OscConf & FCFG1_OSC_CONF_HPOSC_BIAS_RES_SET_M ) >> FCFG1_OSC_CONF_HPOSC_BIAS_RES_SET_S ) << ADI_2_REFSYS_HPOSCCTL1_BIAS_RES_SET_S ) );
HWREG( ADI2_BASE + ADI_2_REFSYS_O_HPOSCCTL0 ) = (( HWREG( ADI2_BASE + ADI_2_REFSYS_O_HPOSCCTL0 ) &
~( ADI_2_REFSYS_HPOSCCTL0_FILTER_EN_M | ADI_2_REFSYS_HPOSCCTL0_BIAS_RECHARGE_DLY_M | ADI_2_REFSYS_HPOSCCTL0_SERIES_CAP_M | ADI_2_REFSYS_HPOSCCTL0_DIV3_BYPASS_M )) |
((( fcfg1OscConf & FCFG1_OSC_CONF_HPOSC_FILTER_EN_M ) >> FCFG1_OSC_CONF_HPOSC_FILTER_EN_S ) << ADI_2_REFSYS_HPOSCCTL0_FILTER_EN_S ) |
((( fcfg1OscConf & FCFG1_OSC_CONF_HPOSC_BIAS_RECHARGE_DELAY_M ) >> FCFG1_OSC_CONF_HPOSC_BIAS_RECHARGE_DELAY_S ) << ADI_2_REFSYS_HPOSCCTL0_BIAS_RECHARGE_DLY_S ) |
((( fcfg1OscConf & FCFG1_OSC_CONF_HPOSC_SERIES_CAP_M ) >> FCFG1_OSC_CONF_HPOSC_SERIES_CAP_S ) << ADI_2_REFSYS_HPOSCCTL0_SERIES_CAP_S ) |
((( fcfg1OscConf & FCFG1_OSC_CONF_HPOSC_DIV3_BYPASS_M ) >> FCFG1_OSC_CONF_HPOSC_DIV3_BYPASS_S ) << ADI_2_REFSYS_HPOSCCTL0_DIV3_BYPASS_S ) );
break;
}
// Not a HPOSC chip - fall through to default
default :
// XOSC source is a 24 MHz xtal (default)
// Set bit DDI_0_OSC_CTL0_XTAL_IS_24M (this is bit 31 in DDI_0_OSC_O_CTL0)
HWREG( AUX_DDI0_OSC_BASE + DDI_O_SET + DDI_0_OSC_O_CTL0 ) = DDI_0_OSC_CTL0_XTAL_IS_24M;
break;
}
// Set XOSC_HF in bypass mode if CCFG is configured for external TCXO
// Please note that it is up to the custommer to make sure that the external clock source is up and running before XOSC_HF can be used.
if (( HWREG( CCFG_BASE + CCFG_O_SIZE_AND_DIS_FLAGS ) & CCFG_SIZE_AND_DIS_FLAGS_DIS_TCXO ) == 0 ) {
HWREG( AUX_DDI0_OSC_BASE + DDI_O_SET + DDI_0_OSC_O_XOSCHFCTL ) = DDI_0_OSC_XOSCHFCTL_BYPASS;
}
// Clear DDI_0_OSC_CTL0_CLK_LOSS_EN (ClockLossEventEnable()). This is bit 9 in DDI_0_OSC_O_CTL0.
// This is typically already 0 except on Lizard where it is set in ROM-boot
HWREG( AUX_DDI0_OSC_BASE + DDI_O_CLR + DDI_0_OSC_O_CTL0 ) = DDI_0_OSC_CTL0_CLK_LOSS_EN;
// Setting DDI_0_OSC_CTL1_XOSC_HF_FAST_START according to value found in FCFG1
ui32Trim = SetupGetTrimForXoscHfFastStart();
HWREGB( AUX_DDI0_OSC_BASE + DDI_O_MASK4B + ( DDI_0_OSC_O_CTL1 * 2 )) = ( 0x30 | ui32Trim );
// setup the LF clock based upon CCFG:MODE_CONF:SCLK_LF_OPTION
switch (( ccfg_ModeConfReg & CCFG_MODE_CONF_SCLK_LF_OPTION_M ) >> CCFG_MODE_CONF_SCLK_LF_OPTION_S ) {
case 0 : // XOSC_HF_DLF (XOSCHF/1536) -> SCLK_LF (=31250Hz)
OSCClockSourceSet( OSC_SRC_CLK_LF, OSC_XOSC_HF );
SetupSetAonRtcSubSecInc( 0x8637BD );
break;
case 1 : // EXTERNAL signal -> SCLK_LF (frequency=2^38/CCFG_EXT_LF_CLK_RTC_INCREMENT)
// Set SCLK_LF to use the same source as SCLK_HF
// Can be simplified a bit since possible return values for HF matches LF settings
currentHfClock = OSCClockSourceGet( OSC_SRC_CLK_HF );
OSCClockSourceSet( OSC_SRC_CLK_LF, currentHfClock );
while( OSCClockSourceGet( OSC_SRC_CLK_LF ) != currentHfClock ) {
// Wait until switched
}
ccfgExtLfClk = HWREG( CCFG_BASE + CCFG_O_EXT_LF_CLK );
SetupSetAonRtcSubSecInc(( ccfgExtLfClk & CCFG_EXT_LF_CLK_RTC_INCREMENT_M ) >> CCFG_EXT_LF_CLK_RTC_INCREMENT_S );
IOCPortConfigureSet(( ccfgExtLfClk & CCFG_EXT_LF_CLK_DIO_M ) >> CCFG_EXT_LF_CLK_DIO_S,
IOC_PORT_AON_CLK32K,
IOC_STD_INPUT | IOC_HYST_ENABLE ); // Route external clock to AON IOC w/hysteresis
// Set XOSC_LF in bypass mode to allow external 32k clock
HWREG( AUX_DDI0_OSC_BASE + DDI_O_SET + DDI_0_OSC_O_CTL0 ) = DDI_0_OSC_CTL0_XOSC_LF_DIG_BYPASS;
// Fall through to set XOSC_LF as SCLK_LF source
case 2 : // XOSC_LF -> SLCK_LF (32768 Hz)
OSCClockSourceSet( OSC_SRC_CLK_LF, OSC_XOSC_LF );
break;
default : // (=3) RCOSC_LF
OSCClockSourceSet( OSC_SRC_CLK_LF, OSC_RCOSC_LF );
break;
}
// Update ADI_4_AUX_ADCREF1_VTRIM with value from FCFG1
HWREGB( AUX_ADI4_BASE + ADI_4_AUX_O_ADCREF1 ) =
((( HWREG( FCFG1_BASE + FCFG1_O_SOC_ADC_REF_TRIM_AND_OFFSET_EXT ) >>
FCFG1_SOC_ADC_REF_TRIM_AND_OFFSET_EXT_SOC_ADC_REF_VOLTAGE_TRIM_TEMP1_S ) <<
ADI_4_AUX_ADCREF1_VTRIM_S ) &
ADI_4_AUX_ADCREF1_VTRIM_M );
// Set ADI_4_AUX:ADC0.SMPL_CYCLE_EXP to it's default minimum value (=3)
// (Note: Using MASK8B requires that the bits to be modified must be within the same
// byte boundary which is the case for the ADI_4_AUX_ADC0_SMPL_CYCLE_EXP field)
HWREGH( AUX_ADI4_BASE + ADI_O_MASK8B + ( ADI_4_AUX_O_ADC0 * 2 )) =
( ADI_4_AUX_ADC0_SMPL_CYCLE_EXP_M << 8 ) | ( 3 << ADI_4_AUX_ADC0_SMPL_CYCLE_EXP_S );
// Sync with AON
SysCtrlAonSync();
}
uint32_t SetupGetTrimForAnabypassValue1( uint32_t ccfg_ModeConfReg ) {
uint32_t ui32Fcfg1Value ;
uint32_t ui32XoscHfRow ;
uint32_t ui32XoscHfCol ;
int32_t i32CustomerDeltaAdjust ;
uint32_t ui32TrimValue ;
// Use device specific trim values located in factory configuration
// area for the XOSC_HF_COLUMN_Q12 and XOSC_HF_ROW_Q12 bit fields in
// the ANABYPASS_VALUE1 register. Value for the other bit fields
// are set to 0.
ui32Fcfg1Value = HWREG(FCFG1_BASE + FCFG1_O_CONFIG_OSC_TOP);
ui32XoscHfRow = (( ui32Fcfg1Value &
FCFG1_CONFIG_OSC_TOP_XOSC_HF_ROW_Q12_M ) >>
FCFG1_CONFIG_OSC_TOP_XOSC_HF_ROW_Q12_S );
ui32XoscHfCol = (( ui32Fcfg1Value &
FCFG1_CONFIG_OSC_TOP_XOSC_HF_COLUMN_Q12_M ) >>
FCFG1_CONFIG_OSC_TOP_XOSC_HF_COLUMN_Q12_S );
i32CustomerDeltaAdjust = 0;
if (( ccfg_ModeConfReg & CCFG_MODE_CONF_XOSC_CAP_MOD ) == 0 ) {
// XOSC_CAP_MOD = 0 means: CAP_ARRAY_DELTA is in use -> Apply compensation
// XOSC_CAPARRAY_DELTA is located in bit[15:8] of ccfg_ModeConfReg
// Note: HW_REV_DEPENDENT_IMPLEMENTATION. Field width is not given by
// a define and sign extension must therefore be hardcoded.
// ( A small test program is created verifying the code lines below:
// Ref.: ..\test\small_standalone_test_programs\CapArrayDeltaAdjust_test.c)
i32CustomerDeltaAdjust = ((int32_t)ccfg_ModeConfReg << 16 ) >> 24;
while ( i32CustomerDeltaAdjust < 0 ) {
ui32XoscHfCol >>= 1; // COL 1 step down
if ( ui32XoscHfCol == 0 ) { // if COL below minimum
ui32XoscHfCol = 0xFFFF; // Set COL to maximum
ui32XoscHfRow >>= 1; // ROW 1 step down
if ( ui32XoscHfRow == 0 ) { // if ROW below minimum
ui32XoscHfRow = 1; // Set both ROW and COL
ui32XoscHfCol = 1; // to minimum
}
}
i32CustomerDeltaAdjust++;
}
while ( i32CustomerDeltaAdjust > 0 ) {
ui32XoscHfCol = ( ui32XoscHfCol << 1 ) | 1; // COL 1 step up
if ( ui32XoscHfCol > 0xFFFF ) { // if COL above maximum
ui32XoscHfCol = 1; // Set COL to minimum
ui32XoscHfRow = ( ui32XoscHfRow << 1 ) | 1; // ROW 1 step up
if ( ui32XoscHfRow > 0xF ) { // if ROW above maximum
ui32XoscHfRow = 0xF; // Set both ROW and COL
ui32XoscHfCol = 0xFFFF; // to maximum
}
}
i32CustomerDeltaAdjust--;
}
}
ui32TrimValue = (( ui32XoscHfRow << DDI_0_OSC_ANABYPASSVAL1_XOSC_HF_ROW_Q12_S ) |
( ui32XoscHfCol << DDI_0_OSC_ANABYPASSVAL1_XOSC_HF_COLUMN_Q12_S ) );
return (ui32TrimValue);
}
uint32_t SetupGetTrimForRcOscLfRtuneCtuneTrim( void ) {
uint32_t ui32TrimValue;
// Use device specific trim values located in factory configuration
// area
ui32TrimValue =
((HWREG(FCFG1_BASE + FCFG1_O_CONFIG_OSC_TOP) &
FCFG1_CONFIG_OSC_TOP_RCOSCLF_CTUNE_TRIM_M)>>
FCFG1_CONFIG_OSC_TOP_RCOSCLF_CTUNE_TRIM_S)<<
DDI_0_OSC_LFOSCCTL_RCOSCLF_CTUNE_TRIM_S;
ui32TrimValue |=
((HWREG(FCFG1_BASE + FCFG1_O_CONFIG_OSC_TOP) &
FCFG1_CONFIG_OSC_TOP_RCOSCLF_RTUNE_TRIM_M)>>
FCFG1_CONFIG_OSC_TOP_RCOSCLF_RTUNE_TRIM_S)<<
DDI_0_OSC_LFOSCCTL_RCOSCLF_RTUNE_TRIM_S;
return(ui32TrimValue);
}
uint32_t SetupGetTrimForXoscHfIbiastherm( void ) {
uint32_t ui32TrimValue;
// Use device specific trim value located in factory configuration
// area
ui32TrimValue =
(HWREG(FCFG1_BASE + FCFG1_O_ANABYPASS_VALUE2) &
FCFG1_ANABYPASS_VALUE2_XOSC_HF_IBIASTHERM_M)>>
FCFG1_ANABYPASS_VALUE2_XOSC_HF_IBIASTHERM_S;
return(ui32TrimValue);
}
uint32_t SetupGetTrimForAmpcompTh2( void ) {
uint32_t ui32TrimValue;
uint32_t ui32Fcfg1Value;
// Use device specific trim value located in factory configuration
// area. All defined register bit fields have corresponding trim
// value in the factory configuration area
ui32Fcfg1Value = HWREG(FCFG1_BASE + FCFG1_O_AMPCOMP_TH2);
ui32TrimValue = ((ui32Fcfg1Value &
FCFG1_AMPCOMP_TH2_LPMUPDATE_LTH_M)>>
FCFG1_AMPCOMP_TH2_LPMUPDATE_LTH_S)<<
DDI_0_OSC_AMPCOMPTH2_LPMUPDATE_LTH_S;
ui32TrimValue |= (((ui32Fcfg1Value &
FCFG1_AMPCOMP_TH2_LPMUPDATE_HTM_M)>>
FCFG1_AMPCOMP_TH2_LPMUPDATE_HTM_S)<<
DDI_0_OSC_AMPCOMPTH2_LPMUPDATE_HTH_S);
ui32TrimValue |= (((ui32Fcfg1Value &
FCFG1_AMPCOMP_TH2_ADC_COMP_AMPTH_LPM_M)>>
FCFG1_AMPCOMP_TH2_ADC_COMP_AMPTH_LPM_S)<<
DDI_0_OSC_AMPCOMPTH2_ADC_COMP_AMPTH_LPM_S);
ui32TrimValue |= (((ui32Fcfg1Value &
FCFG1_AMPCOMP_TH2_ADC_COMP_AMPTH_HPM_M)>>
FCFG1_AMPCOMP_TH2_ADC_COMP_AMPTH_HPM_S)<<
DDI_0_OSC_AMPCOMPTH2_ADC_COMP_AMPTH_HPM_S);
return(ui32TrimValue);
}
uint32_t SetupGetTrimForAmpcompTh1( void ) {
uint32_t ui32TrimValue;
uint32_t ui32Fcfg1Value;
// Use device specific trim values located in factory configuration
// area. All defined register bit fields have a corresponding trim
// value in the factory configuration area
ui32Fcfg1Value = HWREG(FCFG1_BASE + FCFG1_O_AMPCOMP_TH1);
ui32TrimValue = (((ui32Fcfg1Value &
FCFG1_AMPCOMP_TH1_HPMRAMP3_LTH_M)>>
FCFG1_AMPCOMP_TH1_HPMRAMP3_LTH_S)<<
DDI_0_OSC_AMPCOMPTH1_HPMRAMP3_LTH_S);
ui32TrimValue |= (((ui32Fcfg1Value &
FCFG1_AMPCOMP_TH1_HPMRAMP3_HTH_M)>>
FCFG1_AMPCOMP_TH1_HPMRAMP3_HTH_S)<<
DDI_0_OSC_AMPCOMPTH1_HPMRAMP3_HTH_S);
ui32TrimValue |= (((ui32Fcfg1Value &
FCFG1_AMPCOMP_TH1_IBIASCAP_LPTOHP_OL_CNT_M)>>
FCFG1_AMPCOMP_TH1_IBIASCAP_LPTOHP_OL_CNT_S)<<
DDI_0_OSC_AMPCOMPTH1_IBIASCAP_LPTOHP_OL_CNT_S);
ui32TrimValue |= (((ui32Fcfg1Value &
FCFG1_AMPCOMP_TH1_HPMRAMP1_TH_M)>>
FCFG1_AMPCOMP_TH1_HPMRAMP1_TH_S)<<
DDI_0_OSC_AMPCOMPTH1_HPMRAMP1_TH_S);
return(ui32TrimValue);
}
uint32_t SetupGetTrimForAmpcompCtrl( uint32_t ui32Fcfg1Revision ) {
uint32_t ui32TrimValue ;
uint32_t ui32Fcfg1Value ;
uint32_t ibiasOffset ;
uint32_t ibiasInit ;
uint32_t modeConf1 ;
int32_t deltaAdjust ;
// Use device specific trim values located in factory configuration
// area. Register bit fields without trim values in the factory
// configuration area will be set to the value of 0.
ui32Fcfg1Value = HWREG( FCFG1_BASE + FCFG1_O_AMPCOMP_CTRL1 );
ibiasOffset = ( ui32Fcfg1Value &
FCFG1_AMPCOMP_CTRL1_IBIAS_OFFSET_M ) >>
FCFG1_AMPCOMP_CTRL1_IBIAS_OFFSET_S ;
ibiasInit = ( ui32Fcfg1Value &
FCFG1_AMPCOMP_CTRL1_IBIAS_INIT_M ) >>
FCFG1_AMPCOMP_CTRL1_IBIAS_INIT_S ;
if (( HWREG( CCFG_BASE + CCFG_O_SIZE_AND_DIS_FLAGS ) & CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR_M ) == 0 ) {
// Adjust with DELTA_IBIAS_OFFSET and DELTA_IBIAS_INIT from CCFG
modeConf1 = HWREG( CCFG_BASE + CCFG_O_MODE_CONF_1 );
// Both fields are signed 4-bit values. This is an assumption when doing the sign extension.
deltaAdjust = ((int32_t)modeConf1 << ( 32 - CCFG_MODE_CONF_1_DELTA_IBIAS_OFFSET_S - 4 )) >> 28;
deltaAdjust += (int32_t)ibiasOffset;
if ( deltaAdjust < 0 ) {
deltaAdjust = 0;
}
if ( deltaAdjust > ( DDI_0_OSC_AMPCOMPCTL_IBIAS_OFFSET_M >> DDI_0_OSC_AMPCOMPCTL_IBIAS_OFFSET_S )) {
deltaAdjust = ( DDI_0_OSC_AMPCOMPCTL_IBIAS_OFFSET_M >> DDI_0_OSC_AMPCOMPCTL_IBIAS_OFFSET_S );
}
ibiasOffset = (uint32_t)deltaAdjust;
deltaAdjust = ((int32_t)modeConf1 << ( 32 - CCFG_MODE_CONF_1_DELTA_IBIAS_INIT_S - 4 )) >> 28;
deltaAdjust += (int32_t)ibiasInit;
if ( deltaAdjust < 0 ) {
deltaAdjust = 0;
}
if ( deltaAdjust > ( DDI_0_OSC_AMPCOMPCTL_IBIAS_INIT_M >> DDI_0_OSC_AMPCOMPCTL_IBIAS_INIT_S )) {
deltaAdjust = ( DDI_0_OSC_AMPCOMPCTL_IBIAS_INIT_M >> DDI_0_OSC_AMPCOMPCTL_IBIAS_INIT_S );
}
ibiasInit = (uint32_t)deltaAdjust;
}
ui32TrimValue = ( ibiasOffset << DDI_0_OSC_AMPCOMPCTL_IBIAS_OFFSET_S ) |
( ibiasInit << DDI_0_OSC_AMPCOMPCTL_IBIAS_INIT_S ) ;
ui32TrimValue |= (((ui32Fcfg1Value &
FCFG1_AMPCOMP_CTRL1_LPM_IBIAS_WAIT_CNT_FINAL_M)>>
FCFG1_AMPCOMP_CTRL1_LPM_IBIAS_WAIT_CNT_FINAL_S)<<
DDI_0_OSC_AMPCOMPCTL_LPM_IBIAS_WAIT_CNT_FINAL_S);
ui32TrimValue |= (((ui32Fcfg1Value &
FCFG1_AMPCOMP_CTRL1_CAP_STEP_M)>>
FCFG1_AMPCOMP_CTRL1_CAP_STEP_S)<<
DDI_0_OSC_AMPCOMPCTL_CAP_STEP_S);
ui32TrimValue |= (((ui32Fcfg1Value &
FCFG1_AMPCOMP_CTRL1_IBIASCAP_HPTOLP_OL_CNT_M)>>
FCFG1_AMPCOMP_CTRL1_IBIASCAP_HPTOLP_OL_CNT_S)<<
DDI_0_OSC_AMPCOMPCTL_IBIASCAP_HPTOLP_OL_CNT_S);
if ( ui32Fcfg1Revision >= 0x00000022 ) {
ui32TrimValue |= ((( ui32Fcfg1Value &
FCFG1_AMPCOMP_CTRL1_AMPCOMP_REQ_MODE_M ) >>
FCFG1_AMPCOMP_CTRL1_AMPCOMP_REQ_MODE_S ) <<
DDI_0_OSC_AMPCOMPCTL_AMPCOMP_REQ_MODE_S );
}
return(ui32TrimValue);
}
uint32_t SetupGetTrimForDblrLoopFilterResetVoltage( uint32_t ui32Fcfg1Revision ) {
uint32_t dblrLoopFilterResetVoltageValue = 0; // Reset value
if ( ui32Fcfg1Revision >= 0x00000020 ) {
dblrLoopFilterResetVoltageValue = ( HWREG( FCFG1_BASE + FCFG1_O_MISC_OTP_DATA_1 ) &
FCFG1_MISC_OTP_DATA_1_DBLR_LOOP_FILTER_RESET_VOLTAGE_M ) >>
FCFG1_MISC_OTP_DATA_1_DBLR_LOOP_FILTER_RESET_VOLTAGE_S;
}
return ( dblrLoopFilterResetVoltageValue );
}
uint32_t SetupGetTrimForAdcShModeEn( uint32_t ui32Fcfg1Revision ) {
uint32_t getTrimForAdcShModeEnValue = 1; // Recommended default setting
if ( ui32Fcfg1Revision >= 0x00000022 ) {
getTrimForAdcShModeEnValue = ( HWREG( FCFG1_BASE + FCFG1_O_OSC_CONF ) &
FCFG1_OSC_CONF_ADC_SH_MODE_EN_M ) >>
FCFG1_OSC_CONF_ADC_SH_MODE_EN_S;
}
return ( getTrimForAdcShModeEnValue );
}
uint32_t SetupGetTrimForAdcShVbufEn( uint32_t ui32Fcfg1Revision ) {
uint32_t getTrimForAdcShVbufEnValue = 1; // Recommended default setting
if ( ui32Fcfg1Revision >= 0x00000022 ) {
getTrimForAdcShVbufEnValue = ( HWREG( FCFG1_BASE + FCFG1_O_OSC_CONF ) &
FCFG1_OSC_CONF_ADC_SH_VBUF_EN_M ) >>
FCFG1_OSC_CONF_ADC_SH_VBUF_EN_S;
}
return ( getTrimForAdcShVbufEnValue );
}
uint32_t SetupGetTrimForXoscHfCtl( uint32_t ui32Fcfg1Revision ) {
uint32_t getTrimForXoschfCtlValue = 0; // Recommended default setting
uint32_t fcfg1Data;
if ( ui32Fcfg1Revision >= 0x00000020 ) {
fcfg1Data = HWREG( FCFG1_BASE + FCFG1_O_MISC_OTP_DATA_1 );
getTrimForXoschfCtlValue =
( ( ( fcfg1Data & FCFG1_MISC_OTP_DATA_1_PEAK_DET_ITRIM_M ) >>
FCFG1_MISC_OTP_DATA_1_PEAK_DET_ITRIM_S ) <<
DDI_0_OSC_XOSCHFCTL_PEAK_DET_ITRIM_S);
getTrimForXoschfCtlValue |=
( ( ( fcfg1Data & FCFG1_MISC_OTP_DATA_1_HP_BUF_ITRIM_M ) >>
FCFG1_MISC_OTP_DATA_1_HP_BUF_ITRIM_S ) <<
DDI_0_OSC_XOSCHFCTL_HP_BUF_ITRIM_S);
getTrimForXoschfCtlValue |=
( ( ( fcfg1Data & FCFG1_MISC_OTP_DATA_1_LP_BUF_ITRIM_M ) >>
FCFG1_MISC_OTP_DATA_1_LP_BUF_ITRIM_S ) <<
DDI_0_OSC_XOSCHFCTL_LP_BUF_ITRIM_S);
}
return ( getTrimForXoschfCtlValue );
}
uint32_t SetupGetTrimForXoscHfFastStart( void ) {
uint32_t ui32XoscHfFastStartValue ;
// Get value from FCFG1
ui32XoscHfFastStartValue = ( HWREG( FCFG1_BASE + FCFG1_O_OSC_CONF ) &
FCFG1_OSC_CONF_XOSC_HF_FAST_START_M ) >>
FCFG1_OSC_CONF_XOSC_HF_FAST_START_S;
return ( ui32XoscHfFastStartValue );
}
uint32_t SetupGetTrimForRadcExtCfg( uint32_t ui32Fcfg1Revision ) {
uint32_t getTrimForRadcExtCfgValue = 0x403F8000; // Recommended default setting
uint32_t fcfg1Data;
if ( ui32Fcfg1Revision >= 0x00000020 ) {
fcfg1Data = HWREG( FCFG1_BASE + FCFG1_O_MISC_OTP_DATA_1 );
getTrimForRadcExtCfgValue =
( ( ( fcfg1Data & FCFG1_MISC_OTP_DATA_1_HPM_IBIAS_WAIT_CNT_M ) >>
FCFG1_MISC_OTP_DATA_1_HPM_IBIAS_WAIT_CNT_S ) <<
DDI_0_OSC_RADCEXTCFG_HPM_IBIAS_WAIT_CNT_S);
getTrimForRadcExtCfgValue |=
( ( ( fcfg1Data & FCFG1_MISC_OTP_DATA_1_LPM_IBIAS_WAIT_CNT_M ) >>
FCFG1_MISC_OTP_DATA_1_LPM_IBIAS_WAIT_CNT_S ) <<
DDI_0_OSC_RADCEXTCFG_LPM_IBIAS_WAIT_CNT_S);
getTrimForRadcExtCfgValue |=
( ( ( fcfg1Data & FCFG1_MISC_OTP_DATA_1_IDAC_STEP_M ) >>
FCFG1_MISC_OTP_DATA_1_IDAC_STEP_S ) <<
DDI_0_OSC_RADCEXTCFG_IDAC_STEP_S);
}
return ( getTrimForRadcExtCfgValue );
}
uint32_t SetupGetTrimForRcOscLfIBiasTrim( uint32_t ui32Fcfg1Revision ) {
uint32_t trimForRcOscLfIBiasTrimValue = 0; // Default value
if ( ui32Fcfg1Revision >= 0x00000022 ) {
trimForRcOscLfIBiasTrimValue = ( HWREG( FCFG1_BASE + FCFG1_O_OSC_CONF ) &
FCFG1_OSC_CONF_ATESTLF_RCOSCLF_IBIAS_TRIM_M ) >>
FCFG1_OSC_CONF_ATESTLF_RCOSCLF_IBIAS_TRIM_S ;
}
return ( trimForRcOscLfIBiasTrimValue );
}
uint32_t SetupGetTrimForXoscLfRegulatorAndCmirrwrRatio( uint32_t ui32Fcfg1Revision ) {
uint32_t trimForXoscLfRegulatorAndCmirrwrRatioValue = 0; // Default value for both fields
if ( ui32Fcfg1Revision >= 0x00000022 ) {
trimForXoscLfRegulatorAndCmirrwrRatioValue = ( HWREG( FCFG1_BASE + FCFG1_O_OSC_CONF ) &
( FCFG1_OSC_CONF_XOSCLF_REGULATOR_TRIM_M |
FCFG1_OSC_CONF_XOSCLF_CMIRRWR_RATIO_M )) >>
FCFG1_OSC_CONF_XOSCLF_CMIRRWR_RATIO_S ;
}
return ( trimForXoscLfRegulatorAndCmirrwrRatioValue );
}
void SetupSetCacheModeAccordingToCcfgSetting( void ) {
// - Make sure to enable aggressive VIMS clock gating for power optimization
// Only for PG2 devices.
// - Enable cache prefetch enable as default setting
// (Slightly higher power consumption, but higher CPU performance)
// - IF ( CCFG_..._DIS_GPRAM == 1 )
// then: Enable cache (set cache mode = 1), even if set by ROM boot code
// (This is done because it's not set by boot code when running inside
// a debugger supporting the Halt In Boot (HIB) functionality).
// else: Set MODE_GPRAM if not already set (see inline comments as well)
uint32_t vimsCtlMode0 ;
while ( HWREGBITW( VIMS_BASE + VIMS_O_STAT, VIMS_STAT_MODE_CHANGING_BITN )) {
// Do nothing - wait for an eventual ongoing mode change to complete.
// (There should typically be no wait time here, but need to be sure)
}
// Note that Mode=0 is equal to MODE_GPRAM
vimsCtlMode0 = (( HWREG( VIMS_BASE + VIMS_O_CTL ) & ~VIMS_CTL_MODE_M ) | VIMS_CTL_DYN_CG_EN_M | VIMS_CTL_PREF_EN_M );
#if defined( DO_NOT_ENABLE_CACHE_IN_TRIM_DEVICE )
HWREG( VIMS_BASE + VIMS_O_CTL ) = vimsCtlMode0;
#else
if ( HWREG( CCFG_BASE + CCFG_O_SIZE_AND_DIS_FLAGS ) & CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM ) {
// Enable cache (and hence disable GPRAM)
HWREG( VIMS_BASE + VIMS_O_CTL ) = ( vimsCtlMode0 | VIMS_CTL_MODE_CACHE );
} else if (( HWREG( VIMS_BASE + VIMS_O_STAT ) & VIMS_STAT_MODE_M ) != VIMS_STAT_MODE_GPRAM ) {
// GPRAM is enabled in CCFG but not selected
// Note: It is recommended to go via MODE_OFF when switching to MODE_GPRAM
HWREG( VIMS_BASE + VIMS_O_CTL ) = ( vimsCtlMode0 | VIMS_CTL_MODE_OFF );
while (( HWREG( VIMS_BASE + VIMS_O_STAT ) & VIMS_STAT_MODE_M ) != VIMS_STAT_MODE_OFF ) {
// Do nothing - wait for an eventual mode change to complete (This goes fast).
}
HWREG( VIMS_BASE + VIMS_O_CTL ) = vimsCtlMode0;
} else {
// Correct mode, but make sure PREF_EN and DYN_CG_EN always are set
HWREG( VIMS_BASE + VIMS_O_CTL ) = vimsCtlMode0;
}
#endif
}
void SetupSetAonRtcSubSecInc( uint32_t subSecInc ) {
// Loading a new RTCSUBSECINC value is done in 5 steps:
// 1. Write bit[15:0] of new SUBSECINC value to AUX_SYSIF_O_RTCSUBSECINC0
// 2. Write bit[23:16] of new SUBSECINC value to AUX_SYSIF_O_RTCSUBSECINC1
// 3. Set AUX_SYSIF_RTCSUBSECINCCTL_UPD_REQ
// 4. Wait for AUX_SYSIF_RTCSUBSECINCCTL_UPD_ACK
// 5. Clear AUX_SYSIF_RTCSUBSECINCCTL_UPD_REQ
HWREG( AUX_SYSIF_BASE + AUX_SYSIF_O_RTCSUBSECINC0 ) = (( subSecInc ) & AUX_SYSIF_RTCSUBSECINC0_INC15_0_M );
HWREG( AUX_SYSIF_BASE + AUX_SYSIF_O_RTCSUBSECINC1 ) = (( subSecInc >> 16 ) & AUX_SYSIF_RTCSUBSECINC1_INC23_16_M );
HWREG( AUX_SYSIF_BASE + AUX_SYSIF_O_RTCSUBSECINCCTL ) = AUX_SYSIF_RTCSUBSECINCCTL_UPD_REQ;
while( ! ( HWREGBITW( AUX_SYSIF_BASE + AUX_SYSIF_O_RTCSUBSECINCCTL, AUX_SYSIF_RTCSUBSECINCCTL_UPD_ACK_BITN )));
HWREG( AUX_SYSIF_BASE + AUX_SYSIF_O_RTCSUBSECINCCTL ) = 0;
}
void I2SPointerSet(uint32_t ui32Base, bool bInput, void * pNextPointer) {
// Check the arguments.
ASSERT(I2SBaseValid(ui32Base));
// Update the next input/output pointer with the correct address.
if(bInput == true)
{
HWREG(I2S0_BASE + I2S_O_AIFINPTRNEXT) = (uint32_t)pNextPointer;
}
else
{
HWREG(I2S0_BASE + I2S_O_AIFOUTPTRNEXT) = (uint32_t)pNextPointer;
}
}
uint32_t I2SSampleStampGet(uint32_t ui32Base, uint32_t ui32Channel) {
uint32_t ui32FrameClkCnt;
uint32_t ui32SysClkCnt;
uint32_t ui32PeriodSysClkCnt;
uint32_t ui32SampleStamp;
// Get the number of Frame clock counts since last stamp.
ui32FrameClkCnt = HWREG(I2S0_BASE + I2S_O_STMPWCNTCAPT0);
// Get the number of system clock ticks since last frame clock edge.
ui32SysClkCnt = HWREG(I2S0_BASE + I2S_O_STMPXCNTCAPT0);
// Get the number system clock ticks in the last frame clock period.
ui32PeriodSysClkCnt = HWREG(I2S0_BASE + I2S_O_STMPXPER);
// Calculate the sample stamp.
ui32SampleStamp = (ui32SysClkCnt << 16) / ui32PeriodSysClkCnt;
ui32SampleStamp = (ui32SampleStamp > I2S_STMP_SATURATION) ?
I2S_STMP_SATURATION : ui32SampleStamp;
ui32SampleStamp |= (ui32FrameClkCnt << 16);
return (ui32SampleStamp);
}
void PowerCtrlSourceSet(uint32_t ui32PowerConfig) {
// Check the arguments.
ASSERT((ui32PowerConfig == PWRCTRL_PWRSRC_DCDC) ||
(ui32PowerConfig == PWRCTRL_PWRSRC_GLDO) ||
(ui32PowerConfig == PWRCTRL_PWRSRC_ULDO));
// Configure the power.
if(ui32PowerConfig == PWRCTRL_PWRSRC_DCDC) {
HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) |=
(AON_PMCTL_PWRCTL_DCDC_EN | AON_PMCTL_PWRCTL_DCDC_ACTIVE);
}
else if (ui32PowerConfig == PWRCTRL_PWRSRC_GLDO)
{
HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) &=
~(AON_PMCTL_PWRCTL_DCDC_EN | AON_PMCTL_PWRCTL_DCDC_ACTIVE);
}
else
{
PRCMMcuUldoConfigure(true);
}
}