caplesense.c

Go to the documentation of this file.
00001 /**************************************************************************/
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 
00036 /**************************************************************************/
00040 static volatile uint32_t channelValues[LESENSE_CHANNELS] =
00041 {
00042 /*  Ch0,   Ch1,   Ch2,   Ch3,   Ch4,   Ch5,   Ch6,   Ch7    */
00043   0, 0, 0, 0, 0, 0, 0, 0,
00044 /*  Ch8,   Ch9,   Ch10,  Ch11,  Ch12,  Ch13,  Ch14,  Ch15   */
00045   0, 0, 0, 0, 0, 0, 0, 0
00046 };
00047 
00048 
00049 /**************************************************************************/
00053 static volatile uint32_t channelMaxValues[LESENSE_CHANNELS] =
00054 {
00055 /*  Ch0,   Ch1,   Ch2,   Ch3,   Ch4,   Ch5,   Ch6,   Ch7    */
00056   1, 1, 1, 1, 1, 1, 1, 1,
00057 /*  Ch8,   Ch9,   Ch11,  Ch11,  Ch12,  Ch13,  Ch14,  Ch15   */
00058   1, 1, 1, 1, 1, 1, 1, 1
00059 };
00060 
00061 /**************************************************************************/
00065 static const bool channelsInUse[LESENSE_CHANNELS] = LESENSE_CAPSENSE_CH_IN_USE;
00066 
00067 /**************************************************************************/
00070 void CAPLESENSE_setupCMU(void);
00071 void CAPLESENSE_setupGPIO(void);
00072 void CAPLESENSE_setupACMP(void);
00073 
00074 
00075 /**************************************************************************/
00079 static void (*lesenseScanCb)(void);
00081 static void (*lesenseChCb)(void);
00082 
00084 static volatile uint8_t currentChannel;
00085 
00086 
00087 
00088 /**************************************************************************/
00091 void CAPLESENSE_setupCMU(void)
00092 {
00093   /* Ensure core frequency has been updated */
00094   SystemCoreClockUpdate();
00095 
00096   /* Select clock source for HF clock. */
00097   CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO);
00098   /* Select clock source for LFA clock. */
00099   CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
00100   /* Select clock source for LFB clock. */
00101   CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_Disabled);
00102 
00103   /* Enable HF peripheral clock. */
00104   CMU_ClockEnable(cmuClock_HFPER, 1);
00105   /* Enable clock for GPIO. */
00106   CMU_ClockEnable(cmuClock_GPIO, 1);
00107   /* Enable clock for ACMP0. */
00108   CMU_ClockEnable(cmuClock_ACMP0, 1);
00109   /* Enable clock for ACMP1. */
00110   CMU_ClockEnable(cmuClock_ACMP1, 1);
00111   /* Enable CORELE clock. */
00112   CMU_ClockEnable(cmuClock_CORELE, 1);
00113   /* Enable clock for LESENSE. */
00114   CMU_ClockEnable(cmuClock_LESENSE, 1);
00115 
00116   /* Enable clock divider for LESENSE. */
00117   CMU_ClockDivSet(cmuClock_LESENSE, cmuClkDiv_1);
00118 }
00119 
00120 
00121 /**************************************************************************/
00124 void CAPLESENSE_setupGPIO(void)
00125 {
00126   /* Configure the drive strength of the ports for the light sensor. */
00127   GPIO_DriveModeSet(CAPLESENSE_SLIDER_PORT0, gpioDriveModeStandard);
00128 
00129   /* Initialize the 4 GPIO pins of the touch slider for using them as LESENSE
00130    * scan channels for capacitive sensing. */
00131   GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER0_PIN, gpioModeDisabled, 0);
00132   GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER1_PIN, gpioModeDisabled, 0);
00133   GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER2_PIN, gpioModeDisabled, 0);
00134   GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER3_PIN, gpioModeDisabled, 0);
00135 }
00136 
00137 
00138 /**************************************************************************/
00141 void CAPLESENSE_setupACMP(void)
00142 {
00143   /* ACMP capsense configuration constant table. */
00144   static const ACMP_CapsenseInit_TypeDef initACMP =
00145   {
00146     .fullBias                 = false,
00147     .halfBias                 = false,
00148     .biasProg                 =                  0x7,
00149     .warmTime                 = acmpWarmTime512,
00150     .hysteresisLevel          = acmpHysteresisLevel7,
00151     .resistor                 = acmpResistor0,
00152     .lowPowerReferenceEnabled = false,
00153     .vddLevel                 =                 0x3D,
00154     .enable                   = false
00155   };
00156 
00157 
00158   /* Configure ACMP locations, ACMP output to pin disabled. */
00159   ACMP_GPIOSetup(ACMP0, 0, false, false);
00160   ACMP_GPIOSetup(ACMP1, 0, false, false);
00161 
00162   /* Initialize ACMPs in capacitive sense mode. */
00163   ACMP_CapsenseInit(ACMP0, &initACMP);
00164   ACMP_CapsenseInit(ACMP1, &initACMP);
00165 
00166   /* Don't enable ACMP, LESENSE controls it! */
00167 }
00168 
00169 
00170 /**************************************************************************/
00174 void CAPLESENSE_setupLESENSE(bool sleep)
00175 {
00176   uint8_t     i;
00177   static bool init = true;
00178 
00179   /* Array for storing the calibration values. */
00180   static uint16_t capsenseCalibrateVals[4];
00181 
00182   /* LESENSE channel configuration constant table in sense mode. */
00183   static const LESENSE_ChAll_TypeDef initChsSense = LESENSE_CAPSENSE_SCAN_CONF_SENSE;
00184   /* LESENSE channel configuration constant table in sleep mode. */
00185   static const LESENSE_ChAll_TypeDef initChsSleep = LESENSE_CAPSENSE_SCAN_CONF_SLEEP;
00186   /* LESENSE central configuration constant table. */
00187   static const LESENSE_Init_TypeDef  initLESENSE =
00188   {
00189     .coreCtrl         =
00190     {
00191       .scanStart    = lesenseScanStartPeriodic,
00192       .prsSel       = lesensePRSCh0,
00193       .scanConfSel  = lesenseScanConfDirMap,
00194       .invACMP0     = false,
00195       .invACMP1     = false,
00196       .dualSample   = false,
00197       .storeScanRes = false,
00198       .bufOverWr    = true,
00199       .bufTrigLevel = lesenseBufTrigHalf,
00200       .wakeupOnDMA  = lesenseDMAWakeUpDisable,
00201       .biasMode     = lesenseBiasModeDutyCycle,
00202       .debugRun     = false
00203     },
00204 
00205     .timeCtrl         =
00206     {
00207       .startDelay     =          0U
00208     },
00209 
00210     .perCtrl          =
00211     {
00212       .dacCh0Data     = lesenseDACIfData,
00213       .dacCh0ConvMode = lesenseDACConvModeDisable,
00214       .dacCh0OutMode  = lesenseDACOutModeDisable,
00215       .dacCh1Data     = lesenseDACIfData,
00216       .dacCh1ConvMode = lesenseDACConvModeDisable,
00217       .dacCh1OutMode  = lesenseDACOutModeDisable,
00218       .dacPresc       =                        0U,
00219       .dacRef         = lesenseDACRefBandGap,
00220       .acmp0Mode      = lesenseACMPModeMuxThres,
00221       .acmp1Mode      = lesenseACMPModeMuxThres,
00222       .warmupMode     = lesenseWarmupModeNormal
00223     },
00224 
00225     .decCtrl          =
00226     {
00227       .decInput  = lesenseDecInputSensorSt,
00228       .chkState  = false,
00229       .intMap    = true,
00230       .hystPRS0  = false,
00231       .hystPRS1  = false,
00232       .hystPRS2  = false,
00233       .hystIRQ   = false,
00234       .prsCount  = true,
00235       .prsChSel0 = lesensePRSCh0,
00236       .prsChSel1 = lesensePRSCh1,
00237       .prsChSel2 = lesensePRSCh2,
00238       .prsChSel3 = lesensePRSCh3
00239     }
00240   };
00241 
00242   /* Only initialize main LESENSE parameters once. */
00243   if (init)
00244   {
00245     /* Initialize LESENSE interface with RESET. */
00246     LESENSE_Init(&initLESENSE, true);
00247   }
00248 
00249   /* Different configuration for "sleep" and "sense" modes. */
00250   if (sleep)
00251   {
00252     /* Stop LESENSE before configuration. */
00253     LESENSE_ScanStop();
00254 
00255     /* Wait until the currently active scan is finished. */
00256     while (LESENSE_STATUS_SCANACTIVE & LESENSE_StatusGet()) ;
00257 
00258     /* Clear result buffer. */
00259     LESENSE_ResultBufferClear();
00260 
00261     /* Set scan frequency (in Hz). */
00262     (void) LESENSE_ScanFreqSet(0U, 4U);
00263 
00264     /* Set clock divisor for LF clock. */
00265     LESENSE_ClkDivSet(lesenseClkLF, lesenseClkDiv_1);
00266 
00267     /* Configure scan channels. */
00268     LESENSE_ChannelAllConfig(&initChsSleep);
00269 
00270     /* Restore calibration values. */
00271     LESENSE_ChannelThresSet(CAPLESENSE_SLIDER0_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[0]);
00272     LESENSE_ChannelThresSet(CAPLESENSE_SLIDER1_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[1]);
00273     LESENSE_ChannelThresSet(CAPLESENSE_SLIDER2_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[2]);
00274     LESENSE_ChannelThresSet(CAPLESENSE_SLIDER3_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[3]);
00275 
00276     /* Disable scan complete interrupt. */
00277     LESENSE_IntDisable(LESENSE_IEN_SCANCOMPLETE);
00278   }
00279   else
00280   {
00281     /* Stop LESENSE before configuration. */
00282     LESENSE_ScanStop();
00283 
00284     /* Wait until the currently active scan is finished. */
00285     while (LESENSE_STATUS_SCANACTIVE & LESENSE_StatusGet()) ;
00286 
00287     /* Clean scan complete interrupt flag. */
00288     LESENSE_IntClear(LESENSE_IEN_SCANCOMPLETE);
00289 
00290     /* Clear result buffer. */
00291     LESENSE_ResultBufferClear();
00292 
00293     /* Set scan frequency (in Hz). */
00294     (void) LESENSE_ScanFreqSet(0U, 64U);
00295 
00296     /* Set clock divisor for LF clock. */
00297     LESENSE_ClkDivSet(lesenseClkLF, lesenseClkDiv_8);
00298 
00299     /* Configure scan channels. */
00300     LESENSE_ChannelAllConfig(&initChsSense);
00301 
00302     /* Enable scan complete interrupt. */
00303     LESENSE_IntEnable(LESENSE_IEN_SCANCOMPLETE);
00304   }
00305 
00306   /* Enable LESENSE interrupt in NVIC. */
00307   NVIC_EnableIRQ(LESENSE_IRQn);
00308 
00309   /* Start scanning LESENSE channels. */
00310   LESENSE_ScanStart();
00311 
00312   /* Run it only once. */
00313   if (init)
00314   {
00315     /* Assuming that the pads are not touched at first, we can use the result as
00316      * the threshold value to calibrate the capacitive sensing in LESENSE. */
00317     init = false;
00318 
00319     /* Waiting for buffer to be full. */
00320     while (!(LESENSE->STATUS & LESENSE_STATUS_BUFHALFFULL)) ;
00321 
00322     /* Read out steady state values from LESENSE for calibration. */
00323     for (i = 0U; i < CAPLESENSE_NUMOF_SLIDERS; i++)
00324     {
00325       capsenseCalibrateVals[i] = LESENSE_ScanResultDataBufferGet(i) - CAPLESENSE_SENSITIVITY_OFFS;
00326     }
00327 
00328     /* Set calibration values. */
00329     LESENSE_ChannelThresSet(CAPLESENSE_SLIDER0_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[0]);
00330     LESENSE_ChannelThresSet(CAPLESENSE_SLIDER1_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[1]);
00331     LESENSE_ChannelThresSet(CAPLESENSE_SLIDER2_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[2]);
00332     LESENSE_ChannelThresSet(CAPLESENSE_SLIDER3_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[3]);
00333   }
00334 }
00335 
00336 
00337 /**************************************************************************/
00342 void CAPLESENSE_setupCallbacks(void (*scanCb)(void), void (*chCb)(void))
00343 {
00344   lesenseScanCb = scanCb;
00345   lesenseChCb   = chCb;
00346 }
00347 
00348 
00349 /**************************************************************************/
00352 void LESENSE_IRQHandler(void)
00353 {
00354   uint32_t count;
00355 
00356 
00357   /* LESENSE scan complete interrupt. */
00358   if (LESENSE_IF_SCANCOMPLETE & LESENSE_IntGetEnabled())
00359   {
00360     LESENSE_IntClear(LESENSE_IF_SCANCOMPLETE);
00361 
00362     /* Iterate trough all channels */
00363     for (currentChannel = 0; currentChannel < LESENSE_CHANNELS; currentChannel++)
00364     {
00365       /* If this channel is not in use, skip to the next one */
00366       if (!channelsInUse[currentChannel])
00367       {
00368         continue;
00369       }
00370 
00371       /* Read out value from LESENSE buffer */
00372       count = LESENSE_ScanResultDataGet();
00373 
00374       /* Store value in channelValues */
00375       channelValues[currentChannel] = count;
00376 
00377       /* Update channelMaxValues */
00378       if (count > channelMaxValues[currentChannel])
00379       {
00380         channelMaxValues[currentChannel] = count;
00381       }
00382     }
00383 
00384     /* Call callback function. */
00385     if (lesenseScanCb != 0x00000000)
00386     {
00387       lesenseScanCb();
00388     }
00389   }
00390 
00391   /* LESENSE channel interrupt. */
00392   if (CAPLESENSE_CHANNEL_INT & LESENSE_IntGetEnabled())
00393   {
00394     /* Clear flags. */
00395     LESENSE_IntClear(CAPLESENSE_CHANNEL_INT);
00396 
00397     /* Call callback function. */
00398     if (lesenseChCb != 0x00000000)
00399     {
00400       lesenseChCb();
00401     }
00402   }
00403 }
00404 
00405 
00406 /**************************************************************************/
00411 uint8_t  CAPLESENSE_getSegmentChannel(uint8_t capSegment)
00412 {
00413   uint8_t channel;
00414 
00415   switch (capSegment)
00416   {
00417   case(0):
00418     channel = SLIDER_PART0_CHANNEL;
00419     break;
00420   case(1):
00421     channel = SLIDER_PART1_CHANNEL;
00422     break;
00423   case(2):
00424     channel = SLIDER_PART2_CHANNEL;
00425     break;
00426   default:
00427     channel = SLIDER_PART3_CHANNEL;
00428     break;
00429   }
00430   return channel;
00431 
00432 }
00433 
00434 
00435 /**************************************************************************/
00440 uint32_t CAPLESENSE_getVal(uint8_t channel)
00441 {
00442   return channelValues[channel];
00443 }
00444 
00445 /**************************************************************************/
00450 uint32_t CAPLESENSE_getNormalizedVal(uint8_t channel)
00451 {
00452   uint32_t max = channelMaxValues[channel];
00453   return (channelValues[channel] << 8) / max;
00454 }
00455 
00456 
00457 
00458 /**************************************************************************/
00463 int32_t CAPLESENSE_getSliderPosition(void)
00464 {
00465   int      i;
00466   int      minPos = -1;
00467   uint32_t minVal = 236; /* adjust it */
00468   /* Values used for interpolation. There is two more which represents the edges.
00469    * This makes the interpolation code a bit cleaner as we do not have to make special
00470    * cases for handling them */
00471   uint32_t interpol[6]      = { 255, 255, 255, 255, 255, 255 };
00472   uint32_t channelPattern[] = { 0,                        SLIDER_PART0_CHANNEL + 1,
00473                                 SLIDER_PART1_CHANNEL + 1,
00474                                 SLIDER_PART2_CHANNEL + 1,
00475                                 SLIDER_PART3_CHANNEL + 1 };
00476 
00477   /* The calculated slider position. */
00478   int position;
00479 
00480   /* Iterate through the 4 slider bars and calculate the current value divided by
00481    * the maximum value multiplied by 256.
00482    * Note that there is an offset of 1 between channelValues and interpol.
00483    * This is done to make interpolation easier.
00484    */
00485   for (i = 1; i < CAPLESENSE_NUMOF_SLIDERS + 1; i++)
00486   {
00487     /* interpol[i] will be in the range 0-256 depending on channelMax */
00488     interpol[i]  = channelValues[channelPattern[i] - 1] << 8;
00489     interpol[i] /= channelMaxValues[channelPattern[i] - 1];
00490     /* Find the minimum value and position */
00491     if (interpol[i] < minVal)
00492     {
00493       minVal = interpol[i];
00494       minPos = i;
00495     }
00496   }
00497   /* Check if the slider has not been touched */
00498   if (minPos == -1)
00499     return -1;
00500 
00501   /* Start position. Shift by 4 to get additional resolution. */
00502   /* Because of the interpol trick earlier we have to substract one to offset that effect */
00503   position = (minPos - 1) << 4;
00504 
00505   /* Interpolate with pad to the left */
00506   position -= ((256 - interpol[minPos - 1]) << 3)
00507               / (256 - interpol[minPos]);
00508 
00509   /* Interpolate with pad to the right */
00510   position += ((256 - interpol[minPos + 1]) << 3)
00511               / (256 - interpol[minPos]);
00512 
00513   return position;
00514 }
00515 
00516 
00517 /**************************************************************************/
00520 void CAPLESENSE_Sleep(void)
00521 {
00522   /* Go to EM2 and wait for the measurement to complete. */
00523   EMU_EnterEM2(true);
00524 }
00525 
00526 
00527 /**************************************************************************/
00531 void CAPLESENSE_Init(bool sleep)
00532 {
00533   /* Disable interrupts */
00534   INT_Disable();
00535 
00536   /* Setup CMU. */
00537   CAPLESENSE_setupCMU();
00538   /* Setup GPIO. */
00539   CAPLESENSE_setupGPIO();
00540   /* Setup ACMP. */
00541   CAPLESENSE_setupACMP();
00542   /* Setup LESENSE. */
00543   CAPLESENSE_setupLESENSE(sleep);
00544 
00545   /* Initialization done, enable interrupts globally. */
00546   INT_Enable();
00547 }
00548 
00549