/* --COPYRIGHT--,BSD * Copyright (c) 2017, 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" #if defined(__MSP430_HAS_CS__) || defined(__MSP430_HAS_SFR__) #include "cs.h" #include //***************************************************************************** // // 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 frequency 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; uint16_t temp = HWREG16(CS_BASE + OFS_CSCTL3); 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) = temp & ~(DIVA0 + DIVA1 + DIVA2) | 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) = temp & ~(DIVS0 + DIVS1 + DIVS2) | 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) = temp & ~(DIVM0 + DIVM1 + DIVM2) | 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_turnOffSMCLK(void) { //Unlock CS control register HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; HWREG16(CS_BASE + OFS_CSCTL4) |= SMCLKOFF; //Lock CS control register HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; } void CS_turnOnSMCLK(void) { //Unlock CS control register HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; HWREG16(CS_BASE + OFS_CSCTL4) &= ~SMCLKOFF; //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 (16, 24] MHz if (privateHFXTClockFrequency > 16000000) { HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_3; } //If HFFrequency is (8, 16] MHz else if (privateHFXTClockFrequency > 8000000) { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_2; } //If HFFrequency is (4, 8] MHz else if (privateHFXTClockFrequency > 4000000) { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_1; } //If HFFrequency is [0, 4] MHz else { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; } 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; } 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 ); //If HFFrequency is (16, 24] MHz if (privateHFXTClockFrequency > 16000000) { HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_3; } //If HFFrequency is (8, 16] MHz else if (privateHFXTClockFrequency > 8000000) { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_2; } //If HFFrequency is (4, 8] MHz else if (privateHFXTClockFrequency > 4000000) { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_1; } //If HFFrequency is [0, 4] MHz else { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; } 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; //If HFFrequency is (16, 24] MHz if (privateHFXTClockFrequency > 16000000) { HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_3; } //If HFFrequency is (8, 16] MHz else if (privateHFXTClockFrequency > 8000000) { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_2; } //If HFFrequency is (4, 8] MHz else if (privateHFXTClockFrequency > 4000000) { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_1; } //If HFFrequency is [0, 4] MHz else { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; } 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 (16, 24] MHz if (privateHFXTClockFrequency > 16000000) { HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_3; } //If HFFrequency is (8, 16] MHz else if (privateHFXTClockFrequency > 8000000) { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_2; } //If HFFrequency is (4, 8] MHz else if (privateHFXTClockFrequency > 4000000) { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; HWREG16(CS_BASE + OFS_CSCTL4) |= HFFREQ_1; } //If HFFrequency is [0, 4] MHz else { HWREG16(CS_BASE + OFS_CSCTL4) &= ~HFFREQ_3; } //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 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)); uint16_t tempCSCTL3 = 0; //Unlock CS control register HWREG16(CS_BASE + OFS_CSCTL0) = CSKEY; //Assuming SMCLK and MCLK are sourced from DCO //Store CSCTL3 settings to recover later tempCSCTL3 = HWREG16(CS_BASE + OFS_CSCTL3); //Keep overshoot transient within specification by setting clk //sources to divide by 4 //Clear the DIVS & DIVM masks (~0x77) and set both fields to 4 divider HWREG16(CS_BASE + OFS_CSCTL3) = HWREG16(CS_BASE + OFS_CSCTL3) & (~(0x77)) | DIVS1 | DIVM1; //Set user's frequency selection for DCO HWREG16(CS_BASE + OFS_CSCTL1) = (dcorsel + dcofsel); //Delay by ~10us to let DCO settle. cycles to wait = 20 cycles buffer + //(10us * (x MHz/4)) switch(dcofsel) { case(CS_DCOFSEL_0): //1 MHz or 1 MHz (dcorsel == CS_DCORSEL_0) ? __delay_cycles(23) : __delay_cycles(23); break; case(CS_DCOFSEL_1): //2.67 MHz or 5.33 MHz (dcorsel == CS_DCORSEL_0) ? __delay_cycles(27) : __delay_cycles(34); break; case(CS_DCOFSEL_2): //3.33 MHz or 6.67 MHz (dcorsel == CS_DCORSEL_0) ? __delay_cycles(29) : __delay_cycles(37); break; case(CS_DCOFSEL_3): //4 MHz or 8 MHz (dcorsel == CS_DCORSEL_0) ? __delay_cycles(30) : __delay_cycles(40); break; case(CS_DCOFSEL_4): //5.33 MHz or 16 MHz (dcorsel == CS_DCORSEL_0) ? __delay_cycles(34) : __delay_cycles(60); break; case(CS_DCOFSEL_5): //6.67 MHz or 21 MHz (dcorsel == CS_DCORSEL_0) ? __delay_cycles(37) : __delay_cycles(73); break; case(CS_DCOFSEL_6): //8 MHz or 24 MHz (dcorsel == CS_DCORSEL_0) ? __delay_cycles(40) : __delay_cycles(80); break; default: //Should not be used, but default is 8 MHz or 24 MHz (dcorsel == CS_DCORSEL_0) ? __delay_cycles(40) : __delay_cycles(80); break; } //Set all dividers HWREG16(CS_BASE + OFS_CSCTL3) = tempCSCTL3; //Lock CS control register HWREG8(CS_BASE + OFS_CSCTL0_H) = 0x00; } #endif //***************************************************************************** // //! Close the doxygen group for cs_api //! @} // //*****************************************************************************