/**************************************************************************//** * @brief Setup the ACMP *****************************************************************************/ void setupACMP(void) { /* ACMP configuration constant table. */ static const ACMP_Init_TypeDef initACMP = { .fullBias = false, /* fullBias */ .halfBias = true, /* halfBias */ .biasProg = 0x0, /* biasProg */ .interruptOnFallingEdge = false, /* interrupt on rising edge */ .interruptOnRisingEdge = false, /* interrupt on falling edge */ //.interruptOnFallingEdge = true, /* interrupt on rising edge */ //.interruptOnRisingEdge = true, /* interrupt on falling edge */ .warmTime = acmpWarmTime4, /* 512 cycle warmup to be safe */ .hysteresisLevel = acmpHysteresisLevel0, /* No Hysteresis */ .inactiveValue = false, /* inactive value */ .lowPowerReferenceEnabled = true, /* low power reference */ .vddLevel = 32, /* VDD level : VDD/2 */ .enable = false /* Don't request enabling. */ }; /* Configure ACMP. */ ACMP_Init(ACMP1, &initACMP); /* Disable ACMP0 out to a pin. */ ACMP_GPIOSetup(ACMP1, 0, false, false); /* Set up ACMP negSel to VDD, posSel is controlled by LESENSE. */ ACMP_ChannelSet(ACMP1, acmpChannelVDD, acmpChannel0); /* LESENSE controls ACMP thus ACMP_Enable(ACMP0) should NOT be called in order * to ensure lower current consumption. */ #ifdef DEBUG_ACMP ACMP_ChannelSet(ACMP1, acmpChannelVDD, acmpChannel2); ACMP1->IEN = 1; ACMP_Enable(ACMP1); NVIC_ClearPendingIRQ(ACMP0_IRQn); NVIC_EnableIRQ(ACMP0_IRQn); #endif } #ifdef DEBUG_ACMP // ACMP IRQ Handler is shared between ACMP0 and ACMP1 void ACMP0_IRQHandler(void) { PRINTF("%s\r\n",__func__); ACMP1->IFC = 1; NVIC_ClearPendingIRQ(ACMP0_IRQn); }
/**************************************************************************//** * @brief ACMP_setup * Configures and starts the ACMP *****************************************************************************/ void ACMP_setup(void) { /* Enable necessary clocks */ CMU_ClockEnable(cmuClock_ACMP0, true); CMU_ClockEnable(cmuClock_GPIO, true); /* Configure PC4 as input with pull down for ACMP channel 4 input */ GPIO_PinModeSet(gpioPortC, 4, gpioModeInputPullFilter, 0); /* Analog comparator parameters */ const ACMP_Init_TypeDef acmpInit = { .fullBias = false, /* no full bias current*/ .halfBias = false, /* no half bias current */ .biasProg = 7, /* Biasprog current 1.4 uA */ .interruptOnFallingEdge = false, /* disable interrupt for falling edge */ .interruptOnRisingEdge = false, /* disable interrupt for rising edge */ .warmTime = acmpWarmTime256, /* Warm-up time in clock cycles, should be >140 cycles for >10us warm-up @ 14MHz */ .hysteresisLevel = acmpHysteresisLevel0, /* Hysteresis level 0 - no hysteresis */ .inactiveValue = 0, /* Inactive comparator output value */ .lowPowerReferenceEnabled = false, /* Low power reference mode disabled */ .vddLevel = 32, /* Vdd reference scaling of 32 */ }; /* Init ACMP and set ACMP channel 4 as positive input and scaled Vdd as negative input */ ACMP_Init(ACMP0, &acmpInit); ACMP_ChannelSet(ACMP0, acmpChannelVDD, acmpChannel4); ACMP_Enable(ACMP0); } /**************************************************************************//** * @brief PRS_ScanChannel * Waits for activity on a selected PRS channel and writes on the LCD when activity occurs * * @param[in] timer * Pointer to TIMER peripheral register block. * * @param[in] prsCh * PRS Channel to be monitored * * @param[in] edgeType * Signal edge to be monitored/captured *****************************************************************************/ void PRS_ScanChannel(TIMER_TypeDef *timer, TIMER_PRSSEL_TypeDef prsCh, TIMER_Edge_TypeDef edgeType) { /* enable the clock for the correct timer */ #define TIMER_Clock(T) (T==TIMER0 ? cmuClock_TIMER0 : \ T==TIMER1 ? cmuClock_TIMER1 : 0) /* Enable necessary clocks */ CMU_ClockEnable((CMU_Clock_TypeDef)TIMER_Clock(timer), true); /* Initialize LCD */ SegmentLCD_Init(false); /* Select CC channel parameters */ const TIMER_InitCC_TypeDef timerCCInit = { .eventCtrl = timerEventFalling, /* input capture event control */ .edge = edgeType, /* input capture on falling edge */ .prsSel = prsCh, /* prs channel select channel 5*/ .cufoa = timerOutputActionNone, /* no action on counter underflow */ .cofoa = timerOutputActionNone, /* no action on counter overflow */ .cmoa = timerOutputActionNone, /* no action on counter match */ .mode = timerCCModeCapture, /* CC channel mode capture */ .filter = false, /* no filter */ .prsInput = true, /* CC channel PRS input */ .coist = false, /* comparator output initial state */ .outInvert = false, /* no output invert */ }; /* Initialize TIMER0 CC0 */ TIMER_InitCC(timer, 0, &timerCCInit); /* Select timer parameters */ const TIMER_Init_TypeDef timerInit = { .enable = true, /* start counting when init complete */ .debugRun = false, /* counter not running on debug halt */ .prescale = timerPrescale1024, /* prescaler of 64 */ .clkSel = timerClkSelHFPerClk, /* TIMER0 clocked by the HFPERCLK */ .fallAction = timerInputActionNone, /* stop counter on falling edge */ .riseAction = timerInputActionNone, /* reload and start on rising edge */ .mode = timerModeUp, /* counting up */ .dmaClrAct = false, /* no DMA */ .quadModeX4 = false, /* no quad decoding */ .oneShot = false, /* counting up constinuously */ .sync = false, /* no start/stop/reload by other timers */ }; /* Initialize TIMER0 */ TIMER_Init(timer, &timerInit); /* Poll the Input Capture Valid flag in the Status register The program will hang at this point waiting for activity on this channel */ while(!((TIMER0->STATUS & _TIMER_STATUS_ICV0_MASK )>>16)); } /**************************************************************************//** * @brief Main function * Main is called from __iar_program_start, see assembly startup file *****************************************************************************/ int main(void) { /* Align different chip revisions*/ CHIP_Init(); /* Initialise the ACMP */ ACMP_setup(); /* PRS setup */ /* Enable clock for PRS and select ACMP as source and ACMP0OUT (ACMP0 OUTPUT) as signal for channel 5 */ CMU_ClockEnable(cmuClock_PRS, true); PRS_SourceSignalSet(5, PRS_CH_CTRL_SOURCESEL_ACMP0, PRS_CH_CTRL_SIGSEL_ACMP0OUT, prsEdgeOff); /* Start PRS scan This function will halt the program while there is no PRS activity This function assumes that the PRS has been setup previously */ PRS_ScanChannel(TIMER0, timerPRSSELCh5, timerEdgeFalling); /* Write PRS and channel number on the LCD to acknowledge PRS activity */ SegmentLCD_Write("PRS"); SegmentLCD_Number((int)timerPRSSELCh5); while(1) { /* Enter EM1 while waiting for capture. */ EMU_EnterEM1(); } }
/**************************************************************************//** * @brief TIMER0_setup * Configures the TIMER *****************************************************************************/ void TIMER_setup(void) { /* Enable necessary clocks */ CMU_ClockEnable(cmuClock_TIMER0, true); CMU_ClockEnable(cmuClock_PRS, true); /* Select CC channel parameters */ TIMER_InitCC_TypeDef timerCCInit = { .eventCtrl = timerEventEveryEdge, /* Input capture event control */ .edge = timerEdgeBoth, /* Input capture on falling edge */ .prsSel = timerPRSSELCh5, /* Prs channel select channel 5*/ .cufoa = timerOutputActionNone, /* No action on counter underflow */ .cofoa = timerOutputActionNone, /* No action on counter overflow */ .cmoa = timerOutputActionNone, /* No action on counter match */ .mode = timerCCModeCapture, /* CC channel mode capture */ .filter = false, /* No filter */ .prsInput = true, /* CC channel PRS input */ .coist = false, /* Comparator output initial state */ .outInvert = false, /* No output invert */ }; /* Initialize TIMER0 CC0 channel */ TIMER_InitCC(HIJACK_RX_TIMER, 0, &timerCCInit); /* Select timer parameters */ const TIMER_Init_TypeDef timerInit = { .enable = false, /* Do not start counting when init complete */ .debugRun = false, /* Counter not running on debug halt */ .prescale = HIJACK_TIMER_RESOLUTION, /* Prescaler of 1 */ .clkSel = timerClkSelHFPerClk, /* TIMER0 clocked by the HFPERCLK */ .fallAction = timerInputActionReloadStart, /* Stop counter on falling edge */ .riseAction = timerInputActionReloadStart, /* Reload and start on rising edge */ .mode = timerModeUp, /* Counting up */ .dmaClrAct = false, /* No DMA */ .quadModeX4 = false, /* No quad decoding */ .oneShot = false, /* Counting up constinuously */ .sync = false, /* No start/stop/reload by other timers */ }; /* Initialize TIMER0 */ TIMER_Init(HIJACK_RX_TIMER, &timerInit); /* PRS setup */ /* Select ACMP as source and ACMP0OUT (ACMP0 OUTPUT) as signal */ PRS_SourceSignalSet(5, PRS_CH_CTRL_SOURCESEL_ACMP0, PRS_CH_CTRL_SIGSEL_ACMP0OUT, prsEdgeOff); /* Enable CC0 interrupt */ TIMER_IntEnable(HIJACK_RX_TIMER, TIMER_IF_CC0); /* Enable TIMER0 interrupt vector in NVIC */ NVIC_EnableIRQ(TIMER0_IRQn); } /**************************************************************************//** * @brief ACMP_setup * Configures and starts the ACMP *****************************************************************************/ static void ACMP_setup(void) { /* Enable necessary clocks */ CMU_ClockEnable(HIJACK_RX_ACMPCLK, true); CMU_ClockEnable(cmuClock_GPIO, true); /* Configure ACMP input pin. */ GPIO_PinModeSet(HIJACK_RX_GPIO_PORT, HIJACK_RX_GPIO_PIN, gpioModeInput, 0); /* Analog comparator parameters */ const ACMP_Init_TypeDef acmpInit = { .fullBias = false, /* No full bias current*/ .halfBias = true, /* No half bias current */ .biasProg = 2, /* Biasprog current 1.4 uA */ .interruptOnFallingEdge = false, /* Disable interrupt for falling edge */ .interruptOnRisingEdge = false, /* Disable interrupt for rising edge */ .warmTime = acmpWarmTime256, /* Warm-up time in clock cycles, should be >140 cycles for >10us warm-up @ 14MHz */ .hysteresisLevel = acmpHysteresisLevel7, /* Hysteresis level 0 - no hysteresis */ .inactiveValue = 1, /* Inactive comparator output value */ .lowPowerReferenceEnabled = false, /* Low power reference mode disabled */ .vddLevel = HIJACK_RX_ACMP_LEVEL, /* Vdd reference scaling of 32 */ }; /* Use ACMP0 output, PD6 . */ //GPIO_PinModeSet(gpioPortD, 6, gpioModePushPull, 0); //ACMP_GPIOSetup(ACMP0, 2, true, false); /* Init ACMP and set ACMP channel 4 as positive input and scaled Vdd as negative input */ ACMP_Init(HIJACK_RX_ACMP, &acmpInit); ACMP_ChannelSet(HIJACK_RX_ACMP, HIJACK_RX_ACMP_NEG, HIJACK_RX_ACMP_CH); ACMP_Enable(HIJACK_RX_ACMP); } /** * @brief calculate whether cnt is in 500us region * ticker = 64Mhz/128 = 2us * 475us < cnt < 510us * */ static chk_result_t IsTime2Detect(uint32_t inv) { chk_result_t ret; if( inv < HIJACK_DEC_NUM_TICKS_MIN){ offset = inv; ret = pass; } else if ( ( inv <= HIJACK_DEC_NUM_TICKS_MAX ) && ( inv >= HIJACK_DEC_NUM_TICKS_MIN ) ) { offset = 0; inv = 0; ret = suit; } else{ offset = 0; inv = 0; ret = error; } return ret; } /* * Find phase remain or phase reversal. */ static void dec_parser(uint8_t bit_msk, state_t state) { if ( ( suit == IsTime2Detect(inv) ) ){ //it's time to determine if( falling == cur_edge ){ dec.data &= ~(1 << bit_msk); #if DEC_DEBUG == 1 uartPutChar( '+' ) ; uartPutChar( '_' ) ; #endif//DEC_DEBUG == 1 } else{ dec.data |= (1 << bit_msk); #if DEC_DEBUG == 1 uartPutChar( '_' ) ; uartPutChar( '+' ) ; #endif//DEC_DEBUG == 1 dec.odd++; } dec.state = state; //state switch } else if ( error == IsTime2Detect(inv) ){ //wait for edge detection time dec.state = Waiting; //state switch } } /**************************************************************************//** * @brief decode state machine * Invoke in TIMER_ISR for decoding. *****************************************************************************/ void decode_machine(void) { inv = offset + cur_stamp; //update offset #if 0 if( dec.state > Waiting ){ USART_printHexBy16u(inv); if(cur_edge == rising){ uartPutChar( '\\' ) ; } else{ uartPutChar( '/' ) ; } } #endif switch (dec.state){ case Waiting: /* go to start bit if rising edge exist. */ if (rising == cur_edge) { dec.state = Sta0; offset = 0; inv = 0; } break; // case Sta0: if( ( suit == IsTime2Detect(inv) ) && ( falling == cur_edge ) ){ dec.data = 0; //clear data field for store new potential data dec.odd = 0; //clear odd field parity counter dec.state = Bit0; #if DEC_DEBUG == 1 uartPutChar( 'S' ) ; uartPutChar( '+' ) ; uartPutChar( '_' ) ; #endif } else{ dec.state = Waiting; } break; // case Bit0: #if DEC_DEBUG == 1 uartPutChar( '0' ) ; #endif dec_parser(BIT0, Bit1); break; // case Bit1: #if DEC_DEBUG == 1 uartPutChar( '1' ) ; #endif dec_parser(BIT1, Bit2); break; // case Bit2: #if DEC_DEBUG == 1 uartPutChar( '2' ) ; #endif dec_parser(BIT2, Bit3); break; // case Bit3: #if DEC_DEBUG == 1 uartPutChar( '3' ) ; #endif dec_parser(BIT3, Bit4); break; // case Bit4: #if DEC_DEBUG == 1 uartPutChar( '4' ) ; #endif dec_parser(BIT4, Bit5); break; // case Bit5: #if DEC_DEBUG == 1 uartPutChar( '5' ) ; #endif dec_parser(BIT5, Bit6); break; // case Bit6: #if DEC_DEBUG == 1 uartPutChar( '6' ) ; #endif dec_parser(BIT6, Bit7); break; // case Bit7: #if DEC_DEBUG == 1 uartPutChar( '7' ) ; #endif dec_parser(BIT7, Parity); break; // case Parity: if ( ( suit == IsTime2Detect(inv) ) ){ //it's time to determine if( rising == cur_edge ){ dec.odd++; #if DEC_DEBUG == 1 uartPutChar( '_' ) ; uartPutChar( '+' ) ; #endif } else{ #if DEC_DEBUG == 1 uartPutChar( '+' ) ; uartPutChar( '_' ) ; #endif } #if DEC_DEBUG == 1 uartPutChar( dec.odd + 0x30) ; #endif if( 1 == (dec.odd%2)){ //parity pass dec.state = Sto0; } else{ //parity failed dec.state = Waiting; } } else if ( error == IsTime2Detect(inv) ){ //wait for edge detection time dec.state = Waiting; } break; // case Sto0: if ( ( suit == IsTime2Detect(inv) ) ){ //it's time to determine if( rising == cur_edge ){ //stop bit is rising edge USART_txByte(dec.data); #if DEC_DEBUG == 1 uartPutChar( '_' ) ; uartPutChar( '+' ) ; #endif HIJACKPutData(&dec.data, &decBuf, sizeof(uint8_t)); } else{ #if DEC_DEBUG == 1 uartPutChar( '+' ) ; uartPutChar( '_' ) ; #endif } dec.state = Waiting; #if DEC_DEBUG == 1 uartPutChar( '\r' ) ; uartPutChar( '\n' ) ; #endif } else if ( error == IsTime2Detect(inv) ){ //wait for edge detection time dec.state = Waiting; } break; // default: break; // } }
/**************************************************************************//** * @brief Sets up the ACMP *****************************************************************************/ void setupACMP(void) { /* Configuration structure for ACMP */ static const ACMP_Init_TypeDef acmpInit = { .fullBias = false, .halfBias = false, .biasProg = 0x6, /* Experiment with higher value if sensor doesn't work */ .interruptOnFallingEdge = false, .interruptOnRisingEdge = false, .warmTime = acmpWarmTime256, /* Warmuptime should be longer than 10 micro s */ .hysteresisLevel = acmpHysteresisLevel0, .inactiveValue = false, .lowPowerReferenceEnabled = false, .vddLevel = 0x00, /* Controlled by LESENSE */ .enable = false }; /* Initialize ACMP */ ACMP_Init(ACMP0, &acmpInit); /* Disable ACMP0 out to a pin. */ ACMP_GPIOSetup(ACMP0, 0, false, false); /* Set up ACMP negSel to VDD, posSel is controlled by LESENSE. */ ACMP_ChannelSet(ACMP0, acmpChannelVDD, acmpChannel0); /* LESENSE controls ACMP thus ACMP_Enable(ACMP0) should NOT be called in order * to ensure lower current consumption. */ } /**************************************************************************//** * @brief Sets up the LESENSE *****************************************************************************/ void setupLESENSE(void) { /* LESENSE configuration structure */ static const LESENSE_Init_TypeDef initLesense = { .coreCtrl = LESENSE_CORECTRL_DESC_DEFAULT, .timeCtrl = LESENSE_TIMECTRL_DESC_DEFAULT, .perCtrl = { .dacCh0Data = lesenseDACIfData, .dacCh0ConvMode = lesenseDACConvModeDisable, .dacCh0OutMode = lesenseDACOutModeDisable, .dacCh1Data = lesenseDACIfData, .dacCh1ConvMode = lesenseDACConvModeDisable, .dacCh1OutMode = lesenseDACOutModeDisable, .dacPresc = 0, .dacRef = lesenseDACRefBandGap, .acmp0Mode = lesenseACMPModeMuxThres, /* LESENSE controls the threshold value (VDDLEVEL) of ACMP0 */ .acmp1Mode = lesenseACMPModeMuxThres, /* LESENSE controls the threshold value (VDDLEVEL) of ACMP1 */ .warmupMode = lesenseWarmupModeNormal /* The analog comparators are shut down when LESENSE is idle */ }, .decCtrl = LESENSE_DECCTRL_DESC_DEFAULT }; /* Channel configuration */ static const LESENSE_ChDesc_TypeDef initLesenseCh = { .enaScanCh = true, /* Enable scan on this channel */ .enaPin = false, .enaInt = false, .chPinExMode = lesenseChPinExHigh, /* Pin is high when excitating */ .chPinIdleMode = lesenseChPinIdleDis, /* Pin idle when channel idle */ .useAltEx = true, /* Use alternative excitation pin */ .shiftRes = true, /* Result is shifted into the decoder register */ .invRes = false, .storeCntRes = true, .exClk = lesenseClkHF, /* Use HF clock for excitation timing */ .sampleClk = lesenseClkHF, /* Use HF clock for sample timing */ .exTime = 0x1F, /* Clk cycles to excite emitter and decoder */ .sampleDelay = 0x1F, /* Clc cycles to wait before sampling comparator */ .measDelay = 0x00, .acmpThres = 0x0F, /* Initial comperator threshold */ .sampleMode = lesenseSampleModeACMP, .intMode = lesenseSetIntNone, .cntThres = 0x0000, .compMode = lesenseCompModeLess }; /* Alternate excitation channels configuration */ static const LESENSE_ConfAltEx_TypeDef initAltEx = { .altExMap = lesenseAltExMapALTEX, .AltEx[0] = { .enablePin = true, .idleConf = lesenseAltExPinIdleDis, .alwaysEx = true /* Connected to IR sensor */ }, .AltEx[1] = { .enablePin = true, .idleConf = lesenseAltExPinIdleDis, .alwaysEx = false /* Connected to IR LED */ } }; /* Initialize LESENSE interface _with_ RESET. */ LESENSE_Init(&initLesense, true); /* Configure channels */ LESENSE_ChannelConfig(&initLesenseCh, 0); LESENSE_ChannelConfig(&initLesenseCh, 1); /* Configure alternate excitation channels */ LESENSE_AltExConfig(&initAltEx); /* State machine proximity sensor setup */ LESENSE_DecStDesc_TypeDef decConf = { .chainDesc = false, .confA = { .compVal = 0x1, /* Trigger transition when scan result = compVal */ .compMask = 0xC, /* Mask out the upper two bits */ .nextState = STATE_1, .prsAct = lesenseTransActNone, .setInt = true }, .confB = { .compVal = 0x1, .compMask = 0xC, .nextState = STATE_1, .prsAct = lesenseTransActNone, .setInt = true } };
/**************************************************************************//** * @brief Setup the ACMP *****************************************************************************/ void setupACMP(void) { /* ACMP configuration constant table. */ static const ACMP_Init_TypeDef initACMP = { .fullBias = false, /* fullBias */ .halfBias = true, /* halfBias */ .biasProg = 0xE, /* biasProg */ .interruptOnFallingEdge = false, /* interrupt on rising edge */ .interruptOnRisingEdge = false, /* interrupt on falling edge */ .warmTime = acmpWarmTime512, /* 512 cycle warmup to be safe */ .hysteresisLevel = acmpHysteresisLevel0, /* hysteresis level 0 */ .inactiveValue = false, /* inactive value */ .lowPowerReferenceEnabled = false, /* low power reference */ .vddLevel = 0x0D /* VDD level */ }; /* Initialize ACMP */ ACMP_Init(ACMP0, &initACMP); ACMP_ChannelSet(ACMP0, acmpChannelVDD, acmpChannel7); /* don't disable ACMP so that output can be routed out to a pin */ ACMP0->CTRL &= ~ACMP_CTRL_EN; } /**************************************************************************//** * @brief Setup the LESENSE *****************************************************************************/ void setupLESENSE(void) { /* LESENSE channel configuration constant table. */ static const LESENSE_ChAll_TypeDef initChs = LESENSE_LCSENSE_SCAN_CONF; /* LESENSE central configuration constant table. */ static const LESENSE_Init_TypeDef initLESENSE = { .coreCtrl = { .scanStart = lesenseScanStartPeriodic, .prsSel = lesensePRSCh0, .scanConfSel = lesenseScanConfDirMap, .invACMP0 = false, .invACMP1 = false, .dualSample = false, .storeScanRes = false, .bufOverWr = true, .bufTrigLevel = lesenseBufTrigHalf, .wakeupOnDMA = lesenseDMAWakeUpDisable, .biasMode = lesenseBiasModeDutyCycle, .debugRun = false }, .timeCtrl = { .startDelay = 0U }, .perCtrl = { .dacCh0Data = lesenseDACIfData, .dacCh0ConvMode = lesenseDACConvModeSampleOff, .dacCh0OutMode = lesenseDACOutModeDisable, .dacCh1Data = lesenseDACIfData, .dacCh1ConvMode = lesenseDACConvModeSampleOff, .dacCh1OutMode = lesenseDACOutModePin, .dacPresc = 31U, .dacRef = lesenseDACRefVdd, .acmp0Mode = lesenseACMPModeMux, .acmp1Mode = lesenseACMPModeDisable, .warmupMode = lesenseWarmupModeNormal }, .decCtrl =
/**************************************************************************//** * @brief Sets up the DAC *****************************************************************************/ void setupDAC(void) { /* Configuration structure for the DAC */ static const DAC_Init_TypeDef dacInit = { .refresh = dacRefresh8, .reference = dacRefVDD, .outMode = dacOutputPin, .convMode = dacConvModeContinuous, .prescale = 0, .lpEnable = false, .ch0ResetPre = false, .outEnablePRS = false, .sineEnable = false, .diff = false }; /* Initialize DAC */ DAC_Init(DAC0, &dacInit); /* Set data for DAC channel 0 */ writeDataDAC(DAC0, (unsigned int) DAC_DATA, DAC_CHANNEL); } /**************************************************************************//** * @brief Write DAC conversion value *****************************************************************************/ void writeDataDAC(DAC_TypeDef *dac, unsigned int value, unsigned int ch) { /* Write data output value to the correct register. */ if (!ch) { /* Write data to DAC ch 0 */ dac->CH0DATA = value; } else { /* Write data to DAC ch 1 */ dac->CH1DATA = value; } } /**************************************************************************//** * @brief Sets up the ACMP *****************************************************************************/ void setupACMP(void) { /* There is no default configuration for this */ static const ACMP_Init_TypeDef acmpInit = { .fullBias = false, .halfBias = true, .biasProg = 0xF, .interruptOnFallingEdge = false, .interruptOnRisingEdge = false, .warmTime = acmpWarmTime4, .hysteresisLevel = acmpHysteresisLevel0, .inactiveValue = false, .lowPowerReferenceEnabled = false, .vddLevel = ACMP_VDD_SCALE, .enable = false }; /* Initialize ACMPs */ ACMP_Init(ACMP0, &acmpInit); ACMP_Init(ACMP1, &acmpInit); /* Select Vdd as negative reference * Positive reference is controlled by LESENSE */ ACMP_ChannelSet(ACMP0, acmpChannelVDD, acmpChannel6); ACMP_ChannelSet(ACMP1, acmpChannelVDD, acmpChannel4); } /**************************************************************************//** * @brief Sets up the LESENSE *****************************************************************************/ void setupLESENSE(void) { static const LESENSE_Init_TypeDef initLesense = { .coreCtrl = { .scanStart = lesenseScanStartPeriodic, .prsSel = lesensePRSCh0, .scanConfSel = lesenseScanConfDirMap, .invACMP0 = false, .invACMP1 = false, .dualSample = false, .storeScanRes = false, .bufOverWr = true, .bufTrigLevel = lesenseBufTrigHalf, .wakeupOnDMA = lesenseDMAWakeUpDisable, .biasMode = lesenseBiasModeDutyCycle, .debugRun = false }, .timeCtrl = { .startDelay = 0 }, .perCtrl = { .dacCh0Data = lesenseDACIfData, .dacCh0ConvMode = lesenseDACConvModeSampleOff, .dacCh0OutMode = lesenseDACOutModeDisable, .dacCh1Data = lesenseDACIfData, .dacCh1ConvMode = lesenseDACConvModeSampleOff, .dacCh1OutMode = lesenseDACOutModePin, .dacPresc = 31, .dacRef = lesenseDACRefVdd, .acmp0Mode = lesenseACMPModeMux, .acmp1Mode = lesenseACMPModeMux, .warmupMode = lesenseWarmupModeNormal }, .decCtrl = { .decInput = lesenseDecInputSensorSt, .initState = 0, .chkState = true, .intMap = false, .hystPRS0 = false, .hystPRS1 = false, .hystPRS2 = false, .hystIRQ = false, .prsCount = true, .prsChSel0 = lesensePRSCh0, .prsChSel1 = lesensePRSCh1, .prsChSel2 = lesensePRSCh2, .prsChSel3 = lesensePRSCh3 } };
/**************************************************************************//** * @brief Setup the ACMP *****************************************************************************/ void setupACMP(void) { /* ACMP configuration constant table. */ static const ACMP_Init_TypeDef initACMP = { .fullBias = false, /* fullBias */ .halfBias = true, /* halfBias */ .biasProg = 0x0, /* biasProg */ .interruptOnFallingEdge = false, /* interrupt on rising edge */ .interruptOnRisingEdge = false, /* interrupt on falling edge */ .warmTime = acmpWarmTime512, /* 512 cycle warmup to be safe */ .hysteresisLevel = acmpHysteresisLevel5, /* hysteresis level 5 */ .inactiveValue = false, /* inactive value */ .lowPowerReferenceEnabled = false, /* low power reference */ .vddLevel = 0x00, /* VDD level */ .enable = false /* Don't request enabling. */ }; /* Configure ACMP. */ ACMP_Init(ACMP0, &initACMP); /* Disable ACMP0 out to a pin. */ ACMP_GPIOSetup(ACMP0, 0, false, false); /* Set up ACMP negSel to VDD, posSel is controlled by LESENSE. */ ACMP_ChannelSet(ACMP0, acmpChannelVDD, acmpChannel0); /* LESENSE controls ACMP thus ACMP_Enable(ACMP0) should NOT be called in order * to ensure lower current consumption. */ } /**************************************************************************//** * @brief Setup the LESENSE *****************************************************************************/ void setupLESENSE(void) { /* LESENSE channel configuration constant table. */ static const LESENSE_ChAll_TypeDef initChs = LESENSE_LIGHTSENSE_SCAN_CONF; /* LESENSE alternate excitation channel configuration constant table. */ static const LESENSE_ConfAltEx_TypeDef initAltEx = LESENSE_LIGHTSENSE_ALTEX_CONF; /* LESENSE central configuration constant table. */ static const LESENSE_Init_TypeDef initLESENSE = { .coreCtrl = { .scanStart = lesenseScanStartPeriodic, .prsSel = lesensePRSCh0, .scanConfSel = lesenseScanConfDirMap, .invACMP0 = false, .invACMP1 = false, .dualSample = false, .storeScanRes = false, .bufOverWr = true, .bufTrigLevel = lesenseBufTrigHalf, .wakeupOnDMA = lesenseDMAWakeUpDisable, .biasMode = lesenseBiasModeDutyCycle, .debugRun = false }, .timeCtrl = { .startDelay = 0U }, .perCtrl = { .dacCh0Data = lesenseDACIfData, .dacCh0ConvMode = lesenseDACConvModeDisable, .dacCh0OutMode = lesenseDACOutModeDisable, .dacCh1Data = lesenseDACIfData, .dacCh1ConvMode = lesenseDACConvModeDisable, .dacCh1OutMode = lesenseDACOutModeDisable, .dacPresc = 0U, .dacRef = lesenseDACRefBandGap, .acmp0Mode = lesenseACMPModeMuxThres, .acmp1Mode = lesenseACMPModeMuxThres, .warmupMode = lesenseWarmupModeNormal }, .decCtrl =