EFM32 Happy Gecko Software Documentation  efm32hg-doc-5.1.2
capsense.c
Go to the documentation of this file.
1 /**************************************************************************/
16 /* EM header files */
17 #include "em_device.h"
18 
19 /* Drivers */
20 #include "em_acmp.h"
21 #include "em_cmu.h"
22 #include "em_emu.h"
23 #include "capsense.h"
24 
28 static volatile uint8_t currentChannel;
30 static volatile bool measurementComplete;
31 
32 #if defined(CAPSENSE_CH_IN_USE)
33 /**************************************************************************/
44 static const bool channelsInUse[ACMP_CHANNELS] = CAPSENSE_CH_IN_USE;
45 #elif defined(CAPSENSE_CHANNELS)
46 /**************************************************************************/
57 static const ACMP_Channel_TypeDef channelList[ACMP_CHANNELS] = CAPSENSE_CHANNELS;
58 #endif
59 
60 /**************************************************************************/
64 #if !defined(NUM_SLIDER_CHANNELS)
65 #define NUM_SLIDER_CHANNELS 4
66 #endif
67 
68 /**************************************************************************/
72 static volatile uint32_t channelValues[ACMP_CHANNELS] = {0};
73 
74 /**************************************************************************/
78 static volatile uint32_t channelMaxValues[ACMP_CHANNELS] = {0};
79 
82 /**************************************************************************/
93 {
94  uint32_t count;
95 
96  /* Stop timers */
97  TIMER0->CMD = TIMER_CMD_STOP;
98  TIMER1->CMD = TIMER_CMD_STOP;
99 
100  /* Clear interrupt flag */
101  TIMER0->IFC = TIMER_IFC_OF;
102 
103  /* Read out value of TIMER1 */
104  count = TIMER1->CNT;
105 
106  /* Store value in channelValues */
107  channelValues[currentChannel] = count;
108 
109  /* Update channelMaxValues */
110  if (count > channelMaxValues[currentChannel])
112 
113  measurementComplete = true;
114 }
115 
116 /**************************************************************************/
121 uint32_t CAPSENSE_getVal(uint8_t channel)
122 {
123  return channelValues[channel];
124 }
125 
126 /**************************************************************************/
131 uint32_t CAPSENSE_getNormalizedVal(uint8_t channel)
132 {
133  uint32_t max = channelMaxValues[channel];
134  return (channelValues[channel] << 8) / max;
135 }
136 
137 /**************************************************************************/
143 bool CAPSENSE_getPressed(uint8_t channel)
144 {
145  uint32_t treshold;
146  /* Treshold is set to 12.5% below the maximum value */
147  /* This calculation is performed in two steps because channelMaxValues is
148  * volatile. */
149  treshold = channelMaxValues[channel];
150  treshold -= channelMaxValues[channel] >> 2;
151 
152  if (channelValues[channel] < treshold)
153  {
154  return true;
155  }
156  return false;
157 }
158 
159 /**************************************************************************/
165 {
166  int i;
167  int minPos = -1;
168  uint32_t minVal = 224; /* 0.875 * 256 */
169  /* Values used for interpolation. There is two more which represents the edges.
170  * This makes the interpolation code a bit cleaner as we do not have to make special
171  * cases for handling them */
172  uint32_t interpol[(NUM_SLIDER_CHANNELS+2)];
173  for (i = 0; i < (NUM_SLIDER_CHANNELS+2); i++)
174  {
175  interpol[i] = 255;
176  }
177 
178  /* The calculated slider position. */
179  int position;
180 
181  /* Iterate through the slider bars and calculate the current value divided by
182  * the maximum value multiplied by 256.
183  * Note that there is an offset of 1 between channelValues and interpol.
184  * This is done to make interpolation easier.
185  */
186  for (i = 1; i < (NUM_SLIDER_CHANNELS+1); i++)
187  {
188  /* interpol[i] will be in the range 0-256 depending on channelMax */
189  interpol[i] = channelValues[i - 1] << 8;
190  interpol[i] /= channelMaxValues[i - 1];
191  /* Find the minimum value and position */
192  if (interpol[i] < minVal)
193  {
194  minVal = interpol[i];
195  minPos = i;
196  }
197  }
198  /* Check if the slider has not been touched */
199  if (minPos == -1)
200  return -1;
201 
202  /* Start position. Shift by 4 to get additional resolution. */
203  /* Because of the interpol trick earlier we have to substract one to offset that effect */
204  position = (minPos - 1) << 4;
205 
206  /* Interpolate with pad to the left */
207  position -= ((256 - interpol[minPos - 1]) << 3)
208  / (256 - interpol[minPos]);
209 
210  /* Interpolate with pad to the right */
211  position += ((256 - interpol[minPos + 1]) << 3)
212  / (256 - interpol[minPos]);
213 
214  return position;
215 }
216 
217 /**************************************************************************/
223 {
224  /* Set up this channel in the ACMP. */
225  ACMP_CapsenseChannelSet(ACMP_CAPSENSE, channel);
226 
227  /* Reset timers */
228  TIMER0->CNT = 0;
229  TIMER1->CNT = 0;
230 
231  measurementComplete = false;
232 
233  /* Start timers */
234  TIMER0->CMD = TIMER_CMD_START;
235  TIMER1->CMD = TIMER_CMD_START;
236 
237  /* Wait for measurement to complete */
238  while ( measurementComplete == false )
239  {
240  EMU_EnterEM1();
241  }
242 }
243 
244 /**************************************************************************/
250 void CAPSENSE_Sense(void)
251 {
252  /* Use the default STK capacative sensing setup and enable it */
253  ACMP_Enable(ACMP_CAPSENSE);
254 
255 #if defined(CAPSENSE_CHANNELS)
256  /* Iterate through only the channels in the channelList */
257  for (currentChannel = 0; currentChannel < ACMP_CHANNELS; currentChannel++)
258  {
259  CAPSENSE_Measure(channelList[currentChannel]);
260  }
261 #else
262  /* Iterate through all channels and check which channel is in use */
263  for (currentChannel = 0; currentChannel < ACMP_CHANNELS; currentChannel++)
264  {
265  /* If this channel is not in use, skip to the next one */
267  {
268  continue;
269  }
270 
271  CAPSENSE_Measure((ACMP_Channel_TypeDef) currentChannel);
272  }
273 #endif
274 
275  /* Disable ACMP while not sensing to reduce power consumption */
276  ACMP_Disable(ACMP_CAPSENSE);
277 }
278 
279 /**************************************************************************/
290 void CAPSENSE_Init(void)
291 {
292  /* Use the default STK capacative sensing setup */
294 
295  /* Enable TIMER0, TIMER1, ACMP_CAPSENSE and PRS clock */
299 #if defined(ACMP_CAPSENSE_CMUCLOCK)
300  CMU_ClockEnable(ACMP_CAPSENSE_CMUCLOCK, true);
301 #else
302  CMU->HFPERCLKEN0 |= ACMP_CAPSENSE_CLKEN;
303 #endif
305 
306  /* Initialize TIMER0 - Prescaler 2^9, top value 10, interrupt on overflow */
308  TIMER0->TOP = 10;
309  TIMER0->IEN = TIMER_IEN_OF;
310  TIMER0->CNT = 0;
311 
312  /* Initialize TIMER1 - Prescaler 2^10, clock source CC1, top value 0xFFFF */
314  TIMER1->TOP = 0xFFFF;
315 
316  /*Set up TIMER1 CC1 to trigger on PRS channel 0 */
317  TIMER1->CC[1].CTRL = TIMER_CC_CTRL_MODE_INPUTCAPTURE /* Input capture */
318  | TIMER_CC_CTRL_PRSSEL_PRSCH0 /* PRS channel 0 */
319  | TIMER_CC_CTRL_INSEL_PRS /* PRS input selected */
320  | TIMER_CC_CTRL_ICEVCTRL_RISING /* PRS on rising edge */
321  | TIMER_CC_CTRL_ICEDGE_BOTH; /* PRS on rising edge */
322 
323  /*Set up PRS channel 0 to trigger on ACMP1 output*/
324  PRS->CH[0].CTRL = PRS_CH_CTRL_EDSEL_POSEDGE /* Posedge triggers action */
325  | PRS_CH_CTRL_SOURCESEL_ACMP_CAPSENSE /* PRS source */
326  | PRS_CH_CTRL_SIGSEL_ACMPOUT_CAPSENSE; /* PRS source */
327 
328  /* Set up ACMP1 in capsense mode */
329  ACMP_CapsenseInit(ACMP_CAPSENSE, &capsenseInit);
330 
331  /* Enable TIMER0 interrupt */
332  NVIC_EnableIRQ(TIMER0_IRQn);
333 }
Clock management unit (CMU) API.
#define TIMER_CTRL_CLKSEL_CC1
uint32_t CAPSENSE_getVal(uint8_t channel)
Get the current channelValue for a channel.
Definition: capsense.c:121
void ACMP_Disable(ACMP_TypeDef *acmp)
Disables the ACMP.
Definition: em_acmp.c:210
#define TIMER_CTRL_PRESC_DIV512
ACMP_Channel_TypeDef
Definition: em_acmp.h:465
Capacitive sense driver.
#define ACMP_CAPSENSE_INIT_DEFAULT
Definition: em_acmp.h:622
static volatile uint8_t currentChannel
Definition: caplesense.c:81
void ACMP_CapsenseChannelSet(ACMP_TypeDef *acmp, ACMP_Channel_TypeDef channel)
Sets the ACMP channel used for capacative sensing.
Definition: em_acmp.c:185
bool CAPSENSE_getPressed(uint8_t channel)
Get the state of the Gecko Button.
Definition: capsense.c:143
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
#define TIMER_CC_CTRL_INSEL_PRS
#define TIMER_IFC_OF
#define TIMER_CC_CTRL_ICEVCTRL_RISING
static void CAPSENSE_Measure(ACMP_Channel_TypeDef channel)
Start a capsense measurement of a specific channel and waits for it to complete.
Definition: capsense.c:222
void CAPSENSE_Init(void)
Initializes the capacitive sense system.
Definition: capsense.c:290
void ACMP_Enable(ACMP_TypeDef *acmp)
Enables the ACMP.
Definition: em_acmp.c:225
#define TIMER0
#define TIMER_CC_CTRL_PRSSEL_PRSCH0
#define TIMER_CMD_START
int32_t CAPSENSE_getSliderPosition(void)
Get the position of the slider.
Definition: capsense.c:164
#define PRS
#define PRS_CH_CTRL_EDSEL_POSEDGE
Definition: efm32hg_prs.h:301
__STATIC_INLINE void EMU_EnterEM1(void)
Enter energy mode 1 (EM1).
Definition: em_emu.h:713
void ACMP_CapsenseInit(ACMP_TypeDef *acmp, const ACMP_CapsenseInit_TypeDef *init)
Sets up the ACMP for use in capacative sense applications.
Definition: em_acmp.c:109
void TIMER0_IRQHandler(void)
TIMER0 interrupt handler.
Definition: capsense.c:92
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
Definition: em_cmu.c:1453
static const bool channelsInUse[LESENSE_CHANNELS]
A bit vector which represents the channels to iterate through.
Definition: caplesense.c:62
Analog Comparator (ACMP) peripheral API.
Energy management unit (EMU) peripheral API.
#define TIMER_CC_CTRL_MODE_INPUTCAPTURE
#define TIMER_CTRL_PRESC_DIV1024
#define TIMER_IEN_OF
#define TIMER_CC_CTRL_ICEDGE_BOTH
#define TIMER_CMD_STOP
static volatile uint32_t channelValues[LESENSE_CHANNELS]
This vector stores the latest read values from LESENSE.
Definition: caplesense.c:37
void CAPSENSE_Sense(void)
This function iterates through all the capsensors and reads and initiates a reading. Uses EM1 while waiting for the result from each sensor.
Definition: capsense.c:250
uint32_t CAPSENSE_getNormalizedVal(uint8_t channel)
Get the current normalized channelValue for a channel.
Definition: capsense.c:131
#define TIMER1
static volatile uint32_t channelMaxValues[LESENSE_CHANNELS]
This stores the maximum values seen by a channel.
Definition: caplesense.c:50
#define CMU