Silicon Labs / EFM32_CapSenseSlider

Dependents:   EFM32 RDA5807M RDS Radio EMF32-Segment-Touch-Demo EFM32_Bugs MFALHIMOHAMMED ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers caplesense.c Source File

caplesense.c

Go to the documentation of this file.
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