/* --COPYRIGHT--,BSD | |
* Copyright (c) 2014, 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_regaccess.h" | |
#include "inc/hw_memmap.h" | |
#if defined(__MSP430_HAS_CS__) || defined(__MSP430_HAS_SFR__) | |
#include "cs.h" | |
#include <assert.h> | |
//***************************************************************************** | |
// | |
// The following value is used by CS_getACLK, CS_getSMCLK, CS_getMCLK to | |
// determine the operating frequency based on the available DCO frequencies. | |
// | |
//***************************************************************************** | |
#define CS_DCO_FREQ_1 1000000 | |
#define CS_DCO_FREQ_2 2670000 | |
#define CS_DCO_FREQ_3 3330000 | |
#define CS_DCO_FREQ_4 4000000 | |
#define CS_DCO_FREQ_5 5330000 | |
#define CS_DCO_FREQ_6 6670000 | |
#define CS_DCO_FREQ_7 8000000 | |
#define CS_DCO_FREQ_8 16000000 | |
#define CS_DCO_FREQ_9 20000000 | |
#define CS_DCO_FREQ_10 24000000 | |
//***************************************************************************** | |
// | |
// Internal very low power VLOCLK, low frequency oscillator with 10kHz typical | |
// frequency, internal low-power oscillator MODCLK with 5 MHz typical | |
// frequency and LFMODCLK is MODCLK divided by 128. | |
// | |
//***************************************************************************** | |
#define CS_VLOCLK_FREQUENCY 10000 | |
#define CS_MODCLK_FREQUENCY 5000000 | |
#define CS_LFMODCLK_FREQUENCY 39062 | |
//***************************************************************************** | |
// | |
// The following value is used by CS_XT1Start, CS_bypassXT1, | |
// CS_XT1StartWithTimeout, CS_bypassXT1WithTimeout to properly set the XTS | |
// bit. This frequnecy threshold is specified in the User's Guide. | |
// | |
//***************************************************************************** | |
#define LFXT_FREQUENCY_THRESHOLD 50000 | |
//***************************************************************************** | |
// | |
// LFXT crystal frequency. Should be set with | |
// CS_externalClockSourceInit if LFXT is used and user intends to invoke | |
// CS_getSMCLK, CS_getMCLK, CS_getACLK and | |
// CS_turnOnLFXT, CS_LFXTByPass, CS_turnOnLFXTWithTimeout, | |
// CS_LFXTByPassWithTimeout. | |
// | |
//***************************************************************************** | |
static uint32_t privateLFXTClockFrequency = 0; | |
//***************************************************************************** | |
// | |
// The HFXT crystal frequency. Should be set with | |
// CS_externalClockSourceInit if HFXT is used and user intends to invoke | |
// CS_getSMCLK, CS_getMCLK, CS_getACLK, | |
// CS_turnOnLFXT, CS_LFXTByPass, CS_turnOnLFXTWithTimeout, | |
// CS_LFXTByPassWithTimeout. | |
// | |
//***************************************************************************** | |
static uint32_t privateHFXTClockFrequency = 0; | |
static uint32_t privateCSASourceClockFromDCO(uint8_t clockdivider) | |
{ | |
uint32_t CLKFrequency = 0; | |
if(HWREG16(CS_BASE + OFS_CSCTL1) & DCORSEL) | |
{ | |
switch(HWREG16(CS_BASE + OFS_CSCTL1) & DCOFSEL_7) | |
{ | |
case DCOFSEL_0: | |
CLKFrequency = CS_DCO_FREQ_1 / clockdivider; | |
break; | |
case DCOFSEL_1: | |
CLKFrequency = CS_DCO_FREQ_5 / clockdivider; | |
break; | |
case DCOFSEL_2: | |
CLKFrequency = CS_DCO_FREQ_6 / clockdivider; | |
break; | |
case DCOFSEL_3: | |
CLKFrequency = CS_DCO_FREQ_7 / clockdivider; | |
break; | |
case DCOFSEL_4: | |
CLKFrequency = CS_DCO_FREQ_8 / clockdivider; | |
break; | |
case DCOFSEL_5: | |
CLKFrequency = CS_DCO_FREQ_9 / clockdivider; | |
break; | |
case DCOFSEL_6: | |
case DCOFSEL_7: | |
CLKFrequency = CS_DCO_FREQ_10 / clockdivider; | |
break; | |
default: | |
CLKFrequency = 0; | |
break; | |
} | |
} | |
else | |
{ | |
switch(HWREG16(CS_BASE + OFS_CSCTL1) & DCOFSEL_7) | |
{ | |
case DCOFSEL_0: | |
CLKFrequency = CS_DCO_FREQ_1 / clockdivider; | |
break; | |
case DCOFSEL_1: | |
CLKFrequency = CS_DCO_FREQ_2 / clockdivider; | |
break; | |
case DCOFSEL_2: | |
CLKFrequency = CS_DCO_FREQ_3 / clockdivider; | |
break; | |
case DCOFSEL_3: | |
CLKFrequency = CS_DCO_FREQ_4 / clockdivider; | |
break; | |
case DCOFSEL_4: | |
CLKFrequency = CS_DCO_FREQ_5 / clockdivider; | |
break; | |
case DCOFSEL_5: | |
CLKFrequency = CS_DCO_FREQ_6 / clockdivider; | |
break; | |
case DCOFSEL_6: | |
case DCOFSEL_7: | |
CLKFrequency = CS_DCO_FREQ_7 / clockdivider; | |
break; | |
default: | |
CLKFrequency = 0; | |
break; | |
} | |
} | |
return (CLKFrequency); | |
} | |
static uint32_t privateCSAComputeCLKFrequency(uint16_t CLKSource, | |
uint16_t CLKSourceDivider) | |
{ | |
uint32_t CLKFrequency = 0; | |
uint8_t CLKSourceFrequencyDivider = 1; | |
uint8_t i = 0; | |
// Determine Frequency divider | |
for(i = 0; i < CLKSourceDivider; i++) | |
{ | |
CLKSourceFrequencyDivider *= 2; | |
} | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
// Determine clock source based on CLKSource | |
switch(CLKSource) | |
{ | |
// If LFXT is selected as clock source | |
case SELM__LFXTCLK: | |
CLKFrequency = (privateLFXTClockFrequency / | |
CLKSourceFrequencyDivider); | |
//Check if LFXTOFFG is not set. If fault flag is set | |
//VLO is used as source clock | |
if(HWREG8(CS_BASE + OFS_CSCTL5) & LFXTOFFG) | |
{ | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~(LFXTOFFG); | |
//Clear OFIFG fault flag | |
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; | |
if(HWREG8(CS_BASE + OFS_CSCTL5) & LFXTOFFG) | |
{ | |
CLKFrequency = CS_LFMODCLK_FREQUENCY; | |
} | |
} | |
break; | |
case SELM__VLOCLK: | |
CLKFrequency = | |
(CS_VLOCLK_FREQUENCY / CLKSourceFrequencyDivider); | |
break; | |
case SELM__LFMODOSC: | |
CLKFrequency = | |
(CS_LFMODCLK_FREQUENCY / CLKSourceFrequencyDivider); | |
break; | |
case SELM__DCOCLK: | |
CLKFrequency = | |
privateCSASourceClockFromDCO(CLKSourceFrequencyDivider); | |
break; | |
case SELM__MODOSC: | |
CLKFrequency = | |
(CS_MODCLK_FREQUENCY / CLKSourceFrequencyDivider); | |
break; | |
case SELM__HFXTCLK: | |
CLKFrequency = | |
(privateHFXTClockFrequency / CLKSourceFrequencyDivider); | |
if(HWREG8(CS_BASE + OFS_CSCTL5) & HFXTOFFG) | |
{ | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~HFXTOFFG; | |
//Clear OFIFG fault flag | |
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; | |
} | |
if(HWREG8(CS_BASE + OFS_CSCTL5) & HFXTOFFG) | |
{ | |
CLKFrequency = CS_MODCLK_FREQUENCY; | |
} | |
break; | |
} | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
return (CLKFrequency); | |
} | |
void CS_setExternalClockSource(uint32_t LFXTCLK_frequency, | |
uint32_t HFXTCLK_frequency) | |
{ | |
privateLFXTClockFrequency = LFXTCLK_frequency; | |
privateHFXTClockFrequency = HFXTCLK_frequency; | |
} | |
void CS_initClockSignal(uint8_t selectedClockSignal, | |
uint16_t clockSource, | |
uint16_t clockSourceDivider) | |
{ | |
//Verify User has selected a valid Frequency divider | |
assert( | |
(CS_CLOCK_DIVIDER_1 == clockSourceDivider) || | |
(CS_CLOCK_DIVIDER_2 == clockSourceDivider) || | |
(CS_CLOCK_DIVIDER_4 == clockSourceDivider) || | |
(CS_CLOCK_DIVIDER_8 == clockSourceDivider) || | |
(CS_CLOCK_DIVIDER_16 == clockSourceDivider) || | |
(CS_CLOCK_DIVIDER_32 == clockSourceDivider) | |
); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
switch(selectedClockSignal) | |
{ | |
case CS_ACLK: | |
assert( | |
(CS_LFXTCLK_SELECT == clockSource) || | |
(CS_VLOCLK_SELECT == clockSource) || | |
(CS_LFMODOSC_SELECT == clockSource) | |
); | |
clockSourceDivider = clockSourceDivider << 8; | |
clockSource = clockSource << 8; | |
HWREG16(CS_BASE + OFS_CSCTL2) &= ~(SELA_7); | |
HWREG16(CS_BASE + OFS_CSCTL2) |= (clockSource); | |
HWREG16(CS_BASE + OFS_CSCTL3) &= ~(DIVA0 + DIVA1 + DIVA2); | |
HWREG16(CS_BASE + OFS_CSCTL3) |= clockSourceDivider; | |
break; | |
case CS_SMCLK: | |
assert( | |
(CS_LFXTCLK_SELECT == clockSource) || | |
(CS_VLOCLK_SELECT == clockSource) || | |
(CS_DCOCLK_SELECT == clockSource) || | |
(CS_HFXTCLK_SELECT == clockSource) || | |
(CS_LFMODOSC_SELECT == clockSource)|| | |
(CS_MODOSC_SELECT == clockSource) | |
); | |
clockSource = clockSource << 4; | |
clockSourceDivider = clockSourceDivider << 4; | |
HWREG16(CS_BASE + OFS_CSCTL2) &= ~(SELS_7); | |
HWREG16(CS_BASE + OFS_CSCTL2) |= clockSource; | |
HWREG16(CS_BASE + OFS_CSCTL3) &= ~(DIVS0 + DIVS1 + DIVS2); | |
HWREG16(CS_BASE + OFS_CSCTL3) |= clockSourceDivider; | |
break; | |
case CS_MCLK: | |
assert( | |
(CS_LFXTCLK_SELECT == clockSource) || | |
(CS_VLOCLK_SELECT == clockSource) || | |
(CS_DCOCLK_SELECT == clockSource) || | |
(CS_HFXTCLK_SELECT == clockSource) || | |
(CS_LFMODOSC_SELECT == clockSource)|| | |
(CS_MODOSC_SELECT == clockSource) | |
); | |
HWREG16(CS_BASE + OFS_CSCTL2) &= ~(SELM_7); | |
HWREG16(CS_BASE + OFS_CSCTL2) |= clockSource; | |
HWREG16(CS_BASE + OFS_CSCTL3) &= ~(DIVM0 + DIVM1 + DIVM2); | |
HWREG16(CS_BASE + OFS_CSCTL3) |= clockSourceDivider; | |
break; | |
} | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
void CS_turnOnLFXT(uint16_t lfxtdrive) | |
{ | |
assert(privateLFXTClockFrequency != 0); | |
assert((lfxtdrive == CS_LFXT_DRIVE_0) || | |
(lfxtdrive == CS_LFXT_DRIVE_1) || | |
(lfxtdrive == CS_LFXT_DRIVE_2) || | |
(lfxtdrive == CS_LFXT_DRIVE_3)); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
//Switch ON LFXT oscillator | |
HWREG16(CS_BASE + OFS_CSCTL4) &= ~LFXTOFF; | |
//Highest drive setting for LFXTstartup | |
HWREG16(CS_BASE + OFS_CSCTL4_L) |= LFXTDRIVE1_L + LFXTDRIVE0_L; | |
HWREG16(CS_BASE + OFS_CSCTL4) &= ~LFXTBYPASS; | |
//Wait for Crystal to stabilize | |
while(HWREG8(CS_BASE + OFS_CSCTL5) & LFXTOFFG) | |
{ | |
//Clear OSC flaut Flags fault flags | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~(LFXTOFFG); | |
//Clear OFIFG fault flag | |
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; | |
} | |
//set requested Drive mode | |
HWREG16(CS_BASE + OFS_CSCTL4) = (HWREG16(CS_BASE + OFS_CSCTL4) & | |
~(LFXTDRIVE_3) | |
) | | |
(lfxtdrive); | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
void CS_bypassLFXT(void) | |
{ | |
//Verify user has set frequency of LFXT with SetExternalClockSource | |
assert(privateLFXTClockFrequency != 0); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
assert(privateLFXTClockFrequency < LFXT_FREQUENCY_THRESHOLD); | |
// Set LFXT in LF mode Switch off LFXT oscillator and enable BYPASS mode | |
HWREG16(CS_BASE + OFS_CSCTL4) |= (LFXTBYPASS + LFXTOFF); | |
//Wait until LFXT stabilizes | |
while(HWREG8(CS_BASE + OFS_CSCTL5) & LFXTOFFG) | |
{ | |
//Clear OSC flaut Flags fault flags | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~(LFXTOFFG); | |
// Clear the global fault flag. In case the LFXT 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; | |
} | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
bool CS_turnOnLFXTWithTimeout(uint16_t lfxtdrive, | |
uint32_t timeout) | |
{ | |
assert(privateLFXTClockFrequency != 0); | |
assert((lfxtdrive == CS_LFXT_DRIVE_0) || | |
(lfxtdrive == CS_LFXT_DRIVE_1) || | |
(lfxtdrive == CS_LFXT_DRIVE_2) || | |
(lfxtdrive == CS_LFXT_DRIVE_3)); | |
assert(timeout > 0); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
//Switch ON LFXT oscillator | |
HWREG16(CS_BASE + OFS_CSCTL4) &= ~LFXTOFF; | |
//Highest drive setting for LFXTstartup | |
HWREG16(CS_BASE + OFS_CSCTL4_L) |= LFXTDRIVE1_L + LFXTDRIVE0_L; | |
HWREG16(CS_BASE + OFS_CSCTL4) &= ~LFXTBYPASS; | |
while((HWREG8(CS_BASE + OFS_CSCTL5) & LFXTOFFG) && --timeout) | |
{ | |
//Clear OSC fault Flags fault flags | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~(LFXTOFFG); | |
// Clear the global fault flag. In case the LFXT 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; | |
} | |
if(timeout) | |
{ | |
//set requested Drive mode | |
HWREG16(CS_BASE + OFS_CSCTL4) = (HWREG16(CS_BASE + OFS_CSCTL4) & | |
~(LFXTDRIVE_3) | |
) | | |
(lfxtdrive); | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
return (STATUS_SUCCESS); | |
} | |
else | |
{ | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
return (STATUS_FAIL); | |
} | |
} | |
bool CS_bypassLFXTWithTimeout(uint32_t timeout) | |
{ | |
assert(privateLFXTClockFrequency != 0); | |
assert(privateLFXTClockFrequency < LFXT_FREQUENCY_THRESHOLD); | |
assert(timeout > 0); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
// Set LFXT in LF mode Switch off LFXT oscillator and enable BYPASS mode | |
HWREG16(CS_BASE + OFS_CSCTL4) |= (LFXTBYPASS + LFXTOFF); | |
while((HWREG8(CS_BASE + OFS_CSCTL5) & LFXTOFFG) && --timeout) | |
{ | |
//Clear OSC fault Flags fault flags | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~(LFXTOFFG); | |
// Clear the global fault flag. In case the LFXT 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; | |
} | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
if(timeout) | |
{ | |
return (STATUS_SUCCESS); | |
} | |
else | |
{ | |
return (STATUS_FAIL); | |
} | |
} | |
void CS_turnOffLFXT(void) | |
{ | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
//Switch off LFXT oscillator | |
HWREG16(CS_BASE + OFS_CSCTL4) |= LFXTOFF; | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
void CS_turnOnHFXT(uint16_t hfxtdrive) | |
{ | |
assert(privateHFXTClockFrequency != 0); | |
assert((hfxtdrive == CS_HFXT_DRIVE_4MHZ_8MHZ) || | |
(hfxtdrive == CS_HFXT_DRIVE_8MHZ_16MHZ) || | |
(hfxtdrive == CS_HFXT_DRIVE_16MHZ_24MHZ)|| | |
(hfxtdrive == CS_HFXT_DRIVE_24MHZ_32MHZ)); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
// Switch ON HFXT oscillator | |
HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFXTOFF; | |
//Disable HFXTBYPASS mode and Switch on HFXT oscillator | |
HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFXTBYPASS; | |
//If HFFrequency is 16MHz or above | |
if(privateHFXTClockFrequency > 16000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_3; | |
} | |
//If HFFrequency is between 8MHz and 16MHz | |
else if(privateHFXTClockFrequency > 8000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_2; | |
} | |
//If HFFrequency is between 0MHz and 4MHz | |
else if(privateHFXTClockFrequency < 4000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_0; | |
} | |
//If HFFrequency is between 4MHz and 8MHz | |
else | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_1; | |
} | |
while(HWREG8(CS_BASE + OFS_CSCTL5) & HFXTOFFG) | |
{ | |
//Clear OSC flaut Flags | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~(HFXTOFFG); | |
//Clear OFIFG fault flag | |
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; | |
} | |
HWREG16(CS_BASE + OFS_CSCTL4) = (HWREG16(CS_BASE + OFS_CSCTL4) & | |
~(CS_HFXT_DRIVE_24MHZ_32MHZ) | |
) | | |
(hfxtdrive); | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
void CS_bypassHFXT(void) | |
{ | |
//Verify user has initialized value of HFXTClock | |
assert(privateHFXTClockFrequency != 0); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
//Switch off HFXT oscillator and set it to BYPASS mode | |
HWREG16(CS_BASE + OFS_CSCTL4) |= (HFXTBYPASS + HFXTOFF); | |
//Set correct HFFREQ bit for FR58xx/FR59xx devices | |
//If HFFrequency is 16MHz or above | |
if(privateHFXTClockFrequency > 16000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_3; | |
} | |
//If HFFrequency is between 8MHz and 16MHz | |
else if(privateHFXTClockFrequency > 8000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_2; | |
} | |
//If HFFrequency is between 0MHz and 4MHz | |
else if(privateHFXTClockFrequency < 4000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_0; | |
} | |
//If HFFrequency is between 4MHz and 8MHz | |
else | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_1; | |
} | |
while(HWREG8(CS_BASE + OFS_CSCTL5) & HFXTOFFG) | |
{ | |
//Clear OSC fault Flags | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~(HFXTOFFG); | |
//Clear OFIFG fault flag | |
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; | |
} | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
bool CS_turnOnHFXTWithTimeout(uint16_t hfxtdrive, | |
uint32_t timeout) | |
{ | |
//Verify user has initialized value of HFXTClock | |
assert(privateHFXTClockFrequency != 0); | |
assert(timeout > 0); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
//Switch on HFXT oscillator | |
HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFXTOFF; | |
// Disable HFXTBYPASS mode | |
HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFXTBYPASS; | |
//Set correct HFFREQ bit for FR58xx/FR59xx devices based | |
//on HFXTClockFrequency | |
//If HFFrequency is 16MHz or above | |
if(privateHFXTClockFrequency > 16000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_3; | |
} | |
//If HFFrequency is between 8MHz and 16MHz | |
else if(privateHFXTClockFrequency > 8000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_2; | |
} | |
//If HFFrequency is between 0MHz and 4MHz | |
else if(privateHFXTClockFrequency < 4000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_0; | |
} | |
//If HFFrequency is between 4MHz and 8MHz | |
else | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_1; | |
} | |
while((HWREG8(CS_BASE + OFS_CSCTL5) & HFXTOFFG) && --timeout) | |
{ | |
//Clear OSC fault Flags fault flags | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~(HFXTOFFG); | |
// Clear the global fault flag. In case the LFXT 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; | |
} | |
if(timeout) | |
{ | |
//Set drive strength for HFXT | |
HWREG16(CS_BASE + OFS_CSCTL4) = (HWREG16(CS_BASE + OFS_CSCTL4) & | |
~(CS_HFXT_DRIVE_24MHZ_32MHZ) | |
) | | |
(hfxtdrive); | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
return (STATUS_SUCCESS); | |
} | |
else | |
{ | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
return (STATUS_FAIL); | |
} | |
} | |
bool CS_bypassHFXTWithTimeout(uint32_t timeout) | |
{ | |
//Verify user has initialized value of HFXTClock | |
assert(privateHFXTClockFrequency != 0); | |
assert(timeout > 0); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
//If HFFrequency is 16MHz or above | |
if(privateHFXTClockFrequency > 16000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_3; | |
} | |
//If HFFrequency is between 8MHz and 16MHz | |
else if(privateHFXTClockFrequency > 8000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_2; | |
} | |
//If HFFrequency is between 0MHz and 4MHz | |
else if(privateHFXTClockFrequency < 4000000) | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_0; | |
} | |
//If HFFrequency is between 4MHz and 8MHz | |
else | |
{ | |
HWREG16(CS_BASE + OFS_CSCTL4) = HFFREQ_1; | |
} | |
//Switch off HFXT oscillator and enable BYPASS mode | |
HWREG16(CS_BASE + OFS_CSCTL4) |= (HFXTBYPASS + HFXTOFF); | |
while((HWREG8(CS_BASE + OFS_CSCTL5) & HFXTOFFG) && --timeout) | |
{ | |
//Clear OSC fault Flags fault flags | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~(HFXTOFFG); | |
// Clear the global fault flag. In case the LFXT 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; | |
} | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
if(timeout) | |
{ | |
return (STATUS_SUCCESS); | |
} | |
else | |
{ | |
return (STATUS_FAIL); | |
} | |
} | |
void CS_turnOffHFXT(void) | |
{ | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
//Switch off HFXT oscillator | |
HWREG16(CS_BASE + OFS_CSCTL4) |= HFXTOFF; | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
void CS_enableClockRequest(uint8_t selectClock) | |
{ | |
assert( | |
(CS_ACLK == selectClock)|| | |
(CS_SMCLK == selectClock)|| | |
(CS_MCLK == selectClock)|| | |
(CS_MODOSC == selectClock)); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
HWREG8(CS_BASE + OFS_CSCTL6) |= selectClock; | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
void CS_disableClockRequest(uint8_t selectClock) | |
{ | |
assert( | |
(CS_ACLK == selectClock)|| | |
(CS_SMCLK == selectClock)|| | |
(CS_MCLK == selectClock)|| | |
(CS_MODOSC == selectClock)); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
HWREG8(CS_BASE + OFS_CSCTL6) &= ~selectClock; | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
uint8_t CS_getFaultFlagStatus(uint8_t mask) | |
{ | |
assert( | |
(CS_HFXTOFFG == mask)|| | |
(CS_LFXTOFFG == mask) | |
); | |
return (HWREG8(CS_BASE + OFS_CSCTL5) & mask); | |
} | |
void CS_clearFaultFlag(uint8_t mask) | |
{ | |
assert( | |
(CS_HFXTOFFG == mask)|| | |
(CS_LFXTOFFG == mask) | |
); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~mask; | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
uint32_t CS_getACLK(void) | |
{ | |
//Find ACLK source | |
uint16_t ACLKSource = (HWREG16(CS_BASE + OFS_CSCTL2) & SELA_7); | |
ACLKSource = ACLKSource >> 8; | |
//Find ACLK frequency divider | |
uint16_t ACLKSourceDivider = HWREG16(CS_BASE + OFS_CSCTL3) & SELA_7; | |
ACLKSourceDivider = ACLKSourceDivider >> 8; | |
return (privateCSAComputeCLKFrequency( | |
ACLKSource, | |
ACLKSourceDivider)); | |
} | |
uint32_t CS_getSMCLK(void) | |
{ | |
//Find SMCLK source | |
uint16_t SMCLKSource = HWREG8(CS_BASE + OFS_CSCTL2) & SELS_7; | |
SMCLKSource = SMCLKSource >> 4; | |
//Find SMCLK frequency divider | |
uint16_t SMCLKSourceDivider = HWREG16(CS_BASE + OFS_CSCTL3) & SELS_7; | |
SMCLKSourceDivider = SMCLKSourceDivider >> 4; | |
return (privateCSAComputeCLKFrequency( | |
SMCLKSource, | |
SMCLKSourceDivider) | |
); | |
} | |
uint32_t CS_getMCLK(void) | |
{ | |
//Find MCLK source | |
uint16_t MCLKSource = (HWREG16(CS_BASE + OFS_CSCTL2) & SELM_7); | |
//Find MCLK frequency divider | |
uint16_t MCLKSourceDivider = HWREG16(CS_BASE + OFS_CSCTL3) & SELM_7; | |
return (privateCSAComputeCLKFrequency( | |
MCLKSource, | |
MCLKSourceDivider) | |
); | |
} | |
void CS_turnOffVLO(void) | |
{ | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
HWREG16(CS_BASE + OFS_CSCTL4) |= VLOOFF; | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
uint16_t CS_clearAllOscFlagsWithTimeout(uint32_t timeout) | |
{ | |
assert(timeout > 0); | |
// Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
do | |
{ | |
// Clear all osc fault flags | |
HWREG8(CS_BASE + OFS_CSCTL5) &= ~(LFXTOFFG + HFXTOFFG); | |
// Clear the global osc fault flag. | |
HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG; | |
// Check LFXT fault flags | |
} | |
while((HWREG8(SFR_BASE + OFS_SFRIFG1) & OFIFG) && --timeout); | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
return (HWREG8(CS_BASE + OFS_CSCTL5) & (LFXTOFFG + HFXTOFFG)); | |
} | |
void CS_setDCOFreq(uint16_t dcorsel, | |
uint16_t dcofsel) | |
{ | |
assert( | |
(dcofsel == CS_DCOFSEL_0)|| | |
(dcofsel == CS_DCOFSEL_1)|| | |
(dcofsel == CS_DCOFSEL_2)|| | |
(dcofsel == CS_DCOFSEL_3)|| | |
(dcofsel == CS_DCOFSEL_4)|| | |
(dcofsel == CS_DCOFSEL_5)|| | |
(dcofsel == CS_DCOFSEL_6) | |
); | |
//Verify user has selected a valid DCO Frequency Range option | |
assert( | |
(dcorsel == CS_DCORSEL_0)|| | |
(dcorsel == CS_DCORSEL_1)); | |
//Unlock CS control register | |
HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; | |
// Set user's frequency selection for DCO | |
HWREG16(CS_BASE + OFS_CSCTL1) = (dcorsel + dcofsel); | |
// Lock CS control register | |
HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Close the doxygen group for cs_api | |
//! @} | |
// | |
//***************************************************************************** |