ESR-2025/driverlib/MSP430FR2xx_4xx/cs.c

1246 lines
37 KiB
C
Executable File

/* --COPYRIGHT--,BSD
* Copyright (c) 2016, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* --/COPYRIGHT--*/
//*****************************************************************************
//
// cs.c - Driver for the cs Module.
//
//*****************************************************************************
//*****************************************************************************
//
//! \addtogroup cs_api cs
//! @{
//
//*****************************************************************************
#include "inc/hw_memmap.h"
#ifdef __MSP430_HAS_CS__
#include "cs.h"
#include <assert.h>
//*****************************************************************************
//
// Internal very low power VLOCLK, low frequency oscillator with 10 kHz typical
// frequency
//
//*****************************************************************************
#define CS_VLOCLK_FREQUENCY 10000
//*****************************************************************************
//
// Internal, trimmed, low-frequency oscillator with 32768 Hz typical frequency
//
//*****************************************************************************
#define CS_REFOCLK_FREQUENCY 32768
//*****************************************************************************
//
// Internal DCO frequency range
//
//*****************************************************************************
#define CS_DCO_RANGE_1MHZ 1000000
#define CS_DCO_RANGE_2MHZ 2000000
#define CS_DCO_RANGE_4MHZ 4000000
#define CS_DCO_RANGE_8MHZ 8000000
#define CS_DCO_RANGE_12MHZ 12000000
#define CS_DCO_RANGE_16MHZ 16000000
#define CS_DCO_RANGE_20MHZ 20000000
#define CS_DCO_RANGE_24MHZ 24000000
//******************************************************************************
//
//The XT1 crystal frequency. Should be set with CS_externalClockSourceInit
//if XT1 is used and user intends to invoke CS_getSMCLK, CS_getMCLK or
//CS_getACLK
//
//******************************************************************************
static uint32_t privateXT1ClockFrequency = 0;
static uint32_t privateDCORange(void)
{
uint32_t res = 0;
switch((HWREG8(CS_BASE + OFS_CSCTL1)) & DCORSEL_7)
{
case DCORSEL_0:
res = CS_DCO_RANGE_1MHZ;
break;
case DCORSEL_1:
res = CS_DCO_RANGE_2MHZ;
break;
case DCORSEL_2:
res = CS_DCO_RANGE_4MHZ;
break;
case DCORSEL_3:
res = CS_DCO_RANGE_8MHZ;
break;
case DCORSEL_4:
res = CS_DCO_RANGE_12MHZ;
break;
case DCORSEL_5:
res = CS_DCO_RANGE_16MHZ;
break;
case DCORSEL_6:
res = CS_DCO_RANGE_20MHZ;
break;
case DCORSEL_7:
res = CS_DCO_RANGE_24MHZ;
break;
default:
break;
}
return(res);
}
static uint32_t privateCSSourceClockFromDCO(uint16_t FLLRefCLKSource)
{
uint16_t N_value;
uint16_t n_value = 1;
uint32_t Fref_value;
N_value = (HWREG16(CS_BASE + OFS_CSCTL2)) & 0x03FF;
uint16_t tempDivider = HWREG8(CS_BASE + OFS_CSCTL3) & FLLREFDIV_7;
if(tempDivider > 1)
{
n_value = 32 << (tempDivider - 1);
}
switch((HWREG8(CS_BASE + OFS_CSCTL3)) & SELREF_3)
{
case SELREF__XT1CLK:
Fref_value = privateXT1ClockFrequency;
if(HWREG8(CS_BASE + OFS_CSCTL7) & XT1OFFG)
{
HWREG8(CS_BASE + OFS_CSCTL7) &= ~(XT1OFFG);
//Clear OFIFG fault flag
HWREG8(CS_BASE + OFS_SFRIFG1) &= ~OFIFG;
if(HWREG8(CS_BASE + OFS_CSCTL7) & XT1OFFG)
{
if(HWREG16(CS_BASE + OFS_CSCTL6) & XTS)
{
HWREG8(CS_BASE + OFS_CSCTL7) &= ~DCOFFG;
Fref_value = privateDCORange();
}
else
{
Fref_value = CS_REFOCLK_FREQUENCY;
}
}
}
break;
case SELREF__REFOCLK:
Fref_value = CS_REFOCLK_FREQUENCY;
break;
default: break;
}
return (Fref_value * (N_value + 1) / n_value);
}
static uint32_t privateCSComputeCLKFrequency(uint16_t CLKSource,
uint16_t CLKSourceDivider,
uint8_t CLKDest)
{
uint32_t CLKFrequency = 0;
uint8_t CLKSourceFrequencyDivider = 1;
CLKSourceFrequencyDivider = 1 << CLKSourceDivider;
switch(CLKSource)
{
case SELMS__XT1CLK:
CLKFrequency = (privateXT1ClockFrequency /
CLKSourceFrequencyDivider);
if(HWREG8(CS_BASE + OFS_CSCTL7) & XT1OFFG)
{
HWREG8(CS_BASE + OFS_CSCTL7) &= ~(XT1OFFG);
//Clear OFIFG fault flag
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
//fail-safe operation
if(HWREG8(CS_BASE + OFS_CSCTL7) & XT1OFFG)
{
//fail-safe for ACLK or XT1 mode is LF
if(CLKDest == CS_ACLK ||
(HWREG16(CS_BASE + OFS_CSCTL6) & XTS) == 0)
{
CLKFrequency = CS_REFOCLK_FREQUENCY;
}
//XT1 mode is HF
else
{
HWREG8(CS_BASE + OFS_CSCTL7) &= ~DCOFFG;
CLKFrequency = privateDCORange();
}
}
}
break;
case SELMS__VLOCLK:
CLKFrequency =
(CS_VLOCLK_FREQUENCY / CLKSourceFrequencyDivider);
break;
case SELMS__REFOCLK:
CLKFrequency =
(CS_REFOCLK_FREQUENCY / CLKSourceFrequencyDivider);
break;
case SELMS__DCOCLKDIV:
CLKFrequency =
privateCSSourceClockFromDCO(CLKSource)
/ CLKSourceFrequencyDivider;
break;
}
return (CLKFrequency);
}
static void privateCSComputeDCOFTrim(CS_initFLLParam *param)
{
uint16_t oldDcoTap = 0xffff;
uint16_t newDcoTap = 0xffff;
uint16_t newDcoDelta = 0xffff;
uint16_t bestDcoDelta = 0xffff;
uint16_t csCtl0Copy = 0;
uint16_t csCtl1Copy = 0;
uint16_t csCtl0Read = 0;
uint16_t csCtl1Read = 0;
uint16_t dcoFreqTrim = 3;
bool endLoop = false;
do
{
HWREG16(CS_BASE + OFS_CSCTL0) = DCO8; // DCO Tap = 256
do
{
HWREG16(CS_BASE + OFS_CSCTL7) &= ~DCOFFG; // Clear DCO fault flag
}
while(HWREG16(CS_BASE + OFS_CSCTL7) & DCOFFG);
switch((HWREG16(CS_BASE + OFS_CSCTL1) & DCORSEL_7) >> 1)
{
// Wait FLL lock status (FLLUNLOCK) stable
// Suggest to wait 24 cycles of divided FLL refclk
case 0: // 1 MHz
__delay_cycles((uint16_t)3000);
break;
case 1: // 2 MHz
__delay_cycles((uint16_t)3000 * 2);
break;
case 2: // 4 MHz
__delay_cycles((uint16_t)3000 * 4);
break;
case 3: // 8 MHz
__delay_cycles((uint16_t)3000 * 8);
break;
case 4: // 12 MHz
__delay_cycles((uint16_t)3000 * 12);
break;
case 5: // 16 MHz
__delay_cycles((uint16_t)3000 * 16);
break;
case 6: // 20 MHz
__delay_cycles((uint16_t)3000 * 20);
break;
case 7: // 24 MHz
__delay_cycles((uint32_t)3000 * 24);
break;
default: // reserved
__delay_cycles((uint16_t)3000 * 16);
break;
}
// Poll the FLLUNLOCK bits and DCOFFG bit until FLL is locked or DCO fault
while((HWREG16(CS_BASE + OFS_CSCTL7) & (FLLUNLOCK0 | FLLUNLOCK1)) &&
((HWREG16(CS_BASE + OFS_CSCTL7) & DCOFFG) == 0))
{
;
}
csCtl0Read = HWREG16(CS_BASE + OFS_CSCTL0); // Read CSCTL0
csCtl1Read = HWREG16(CS_BASE + OFS_CSCTL1); // Read CSCTL1
oldDcoTap = newDcoTap; // Record DCOTAP value of last time
newDcoTap = csCtl0Read & 0x01ff; // Get DCOTAP value of this time
dcoFreqTrim = (csCtl1Read & 0x0070) >> 4; // Get DCOFTRIM value
if(newDcoTap < 256) // DCOTAP < 256
{
newDcoDelta = 256 - newDcoTap; // Delta value between DCOTAP and 256
if((oldDcoTap != 0xffff) && (oldDcoTap >= 256)) // DCOTAP cross 256
{
endLoop = true; // Stop while loop
}
else
{
dcoFreqTrim--;
HWREG16(CS_BASE +
OFS_CSCTL1) =
(csCtl1Read & (~0x0070)) | (dcoFreqTrim << 4);
}
}
else // DCOTAP >= 256
{
newDcoDelta = newDcoTap - 256; // Delta value between DCOTAP and 256
if(oldDcoTap < 256) // DCOTAP cross 256
{
endLoop = true; // Stop while loop
}
else
{
dcoFreqTrim++;
HWREG16(CS_BASE +
OFS_CSCTL1) =
(csCtl1Read & (~0x0070)) | (dcoFreqTrim << 4);
}
}
if(newDcoDelta < bestDcoDelta) // Record DCOTAP closest to 256
{
csCtl0Copy = csCtl0Read;
csCtl1Copy = csCtl1Read;
bestDcoDelta = newDcoDelta;
}
}
while(endLoop == false); // Poll until endLoop == 1
HWREG16(CS_BASE + OFS_CSCTL0) = csCtl0Copy; // Reload locked DCOTAP
HWREG16(CS_BASE + OFS_CSCTL1) = csCtl1Copy; // Reload locked DCOFTRIM
param->csCtl0 = csCtl0Copy;
param->csCtl1 = csCtl1Copy;
while(HWREG16(CS_BASE + OFS_CSCTL7) & (FLLUNLOCK0 | FLLUNLOCK1))
{
; // Poll until FLL is locked
}
}
void CS_setExternalClockSource(uint32_t XT1CLK_frequency)
{
privateXT1ClockFrequency = XT1CLK_frequency;
}
void CS_initClockSignal(uint8_t selectedClockSignal,
uint16_t clockSource,
uint16_t clockSourceDivider)
{
uint16_t temp;
switch(selectedClockSignal)
{
case CS_ACLK:
HWREG16(CS_BASE + OFS_CSCTL4) &= ~(SELA);
if(clockSource == CS_XT1CLK_SELECT)
{
clockSource = 0x0;
}
else if(clockSource == CS_REFOCLK_SELECT)
{
clockSource = 0x1;
}
else if(clockSource == CS_VLOCLK_SELECT)
{
clockSource = 0x2;
}
clockSource = clockSource << 8;
HWREG16(CS_BASE + OFS_CSCTL4) |= (clockSource);
#ifdef DIVA0
if(HWREG16(CS_BASE + OFS_CSCTL6) & XTS)
{
temp = HWREG16(CS_BASE + OFS_CSCTL6);
if(clockSourceDivider != CS_CLOCK_DIVIDER_1)
{
clockSourceDivider = (clockSourceDivider - 3) << 8;
HWREG16(CS_BASE +
OFS_CSCTL6) |= temp & ~(DIVA3 | DIVA2 | DIVA1 | DIVA0)
| clockSourceDivider;
}
}
#endif
break;
case CS_SMCLK:
HWREG16(CS_BASE + OFS_CSCTL4) &= ~(SELMS_7);
HWREG16(CS_BASE + OFS_CSCTL4) |= (clockSource);
temp = HWREG16(CS_BASE + OFS_CSCTL5);
clockSourceDivider = clockSourceDivider << 4;
HWREG16(CS_BASE + OFS_CSCTL5) = temp & ~(DIVS_3) | clockSourceDivider;
break;
case CS_MCLK:
HWREG16(CS_BASE + OFS_CSCTL4) &= ~(SELMS_7);
HWREG16(CS_BASE + OFS_CSCTL4) |= (clockSource);
temp = HWREG16(CS_BASE + OFS_CSCTL5);
HWREG16(CS_BASE + OFS_CSCTL5) = temp & ~(DIVM_7) | clockSourceDivider;
break;
case CS_FLLREF:
HWREG8(CS_BASE + OFS_CSCTL3) &= ~(SELREF_3);
if(clockSource == CS_XT1CLK_SELECT)
{
clockSource = 0x0;
}
clockSource = clockSource << 4;
HWREG8(CS_BASE + OFS_CSCTL3) |= (clockSource);
temp = HWREG8(CS_BASE + OFS_CSCTL3);
//Note that dividers for FLLREF are slightly different
//Hence handled differently from other CLK signals
if(clockSourceDivider != CS_CLOCK_DIVIDER_1)
{
if(clockSourceDivider == CS_CLOCK_DIVIDER_640)
{
HWREG8(CS_BASE +
OFS_CSCTL3) = temp & ~(FLLREFDIV_7) |
(clockSourceDivider - 10);
}
else if(clockSourceDivider != CS_CLOCK_DIVIDER_512)
{
HWREG8(CS_BASE +
OFS_CSCTL3) = temp & ~(FLLREFDIV_7) |
(clockSourceDivider - 4);
}
else
{
HWREG8(CS_BASE +
OFS_CSCTL3) = temp & ~(FLLREFDIV_7) |
(clockSourceDivider - 5);
}
}
break;
}
}
void CS_turnOnXT1LF(uint16_t xt1Drive){
//Switch ON XT1 oscillator
HWREG16(CS_BASE + OFS_CSCTL6) &= ~XT1AUTOOFF;
//Highest drive setting for turnOnXT1
HWREG16(CS_BASE + OFS_CSCTL6_L) |= XT1DRIVE1_L | XT1DRIVE0_L;
//Enable LF mode and clear bypass
HWREG16(CS_BASE + OFS_CSCTL6) &= ~(XTS | XT1BYPASS);
while(HWREG8(CS_BASE + OFS_CSCTL7) & XT1OFFG)
{
//Clear OSC fault flag
HWREG8(CS_BASE + OFS_CSCTL7) &= ~(XT1OFFG);
//Clear OFIFG fault flag
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
}
//set requested Drive mode
HWREG16(CS_BASE + OFS_CSCTL6) = (HWREG16(CS_BASE + OFS_CSCTL6) &
~(XT1DRIVE_3)
) |
(xt1Drive);
}
void CS_bypassXT1(void)
{
//Enable HF/LF mode
HWREG16(CS_BASE + OFS_CSCTL6) &= ~XTS;
//Switch OFF XT1 oscillator and enable BYPASS mode
HWREG16(CS_BASE + OFS_CSCTL6) |= (XT1BYPASS | XT1AUTOOFF);
while(HWREG8(CS_BASE + OFS_CSCTL7) & (XT1OFFG))
{
//Clear OSC fault flags
HWREG8(CS_BASE + OFS_CSCTL7) &= ~(XT1OFFG);
// Clear the global fault flag. In case the XT1 caused the global fault
// flag to get set this will clear the global error condition. If any
// error condition persists, global flag will get again.
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
}
}
bool CS_turnOnXT1LFWithTimeout(uint16_t xt1Drive,
uint16_t timeout)
{
//Switch ON XT1 oscillator
HWREG16(CS_BASE + OFS_CSCTL6) &= ~XT1AUTOOFF;
//Highest drive setting for turnOnXT1
HWREG16(CS_BASE + OFS_CSCTL6_L) |= XT1DRIVE1_L | XT1DRIVE0_L;
//Enable LF mode and clear bypass
HWREG16(CS_BASE + OFS_CSCTL6) &= ~(XTS | XT1BYPASS);
do
{
HWREG8(CS_BASE + OFS_CSCTL7) &= ~(XT1OFFG);
//Clear OFIFG fault flag
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
}
while((HWREG8(CS_BASE + OFS_CSCTL7) & XT1OFFG) && --timeout);
if(timeout)
{
//set requested Drive mode
HWREG16(CS_BASE + OFS_CSCTL6) = (HWREG16(CS_BASE + OFS_CSCTL6) &
~(XT1DRIVE_3)
) |
(xt1Drive);
return (STATUS_SUCCESS);
}
else
{
return (STATUS_FAIL);
}
}
bool CS_bypassXT1WithTimeout(uint16_t timeout)
{
//Enable HF/LF mode
HWREG16(CS_BASE + OFS_CSCTL6) &= ~XTS;
//Switch OFF XT1 oscillator and enable bypass
HWREG16(CS_BASE + OFS_CSCTL6) |= (XT1BYPASS | XT1AUTOOFF);
do
{
//Clear OSC fault flags
HWREG8(CS_BASE + OFS_CSCTL7) &= ~(XT1OFFG);
// Clear the global fault flag. In case the XT1 caused the global fault
// flag to get set this will clear the global error condition. If any
// error condition persists, global flag will get again.
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
}
while((HWREG8(CS_BASE + OFS_CSCTL7) & (XT1OFFG)) && --timeout);
if(timeout)
{
return (STATUS_SUCCESS);
}
else
{
return (STATUS_FAIL);
}
}
void CS_turnOffXT1(void)
{
//Switch off XT1 oscillator
HWREG16(CS_BASE + OFS_CSCTL6) |= XT1AUTOOFF;
}
void CS_turnOnXT1HF(uint16_t xt1Drive,
uint16_t xt1HFFreq){
#ifdef XT1HFFREQ_3
//Switch ON XT1 oscillator
HWREG16(CS_BASE + OFS_CSCTL6) &= ~XT1AUTOOFF;
//Enable HF and highest drive setting for XT1
HWREG16(CS_BASE + OFS_CSCTL6_L) |= XTS | XT1DRIVE1_L | XT1DRIVE0_L;
//Clear bypass
HWREG16(CS_BASE + OFS_CSCTL6) &= ~XT1BYPASS;
while(HWREG8(CS_BASE + OFS_CSCTL7) & XT1OFFG)
{
//Clear OSC fault flag
HWREG8(CS_BASE + OFS_CSCTL7) &= ~(XT1OFFG);
//Clear OFIFG fault flag
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
}
//set requested Drive mode
HWREG16(CS_BASE + OFS_CSCTL6) = (HWREG16(CS_BASE + OFS_CSCTL6) &
~(XT1DRIVE_3 | XT1HFFREQ_3)) |
xt1Drive | xt1HFFreq;
#endif
}
bool CS_turnOnXT1HFWithTimeout(uint16_t xt1Drive,
uint16_t xt1HFFreq,
uint16_t timeout)
{
#ifdef XT1HFFREQ_3
//Switch ON XT1 oscillator
HWREG16(CS_BASE + OFS_CSCTL6) &= ~XT1AUTOOFF;
//Enable HF and highest drive setting for XT1
HWREG16(CS_BASE + OFS_CSCTL6_L) |= XTS | XT1DRIVE1_L | XT1DRIVE0_L;
//Clear bypass
HWREG16(CS_BASE + OFS_CSCTL6) &= ~XT1BYPASS;
do
{
HWREG8(CS_BASE + OFS_CSCTL7) &= ~(XT1OFFG);
//Clear OFIFG fault flag
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
}
while((HWREG8(CS_BASE + OFS_CSCTL7) & XT1OFFG) && --timeout);
if(timeout)
{
//set requested Drive mode
HWREG16(CS_BASE + OFS_CSCTL6) = (HWREG16(CS_BASE + OFS_CSCTL6) &
~(XT1DRIVE_3 | XT1HFFREQ_3)) |
xt1Drive | xt1HFFreq;
return (STATUS_SUCCESS);
}
else
{
return (STATUS_FAIL);
}
#else
return (STATUS_FAIL);
#endif
}
void CS_turnOnSMCLK(void)
{
//Turn on SMCLK
HWREG16(CS_BASE + OFS_CSCTL5) &= ~SMCLKOFF;
}
void CS_turnOffSMCLK(void)
{
//Turn off SMCLK
HWREG16(CS_BASE + OFS_CSCTL5) |= SMCLKOFF;
}
void CS_enableVLOAutoOff(void)
{
//Enable VLO Auto Off
HWREG16(CS_BASE + OFS_CSCTL5) |= VLOAUTOOFF;
}
void CS_disableVLOAutoOff(void)
{
//Disable VLO Auto Off
HWREG16(CS_BASE + OFS_CSCTL5) &= ~VLOAUTOOFF;
}
bool CS_initFLLSettle(uint16_t fsystem,
uint16_t ratio)
{
volatile uint16_t x = ratio * 32;
bool status = CS_initFLL(fsystem, ratio);
while(x--)
{
__delay_cycles(30);
}
return(status);
}
bool CS_initFLL(uint16_t fsystem,
uint16_t ratio)
{
uint16_t dco_FLLN, dco_FLLD = FLLD__1;
bool status = true;
//Save actual state of FLL loop control, then disable it. This is needed to
//prevent the FLL from acting as we are making fundamental modifications to
//the clock setup.
uint16_t srRegisterState = __get_SR_register() & SCG0;
//Have at least a divider of 2
dco_FLLN = ratio;
// Disable FLL
__bis_SR_register(SCG0);
//Set DCO to lowest Tap
HWREG16(CS_BASE + OFS_CSCTL0) &= ~(DCO8 |
DCO7 |
DCO6 |
DCO5 |
DCO4 |
DCO3 |
DCO2 |
DCO1 |
DCO0
);
//Reset FLLN bits
HWREG16(CS_BASE + OFS_CSCTL2) &= ~(FLLN9 |
FLLN8 |
FLLN7 |
FLLN6 |
FLLN5 |
FLLN4 |
FLLN3 |
FLLN2 |
FLLN1 |
FLLN0
);
HWREG16(CS_BASE + OFS_CSCTL2) = dco_FLLD | (dco_FLLN - 1);
HWREG8(CS_BASE + OFS_CSCTL1) &= ~DCORSEL_7;
if(fsystem <= 1000) //fsystem <= 1MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_0;
}
else if(fsystem <= 2000) //1MHz < fsystem <= 2MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_1;
}
else if(fsystem <= 4000) //2MHz < fsystem <= 4MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_2;
}
else if(fsystem <= 8000) //4MHz < fsystem <= 8MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_3;
}
else if(fsystem <= 12000) //8MHz < fsystem <= 12MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_4;
}
else if(fsystem <= 16000) //12MHz < fsystem <= 16MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_5;
}
else if(fsystem <= 20000) //16MHz < fsystem <= 20MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_6;
}
else if(fsystem <= 24000) //20MHz < fsystem <= 24MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_7;
}
else
{
//exceeds 24MHz, not supported
status = false;
}
// Re-enable FLL
__bic_SR_register(SCG0);
while((HWREG16(CS_BASE + OFS_CSCTL7) & (FLLUNLOCK0 | FLLUNLOCK1)) ||
(HWREG8(CS_BASE + OFS_CSCTL7_L) & DCOFFG))
{
//Clear OSC fault flags
HWREG8(CS_BASE + OFS_CSCTL7_L) &= ~(DCOFFG);
//Clear OFIFG fault flag
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
}
// Restore previous SCG0
__bis_SR_register(srRegisterState);
return(status);
}
bool CS_initFLLCalculateTrim(uint16_t fsystem,
uint16_t ratio,
CS_initFLLParam *param)
{
uint16_t dco_FLLN, dco_FLLD = FLLD__1;
bool status = true;
volatile uint16_t x = ratio * 32;
//Save actual state of FLL loop control, then disable it. This is needed to
//prevent the FLL from acting as we are making fundamental modifications to
//the clock setup.
uint16_t srRegisterState = __get_SR_register() & SCG0;
//Have at least a divider of 2
dco_FLLN = ratio;
// Disable FLL
__bis_SR_register(SCG0);
//Set DCO to lowest Tap
HWREG16(CS_BASE + OFS_CSCTL0) &= ~(DCO8 |
DCO7 |
DCO6 |
DCO5 |
DCO4 |
DCO3 |
DCO2 |
DCO1 |
DCO0
);
//Reset FLLN bits
HWREG16(CS_BASE + OFS_CSCTL2) &= ~(FLLN9 |
FLLN8 |
FLLN7 |
FLLN6 |
FLLN5 |
FLLN4 |
FLLN3 |
FLLN2 |
FLLN1 |
FLLN0
);
HWREG16(CS_BASE + OFS_CSCTL2) = dco_FLLD | (dco_FLLN - 1);
HWREG8(CS_BASE + OFS_CSCTL1) &= ~DCORSEL_7;
if(fsystem <= 1000) //fsystem <= 1MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_0;
}
else if(fsystem <= 2000) //1MHz < fsystem <= 2MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_1;
}
else if(fsystem <= 4000) //2MHz < fsystem <= 4MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_2;
}
else if(fsystem <= 8000) //4MHz < fsystem <= 8MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_3;
}
else if(fsystem <= 12000) //8MHz < fsystem <= 12MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_4;
}
else if(fsystem <= 16000) //12MHz < fsystem <= 16MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_5;
}
else if(fsystem <= 20000) //16MHz < fsystem <= 20MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_6;
}
else if(fsystem <= 24000) //20MHz < fsystem <= 24MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_7;
}
else
{
//exceeds 24MHz, not supported
status = false;
}
// Re-enable FLL
__bic_SR_register(SCG0);
// Enable DCO frequency trim
HWREG16(CS_BASE + OFS_CSCTL1) |= DCOFTRIMEN;
// Calculates DCO frequency trim values and stores them in struct pointer
param->fsystem = fsystem;
privateCSComputeDCOFTrim(param);
while((HWREG16(CS_BASE + OFS_CSCTL7) & (FLLUNLOCK0 | FLLUNLOCK1)) ||
(HWREG8(CS_BASE + OFS_CSCTL7_L) & DCOFFG))
{
//Clear OSC fault flags
HWREG8(CS_BASE + OFS_CSCTL7_L) &= ~(DCOFFG);
//Clear OFIFG fault flag
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
}
// Restore previous SCG0
__bis_SR_register(srRegisterState);
while(x--)
{
__delay_cycles(30);
}
return(status);
}
bool CS_initFLLLoadTrim(uint16_t fsystem,
uint16_t ratio,
CS_initFLLParam *param)
{
if(param->fsystem != fsystem)
{
// Protection against wrong clock frequency and trim combination
return(false);
}
uint16_t dco_FLLN, dco_FLLD = FLLD__1;
bool status = true;
volatile uint16_t x = ratio * 32;
//Save actual state of FLL loop control, then disable it. This is needed to
//prevent the FLL from acting as we are making fundamental modifications to
//the clock setup.
uint16_t srRegisterState = __get_SR_register() & SCG0;
//Have at least a divider of 2
dco_FLLN = ratio;
// Disable FLL
__bis_SR_register(SCG0);
//Set DCO to proper tap
HWREG16(CS_BASE + OFS_CSCTL0) &= ~(DCO8 |
DCO7 |
DCO6 |
DCO5 |
DCO4 |
DCO3 |
DCO2 |
DCO1 |
DCO0
);
HWREG16(CS_BASE + OFS_CSCTL0) |= (param->csCtl0 &
(DCO8 |
DCO7 |
DCO6 |
DCO5 |
DCO4 |
DCO3 |
DCO2 |
DCO1 |
DCO0
));
//Reset FLLN bits
HWREG16(CS_BASE + OFS_CSCTL2) &= ~(FLLN9 |
FLLN8 |
FLLN7 |
FLLN6 |
FLLN5 |
FLLN4 |
FLLN3 |
FLLN2 |
FLLN1 |
FLLN0
);
HWREG16(CS_BASE + OFS_CSCTL2) = dco_FLLD | (dco_FLLN - 1);
// Set proper DCORSEL value
HWREG8(CS_BASE + OFS_CSCTL1) &= ~DCORSEL_7;
if(fsystem <= 1000) //fsystem <= 1MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_0;
}
else if(fsystem <= 2000) //1MHz < fsystem <= 2MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_1;
}
else if(fsystem <= 4000) //2MHz < fsystem <= 4MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_2;
}
else if(fsystem <= 8000) //4MHz < fsystem <= 8MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_3;
}
else if(fsystem <= 12000) //8MHz < fsystem <= 12MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_4;
}
else if(fsystem <= 16000) //12MHz < fsystem <= 16MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_5;
}
else if(fsystem <= 20000) //16MHz < fsystem <= 20MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_6;
}
else if(fsystem <= 24000) //20MHz < fsystem <= 24MHz
{
HWREG8(CS_BASE + OFS_CSCTL1) |= DCORSEL_7;
}
else
{
//exceeds 24MHz, not supported
status = false;
}
// Enable DCO frequency trim
HWREG16(CS_BASE + OFS_CSCTL1) |= DCOFTRIMEN;
// Set proper DCOFTRIM value
HWREG16(CS_BASE + OFS_CSCTL1) &= ~(DCOFTRIM0 | DCOFTRIM1 | DCOFTRIM2);
HWREG16(CS_BASE +
OFS_CSCTL1) |=
(param->csCtl1 & (DCOFTRIM0 | DCOFTRIM1 | DCOFTRIM2));
// Re-enable FLL
__bic_SR_register(SCG0);
while((HWREG16(CS_BASE + OFS_CSCTL7) & (FLLUNLOCK0 | FLLUNLOCK1)) ||
(HWREG8(CS_BASE + OFS_CSCTL7_L) & DCOFFG))
{
//Clear OSC fault flags
HWREG8(CS_BASE + OFS_CSCTL7_L) &= ~(DCOFFG);
//Clear OFIFG fault flag
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
}
// Restore previous SCG0
__bis_SR_register(srRegisterState);
while(x--)
{
__delay_cycles(30);
}
return(status);
}
void CS_enableClockRequest(uint8_t selectClock)
{
HWREG8(CS_BASE + OFS_CSCTL8) |= selectClock;
}
void CS_disableClockRequest(uint8_t selectClock)
{
HWREG8(CS_BASE + OFS_CSCTL8) &= ~selectClock;
}
uint8_t CS_getFaultFlagStatus(uint8_t mask)
{
return (HWREG8(CS_BASE + OFS_CSCTL7) & mask);
}
void CS_clearFaultFlag(uint8_t mask)
{
HWREG8(CS_BASE + OFS_CSCTL7) &= ~mask;
}
uint32_t CS_getACLK(void)
{
//Find ACLK source
uint16_t ACLKSource = (HWREG16(CS_BASE + OFS_CSCTL4) & SELA);
ACLKSource = ACLKSource >> 8;
if(ACLKSource == 0x0)
{
ACLKSource = SELMS__XT1CLK;
}
else if(ACLKSource == 0x1)
{
ACLKSource = SELMS__REFOCLK;
}
else
{
ACLKSource = SELMS__VLOCLK;
}
uint16_t ACLKSourceDivider = 0;
#ifdef DIVA0
if(HWREG16(CS_BASE + OFS_CSCTL6) & XTS)
{
uint16_t div = (HWREG16(CS_BASE + OFS_CSCTL6) &
(DIVA0 | DIVA1 | DIVA2 | DIVA3)) >> 8;
switch(div)
{
case 1:
case 2:
case 3:
case 4:
case 5:
ACLKSourceDivider = 8 * (1 << div);
break;
case 6:
ACLKSourceDivider = 384;
break;
case 7:
ACLKSourceDivider = 512;
break;
case 8:
ACLKSourceDivider = 768;
break;
case 9:
ACLKSourceDivider = 1024;
break;
case 10:
ACLKSourceDivider = 108;
break;
case 11:
ACLKSourceDivider = 338;
break;
case 12:
ACLKSourceDivider = 414;
break;
case 13:
ACLKSourceDivider = 640;
break;
default:
break;
}
}
#endif
return (privateCSComputeCLKFrequency(
ACLKSource,
ACLKSourceDivider,
CS_ACLK)
);
}
uint32_t CS_getSMCLK(void)
{
uint16_t SMCLKSource = HWREG8(CS_BASE + OFS_CSCTL4_L) & SELMS_7;
uint16_t SMCLKSourceDivider =
HWREG16(CS_BASE + OFS_CSCTL5) & DIVS_3;
SMCLKSourceDivider = SMCLKSourceDivider >> 4;
return (privateCSComputeCLKFrequency(
SMCLKSource,
SMCLKSourceDivider,
CS_SMCLK)
);
}
uint32_t CS_getMCLK(void)
{
//Find AMCLK source
uint16_t MCLKSource = (HWREG16(CS_BASE + OFS_CSCTL4) & SELMS_7);
uint16_t MCLKSourceDivider = HWREG16(CS_BASE + OFS_CSCTL5) & DIVM_7;
return (privateCSComputeCLKFrequency(
MCLKSource,
MCLKSourceDivider,
CS_MCLK)
);
}
uint16_t CS_clearAllOscFlagsWithTimeout(uint16_t timeout){
do
{
// Clear all osc fault flags
HWREG8(CS_BASE + OFS_CSCTL7) &= ~(DCOFFG | XT1OFFG);
// Clear the global osc fault flag.
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
// Check XT1 fault flags
}
while((HWREG8(SFR_BASE + OFS_SFRIFG1) & OFIFG) && --timeout);
return (HWREG8(CS_BASE + OFS_CSCTL7) & (DCOFFG | XT1OFFG));
}
void CS_enableXT1AutomaticGainControl(void)
{
HWREG16(CS_BASE + OFS_CSCTL6) &= ~XT1AGCOFF;
}
void CS_disableXT1AutomaticGainControl(void)
{
HWREG16(CS_BASE + OFS_CSCTL6) |= XT1AGCOFF;
}
void CS_enableFLLUnlock(void)
{
HWREG16(CS_BASE + OFS_CSCTL7) |= FLLULPUC;
}
void CS_disableFLLUnlock(void)
{
HWREG16(CS_BASE + OFS_CSCTL7) &= ~FLLULPUC;
}
void CS_enableREFOLP(void)
{
#ifdef REFOLP
HWREG16(CS_BASE + OFS_CSCTL3) |= REFOLP;
#endif
}
void CS_disableREFOLP(void)
{
#ifdef REFOLP
HWREG16(CS_BASE + OFS_CSCTL3) &= ~REFOLP;
#endif
}
bool CS_getREFOLP(void)
{
#ifdef REFOLP
return ((HWREG16(CS_BASE + OFS_CSCTL3) & REFOLP) ? true : false);
#else
return(false);
#endif
}
void CS_enableXT1FaultOff(void)
{
#ifdef XT1FAULTOFF
HWREG16(CS_BASE + OFS_CSCTL6) |= XT1FAULTOFF;
#endif
}
void CS_disableXT1FaultOff(void)
{
#ifdef XT1FAULTOFF
HWREG16(CS_BASE + OFS_CSCTL6) &= ~XT1FAULTOFF;
#endif
}
bool CS_getXT1FaultOff(void)
{
#ifdef XT1FAULTOFF
return ((HWREG16(CS_BASE + OFS_CSCTL6) & XT1FAULTOFF) ? true : false);
#else
return(false);
#endif
}
bool CS_getREFOReady(void)
{
#ifdef REFOREADY
return ((HWREG16(CS_BASE + OFS_CSCTL7) & REFOREADY) ? true : false);
#else
return(false);
#endif
}
#endif
//*****************************************************************************
//
//! Close the doxygen group for cs_api
//! @}
//
//*****************************************************************************