/* --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--*/ | |
//***************************************************************************** | |
// | |
// esi.h - Driver for the ESI Module. | |
// | |
//***************************************************************************** | |
//***************************************************************************** | |
// | |
//! \addtogroup esi_api | |
//! @{ | |
// | |
//***************************************************************************** | |
#include "inc/hw_regaccess.h" | |
#include "inc/hw_memmap.h" | |
#ifdef __MSP430_HAS_ESI__ | |
#include "esi.h" | |
#include <assert.h> | |
// Uncomment for finding lower peak of the lower half cycle. | |
// This required to set ESI comparator output as inverted | |
#define INVERTED | |
static uint16_t measureESIOSC(void); | |
static void FindDAC(uint8_t selected_channel, | |
uint8_t software_trigger); | |
const ESI_AFE1_InitParams ESI_AFE1_INITPARAMS_DEFAULT = | |
{ESI_EXCITATION_CIRCUIT_DISABLED, | |
ESI_SAMPLE_HOLD_DISABLED, | |
ESI_MID_VOLTAGE_GENERATOR_DISABLED, | |
ESI_SAMPLE_HOLD_VSS_TO_ESIVSS, | |
ESI_INVERTER_FOR_AFE1_DISABLE}; | |
const ESI_AFE2_InitParams ESI_AFE2_INITPARAMS_DEFAULT = { | |
ESI_AFE2_INPUT_SELECT_CHx, | |
ESI_INVERTER_FOR_AFE2_DISABLE, | |
ESI_TSM_COMPARATOR_CONTROL_AFE2_DISABLE, | |
ESI_TSM_DAC_CONTROL_AFE2_DISABLE | |
}; | |
const ESI_TSM_InitParams ESI_TSM_INITPARAMS_DEFAULT = { ESI_TSM_SMCLK_DIV_1, | |
ESI_TSM_ACLK_DIV_1, | |
ESI_TSM_START_TRIGGER_DIV_2, | |
ESI_TSM_REPEAT_NEW_TRIGGER, | |
ESI_TSM_STOP_SEQUENCE, | |
ESI_TSM_HIGH_FREQ_CLK_FUNCTION_ON}; | |
const ESI_PSM_InitParams ESI_PSM_INITPARAMS_DEFAULT = { ESI_PSM_Q6_DISABLE, | |
ESI_PSM_Q7_TRIGGER_DISABLE, | |
ESI_PSM_CNT0_DISABLE, | |
ESI_PSM_CNT0_RESET, | |
ESI_PSM_CNT1_DISABLE, | |
ESI_PSM_CNT1_RESET, | |
ESI_PSM_CNT2_DISABLE, | |
ESI_PSM_CNT2_RESET, | |
ESI_PSM_S3_SELECT, | |
ESI_PSM_TEST4_IS_Q2,}; | |
//***************************************************************************** | |
// | |
//! Get ESI PSM Counter 0 Value | |
//! | |
//! This function reads the ESI Counter 0 register | |
//! | |
//! \return Counter value | |
// | |
//***************************************************************************** | |
uint16_t ESI_getCounter0(void) | |
{ | |
return (ESICNT0); | |
} | |
//***************************************************************************** | |
// | |
//! Get ESI PSM Counter 1 Value | |
//! | |
//! This function reads the ESI Counter1 register | |
//! | |
//! \return Counter value | |
// | |
//***************************************************************************** | |
uint16_t ESI_getCounter1(void) | |
{ | |
return (ESICNT1); | |
} | |
//***************************************************************************** | |
// | |
//! Get ESI PSM Counter 2 Value | |
//! | |
//! This function reads the ESI Counter2 register | |
//! | |
//! \return Counter value | |
// | |
//***************************************************************************** | |
uint16_t ESI_getCounter2(void) | |
{ | |
return (ESICNT2); | |
} | |
//***************************************************************************** | |
// | |
//! Get ESI PSM Oscillator Counter Value | |
//! | |
//! This function reads the ESI Oscillator Counter register | |
//! | |
//! \return Counter value | |
// | |
//***************************************************************************** | |
uint16_t ESI_getOscCounter(void) | |
{ | |
return (ESICNT3); | |
} | |
//***************************************************************************** | |
// | |
//! Initializes the ESI analog front end AFE1 | |
//! | |
//! \param params is ESI_AFE1_InitParams struct | |
//! | |
//! This functions initializes the ESI analog front end AFE1. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_AFE1_init(ESI_AFE1_InitParams *params) | |
{ | |
// Unset the AFE1 bits | |
ESIAFE &= ~(ESITEN + ESISH + ESIVCC2 + ESIVSS + ESICACI3 + ESICISEL + | |
ESICA1X + ESICA1INV); | |
ESIAFE |= | |
params->excitationCircuitSelect + | |
params->sampleAndHoldSelect + | |
params->midVoltageGeneratorSelect + | |
params->sampleAndHoldVSSConnect + | |
params->inverterSelectOutputAFE1 | |
; | |
switch(params->inputSelectAFE1) | |
{ | |
case ESI_AFE1_INPUT_SELECT_CHx: | |
break; | |
case ESI_AFE1_INPUT_SELECT_CIx: | |
ESIAFE |= ESICA1X; | |
break; | |
case ESI_AFE1_INPUT_SELECT_CI3: | |
ESIAFE |= ESICA1X; | |
ESIAFE &= ~ESICISEL; | |
ESIAFE |= ESICACI3; | |
break; | |
case ESI_AFE1_INPUT_SELECT_CI: | |
ESIAFE |= ESICA1X; | |
ESIAFE |= ESICISEL; | |
break; | |
default: | |
break; | |
} | |
} | |
//***************************************************************************** | |
// | |
//! Initializes the ESI analog front end - AFE2 | |
//! | |
//! \param params is ESI_AFE2_InitParams struct | |
//! | |
//! This functions initializes the ESI analog front end AFE2 | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_AFE2_init(ESI_AFE2_InitParams *params) | |
{ | |
// Unset the AFE2 bits | |
ESIAFE &= ~(ESICA2X + ESICA2INV + ESICA2EN + ESIDAC2EN); | |
ESIAFE |= | |
params->inputSelectAFE2 + | |
params->inverterSelectOutputAFE2 + | |
params->tsmControlComparatorAFE2 + | |
params->tsmControlDacAFE2 | |
; | |
} | |
//***************************************************************************** | |
// | |
//! Reads the latched comparator outputs form the AFEs | |
//! | |
//! \param channelSelect. Valid values are | |
//! ESI_AFE1_CHANNEL0_SELECT | |
//! ESI_AFE1_CHANNEL1_SELECT | |
//! ESI_AFE1_CHANNEL2_SELECT | |
//! ESI_AFE1_CHANNEL3_SELECT | |
//! ESI_AFE2_CHANNEL0_SELECT | |
//! ESI_AFE2_CHANNEL1_SELECT | |
//! ESI_AFE2_CHANNEL2_SELECT | |
//! ESI_AFE2_CHANNEL3_SELECT | |
//! ESI_AFE1_TEST_CHANNEL0_SELECT | |
//! ESI_AFE1_TEST_CHANNEL1_SELECT | |
//! | |
//! This function gets the ESIPPU register to get latched output values of the | |
//! comparator outputs for AFE1 and AFE2 | |
//! | |
//! \return Valid values are | |
//! ESI_AFE_OUTPUT_LOW | |
//! ESI_AFE_OUTPUT_HIGH | |
// | |
//***************************************************************************** | |
uint16_t ESI_getLatchedComparatorOutput(uint16_t channelSelect) | |
{ | |
uint16_t result; | |
result = ESIPPU; | |
return (result &= channelSelect); | |
} | |
//***************************************************************************** | |
// | |
//! Initializes the TSM | |
//! | |
//! \param params is ESI_TSM_InitParams struct | |
//! | |
//! This function initializes the TSM. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_TSM_init(ESI_TSM_InitParams *params) | |
{ | |
ESITSM = | |
params->smclkDivider + | |
params->aclkDivider + | |
params->startTriggerAclkDivider + | |
params->repeatMode + | |
params->startTriggerSelection + | |
params->tsmFunctionSelection | |
; | |
} | |
//***************************************************************************** | |
// | |
//! Clear TSM entries | |
//! | |
//! This function clears all TSM entries | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_TSM_clearTable(void) | |
{ | |
uint16_t *pTsm, i; | |
// Clear TSM Table (for testing only. not neccessary in real application) | |
pTsm = (uint16_t *)&ESITSM0; | |
for(i = 0; i < 32; i++) | |
{ | |
*pTsm++ = 0x0200; | |
} | |
} | |
//***************************************************************************** | |
// | |
//! Copy TSM entries | |
//! | |
//! This function copies all TSM entries | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_TSM_copyTable(uint16_t* tsmTable, | |
uint16_t size) | |
{ | |
uint16_t *pt_tsmTable; | |
uint16_t i; | |
// Copy the TSM_Table into ESI TSM registers | |
// Destination pointer | |
pt_tsmTable = (uint16_t *)&ESITSM0; | |
// Divided by 2 because of unsigned integer (2bytes) | |
i = size / 2; | |
do | |
{ | |
*pt_tsmTable++ = *tsmTable++; | |
} | |
while(--i); | |
} | |
//***************************************************************************** | |
// | |
//! TSM trigger using software | |
//! | |
//! This function starts a software initiated TSM sequence | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_TSM_softwareTrigger(void) | |
{ | |
ESITSM |= ESISTART; | |
} | |
//***************************************************************************** | |
// | |
//! TSM trigger using software | |
//! | |
//! This function starts a software initiated TSM sequence | |
//! | |
//! \return ESIREATx bits from selected stateRegNum | |
// | |
//***************************************************************************** | |
uint8_t ESI_TSM_getTSMStateDuration(uint8_t stateRegNum) | |
{ | |
volatile uint16_t* stateRegBase = (volatile uint16_t*)&ESITSM0; | |
return((*(stateRegBase + stateRegNum) & 0xf800) >> 11); | |
} | |
//***************************************************************************** | |
// | |
//! TSM trigger using software | |
//! | |
//! This function starts a software initiated TSM sequence | |
//! | |
//! \return ESIREATx bits from selected stateRegNum | |
// | |
//***************************************************************************** | |
void ESI_TSM_setTSMStateDuration(uint8_t stateRegNum, | |
uint8_t duration) | |
{ | |
assert(stateRegNum <= ESI_TSM_STATE_REG_31); | |
assert(duration <= ESI_TSM_STATE_DURATION_MAX); | |
volatile uint16_t* stateRegBase = (volatile uint16_t*)&ESITSM0; | |
*(stateRegBase + stateRegNum) &= ~0xF800; | |
*(stateRegBase + stateRegNum) |= (duration << 11); | |
} | |
//***************************************************************************** | |
// | |
//! Initialize Processing State Machine | |
// | |
//! \param params is ESI_PSM_InitParams struct | |
//! | |
//! This function initializes the PSM registers. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_PSM_init(ESI_PSM_InitParams *params) | |
{ | |
ESIPSM = | |
params->Q6Select + | |
params->Q7TriggerSelect + | |
params->count0Select + | |
params->count0Reset + | |
params->count1Select + | |
params->count1Reset + | |
params->count2Select + | |
params->count2Reset + | |
params->V2Select + | |
params->TEST4Select | |
; | |
} | |
//***************************************************************************** | |
// | |
//! Clear PSM entries | |
//! | |
//! This function clears all PSM entries | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_PSM_clearTable(void) | |
{ | |
uint8_t *pPsm, i; | |
// Clear TSM Table (for testing only. not neccessary in real application) | |
pPsm = (uint8_t *)&ESIRAM0; | |
for(i = 0; i < 128; i++) | |
{ | |
*pPsm++ = 0x0; | |
} | |
} | |
//***************************************************************************** | |
// | |
//! Copy PSM entries | |
//! | |
//! This function copies all PSM entries | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_PSM_copyTable(uint8_t* psmTable, | |
uint8_t size) | |
{ | |
uint8_t *pt_psmTable; | |
uint8_t i; | |
assert(size <= 128); | |
// Copy the TSM_Table into ESI TSM registers | |
pt_psmTable = (uint8_t *)&ESIRAM0; // Destination pointer | |
i = size; | |
do | |
{ | |
*pt_psmTable++ = *psmTable++; | |
} | |
while(--i); | |
} | |
//***************************************************************************** | |
// | |
//! Reset PSM counters | |
//! | |
//! \param counterToReset is the counter that needs t be reset | |
//! | |
//! This function resets the PSM counters | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_PSM_resetCounter(uint16_t counterToReset) | |
{ | |
ESIPSM |= counterToReset; | |
} | |
//***************************************************************************** | |
// | |
//! Enables the internal Oscillator | |
//! | |
//! | |
//! This function enables the high frequency internal oscillator | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_enableInternalOscillator(void) | |
{ | |
ESIOSC |= ESIHFSEL; | |
} | |
//***************************************************************************** | |
// | |
//! Disables the internal Oscillator | |
//! | |
//! | |
//! This function disables the high frequency internal oscillator | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_disableInternalOscillator(void) | |
{ | |
ESIOSC &= ~ESIHFSEL; | |
} | |
//***************************************************************************** | |
// | |
//! Connects comparator output to timerA input | |
//! | |
//! \param counterToReset ESI_TIMERA_INPUT_TSM_COMPOUT or | |
//! ESI_TIMERA_INPUT_TSM_PPUSRC | |
//! | |
//! This function connects the chosen comparator output to TimerA | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_timerAInputSelect(uint16_t select) | |
{ | |
ESICTL |= select; | |
} | |
//***************************************************************************** | |
// | |
//! Connects psm source to comparator output | |
//! | |
//! \param sourceNum PSM_S1_SOURCE, PSM_S2_SOURCE or PSM_S3_SOURCE | |
//! \param sourceSelect can have the following values | |
//! ESI_PSM_SOURCE_IS_ESIOUT0 | |
//! ESI_PSM_SOURCE_IS_ESIOUT1 | |
//! ESI_PSM_SOURCE_IS_ESIOUT2 | |
//! ESI_PSM_SOURCE_IS_ESIOUT3 | |
//! ESI_PSM_SOURCE_IS_ESIOUT4 | |
//! ESI_PSM_SOURCE_IS_ESIOUT5 | |
//! ESI_PSM_SOURCE_IS_ESIOUT6 | |
//! ESI_PSM_SOURCE_IS_ESIOUT7 | |
//! | |
//! This function connects the chosen comparator output to TimerA | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_psmSourceSelect(uint16_t sourceNum, | |
uint16_t sourceSelect) | |
{ | |
switch(sourceNum) | |
{ | |
case PSM_S1_SOURCE: | |
ESICTL &= ~(ESIS1SEL0 | ESIS1SEL1 | ESIS1SEL2); | |
ESICTL |= (sourceSelect << 7); | |
break; | |
case PSM_S2_SOURCE: | |
ESICTL &= ~(ESIS2SEL0 | ESIS2SEL1 | ESIS2SEL2); | |
ESICTL |= (sourceSelect << 10); | |
break; | |
case PSM_S3_SOURCE: | |
ESICTL &= ~(ESIS3SEL0 | ESIS3SEL1 | ESIS3SEL2); | |
ESICTL |= (sourceSelect << 13); | |
break; | |
default: | |
break; | |
} | |
} | |
//***************************************************************************** | |
// | |
//! Connects testChannel0 to comparator input | |
//! | |
//! \param sourceSelect can have the following values | |
//! ESI_TEST_CHANNEL0_SOURCE_IS_CH0_CI0 | |
//! ESI_TEST_CHANNEL0_SOURCE_IS_CH1_CI1 | |
//! ESI_TEST_CHANNEL0_SOURCE_IS_CH2_CI2 | |
//! ESI_TEST_CHANNEL0_SOURCE_IS_CH3_CI3 | |
//! | |
//! This function connects the chosen comparator input to the test channel0 | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_testChannel0SourceSelect(uint16_t sourceSelect) | |
{ | |
ESICTL &= ~(ESI_TEST_CHANNEL0_SOURCE_IS_CH3_CI3); | |
ESICTL |= sourceSelect; | |
} | |
//***************************************************************************** | |
// | |
//! Connects testChannel1to comparator input | |
//! | |
//! \param sourceSelect can have the following values | |
//! ESI_TEST_CHANNEL1_SOURCE_IS_CH0_CI0 | |
//! ESI_TEST_CHANNEL1_SOURCE_IS_CH1_CI1 | |
//! ESI_TEST_CHANNEL1_SOURCE_IS_CH2_CI2 | |
//! ESI_TEST_CHANNEL1_SOURCE_IS_CH3_CI3 | |
//! | |
//! This function connects the chosen comparator input to the test channel1 | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_testChannel1SourceSelect(uint16_t sourceSelect) | |
{ | |
ESICTL &= ~(ESI_TEST_CHANNEL1_SOURCE_IS_CH3_CI3); | |
ESICTL |= sourceSelect; | |
} | |
//***************************************************************************** | |
// | |
//! Enable ESI peripheral | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_enable(void) | |
{ | |
ESICTL |= ESIEN; | |
} | |
//***************************************************************************** | |
// | |
//! Disable ESI peripheral | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_disable(void) | |
{ | |
ESICTL &= ~ESIEN; | |
} | |
//***************************************************************************** | |
// | |
//! Start calibration on ESI internal Oscillator | |
//! | |
//! This function starts calibration of internal osciallator. After calling this | |
//! function the user and use ESI_adjustInternalOscFreq() to adjust the freq. of | |
//! the oscillator. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_startInternalOscCal(void) | |
{ | |
assert(ESIOSC | ESIHFSEL); | |
ESIOSC |= ESICLKGON; | |
} | |
//***************************************************************************** | |
// | |
//! Adjusts frequency ESI internal Oscillator | |
//! | |
//! This function adjusts frequency ESI internal Oscillator. It increases or | |
//! decrease the freq by 3% based on incOrDec value. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_adjustInternalOscFreq(uint16_t incOrDec) | |
{ | |
uint16_t adjustValue; | |
assert(ESIOSC | ESIHFSEL); | |
adjustValue = ESIOSC >> 8; | |
if(incOrDec == ESI_INTERNAL_OSC_FREQ_INCREASE) | |
{ | |
adjustValue = adjustValue + 1; | |
adjustValue = adjustValue << 8; | |
} | |
else | |
{ | |
adjustValue = adjustValue - 1; | |
adjustValue = adjustValue << 8; | |
} | |
ESIOSC |= adjustValue; | |
} | |
//***************************************************************************** | |
// | |
//! Sets frequency of ESI internal Oscillator | |
//! | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_setNominalInternalOscFreq(void) | |
{ | |
ESIOSC = ESICLKFQ5 + ESICLKGON + ESIHFSEL; | |
} | |
//***************************************************************************** | |
// | |
//! The following function return the number of ESIOSC cycle during an ACLK | |
//! cycle. | |
//! | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
static uint16_t measureESIOSC(void){ | |
// This and next instruction realizes a clear->set ESICLKGON bit. | |
ESIOSC &= ~(ESICLKGON); | |
// This starts measurement. | |
ESIOSC |= ESICLKGON + ESIHFSEL; | |
// Reading ESICNT3 while counting always result in reading a 0x01. | |
while(ESICNT3 == 1) | |
{ | |
; | |
} | |
// Stop ESIOSC oscillator | |
ESIOSC &= ~(ESICLKGON); | |
return (ESICNT3); | |
} | |
//****************************************************************************** | |
//! The following function returns the ESICLKFQx bits on ESIOSC register | |
// | |
//! \param none | |
// | |
//! \return ESICLKFQ bits only | |
//****************************************************************************** | |
uint8_t ESI_getESICLKFQ(void){ | |
uint16_t temp; | |
// Store ESIOSC content | |
temp = ESIOSC; | |
// Get ESICLKFQx bits | |
temp = (temp >> 8) & 0x3F; | |
return(temp); | |
} | |
//****************************************************************************** | |
//! The following function sets ESICLKFQx bits on ESIOSC register | |
// | |
//! \param setting is to the loaded to ESIOSC. Valid parameters a value between | |
//! 0x00 and 0x3F. 0x00 corresponds to minimum frequency, 0x20 | |
//! corresponds to nominal frequency and 0x3F corresponds to maximum | |
//! frequency. | |
// | |
//! \return none | |
//****************************************************************************** | |
void ESI_setESICLKFQ(uint8_t setting) | |
{ | |
uint16_t temp; | |
assert(setting < 0x40); | |
temp = ESIOSC; // get actual ESIOSC register content | |
temp &= ~(0x3F00); | |
temp = ((uint16_t) setting << 8) + temp; // and update ESICLKFQ bits | |
ESIOSC = temp; | |
} | |
//***************************************************************************** | |
// | |
//! Calibrate ESI internal Oscillator | |
//! | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_calibrateInternalOscFreq(uint16_t targetAclkCounts) | |
{ | |
ESI_setNominalInternalOscFreq(); | |
ESI_measureESIOSC(ESI_ESIOSC_OVERSAMPLE_4); | |
if(ESICNT3 > targetAclkCounts) | |
{ | |
//freq is too high | |
do | |
{ | |
ESI_adjustInternalOscFreq(ESI_INTERNAL_OSC_FREQ_DECREASE); | |
} | |
while(ESI_measureESIOSC(ESI_ESIOSC_OVERSAMPLE_4) > targetAclkCounts); | |
} | |
else | |
{ | |
//freq is too low | |
do | |
{ | |
ESI_adjustInternalOscFreq(ESI_INTERNAL_OSC_FREQ_INCREASE); | |
} | |
while(ESI_measureESIOSC(ESI_ESIOSC_OVERSAMPLE_4) > targetAclkCounts); | |
ESI_adjustInternalOscFreq(ESI_INTERNAL_OSC_FREQ_DECREASE); | |
} | |
} | |
//***************************************************************************** | |
// | |
//! The following function returns an average of ESIOSC measurement. | |
//! | |
//! \param | |
//! | |
//! \return averaged ESIOSC measurement. | |
// | |
//***************************************************************************** | |
uint16_t ESI_measureESIOSC(uint8_t oversample){ | |
uint8_t i; | |
uint16_t temp = 0; | |
assert(oversample < 9); | |
for(i = oversample; i > 0; i--) | |
{ | |
temp += measureESIOSC(); | |
} | |
temp /= oversample; | |
return(temp); | |
} | |
//***************************************************************************** | |
// | |
//! Set upper threshold for PSM counter 1 | |
//! | |
//! \param threshold is the upper threashold that causes ESIIFG3 to get set. | |
//! | |
//! This function sets the threshold value for PSM counter 1. ESIIFG3 gets set | |
//! when counter value and this threahold are equal. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_setPSMCounter1UpperThreshold(uint16_t threshold) | |
{ | |
ESITHR1 = threshold; | |
} | |
//***************************************************************************** | |
// | |
//! Set lower threshold for PSM counter 1 | |
//! | |
//! \param threshold is the lower threashold that causes ESIIFG3 to get set. | |
//! | |
//! This function set the threshold value for PSM counter 1. ESIIFG3 gets set | |
//! when counter value and this threahold are equal. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_setPSMCounter1LowerThreshold(uint16_t threshold) | |
{ | |
ESITHR2 = threshold; | |
} | |
//***************************************************************************** | |
// | |
//! sets AFE1 DAC threshold Value | |
//! | |
//! \param dacValue is value to be written to DAC register. | |
//! \param dacRegNum is DAC register number | |
//! | |
//! Write DAC threshold value into selected DAC register | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_setAFE1DACValue(uint16_t dacValue, | |
uint8_t dacRegNum) | |
{ | |
volatile uint16_t* dacRegBase = (volatile uint16_t*) &ESIDAC1R0; | |
*(dacRegBase + dacRegNum) = dacValue; | |
} | |
//***************************************************************************** | |
// | |
//! gets AFE1 DAC threshold Value | |
//! | |
//! \param dacValue is value to be written to DAC register. | |
//! \param dacRegNum is DAC register number | |
//! | |
//! Read DAC threshold value into selected DAC register | |
//! | |
//! \return DAC value from selected DAC register. | |
// | |
//***************************************************************************** | |
uint16_t ESI_getAFE1DACValue(uint8_t dacRegNum) | |
{ | |
volatile uint16_t* dacRegBase = (volatile uint16_t*) &ESIDAC1R0; | |
return(*(dacRegBase + dacRegNum)); | |
} | |
//***************************************************************************** | |
// | |
//! sets AFE2 DAC threshold Value | |
//! | |
//! \param dacValue is value to be written to DAC register. | |
//! \param dacRegNum is DAC register number | |
//! | |
//! Write DAC threshold value into selected DAC register | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_setAFE2DACValue(uint16_t dacValue, | |
uint8_t dacRegNum) | |
{ | |
volatile uint16_t* dacRegBase = (volatile uint16_t*) &ESIDAC2R0; | |
*(dacRegBase + dacRegNum) = dacValue; | |
} | |
//***************************************************************************** | |
// | |
//! gets AFE2 DAC threshold Value | |
//! | |
//! \param dacValue is value to be written to DAC register. | |
//! \param dacRegNum is DAC register number | |
//! | |
//! Read DAC threshold value into selected DAC register | |
//! | |
//! \return DAC value from selected DAC register. | |
// | |
//***************************************************************************** | |
uint16_t ESI_getAFE2DACValue(uint8_t dacRegNum) | |
{ | |
volatile uint16_t* dacRegBase = (volatile uint16_t*) &ESIDAC2R0; | |
return(*(dacRegBase + dacRegNum)); | |
} | |
//***************************************************************************** | |
// | |
//! sets TSM state register | |
//! | |
//! \param params constructs the state value | |
//! \param stateRegNum is state register offset | |
//! | |
//! Sets selected TSM state register. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_setTSMstateReg(ESI_TSM_StateParams *params, | |
uint8_t stateRegNum) | |
{ | |
volatile uint16_t* stateRegBase = (volatile uint16_t*) &ESITSM0; | |
*(stateRegBase + stateRegNum) = | |
(params->inputChannelSelect + | |
params->LCDampingSelect + | |
params->excitationSelect + | |
params->comparatorSelect + | |
params->highFreqClkOn_or_compAutoZeroCycle + | |
params->outputLatchSelect + | |
params->testCycleSelect + | |
params->dacSelect + | |
params->tsmStop + | |
params->tsmClkSrc) | | |
(params->duration << 11); | |
} | |
//***************************************************************************** | |
// | |
//! Get ESI interrupt Vector Register | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
uint16_t ESI_getInterruptVectorRegister(void) | |
{ | |
return (ESIIV); | |
} | |
//***************************************************************************** | |
// | |
//! Enables ESI interrupts | |
//! | |
//! \param interruptMask is the bit mask of the interrupt sources to | |
//! be enabled. Mask value is the logical OR of any of the following: | |
//! \b ESI_INTERRUPT_AFE1_ESIOUTX | |
//! \b ESI_INTERRUPT_ESISTOP | |
//! \b ESI_INTERRUPT_ESISTART | |
//! \b ESI_INTERRUPT_ESICNT1 | |
//! \b ESI_INTERRUPT_ESICNT2 | |
//! \b ESI_INTERRUPT_Q6_BIT_SET | |
//! \b ESI_INTERRUPT_Q7_BIT_SET | |
//! \b ESI_INTERRUPT_ESICNT0_COUNT_INTERVAL | |
//! \b ESI_INTERRUPT_AFE2_ESIOUTX | |
//! | |
//! Modified bits of \b ESIINT1 register. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_enableInterrupt(uint16_t interruptMask) | |
{ | |
ESIINT1 |= (interruptMask); | |
} | |
//***************************************************************************** | |
// | |
//! Disables ESI interrupts | |
//! | |
//! \param interruptMask is the bit mask of the interrupt sources to | |
//! be disabled. Mask value is the logical OR of any of the following: | |
//! \b ESI_INTERRUPT_AFE1_ESIOUTX | |
//! \b ESI_INTERRUPT_ESISTOP | |
//! \b ESI_INTERRUPT_ESISTART | |
//! \b ESI_INTERRUPT_ESICNT1 | |
//! \b ESI_INTERRUPT_ESICNT2 | |
//! \b ESI_INTERRUPT_Q6_BIT_SET | |
//! \b ESI_INTERRUPT_Q7_BIT_SET | |
//! \b ESI_INTERRUPT_ESICNT0_COUNT_INTERVAL | |
//! \b ESI_INTERRUPT_AFE2_ESIOUTX | |
//! | |
//! Modified bits of \b ESIINT1 register. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_disableInterrupt(uint16_t interruptMask) | |
{ | |
ESIINT1 &= ~(interruptMask); | |
} | |
//***************************************************************************** | |
// | |
//! Get ESI interrupt status | |
//! | |
//! \param interruptMask is the masked interrupt flag status to be returned. | |
//! Mask value is the logical OR of any of the following: | |
//! - \b ESI_INTERRUPT_FLAG_AFE1_ESIOUTX | |
//! - \b ESI_INTERRUPT_FLAG_ESISTOP | |
//! - \b ESI_INTERRUPT_FLAG_ESISTART | |
//! - \b ESI_INTERRUPT_FLAG_ESICNT1 | |
//! - \b ESI_INTERRUPT_FLAG_ESICNT2 | |
//! - \b ESI_INTERRUPT_FLAG_Q6_BIT_SET | |
//! - \b ESI_INTERRUPT_FLAG_Q7_BIT_SET | |
//! - \b ESI_INTERRUPT_FLAG_ESICNT0_COUNT_INTERVAL | |
//! - \b ESI_INTERRUPT_FLAG_AFE2_ESIOUTX | |
//! | |
//! \return Logical OR of any of the following: | |
//! - \b ESI_INTERRUPT_FLAG_AFE1_ESIOUTX | |
//! - \b ESI_INTERRUPT_FLAG_ESISTOP | |
//! - \b ESI_INTERRUPT_FLAG_ESISTART | |
//! - \b ESI_INTERRUPT_FLAG_ESICNT1 | |
//! - \b ESI_INTERRUPT_FLAG_ESICNT2 | |
//! - \b ESI_INTERRUPT_FLAG_Q6_BIT_SET | |
//! - \b ESI_INTERRUPT_FLAG_Q7_BIT_SET | |
//! - \b ESI_INTERRUPT_FLAG_ESICNT0_COUNT_INTERVAL | |
//! - \b ESI_INTERRUPT_FLAG_AFE2_ESIOUTX | |
//! \n indicating the status of the masked flags | |
// | |
//***************************************************************************** | |
uint16_t ESI_getInterruptStatus(uint16_t interruptMask) | |
{ | |
return (ESIINT2 & interruptMask); | |
} | |
//***************************************************************************** | |
// | |
//! Clear ESI interrupt flag | |
//! | |
//! \param interruptMask is the masked interrupt flag status to be returned. | |
//! Mask value is the logical OR of any of the following: | |
//! - \b ESI_INTERRUPT_FLAG_AFE1_ESIOUTX | |
//! - \b ESI_INTERRUPT_FLAG_ESISTOP | |
//! - \b ESI_INTERRUPT_FLAG_ESISTART | |
//! - \b ESI_INTERRUPT_FLAG_ESICNT1 | |
//! - \b ESI_INTERRUPT_FLAG_ESICNT2 | |
//! - \b ESI_INTERRUPT_FLAG_Q6_BIT_SET | |
//! - \b ESI_INTERRUPT_FLAG_Q7_BIT_SET | |
//! - \b ESI_INTERRUPT_FLAG_ESICNT0_COUNT_INTERVAL | |
//! - \b ESI_INTERRUPT_FLAG_AFE2_ESIOUTX | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_clearInterrupt(uint16_t interruptMask) | |
{ | |
ESIINT2 &= ~(interruptMask); | |
} | |
//***************************************************************************** | |
// | |
//! Set source of IFG0 interrupt flag | |
//! | |
//! \param ifg0Src values are as follows | |
//! ESI_IFG0_SET_WHEN_ESIOUT0_SET | |
//! ESI_IFG0_SET_WHEN_ESIOUT0_RESET | |
//! ESI_IFG0_SET_WHEN_ESIOUT1_SET | |
//! ESI_IFG0_SET_WHEN_ESIOUT1_RESET | |
//! ESI_IFG0_SET_WHEN_ESIOUT2_SET | |
//! ESI_IFG0_SET_WHEN_ESIOUT2_RESET | |
//! ESI_IFG0_SET_WHEN_ESIOUT3_SET | |
//! ESI_IFG0_SET_WHEN_ESIOUT3_RESET | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_setIFG0Source(uint16_t ifg0Src) | |
{ | |
ESIINT1 &= ~ESI_IFG0_SET_WHEN_ESIOUT3_RESET; | |
ESIINT1 |= ifg0Src; | |
} | |
//***************************************************************************** | |
// | |
//! Set source of IFG8 interrupt flag | |
//! | |
//! \param ifg8Src values are as follows | |
//! ESI_IFG8_SET_WHEN_ESIOUT4_SET | |
//! ESI_IFG8_SET_WHEN_ESIOUT4_RESET | |
//! ESI_IFG8_SET_WHEN_ESIOUT5_SET | |
//! ESI_IFG8_SET_WHEN_ESIOUT5_RESET | |
//! ESI_IFG8_SET_WHEN_ESIOUT6_SET | |
//! ESI_IFG8_SET_WHEN_ESIOUT6_RESET | |
//! ESI_IFG8_SET_WHEN_ESIOUT7_SET | |
//! ESI_IFG8_SET_WHEN_ESIOUT7_RESET | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_setIFG8Source(uint16_t ifg8Src) | |
{ | |
ESIINT1 &= ~ESI_IFG8_SET_WHEN_ESIOUT7_RESET; | |
ESIINT1 |= ifg8Src; | |
} | |
//***************************************************************************** | |
// | |
//! Set source of IFG7 interrupt flag | |
//! | |
//! \param ifg7Src values are as follows | |
//! ESI_IFG7_SOURCE_EVERY_COUNT_OF_CNT0 | |
//! ESI_IFG7_SOURCE_CNT0_MOD4 | |
//! ESI_IFG7_SOURCE_CNT0_MOD256 | |
//! ESI_IFG7_SOURCE_CNT0_ROLLOVER | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_setIFG7Source(uint16_t ifg7Src) | |
{ | |
ESIINT2 &= ~ESI_IFG7_SOURCE_CNT0_ROLLOVER; | |
ESIINT2 |= ifg7Src; | |
} | |
//***************************************************************************** | |
// | |
//! Set source of IFG4 interrupt flag | |
//! | |
//! \param ifg4Src values are as follows | |
//! ESI_IFG4_SOURCE_EVERY_COUNT_OF_CNT2 | |
//! ESI_IFG4_SOURCE_CNT2_MOD4 | |
//! ESI_IFG4_SOURCE_CNT2_MOD256 | |
//! ESI_IFG4_SOURCE_CNT2_ROLLOVER | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_setIFG4Source(uint16_t ifg4Src) | |
{ | |
ESIINT2 &= ~ESI_IFG4_SOURCE_CNT2_ROLLOVER; | |
ESIINT2 |= ifg4Src; | |
} | |
//***************************************************************************** | |
// | |
//! Simple DAC calibration code using pre-defined TSM | |
//! Supports AFE1 only. | |
//! \param selected_channel acceptable values | |
//! ESI_AFE1_CHANNEL0_SELECT | |
//! ESI_AFE1_CHANNEL1_SELECT | |
//! ESI_AFE1_CHANNEL2_SELECT | |
//! ESI_AFE1_CHANNEL3_SELECT | |
//! | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
void ESI_LC_DAC_calibration(uint8_t selected_channel) | |
{ | |
#define NUM_SENSOR_CAL 4 | |
#define MIN_HYSTERESIS 30 | |
#define STEP_TO_FINISH 4 | |
unsigned int i; | |
unsigned char test_bit, done; | |
unsigned int hysteresis[NUM_SENSOR_CAL], | |
hysteresis_hi[NUM_SENSOR_CAL], | |
hysteresis_lo[NUM_SENSOR_CAL], | |
current[NUM_SENSOR_CAL], | |
average[NUM_SENSOR_CAL], | |
max[NUM_SENSOR_CAL], | |
min[NUM_SENSOR_CAL]; | |
// State: 0 = output low | |
// 1 = output high | |
// 2 = undetermined (between 2 hysteresis level) | |
unsigned char previous_state[NUM_SENSOR_CAL], | |
current_state[NUM_SENSOR_CAL], | |
step[NUM_SENSOR_CAL]; | |
// Reset values | |
for(i = 0; i < NUM_SENSOR_CAL; i++) | |
{ | |
max[i] = 0; | |
min[i] = 0xffff; | |
previous_state[i] = 2; | |
step[i] = 0; | |
} | |
do | |
{ | |
// Find the current oscillating level, using software mode | |
FindDAC(selected_channel, 1); | |
test_bit = 1; | |
done = 1; | |
for(i = 0; i < NUM_SENSOR_CAL; i++) | |
{ | |
// skip if the channel is not selected | |
if(test_bit & selected_channel) | |
{ | |
current[i] = ESI_getAFE1DACValue(i * 2); | |
// Record max and min value | |
if(current[i] > max[i]) | |
{ | |
max[i] = current[i]; | |
} | |
if(current[i] < min[i]) | |
{ | |
min[i] = current[i]; | |
} | |
// Update average and hysteresis level | |
average[i] = (max[i] + min[i]) >> 1; | |
hysteresis[i] = (max[i] - min[i]) >> 3; | |
if(hysteresis[i] < MIN_HYSTERESIS) | |
{ | |
hysteresis[i] = MIN_HYSTERESIS; | |
} | |
hysteresis[i] >>= 1; | |
hysteresis_hi[i] = average[i] + hysteresis[i]; | |
hysteresis_lo[i] = average[i] - hysteresis[i]; | |
// Determine output state based on hysteresis_hi and hysteresis_lo | |
if(current[i] < hysteresis_lo[i]) | |
{ | |
current_state[i] = 0; | |
} | |
else if(current[i] > hysteresis_hi[i]) | |
{ | |
current_state[i] = 1; | |
} | |
else | |
{ | |
current_state[i] = 2; | |
} | |
// If there is state change, proceed to next step | |
switch(current_state[i]) | |
{ | |
case 0: | |
case 1: | |
if(previous_state[i] != current_state[i]) | |
{ | |
step[i]++; | |
previous_state[i] = current_state[i]; | |
} | |
break; | |
default: | |
break; | |
} | |
// Any selected sensor which has not finished calibration will set done to zero | |
if(step[i] < STEP_TO_FINISH) | |
{ | |
done = 0; | |
} | |
} | |
test_bit <<= 1; | |
} | |
} | |
while(!done); | |
// Record DAC Values | |
test_bit = 1; | |
done = ESI_DAC1_REG0; // Temp value for recording DAC | |
for(i = 0; i < NUM_SENSOR_CAL; i++) | |
{ | |
if(test_bit & selected_channel) | |
{ | |
ESI_setAFE1DACValue(hysteresis_hi[i], done++); | |
ESI_setAFE1DACValue(hysteresis_lo[i], done++); | |
} | |
test_bit <<= 1; | |
} | |
} | |
//***************************************************************************** | |
// | |
//! Find the current oscillating level, using software mode | |
//! | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
static void FindDAC(unsigned char selected_channel, | |
unsigned char software_trigger) | |
{ | |
// DAC Level tester, using successive approximation approach | |
unsigned int DAC_BIT = 0x0800, Prev_DAC_BIT = 0x0C00; | |
unsigned int i; | |
unsigned int test_bit, DAC_index; | |
// Set initial DAC value for each selected channel | |
// AFE 1 | |
if(selected_channel & 0x0f) | |
{ | |
test_bit = 0x01; | |
DAC_index = ESI_DAC1_REG0; | |
for(i = 0; i < 4; i++) | |
{ | |
if(selected_channel & test_bit) | |
{ | |
ESI_setAFE1DACValue(DAC_BIT, DAC_index++); | |
ESI_setAFE1DACValue(DAC_BIT, DAC_index++); | |
} | |
else | |
{ | |
DAC_index += 2; | |
} | |
test_bit <<= 1; | |
} | |
} | |
// AFE 2 | |
if(selected_channel & 0xf0) | |
{ | |
test_bit = 0x10; | |
DAC_index = ESI_DAC2_REG0; | |
for(i = 0; i < 4; i++) | |
{ | |
if(selected_channel & test_bit) | |
{ | |
ESI_setAFE2DACValue(DAC_BIT, DAC_index++); | |
ESI_setAFE2DACValue(DAC_BIT, DAC_index++); | |
} | |
else | |
{ | |
DAC_index += 2; | |
} | |
test_bit <<= 1; | |
} | |
} | |
ESI_enableInterrupt(ESI_INTERRUPT_ESISTOP); // enable ESISTOP INT | |
// Find the DAC value for each selected channel | |
do | |
{ | |
ESI_clearInterrupt (ESI_INTERRUPT_FLAG_ESISTOP); | |
if(software_trigger) | |
{ | |
ESI_TSM_softwareTrigger(); | |
} | |
__bis_SR_register(LPM3_bits + GIE); // wait for the ESISTOP flag | |
DAC_BIT >>= 1; // right shift one bit | |
// AFE 1 | |
if(selected_channel & 0x0f) | |
{ | |
test_bit = 0x01; | |
DAC_index = ESI_DAC1_REG0; | |
for(i = 0; i < 4; i++) | |
{ | |
if(selected_channel & test_bit) | |
{ | |
#ifndef INVERTED | |
if(ESI_getLatchedComparatorOutput(test_bit) == | |
ESI_AFE_OUTPUT_HIGH) | |
#else | |
if(ESI_getLatchedComparatorOutput(test_bit) == | |
ESI_AFE_OUTPUT_LOW) | |
#endif | |
{ | |
ESI_setAFE1DACValue(ESI_getAFE1DACValue( | |
DAC_index) | DAC_BIT, | |
DAC_index); | |
DAC_index++; | |
ESI_setAFE1DACValue(ESI_getAFE1DACValue( | |
DAC_index) | DAC_BIT, | |
DAC_index); | |
DAC_index++; | |
} | |
else | |
{ | |
ESI_setAFE1DACValue(ESI_getAFE1DACValue( | |
DAC_index) ^ Prev_DAC_BIT, | |
DAC_index); | |
DAC_index++; | |
ESI_setAFE1DACValue(ESI_getAFE1DACValue( | |
DAC_index) ^ Prev_DAC_BIT, | |
DAC_index); | |
DAC_index++; | |
} | |
} | |
else | |
{ | |
DAC_index += 2; | |
} | |
test_bit <<= 1; | |
} | |
} | |
// AFE 2 | |
if(selected_channel & 0xf0) | |
{ | |
test_bit = 0x10; | |
DAC_index = ESI_DAC2_REG0; | |
for(i = 0; i < 4; i++) | |
{ | |
if(selected_channel & test_bit) | |
{ | |
#ifndef INVERTED | |
if(ESI_getLatchedComparatorOutput(test_bit) == | |
ESI_AFE_OUTPUT_HIGH) | |
#else | |
if(ESI_getLatchedComparatorOutput(test_bit) == | |
ESI_AFE_OUTPUT_LOW) | |
#endif | |
{ | |
ESI_setAFE1DACValue(ESI_getAFE2DACValue( | |
DAC_index) | DAC_BIT, | |
DAC_index); | |
DAC_index++; | |
ESI_setAFE1DACValue(ESI_getAFE2DACValue( | |
DAC_index) | DAC_BIT, | |
DAC_index); | |
DAC_index++; | |
} | |
else | |
{ | |
ESI_setAFE1DACValue(ESI_getAFE2DACValue( | |
DAC_index) ^ Prev_DAC_BIT, | |
DAC_index); | |
DAC_index++; | |
ESI_setAFE1DACValue(ESI_getAFE2DACValue( | |
DAC_index) ^ Prev_DAC_BIT, | |
DAC_index); | |
DAC_index++; | |
} | |
} | |
else | |
{ | |
DAC_index += 2; | |
} | |
test_bit <<= 1; | |
} | |
} | |
Prev_DAC_BIT >>= 1; // right shift one bit | |
} | |
while(DAC_BIT); | |
ESI_disableInterrupt(ESI_INTERRUPT_ESISTOP); | |
__no_operation(); | |
} | |
//***************************************************************************** | |
// | |
//! Close the doxygen group for esi_api | |
//! @} | |
// | |
//***************************************************************************** | |
#endif |