Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: EFM32 RDA5807M RDS Radio EMF32-Segment-Touch-Demo EFM32_Bugs MFALHIMOHAMMED ... more
caplesense.c
00001 /**************************************************************************//** 00002 * @file 00003 * @brief Capacitive sense driver 00004 * @version 3.20.9 00005 ****************************************************************************** 00006 * @section License 00007 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> 00008 ******************************************************************************* 00009 * 00010 * This file is licensensed under the Silabs License Agreement. See the file 00011 * "Silabs_License_Agreement.txt" for details. Before using this software for 00012 * any purpose, you must agree to the terms of that agreement. 00013 * 00014 ******************************************************************************/ 00015 00016 00017 00018 00019 /* EM header files */ 00020 #include "em_device.h" 00021 00022 /* Drivers */ 00023 #include "caplesense.h" 00024 #include "em_emu.h" 00025 #include "em_acmp.h" 00026 #include "em_assert.h" 00027 #include "em_cmu.h" 00028 #include "em_emu.h" 00029 #include "em_gpio.h" 00030 #include "em_int.h" 00031 #include "em_lesense.h" 00032 00033 /* Capacitive sense configuration */ 00034 //#include "caplesenseconfig.h" 00035 // ^^ Already included through caplesense.h ^^ 00036 00037 /**************************************************************************//** 00038 * @brief This vector stores the latest read values from LESENSE 00039 * @param LESENSE_CHANNELS Vector of channels. 00040 *****************************************************************************/ 00041 static volatile uint32_t channelValues[LESENSE_CHANNELS] = 00042 { 00043 /* Ch0, Ch1, Ch2, Ch3, Ch4, Ch5, Ch6, Ch7 */ 00044 0, 0, 0, 0, 0, 0, 0, 0, 00045 /* Ch8, Ch9, Ch10, Ch11, Ch12, Ch13, Ch14, Ch15 */ 00046 0, 0, 0, 0, 0, 0, 0, 0 00047 }; 00048 00049 00050 /**************************************************************************//** 00051 * @brief This stores the maximum values seen by a channel 00052 * @param LESENSE_CHANNELS Vector of channels. 00053 *****************************************************************************/ 00054 static volatile uint32_t channelMaxValues[LESENSE_CHANNELS] = 00055 { 00056 /* Ch0, Ch1, Ch2, Ch3, Ch4, Ch5, Ch6, Ch7 */ 00057 1, 1, 1, 1, 1, 1, 1, 1, 00058 /* Ch8, Ch9, Ch11, Ch11, Ch12, Ch13, Ch14, Ch15 */ 00059 1, 1, 1, 1, 1, 1, 1, 1 00060 }; 00061 00062 /**************************************************************************//** 00063 * @brief A bit vector which represents the channels to iterate through 00064 * @param LESENSE_CHANNELS Vector of channels. 00065 *****************************************************************************/ 00066 static const bool channelsInUse[LESENSE_CHANNELS] = LESENSE_CAPSENSE_CH_IN_USE; 00067 static bool init = true; 00068 00069 /**************************************************************************//** 00070 * Prototypes 00071 *****************************************************************************/ 00072 void CAPLESENSE_setupCMU(void); 00073 void CAPLESENSE_setupGPIO(void); 00074 void CAPLESENSE_setupACMP(void); 00075 00076 00077 /**************************************************************************//** 00078 * Local variables 00079 *****************************************************************************/ 00080 /** Callback function for LESENSE interrupts. */ 00081 static void (*lesenseScanCb)(void); 00082 /** Callback function for LESENSE interrupts. */ 00083 static void (*lesenseChCb)(void); 00084 00085 /** The current channel we are sensing */ 00086 static volatile uint8_t currentChannel; 00087 00088 00089 00090 /**************************************************************************//** 00091 * @brief Setup the CMU 00092 *****************************************************************************/ 00093 void CAPLESENSE_setupCMU(void) 00094 { 00095 /* Ensure core frequency has been updated */ 00096 SystemCoreClockUpdate(); 00097 00098 /* Enable HF peripheral clock. */ 00099 CMU_ClockEnable(cmuClock_HFPER, 1); 00100 /* Enable clock for GPIO. */ 00101 CMU_ClockEnable(cmuClock_GPIO, 1); 00102 /* Enable clock for ACMP0. */ 00103 CMU_ClockEnable(cmuClock_ACMP0, 1); 00104 /* Enable clock for ACMP1. */ 00105 CMU_ClockEnable(cmuClock_ACMP1, 1); 00106 /* Enable CORELE clock. */ 00107 CMU_ClockEnable(cmuClock_CORELE, 1); 00108 /* Enable clock for LESENSE. */ 00109 CMU_ClockEnable(cmuClock_LESENSE, 1); 00110 00111 /* Enable clock divider for LESENSE. */ 00112 CMU_ClockDivSet(cmuClock_LESENSE, cmuClkDiv_1); 00113 } 00114 00115 00116 /**************************************************************************//** 00117 * @brief Setup the GPIO 00118 *****************************************************************************/ 00119 void CAPLESENSE_setupGPIO(void) 00120 { 00121 /* Configure the drive strength of the ports for the light sensor. */ 00122 GPIO_DriveModeSet(CAPLESENSE_SLIDER_PORT0, gpioDriveModeStandard); 00123 00124 /* Initialize the 4 GPIO pins of the touch slider for using them as LESENSE 00125 * scan channels for capacitive sensing. */ 00126 GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER0_PIN, gpioModeDisabled, 0); 00127 GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER1_PIN, gpioModeDisabled, 0); 00128 GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER2_PIN, gpioModeDisabled, 0); 00129 GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER3_PIN, gpioModeDisabled, 0); 00130 } 00131 00132 00133 /**************************************************************************//** 00134 * @brief Setup the ACMP 00135 *****************************************************************************/ 00136 void CAPLESENSE_setupACMP(void) 00137 { 00138 /* ACMP capsense configuration constant table. */ 00139 static const ACMP_CapsenseInit_TypeDef initACMP = 00140 { 00141 .fullBias = false, 00142 .halfBias = false, 00143 .biasProg = 0x7, 00144 .warmTime = acmpWarmTime512, 00145 .hysteresisLevel = acmpHysteresisLevel7, 00146 .resistor = acmpResistor0, 00147 .lowPowerReferenceEnabled = false, 00148 .vddLevel = 0x3D, 00149 .enable = false 00150 }; 00151 00152 00153 /* Configure ACMP locations, ACMP output to pin disabled. */ 00154 ACMP_GPIOSetup(ACMP0, 0, false, false); 00155 ACMP_GPIOSetup(ACMP1, 0, false, false); 00156 00157 /* Initialize ACMPs in capacitive sense mode. */ 00158 ACMP_CapsenseInit(ACMP0, &initACMP); 00159 ACMP_CapsenseInit(ACMP1, &initACMP); 00160 00161 /* Don't enable ACMP, LESENSE controls it! */ 00162 } 00163 00164 00165 /**************************************************************************//** 00166 * @brief Setup the LESENSE for capavitive sensing 00167 * @param sleep If true, go into sleep mode. 00168 *****************************************************************************/ 00169 void CAPLESENSE_setupLESENSE(bool sleep) 00170 { 00171 uint8_t i; 00172 00173 /* Array for storing the calibration values. */ 00174 static uint16_t capsenseCalibrateVals[4]; 00175 00176 /* LESENSE channel configuration constant table in sense mode. */ 00177 static const LESENSE_ChAll_TypeDef initChsSense = LESENSE_CAPSENSE_SCAN_CONF_SENSE; 00178 /* LESENSE channel configuration constant table in sleep mode. */ 00179 static const LESENSE_ChAll_TypeDef initChsSleep = LESENSE_CAPSENSE_SCAN_CONF_SLEEP; 00180 /* LESENSE central configuration constant table. */ 00181 static const LESENSE_Init_TypeDef initLESENSE = 00182 { 00183 .coreCtrl = 00184 { 00185 .scanStart = lesenseScanStartPeriodic, 00186 .prsSel = lesensePRSCh0, 00187 .scanConfSel = lesenseScanConfDirMap, 00188 .invACMP0 = false, 00189 .invACMP1 = false, 00190 .dualSample = false, 00191 .storeScanRes = false, 00192 .bufOverWr = true, 00193 .bufTrigLevel = lesenseBufTrigHalf, 00194 .wakeupOnDMA = lesenseDMAWakeUpDisable, 00195 .biasMode = lesenseBiasModeDutyCycle, 00196 .debugRun = false 00197 }, 00198 00199 .timeCtrl = 00200 { 00201 .startDelay = 0U 00202 }, 00203 00204 .perCtrl = 00205 { 00206 .dacCh0Data = lesenseDACIfData, 00207 .dacCh0ConvMode = lesenseDACConvModeDisable, 00208 .dacCh0OutMode = lesenseDACOutModeDisable, 00209 .dacCh1Data = lesenseDACIfData, 00210 .dacCh1ConvMode = lesenseDACConvModeDisable, 00211 .dacCh1OutMode = lesenseDACOutModeDisable, 00212 .dacPresc = 0U, 00213 .dacRef = lesenseDACRefBandGap, 00214 .acmp0Mode = lesenseACMPModeMuxThres, 00215 .acmp1Mode = lesenseACMPModeMuxThres, 00216 .warmupMode = lesenseWarmupModeNormal 00217 }, 00218 00219 .decCtrl = 00220 { 00221 .decInput = lesenseDecInputSensorSt, 00222 .chkState = false, 00223 .intMap = true, 00224 .hystPRS0 = false, 00225 .hystPRS1 = false, 00226 .hystPRS2 = false, 00227 .hystIRQ = false, 00228 .prsCount = true, 00229 .prsChSel0 = lesensePRSCh0, 00230 .prsChSel1 = lesensePRSCh1, 00231 .prsChSel2 = lesensePRSCh2, 00232 .prsChSel3 = lesensePRSCh3 00233 } 00234 }; 00235 00236 /* Only initialize main LESENSE parameters once. */ 00237 if (init) 00238 { 00239 /* Initialize LESENSE interface with RESET. */ 00240 LESENSE_Init(&initLESENSE, true); 00241 } 00242 00243 /* Different configuration for "sleep" and "sense" modes. */ 00244 if (sleep) 00245 { 00246 /* Stop LESENSE before configuration. */ 00247 LESENSE_ScanStop(); 00248 00249 /* Wait until the currently active scan is finished. */ 00250 while (LESENSE_STATUS_SCANACTIVE & LESENSE_StatusGet()) ; 00251 00252 /* Clear result buffer. */ 00253 LESENSE_ResultBufferClear(); 00254 00255 /* Set scan frequency (in Hz). */ 00256 (void) LESENSE_ScanFreqSet(0U, 4U); 00257 00258 /* Set clock divisor for LF clock. */ 00259 LESENSE_ClkDivSet(lesenseClkLF, lesenseClkDiv_1); 00260 00261 /* Configure scan channels. */ 00262 LESENSE_ChannelAllConfig(&initChsSleep); 00263 00264 /* Restore calibration values. */ 00265 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER0_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[0]); 00266 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER1_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[1]); 00267 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER2_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[2]); 00268 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER3_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[3]); 00269 00270 /* Disable scan complete interrupt. */ 00271 LESENSE_IntDisable(LESENSE_IEN_SCANCOMPLETE); 00272 } 00273 else 00274 { 00275 /* Stop LESENSE before configuration. */ 00276 LESENSE_ScanStop(); 00277 00278 /* Wait until the currently active scan is finished. */ 00279 while (LESENSE_STATUS_SCANACTIVE & LESENSE_StatusGet()) ; 00280 00281 /* Clean scan complete interrupt flag. */ 00282 LESENSE_IntClear(LESENSE_IEN_SCANCOMPLETE); 00283 00284 /* Clear result buffer. */ 00285 LESENSE_ResultBufferClear(); 00286 00287 /* Set scan frequency (in Hz). */ 00288 (void) LESENSE_ScanFreqSet(0U, 5U); 00289 00290 /* Set clock divisor for LF clock. */ 00291 LESENSE_ClkDivSet(lesenseClkLF, lesenseClkDiv_8); 00292 00293 /* Configure scan channels. */ 00294 LESENSE_ChannelAllConfig(&initChsSense); 00295 00296 /* Enable scan complete interrupt. */ 00297 LESENSE_IntEnable(LESENSE_IEN_SCANCOMPLETE); 00298 } 00299 00300 /* Enable LESENSE interrupt in NVIC. */ 00301 NVIC_SetPriority(LESENSE_IRQn, 2); 00302 NVIC_EnableIRQ(LESENSE_IRQn); 00303 00304 /* Start scanning LESENSE channels. */ 00305 LESENSE_ScanStart(); 00306 00307 /* Run it only once. */ 00308 if (init) 00309 { 00310 /* Assuming that the pads are not touched at first, we can use the result as 00311 * the threshold value to calibrate the capacitive sensing in LESENSE. */ 00312 init = false; 00313 00314 /* Waiting for buffer to be full. */ 00315 while (!(LESENSE->STATUS & LESENSE_STATUS_BUFHALFFULL)) ; 00316 00317 /* Read out steady state values from LESENSE for calibration. */ 00318 for (i = 0U; i < CAPLESENSE_NUMOF_SLIDERS; i++) 00319 { 00320 capsenseCalibrateVals[i] = LESENSE_ScanResultDataBufferGet(i) - CAPLESENSE_SENSITIVITY_OFFS; 00321 } 00322 00323 /* Set calibration values. */ 00324 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER0_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[0]); 00325 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER1_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[1]); 00326 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER2_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[2]); 00327 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER3_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[3]); 00328 } 00329 } 00330 00331 00332 /**************************************************************************//** 00333 * @brief LESENSE callback setup 00334 * @param scanCb Scan callback 00335 * @param chCb Channel callback 00336 *****************************************************************************/ 00337 void CAPLESENSE_setupCallbacks(void (*scanCb)(void), void (*chCb)(void)) 00338 { 00339 lesenseScanCb = scanCb; 00340 lesenseChCb = chCb; 00341 } 00342 00343 00344 /**************************************************************************//** 00345 * @brief LESENSE interrupt handler 00346 *****************************************************************************/ 00347 void LESENSE_IRQHandler(void) 00348 { 00349 uint32_t count; 00350 00351 00352 /* LESENSE scan complete interrupt. */ 00353 if (LESENSE_IF_SCANCOMPLETE & LESENSE_IntGetEnabled()) 00354 { 00355 LESENSE_IntClear(LESENSE_IF_SCANCOMPLETE); 00356 00357 /* Iterate trough all channels */ 00358 for (currentChannel = 0; currentChannel < LESENSE_CHANNELS; currentChannel++) 00359 { 00360 /* If this channel is not in use, skip to the next one */ 00361 if (!channelsInUse[currentChannel]) 00362 { 00363 continue; 00364 } 00365 00366 /* Read out value from LESENSE buffer */ 00367 count = LESENSE_ScanResultDataGet(); 00368 00369 /* Store value in channelValues */ 00370 channelValues[currentChannel] = count; 00371 00372 /* Update channelMaxValues */ 00373 if (count > channelMaxValues[currentChannel]) 00374 { 00375 channelMaxValues[currentChannel] = count; 00376 } 00377 } 00378 00379 /* Call callback function. */ 00380 if (lesenseScanCb != 0x00000000) 00381 { 00382 lesenseScanCb(); 00383 } 00384 } 00385 00386 /* LESENSE channel interrupt. */ 00387 if (CAPLESENSE_CHANNEL_INT & LESENSE_IntGetEnabled()) 00388 { 00389 /* Clear flags. */ 00390 LESENSE_IntClear(CAPLESENSE_CHANNEL_INT); 00391 00392 /* Call callback function. */ 00393 if (lesenseChCb != 0x00000000) 00394 { 00395 lesenseChCb(); 00396 } 00397 } 00398 } 00399 00400 00401 /**************************************************************************//** 00402 * @brief Get the channelValue for a sensor segment 00403 * @param capSegment 00404 * @return channel 00405 *****************************************************************************/ 00406 uint8_t CAPLESENSE_getSegmentChannel(uint8_t capSegment) 00407 { 00408 uint8_t channel; 00409 00410 switch (capSegment) 00411 { 00412 case(0): 00413 channel = SLIDER_PART0_CHANNEL; 00414 break; 00415 case(1): 00416 channel = SLIDER_PART1_CHANNEL; 00417 break; 00418 case(2): 00419 channel = SLIDER_PART2_CHANNEL; 00420 break; 00421 default: 00422 channel = SLIDER_PART3_CHANNEL; 00423 break; 00424 } 00425 return channel; 00426 00427 } 00428 00429 00430 /**************************************************************************//** 00431 * @brief Get the current channelValue for a channel 00432 * @param channel The channel. 00433 * @return The channelValue. 00434 *****************************************************************************/ 00435 uint32_t CAPLESENSE_getVal(uint8_t channel) 00436 { 00437 return channelValues[channel]; 00438 } 00439 00440 /**************************************************************************//** 00441 * @brief Get the current normalized channelValue for a channel 00442 * @param channel The channel. 00443 * @return The channel value in range (0-256). 00444 *****************************************************************************/ 00445 uint32_t CAPLESENSE_getNormalizedVal(uint8_t channel) 00446 { 00447 uint32_t max = channelMaxValues[channel]; 00448 return (channelValues[channel] << 8) / max; 00449 } 00450 00451 00452 00453 /**************************************************************************//** 00454 * @brief Get the position of the slider 00455 * @return The position of the slider if it can be determined, 00456 * -1 otherwise. 00457 *****************************************************************************/ 00458 int32_t CAPLESENSE_getSliderPosition(void) 00459 { 00460 int i; 00461 int minPos = -1; 00462 uint32_t minVal = 236; /* adjust it */ 00463 /* Values used for interpolation. There is two more which represents the edges. 00464 * This makes the interpolation code a bit cleaner as we do not have to make special 00465 * cases for handling them */ 00466 uint32_t interpol[6] = { 255, 255, 255, 255, 255, 255 }; 00467 uint32_t channelPattern[] = { 0, SLIDER_PART0_CHANNEL + 1, 00468 SLIDER_PART1_CHANNEL + 1, 00469 SLIDER_PART2_CHANNEL + 1, 00470 SLIDER_PART3_CHANNEL + 1 }; 00471 00472 /* The calculated slider position. */ 00473 int position; 00474 00475 /* Iterate through the 4 slider bars and calculate the current value divided by 00476 * the maximum value multiplied by 256. 00477 * Note that there is an offset of 1 between channelValues and interpol. 00478 * This is done to make interpolation easier. 00479 */ 00480 for (i = 1; i < CAPLESENSE_NUMOF_SLIDERS + 1; i++) 00481 { 00482 /* interpol[i] will be in the range 0-256 depending on channelMax */ 00483 interpol[i] = channelValues[channelPattern[i] - 1] << 8; 00484 interpol[i] /= channelMaxValues[channelPattern[i] - 1]; 00485 /* Find the minimum value and position */ 00486 if (interpol[i] < minVal) 00487 { 00488 minVal = interpol[i]; 00489 minPos = i; 00490 } 00491 } 00492 /* Check if the slider has not been touched */ 00493 if (minPos == -1) 00494 return -1; 00495 00496 /* Start position. Shift by 4 to get additional resolution. */ 00497 /* Because of the interpol trick earlier we have to substract one to offset that effect */ 00498 position = (minPos - 1) << 4; 00499 00500 /* Interpolate with pad to the left */ 00501 position -= ((256 - interpol[minPos - 1]) << 3) 00502 / (256 - interpol[minPos]); 00503 00504 /* Interpolate with pad to the right */ 00505 position += ((256 - interpol[minPos + 1]) << 3) 00506 / (256 - interpol[minPos]); 00507 00508 return position; 00509 } 00510 00511 00512 /**************************************************************************//** 00513 * @brief Send the capacative sense system to sleep mode. 00514 *****************************************************************************/ 00515 void CAPLESENSE_Sleep(void) 00516 { 00517 /* Go to EM2 and wait for the measurement to complete. */ 00518 EMU_EnterEM2(true); 00519 } 00520 00521 00522 /**************************************************************************//** 00523 * @brief Initializes the capacative sense system without LESENSE. 00524 * @param sleep If true, go into sleep mode. 00525 *****************************************************************************/ 00526 void CAPLESENSE_Init(bool sleep) 00527 { 00528 /* Disable interrupts */ 00529 INT_Disable(); 00530 00531 /* Setup CMU. */ 00532 CAPLESENSE_setupCMU(); 00533 /* Setup GPIO. */ 00534 CAPLESENSE_setupGPIO(); 00535 /* Setup ACMP. */ 00536 CAPLESENSE_setupACMP(); 00537 /* Setup LESENSE. */ 00538 CAPLESENSE_setupLESENSE(sleep); 00539 00540 /* Initialization done, enable interrupts globally. */ 00541 INT_Enable(); 00542 } 00543 00544
Generated on Tue Jul 12 2022 18:58:41 by
1.7.2