caplesense.c

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