Driver for the capacitive sense slider available on the EFM32 Giant, Wonder and Leopard starter kits.

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

Information

All examples in this repo are considered EXPERIMENTAL QUALITY, meaning this code has been created as one-off proof-of-concept and is suitable as a demonstration for experimental purposes only. This code will not be regularly maintained by Silicon Labs and there is no guarantee that these projects will work across all environments, SDK versions and hardware.

/media/uploads/stevew817/screenshot_2015-03-17_13.40.06.png

Committer:
Steven Cooreman
Date:
Mon May 04 09:37:34 2015 -0700
Revision:
3:8d096e5bc045
Parent:
0:459a1af84a64
Merge

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Steven Cooreman 0:459a1af84a64 1 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 2 * @file
Steven Cooreman 0:459a1af84a64 3 * @brief Capacitive sense driver
Steven Cooreman 0:459a1af84a64 4 * @version 3.20.9
Steven Cooreman 0:459a1af84a64 5 ******************************************************************************
Steven Cooreman 0:459a1af84a64 6 * @section License
Steven Cooreman 0:459a1af84a64 7 * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
Steven Cooreman 0:459a1af84a64 8 *******************************************************************************
Steven Cooreman 0:459a1af84a64 9 *
Steven Cooreman 0:459a1af84a64 10 * This file is licensensed under the Silabs License Agreement. See the file
Steven Cooreman 0:459a1af84a64 11 * "Silabs_License_Agreement.txt" for details. Before using this software for
Steven Cooreman 0:459a1af84a64 12 * any purpose, you must agree to the terms of that agreement.
Steven Cooreman 0:459a1af84a64 13 *
Steven Cooreman 0:459a1af84a64 14 ******************************************************************************/
Steven Cooreman 0:459a1af84a64 15
Steven Cooreman 0:459a1af84a64 16
Steven Cooreman 0:459a1af84a64 17
Steven Cooreman 0:459a1af84a64 18
Steven Cooreman 0:459a1af84a64 19 /* EM header files */
Steven Cooreman 0:459a1af84a64 20 #include "em_device.h"
Steven Cooreman 0:459a1af84a64 21
Steven Cooreman 0:459a1af84a64 22 /* Drivers */
Steven Cooreman 0:459a1af84a64 23 #include "caplesense.h"
Steven Cooreman 0:459a1af84a64 24 #include "em_emu.h"
Steven Cooreman 0:459a1af84a64 25 #include "em_acmp.h"
Steven Cooreman 0:459a1af84a64 26 #include "em_assert.h"
Steven Cooreman 0:459a1af84a64 27 #include "em_cmu.h"
Steven Cooreman 0:459a1af84a64 28 #include "em_emu.h"
Steven Cooreman 0:459a1af84a64 29 #include "em_gpio.h"
Steven Cooreman 0:459a1af84a64 30 #include "em_int.h"
Steven Cooreman 0:459a1af84a64 31 #include "em_lesense.h"
Steven Cooreman 0:459a1af84a64 32
Steven Cooreman 0:459a1af84a64 33 /* Capacitive sense configuration */
Steven Cooreman 0:459a1af84a64 34 //#include "caplesenseconfig.h"
Steven Cooreman 0:459a1af84a64 35 // ^^ Already included through caplesense.h ^^
Steven Cooreman 0:459a1af84a64 36
Steven Cooreman 0:459a1af84a64 37 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 38 * @brief This vector stores the latest read values from LESENSE
Steven Cooreman 0:459a1af84a64 39 * @param LESENSE_CHANNELS Vector of channels.
Steven Cooreman 0:459a1af84a64 40 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 41 static volatile uint32_t channelValues[LESENSE_CHANNELS] =
Steven Cooreman 0:459a1af84a64 42 {
Steven Cooreman 0:459a1af84a64 43 /* Ch0, Ch1, Ch2, Ch3, Ch4, Ch5, Ch6, Ch7 */
Steven Cooreman 0:459a1af84a64 44 0, 0, 0, 0, 0, 0, 0, 0,
Steven Cooreman 0:459a1af84a64 45 /* Ch8, Ch9, Ch10, Ch11, Ch12, Ch13, Ch14, Ch15 */
Steven Cooreman 0:459a1af84a64 46 0, 0, 0, 0, 0, 0, 0, 0
Steven Cooreman 0:459a1af84a64 47 };
Steven Cooreman 0:459a1af84a64 48
Steven Cooreman 0:459a1af84a64 49
Steven Cooreman 0:459a1af84a64 50 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 51 * @brief This stores the maximum values seen by a channel
Steven Cooreman 0:459a1af84a64 52 * @param LESENSE_CHANNELS Vector of channels.
Steven Cooreman 0:459a1af84a64 53 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 54 static volatile uint32_t channelMaxValues[LESENSE_CHANNELS] =
Steven Cooreman 0:459a1af84a64 55 {
Steven Cooreman 0:459a1af84a64 56 /* Ch0, Ch1, Ch2, Ch3, Ch4, Ch5, Ch6, Ch7 */
Steven Cooreman 0:459a1af84a64 57 1, 1, 1, 1, 1, 1, 1, 1,
Steven Cooreman 0:459a1af84a64 58 /* Ch8, Ch9, Ch11, Ch11, Ch12, Ch13, Ch14, Ch15 */
Steven Cooreman 0:459a1af84a64 59 1, 1, 1, 1, 1, 1, 1, 1
Steven Cooreman 0:459a1af84a64 60 };
Steven Cooreman 0:459a1af84a64 61
Steven Cooreman 0:459a1af84a64 62 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 63 * @brief A bit vector which represents the channels to iterate through
Steven Cooreman 0:459a1af84a64 64 * @param LESENSE_CHANNELS Vector of channels.
Steven Cooreman 0:459a1af84a64 65 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 66 static const bool channelsInUse[LESENSE_CHANNELS] = LESENSE_CAPSENSE_CH_IN_USE;
Steven Cooreman 0:459a1af84a64 67 static bool init = true;
Steven Cooreman 0:459a1af84a64 68
Steven Cooreman 0:459a1af84a64 69 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 70 * Prototypes
Steven Cooreman 0:459a1af84a64 71 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 72 void CAPLESENSE_setupCMU(void);
Steven Cooreman 0:459a1af84a64 73 void CAPLESENSE_setupGPIO(void);
Steven Cooreman 0:459a1af84a64 74 void CAPLESENSE_setupACMP(void);
Steven Cooreman 0:459a1af84a64 75
Steven Cooreman 0:459a1af84a64 76
Steven Cooreman 0:459a1af84a64 77 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 78 * Local variables
Steven Cooreman 0:459a1af84a64 79 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 80 /** Callback function for LESENSE interrupts. */
Steven Cooreman 0:459a1af84a64 81 static void (*lesenseScanCb)(void);
Steven Cooreman 0:459a1af84a64 82 /** Callback function for LESENSE interrupts. */
Steven Cooreman 0:459a1af84a64 83 static void (*lesenseChCb)(void);
Steven Cooreman 0:459a1af84a64 84
Steven Cooreman 0:459a1af84a64 85 /** The current channel we are sensing */
Steven Cooreman 0:459a1af84a64 86 static volatile uint8_t currentChannel;
Steven Cooreman 0:459a1af84a64 87
Steven Cooreman 0:459a1af84a64 88
Steven Cooreman 0:459a1af84a64 89
Steven Cooreman 0:459a1af84a64 90 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 91 * @brief Setup the CMU
Steven Cooreman 0:459a1af84a64 92 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 93 void CAPLESENSE_setupCMU(void)
Steven Cooreman 0:459a1af84a64 94 {
Steven Cooreman 0:459a1af84a64 95 /* Ensure core frequency has been updated */
Steven Cooreman 0:459a1af84a64 96 SystemCoreClockUpdate();
Steven Cooreman 0:459a1af84a64 97
Steven Cooreman 0:459a1af84a64 98 /* Enable HF peripheral clock. */
Steven Cooreman 0:459a1af84a64 99 CMU_ClockEnable(cmuClock_HFPER, 1);
Steven Cooreman 0:459a1af84a64 100 /* Enable clock for GPIO. */
Steven Cooreman 0:459a1af84a64 101 CMU_ClockEnable(cmuClock_GPIO, 1);
Steven Cooreman 0:459a1af84a64 102 /* Enable clock for ACMP0. */
Steven Cooreman 0:459a1af84a64 103 CMU_ClockEnable(cmuClock_ACMP0, 1);
Steven Cooreman 0:459a1af84a64 104 /* Enable clock for ACMP1. */
Steven Cooreman 0:459a1af84a64 105 CMU_ClockEnable(cmuClock_ACMP1, 1);
Steven Cooreman 0:459a1af84a64 106 /* Enable CORELE clock. */
Steven Cooreman 0:459a1af84a64 107 CMU_ClockEnable(cmuClock_CORELE, 1);
Steven Cooreman 0:459a1af84a64 108 /* Enable clock for LESENSE. */
Steven Cooreman 0:459a1af84a64 109 CMU_ClockEnable(cmuClock_LESENSE, 1);
Steven Cooreman 0:459a1af84a64 110
Steven Cooreman 0:459a1af84a64 111 /* Enable clock divider for LESENSE. */
Steven Cooreman 0:459a1af84a64 112 CMU_ClockDivSet(cmuClock_LESENSE, cmuClkDiv_1);
Steven Cooreman 0:459a1af84a64 113 }
Steven Cooreman 0:459a1af84a64 114
Steven Cooreman 0:459a1af84a64 115
Steven Cooreman 0:459a1af84a64 116 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 117 * @brief Setup the GPIO
Steven Cooreman 0:459a1af84a64 118 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 119 void CAPLESENSE_setupGPIO(void)
Steven Cooreman 0:459a1af84a64 120 {
Steven Cooreman 0:459a1af84a64 121 /* Configure the drive strength of the ports for the light sensor. */
Steven Cooreman 0:459a1af84a64 122 GPIO_DriveModeSet(CAPLESENSE_SLIDER_PORT0, gpioDriveModeStandard);
Steven Cooreman 0:459a1af84a64 123
Steven Cooreman 0:459a1af84a64 124 /* Initialize the 4 GPIO pins of the touch slider for using them as LESENSE
Steven Cooreman 0:459a1af84a64 125 * scan channels for capacitive sensing. */
Steven Cooreman 0:459a1af84a64 126 GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER0_PIN, gpioModeDisabled, 0);
Steven Cooreman 0:459a1af84a64 127 GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER1_PIN, gpioModeDisabled, 0);
Steven Cooreman 0:459a1af84a64 128 GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER2_PIN, gpioModeDisabled, 0);
Steven Cooreman 0:459a1af84a64 129 GPIO_PinModeSet(CAPLESENSE_SLIDER_PORT0, CAPLESENSE_SLIDER3_PIN, gpioModeDisabled, 0);
Steven Cooreman 0:459a1af84a64 130 }
Steven Cooreman 0:459a1af84a64 131
Steven Cooreman 0:459a1af84a64 132
Steven Cooreman 0:459a1af84a64 133 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 134 * @brief Setup the ACMP
Steven Cooreman 0:459a1af84a64 135 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 136 void CAPLESENSE_setupACMP(void)
Steven Cooreman 0:459a1af84a64 137 {
Steven Cooreman 0:459a1af84a64 138 /* ACMP capsense configuration constant table. */
Steven Cooreman 0:459a1af84a64 139 static const ACMP_CapsenseInit_TypeDef initACMP =
Steven Cooreman 0:459a1af84a64 140 {
Steven Cooreman 0:459a1af84a64 141 .fullBias = false,
Steven Cooreman 0:459a1af84a64 142 .halfBias = false,
Steven Cooreman 0:459a1af84a64 143 .biasProg = 0x7,
Steven Cooreman 0:459a1af84a64 144 .warmTime = acmpWarmTime512,
Steven Cooreman 0:459a1af84a64 145 .hysteresisLevel = acmpHysteresisLevel7,
Steven Cooreman 0:459a1af84a64 146 .resistor = acmpResistor0,
Steven Cooreman 0:459a1af84a64 147 .lowPowerReferenceEnabled = false,
Steven Cooreman 0:459a1af84a64 148 .vddLevel = 0x3D,
Steven Cooreman 0:459a1af84a64 149 .enable = false
Steven Cooreman 0:459a1af84a64 150 };
Steven Cooreman 0:459a1af84a64 151
Steven Cooreman 0:459a1af84a64 152
Steven Cooreman 0:459a1af84a64 153 /* Configure ACMP locations, ACMP output to pin disabled. */
Steven Cooreman 0:459a1af84a64 154 ACMP_GPIOSetup(ACMP0, 0, false, false);
Steven Cooreman 0:459a1af84a64 155 ACMP_GPIOSetup(ACMP1, 0, false, false);
Steven Cooreman 0:459a1af84a64 156
Steven Cooreman 0:459a1af84a64 157 /* Initialize ACMPs in capacitive sense mode. */
Steven Cooreman 0:459a1af84a64 158 ACMP_CapsenseInit(ACMP0, &initACMP);
Steven Cooreman 0:459a1af84a64 159 ACMP_CapsenseInit(ACMP1, &initACMP);
Steven Cooreman 0:459a1af84a64 160
Steven Cooreman 0:459a1af84a64 161 /* Don't enable ACMP, LESENSE controls it! */
Steven Cooreman 0:459a1af84a64 162 }
Steven Cooreman 0:459a1af84a64 163
Steven Cooreman 0:459a1af84a64 164
Steven Cooreman 0:459a1af84a64 165 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 166 * @brief Setup the LESENSE for capavitive sensing
Steven Cooreman 0:459a1af84a64 167 * @param sleep If true, go into sleep mode.
Steven Cooreman 0:459a1af84a64 168 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 169 void CAPLESENSE_setupLESENSE(bool sleep)
Steven Cooreman 0:459a1af84a64 170 {
Steven Cooreman 0:459a1af84a64 171 uint8_t i;
Steven Cooreman 0:459a1af84a64 172
Steven Cooreman 0:459a1af84a64 173 /* Array for storing the calibration values. */
Steven Cooreman 0:459a1af84a64 174 static uint16_t capsenseCalibrateVals[4];
Steven Cooreman 0:459a1af84a64 175
Steven Cooreman 0:459a1af84a64 176 /* LESENSE channel configuration constant table in sense mode. */
Steven Cooreman 0:459a1af84a64 177 static const LESENSE_ChAll_TypeDef initChsSense = LESENSE_CAPSENSE_SCAN_CONF_SENSE;
Steven Cooreman 0:459a1af84a64 178 /* LESENSE channel configuration constant table in sleep mode. */
Steven Cooreman 0:459a1af84a64 179 static const LESENSE_ChAll_TypeDef initChsSleep = LESENSE_CAPSENSE_SCAN_CONF_SLEEP;
Steven Cooreman 0:459a1af84a64 180 /* LESENSE central configuration constant table. */
Steven Cooreman 0:459a1af84a64 181 static const LESENSE_Init_TypeDef initLESENSE =
Steven Cooreman 0:459a1af84a64 182 {
Steven Cooreman 0:459a1af84a64 183 .coreCtrl =
Steven Cooreman 0:459a1af84a64 184 {
Steven Cooreman 0:459a1af84a64 185 .scanStart = lesenseScanStartPeriodic,
Steven Cooreman 0:459a1af84a64 186 .prsSel = lesensePRSCh0,
Steven Cooreman 0:459a1af84a64 187 .scanConfSel = lesenseScanConfDirMap,
Steven Cooreman 0:459a1af84a64 188 .invACMP0 = false,
Steven Cooreman 0:459a1af84a64 189 .invACMP1 = false,
Steven Cooreman 0:459a1af84a64 190 .dualSample = false,
Steven Cooreman 0:459a1af84a64 191 .storeScanRes = false,
Steven Cooreman 0:459a1af84a64 192 .bufOverWr = true,
Steven Cooreman 0:459a1af84a64 193 .bufTrigLevel = lesenseBufTrigHalf,
Steven Cooreman 0:459a1af84a64 194 .wakeupOnDMA = lesenseDMAWakeUpDisable,
Steven Cooreman 0:459a1af84a64 195 .biasMode = lesenseBiasModeDutyCycle,
Steven Cooreman 0:459a1af84a64 196 .debugRun = false
Steven Cooreman 0:459a1af84a64 197 },
Steven Cooreman 0:459a1af84a64 198
Steven Cooreman 0:459a1af84a64 199 .timeCtrl =
Steven Cooreman 0:459a1af84a64 200 {
Steven Cooreman 0:459a1af84a64 201 .startDelay = 0U
Steven Cooreman 0:459a1af84a64 202 },
Steven Cooreman 0:459a1af84a64 203
Steven Cooreman 0:459a1af84a64 204 .perCtrl =
Steven Cooreman 0:459a1af84a64 205 {
Steven Cooreman 0:459a1af84a64 206 .dacCh0Data = lesenseDACIfData,
Steven Cooreman 0:459a1af84a64 207 .dacCh0ConvMode = lesenseDACConvModeDisable,
Steven Cooreman 0:459a1af84a64 208 .dacCh0OutMode = lesenseDACOutModeDisable,
Steven Cooreman 0:459a1af84a64 209 .dacCh1Data = lesenseDACIfData,
Steven Cooreman 0:459a1af84a64 210 .dacCh1ConvMode = lesenseDACConvModeDisable,
Steven Cooreman 0:459a1af84a64 211 .dacCh1OutMode = lesenseDACOutModeDisable,
Steven Cooreman 0:459a1af84a64 212 .dacPresc = 0U,
Steven Cooreman 0:459a1af84a64 213 .dacRef = lesenseDACRefBandGap,
Steven Cooreman 0:459a1af84a64 214 .acmp0Mode = lesenseACMPModeMuxThres,
Steven Cooreman 0:459a1af84a64 215 .acmp1Mode = lesenseACMPModeMuxThres,
Steven Cooreman 0:459a1af84a64 216 .warmupMode = lesenseWarmupModeNormal
Steven Cooreman 0:459a1af84a64 217 },
Steven Cooreman 0:459a1af84a64 218
Steven Cooreman 0:459a1af84a64 219 .decCtrl =
Steven Cooreman 0:459a1af84a64 220 {
Steven Cooreman 0:459a1af84a64 221 .decInput = lesenseDecInputSensorSt,
Steven Cooreman 0:459a1af84a64 222 .chkState = false,
Steven Cooreman 0:459a1af84a64 223 .intMap = true,
Steven Cooreman 0:459a1af84a64 224 .hystPRS0 = false,
Steven Cooreman 0:459a1af84a64 225 .hystPRS1 = false,
Steven Cooreman 0:459a1af84a64 226 .hystPRS2 = false,
Steven Cooreman 0:459a1af84a64 227 .hystIRQ = false,
Steven Cooreman 0:459a1af84a64 228 .prsCount = true,
Steven Cooreman 0:459a1af84a64 229 .prsChSel0 = lesensePRSCh0,
Steven Cooreman 0:459a1af84a64 230 .prsChSel1 = lesensePRSCh1,
Steven Cooreman 0:459a1af84a64 231 .prsChSel2 = lesensePRSCh2,
Steven Cooreman 0:459a1af84a64 232 .prsChSel3 = lesensePRSCh3
Steven Cooreman 0:459a1af84a64 233 }
Steven Cooreman 0:459a1af84a64 234 };
Steven Cooreman 0:459a1af84a64 235
Steven Cooreman 0:459a1af84a64 236 /* Only initialize main LESENSE parameters once. */
Steven Cooreman 0:459a1af84a64 237 if (init)
Steven Cooreman 0:459a1af84a64 238 {
Steven Cooreman 0:459a1af84a64 239 /* Initialize LESENSE interface with RESET. */
Steven Cooreman 0:459a1af84a64 240 LESENSE_Init(&initLESENSE, true);
Steven Cooreman 0:459a1af84a64 241 }
Steven Cooreman 0:459a1af84a64 242
Steven Cooreman 0:459a1af84a64 243 /* Different configuration for "sleep" and "sense" modes. */
Steven Cooreman 0:459a1af84a64 244 if (sleep)
Steven Cooreman 0:459a1af84a64 245 {
Steven Cooreman 0:459a1af84a64 246 /* Stop LESENSE before configuration. */
Steven Cooreman 0:459a1af84a64 247 LESENSE_ScanStop();
Steven Cooreman 0:459a1af84a64 248
Steven Cooreman 0:459a1af84a64 249 /* Wait until the currently active scan is finished. */
Steven Cooreman 0:459a1af84a64 250 while (LESENSE_STATUS_SCANACTIVE & LESENSE_StatusGet()) ;
Steven Cooreman 0:459a1af84a64 251
Steven Cooreman 0:459a1af84a64 252 /* Clear result buffer. */
Steven Cooreman 0:459a1af84a64 253 LESENSE_ResultBufferClear();
Steven Cooreman 0:459a1af84a64 254
Steven Cooreman 0:459a1af84a64 255 /* Set scan frequency (in Hz). */
Steven Cooreman 0:459a1af84a64 256 (void) LESENSE_ScanFreqSet(0U, 4U);
Steven Cooreman 0:459a1af84a64 257
Steven Cooreman 0:459a1af84a64 258 /* Set clock divisor for LF clock. */
Steven Cooreman 0:459a1af84a64 259 LESENSE_ClkDivSet(lesenseClkLF, lesenseClkDiv_1);
Steven Cooreman 0:459a1af84a64 260
Steven Cooreman 0:459a1af84a64 261 /* Configure scan channels. */
Steven Cooreman 0:459a1af84a64 262 LESENSE_ChannelAllConfig(&initChsSleep);
Steven Cooreman 0:459a1af84a64 263
Steven Cooreman 0:459a1af84a64 264 /* Restore calibration values. */
Steven Cooreman 0:459a1af84a64 265 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER0_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[0]);
Steven Cooreman 0:459a1af84a64 266 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER1_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[1]);
Steven Cooreman 0:459a1af84a64 267 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER2_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[2]);
Steven Cooreman 0:459a1af84a64 268 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER3_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[3]);
Steven Cooreman 0:459a1af84a64 269
Steven Cooreman 0:459a1af84a64 270 /* Disable scan complete interrupt. */
Steven Cooreman 0:459a1af84a64 271 LESENSE_IntDisable(LESENSE_IEN_SCANCOMPLETE);
Steven Cooreman 0:459a1af84a64 272 }
Steven Cooreman 0:459a1af84a64 273 else
Steven Cooreman 0:459a1af84a64 274 {
Steven Cooreman 0:459a1af84a64 275 /* Stop LESENSE before configuration. */
Steven Cooreman 0:459a1af84a64 276 LESENSE_ScanStop();
Steven Cooreman 0:459a1af84a64 277
Steven Cooreman 0:459a1af84a64 278 /* Wait until the currently active scan is finished. */
Steven Cooreman 0:459a1af84a64 279 while (LESENSE_STATUS_SCANACTIVE & LESENSE_StatusGet()) ;
Steven Cooreman 0:459a1af84a64 280
Steven Cooreman 0:459a1af84a64 281 /* Clean scan complete interrupt flag. */
Steven Cooreman 0:459a1af84a64 282 LESENSE_IntClear(LESENSE_IEN_SCANCOMPLETE);
Steven Cooreman 0:459a1af84a64 283
Steven Cooreman 0:459a1af84a64 284 /* Clear result buffer. */
Steven Cooreman 0:459a1af84a64 285 LESENSE_ResultBufferClear();
Steven Cooreman 0:459a1af84a64 286
Steven Cooreman 0:459a1af84a64 287 /* Set scan frequency (in Hz). */
Steven Cooreman 0:459a1af84a64 288 (void) LESENSE_ScanFreqSet(0U, 5U);
Steven Cooreman 0:459a1af84a64 289
Steven Cooreman 0:459a1af84a64 290 /* Set clock divisor for LF clock. */
Steven Cooreman 0:459a1af84a64 291 LESENSE_ClkDivSet(lesenseClkLF, lesenseClkDiv_8);
Steven Cooreman 0:459a1af84a64 292
Steven Cooreman 0:459a1af84a64 293 /* Configure scan channels. */
Steven Cooreman 0:459a1af84a64 294 LESENSE_ChannelAllConfig(&initChsSense);
Steven Cooreman 0:459a1af84a64 295
Steven Cooreman 0:459a1af84a64 296 /* Enable scan complete interrupt. */
Steven Cooreman 0:459a1af84a64 297 LESENSE_IntEnable(LESENSE_IEN_SCANCOMPLETE);
Steven Cooreman 0:459a1af84a64 298 }
Steven Cooreman 0:459a1af84a64 299
Steven Cooreman 0:459a1af84a64 300 /* Enable LESENSE interrupt in NVIC. */
Steven Cooreman 0:459a1af84a64 301 NVIC_SetPriority(LESENSE_IRQn, 2);
Steven Cooreman 0:459a1af84a64 302 NVIC_EnableIRQ(LESENSE_IRQn);
Steven Cooreman 0:459a1af84a64 303
Steven Cooreman 0:459a1af84a64 304 /* Start scanning LESENSE channels. */
Steven Cooreman 0:459a1af84a64 305 LESENSE_ScanStart();
Steven Cooreman 0:459a1af84a64 306
Steven Cooreman 0:459a1af84a64 307 /* Run it only once. */
Steven Cooreman 0:459a1af84a64 308 if (init)
Steven Cooreman 0:459a1af84a64 309 {
Steven Cooreman 0:459a1af84a64 310 /* Assuming that the pads are not touched at first, we can use the result as
Steven Cooreman 0:459a1af84a64 311 * the threshold value to calibrate the capacitive sensing in LESENSE. */
Steven Cooreman 0:459a1af84a64 312 init = false;
Steven Cooreman 0:459a1af84a64 313
Steven Cooreman 0:459a1af84a64 314 /* Waiting for buffer to be full. */
Steven Cooreman 0:459a1af84a64 315 while (!(LESENSE->STATUS & LESENSE_STATUS_BUFHALFFULL)) ;
Steven Cooreman 0:459a1af84a64 316
Steven Cooreman 0:459a1af84a64 317 /* Read out steady state values from LESENSE for calibration. */
Steven Cooreman 0:459a1af84a64 318 for (i = 0U; i < CAPLESENSE_NUMOF_SLIDERS; i++)
Steven Cooreman 0:459a1af84a64 319 {
Steven Cooreman 0:459a1af84a64 320 capsenseCalibrateVals[i] = LESENSE_ScanResultDataBufferGet(i) - CAPLESENSE_SENSITIVITY_OFFS;
Steven Cooreman 0:459a1af84a64 321 }
Steven Cooreman 0:459a1af84a64 322
Steven Cooreman 0:459a1af84a64 323 /* Set calibration values. */
Steven Cooreman 0:459a1af84a64 324 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER0_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[0]);
Steven Cooreman 0:459a1af84a64 325 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER1_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[1]);
Steven Cooreman 0:459a1af84a64 326 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER2_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[2]);
Steven Cooreman 0:459a1af84a64 327 LESENSE_ChannelThresSet(CAPLESENSE_SLIDER3_PIN, CAPLESENSE_ACMP_VDD_SCALE, capsenseCalibrateVals[3]);
Steven Cooreman 0:459a1af84a64 328 }
Steven Cooreman 0:459a1af84a64 329 }
Steven Cooreman 0:459a1af84a64 330
Steven Cooreman 0:459a1af84a64 331
Steven Cooreman 0:459a1af84a64 332 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 333 * @brief LESENSE callback setup
Steven Cooreman 0:459a1af84a64 334 * @param scanCb Scan callback
Steven Cooreman 0:459a1af84a64 335 * @param chCb Channel callback
Steven Cooreman 0:459a1af84a64 336 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 337 void CAPLESENSE_setupCallbacks(void (*scanCb)(void), void (*chCb)(void))
Steven Cooreman 0:459a1af84a64 338 {
Steven Cooreman 0:459a1af84a64 339 lesenseScanCb = scanCb;
Steven Cooreman 0:459a1af84a64 340 lesenseChCb = chCb;
Steven Cooreman 0:459a1af84a64 341 }
Steven Cooreman 0:459a1af84a64 342
Steven Cooreman 0:459a1af84a64 343
Steven Cooreman 0:459a1af84a64 344 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 345 * @brief LESENSE interrupt handler
Steven Cooreman 0:459a1af84a64 346 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 347 void LESENSE_IRQHandler(void)
Steven Cooreman 0:459a1af84a64 348 {
Steven Cooreman 0:459a1af84a64 349 uint32_t count;
Steven Cooreman 0:459a1af84a64 350
Steven Cooreman 0:459a1af84a64 351
Steven Cooreman 0:459a1af84a64 352 /* LESENSE scan complete interrupt. */
Steven Cooreman 0:459a1af84a64 353 if (LESENSE_IF_SCANCOMPLETE & LESENSE_IntGetEnabled())
Steven Cooreman 0:459a1af84a64 354 {
Steven Cooreman 0:459a1af84a64 355 LESENSE_IntClear(LESENSE_IF_SCANCOMPLETE);
Steven Cooreman 0:459a1af84a64 356
Steven Cooreman 0:459a1af84a64 357 /* Iterate trough all channels */
Steven Cooreman 0:459a1af84a64 358 for (currentChannel = 0; currentChannel < LESENSE_CHANNELS; currentChannel++)
Steven Cooreman 0:459a1af84a64 359 {
Steven Cooreman 0:459a1af84a64 360 /* If this channel is not in use, skip to the next one */
Steven Cooreman 0:459a1af84a64 361 if (!channelsInUse[currentChannel])
Steven Cooreman 0:459a1af84a64 362 {
Steven Cooreman 0:459a1af84a64 363 continue;
Steven Cooreman 0:459a1af84a64 364 }
Steven Cooreman 0:459a1af84a64 365
Steven Cooreman 0:459a1af84a64 366 /* Read out value from LESENSE buffer */
Steven Cooreman 0:459a1af84a64 367 count = LESENSE_ScanResultDataGet();
Steven Cooreman 0:459a1af84a64 368
Steven Cooreman 0:459a1af84a64 369 /* Store value in channelValues */
Steven Cooreman 0:459a1af84a64 370 channelValues[currentChannel] = count;
Steven Cooreman 0:459a1af84a64 371
Steven Cooreman 0:459a1af84a64 372 /* Update channelMaxValues */
Steven Cooreman 0:459a1af84a64 373 if (count > channelMaxValues[currentChannel])
Steven Cooreman 0:459a1af84a64 374 {
Steven Cooreman 0:459a1af84a64 375 channelMaxValues[currentChannel] = count;
Steven Cooreman 0:459a1af84a64 376 }
Steven Cooreman 0:459a1af84a64 377 }
Steven Cooreman 0:459a1af84a64 378
Steven Cooreman 0:459a1af84a64 379 /* Call callback function. */
Steven Cooreman 0:459a1af84a64 380 if (lesenseScanCb != 0x00000000)
Steven Cooreman 0:459a1af84a64 381 {
Steven Cooreman 0:459a1af84a64 382 lesenseScanCb();
Steven Cooreman 0:459a1af84a64 383 }
Steven Cooreman 0:459a1af84a64 384 }
Steven Cooreman 0:459a1af84a64 385
Steven Cooreman 0:459a1af84a64 386 /* LESENSE channel interrupt. */
Steven Cooreman 0:459a1af84a64 387 if (CAPLESENSE_CHANNEL_INT & LESENSE_IntGetEnabled())
Steven Cooreman 0:459a1af84a64 388 {
Steven Cooreman 0:459a1af84a64 389 /* Clear flags. */
Steven Cooreman 0:459a1af84a64 390 LESENSE_IntClear(CAPLESENSE_CHANNEL_INT);
Steven Cooreman 0:459a1af84a64 391
Steven Cooreman 0:459a1af84a64 392 /* Call callback function. */
Steven Cooreman 0:459a1af84a64 393 if (lesenseChCb != 0x00000000)
Steven Cooreman 0:459a1af84a64 394 {
Steven Cooreman 0:459a1af84a64 395 lesenseChCb();
Steven Cooreman 0:459a1af84a64 396 }
Steven Cooreman 0:459a1af84a64 397 }
Steven Cooreman 0:459a1af84a64 398 }
Steven Cooreman 0:459a1af84a64 399
Steven Cooreman 0:459a1af84a64 400
Steven Cooreman 0:459a1af84a64 401 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 402 * @brief Get the channelValue for a sensor segment
Steven Cooreman 0:459a1af84a64 403 * @param capSegment
Steven Cooreman 0:459a1af84a64 404 * @return channel
Steven Cooreman 0:459a1af84a64 405 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 406 uint8_t CAPLESENSE_getSegmentChannel(uint8_t capSegment)
Steven Cooreman 0:459a1af84a64 407 {
Steven Cooreman 0:459a1af84a64 408 uint8_t channel;
Steven Cooreman 0:459a1af84a64 409
Steven Cooreman 0:459a1af84a64 410 switch (capSegment)
Steven Cooreman 0:459a1af84a64 411 {
Steven Cooreman 0:459a1af84a64 412 case(0):
Steven Cooreman 0:459a1af84a64 413 channel = SLIDER_PART0_CHANNEL;
Steven Cooreman 0:459a1af84a64 414 break;
Steven Cooreman 0:459a1af84a64 415 case(1):
Steven Cooreman 0:459a1af84a64 416 channel = SLIDER_PART1_CHANNEL;
Steven Cooreman 0:459a1af84a64 417 break;
Steven Cooreman 0:459a1af84a64 418 case(2):
Steven Cooreman 0:459a1af84a64 419 channel = SLIDER_PART2_CHANNEL;
Steven Cooreman 0:459a1af84a64 420 break;
Steven Cooreman 0:459a1af84a64 421 default:
Steven Cooreman 0:459a1af84a64 422 channel = SLIDER_PART3_CHANNEL;
Steven Cooreman 0:459a1af84a64 423 break;
Steven Cooreman 0:459a1af84a64 424 }
Steven Cooreman 0:459a1af84a64 425 return channel;
Steven Cooreman 0:459a1af84a64 426
Steven Cooreman 0:459a1af84a64 427 }
Steven Cooreman 0:459a1af84a64 428
Steven Cooreman 0:459a1af84a64 429
Steven Cooreman 0:459a1af84a64 430 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 431 * @brief Get the current channelValue for a channel
Steven Cooreman 0:459a1af84a64 432 * @param channel The channel.
Steven Cooreman 0:459a1af84a64 433 * @return The channelValue.
Steven Cooreman 0:459a1af84a64 434 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 435 uint32_t CAPLESENSE_getVal(uint8_t channel)
Steven Cooreman 0:459a1af84a64 436 {
Steven Cooreman 0:459a1af84a64 437 return channelValues[channel];
Steven Cooreman 0:459a1af84a64 438 }
Steven Cooreman 0:459a1af84a64 439
Steven Cooreman 0:459a1af84a64 440 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 441 * @brief Get the current normalized channelValue for a channel
Steven Cooreman 0:459a1af84a64 442 * @param channel The channel.
Steven Cooreman 0:459a1af84a64 443 * @return The channel value in range (0-256).
Steven Cooreman 0:459a1af84a64 444 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 445 uint32_t CAPLESENSE_getNormalizedVal(uint8_t channel)
Steven Cooreman 0:459a1af84a64 446 {
Steven Cooreman 0:459a1af84a64 447 uint32_t max = channelMaxValues[channel];
Steven Cooreman 0:459a1af84a64 448 return (channelValues[channel] << 8) / max;
Steven Cooreman 0:459a1af84a64 449 }
Steven Cooreman 0:459a1af84a64 450
Steven Cooreman 0:459a1af84a64 451
Steven Cooreman 0:459a1af84a64 452
Steven Cooreman 0:459a1af84a64 453 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 454 * @brief Get the position of the slider
Steven Cooreman 0:459a1af84a64 455 * @return The position of the slider if it can be determined,
Steven Cooreman 0:459a1af84a64 456 * -1 otherwise.
Steven Cooreman 0:459a1af84a64 457 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 458 int32_t CAPLESENSE_getSliderPosition(void)
Steven Cooreman 0:459a1af84a64 459 {
Steven Cooreman 0:459a1af84a64 460 int i;
Steven Cooreman 0:459a1af84a64 461 int minPos = -1;
Steven Cooreman 0:459a1af84a64 462 uint32_t minVal = 236; /* adjust it */
Steven Cooreman 0:459a1af84a64 463 /* Values used for interpolation. There is two more which represents the edges.
Steven Cooreman 0:459a1af84a64 464 * This makes the interpolation code a bit cleaner as we do not have to make special
Steven Cooreman 0:459a1af84a64 465 * cases for handling them */
Steven Cooreman 0:459a1af84a64 466 uint32_t interpol[6] = { 255, 255, 255, 255, 255, 255 };
Steven Cooreman 0:459a1af84a64 467 uint32_t channelPattern[] = { 0, SLIDER_PART0_CHANNEL + 1,
Steven Cooreman 0:459a1af84a64 468 SLIDER_PART1_CHANNEL + 1,
Steven Cooreman 0:459a1af84a64 469 SLIDER_PART2_CHANNEL + 1,
Steven Cooreman 0:459a1af84a64 470 SLIDER_PART3_CHANNEL + 1 };
Steven Cooreman 0:459a1af84a64 471
Steven Cooreman 0:459a1af84a64 472 /* The calculated slider position. */
Steven Cooreman 0:459a1af84a64 473 int position;
Steven Cooreman 0:459a1af84a64 474
Steven Cooreman 0:459a1af84a64 475 /* Iterate through the 4 slider bars and calculate the current value divided by
Steven Cooreman 0:459a1af84a64 476 * the maximum value multiplied by 256.
Steven Cooreman 0:459a1af84a64 477 * Note that there is an offset of 1 between channelValues and interpol.
Steven Cooreman 0:459a1af84a64 478 * This is done to make interpolation easier.
Steven Cooreman 0:459a1af84a64 479 */
Steven Cooreman 0:459a1af84a64 480 for (i = 1; i < CAPLESENSE_NUMOF_SLIDERS + 1; i++)
Steven Cooreman 0:459a1af84a64 481 {
Steven Cooreman 0:459a1af84a64 482 /* interpol[i] will be in the range 0-256 depending on channelMax */
Steven Cooreman 0:459a1af84a64 483 interpol[i] = channelValues[channelPattern[i] - 1] << 8;
Steven Cooreman 0:459a1af84a64 484 interpol[i] /= channelMaxValues[channelPattern[i] - 1];
Steven Cooreman 0:459a1af84a64 485 /* Find the minimum value and position */
Steven Cooreman 0:459a1af84a64 486 if (interpol[i] < minVal)
Steven Cooreman 0:459a1af84a64 487 {
Steven Cooreman 0:459a1af84a64 488 minVal = interpol[i];
Steven Cooreman 0:459a1af84a64 489 minPos = i;
Steven Cooreman 0:459a1af84a64 490 }
Steven Cooreman 0:459a1af84a64 491 }
Steven Cooreman 0:459a1af84a64 492 /* Check if the slider has not been touched */
Steven Cooreman 0:459a1af84a64 493 if (minPos == -1)
Steven Cooreman 0:459a1af84a64 494 return -1;
Steven Cooreman 0:459a1af84a64 495
Steven Cooreman 0:459a1af84a64 496 /* Start position. Shift by 4 to get additional resolution. */
Steven Cooreman 0:459a1af84a64 497 /* Because of the interpol trick earlier we have to substract one to offset that effect */
Steven Cooreman 0:459a1af84a64 498 position = (minPos - 1) << 4;
Steven Cooreman 0:459a1af84a64 499
Steven Cooreman 0:459a1af84a64 500 /* Interpolate with pad to the left */
Steven Cooreman 0:459a1af84a64 501 position -= ((256 - interpol[minPos - 1]) << 3)
Steven Cooreman 0:459a1af84a64 502 / (256 - interpol[minPos]);
Steven Cooreman 0:459a1af84a64 503
Steven Cooreman 0:459a1af84a64 504 /* Interpolate with pad to the right */
Steven Cooreman 0:459a1af84a64 505 position += ((256 - interpol[minPos + 1]) << 3)
Steven Cooreman 0:459a1af84a64 506 / (256 - interpol[minPos]);
Steven Cooreman 0:459a1af84a64 507
Steven Cooreman 0:459a1af84a64 508 return position;
Steven Cooreman 0:459a1af84a64 509 }
Steven Cooreman 0:459a1af84a64 510
Steven Cooreman 0:459a1af84a64 511
Steven Cooreman 0:459a1af84a64 512 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 513 * @brief Send the capacative sense system to sleep mode.
Steven Cooreman 0:459a1af84a64 514 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 515 void CAPLESENSE_Sleep(void)
Steven Cooreman 0:459a1af84a64 516 {
Steven Cooreman 0:459a1af84a64 517 /* Go to EM2 and wait for the measurement to complete. */
Steven Cooreman 0:459a1af84a64 518 EMU_EnterEM2(true);
Steven Cooreman 0:459a1af84a64 519 }
Steven Cooreman 0:459a1af84a64 520
Steven Cooreman 0:459a1af84a64 521
Steven Cooreman 0:459a1af84a64 522 /**************************************************************************//**
Steven Cooreman 0:459a1af84a64 523 * @brief Initializes the capacative sense system without LESENSE.
Steven Cooreman 0:459a1af84a64 524 * @param sleep If true, go into sleep mode.
Steven Cooreman 0:459a1af84a64 525 *****************************************************************************/
Steven Cooreman 0:459a1af84a64 526 void CAPLESENSE_Init(bool sleep)
Steven Cooreman 0:459a1af84a64 527 {
Steven Cooreman 0:459a1af84a64 528 /* Disable interrupts */
Steven Cooreman 0:459a1af84a64 529 INT_Disable();
Steven Cooreman 0:459a1af84a64 530
Steven Cooreman 0:459a1af84a64 531 /* Setup CMU. */
Steven Cooreman 0:459a1af84a64 532 CAPLESENSE_setupCMU();
Steven Cooreman 0:459a1af84a64 533 /* Setup GPIO. */
Steven Cooreman 0:459a1af84a64 534 CAPLESENSE_setupGPIO();
Steven Cooreman 0:459a1af84a64 535 /* Setup ACMP. */
Steven Cooreman 0:459a1af84a64 536 CAPLESENSE_setupACMP();
Steven Cooreman 0:459a1af84a64 537 /* Setup LESENSE. */
Steven Cooreman 0:459a1af84a64 538 CAPLESENSE_setupLESENSE(sleep);
Steven Cooreman 0:459a1af84a64 539
Steven Cooreman 0:459a1af84a64 540 /* Initialization done, enable interrupts globally. */
Steven Cooreman 0:459a1af84a64 541 INT_Enable();
Steven Cooreman 0:459a1af84a64 542 }
Steven Cooreman 0:459a1af84a64 543
Steven Cooreman 0:459a1af84a64 544