EFM32 Jade Gecko 12 Software Documentation  efm32jg12-doc-5.1.2
si114x_algorithm.c
1 /**************************************************************************/
16 #include "si114x_algorithm.h"
17 #include "si114x_functions.h"
18 #include "si1147_i2c.h"
19 
20 #define LED1I 0xb
21 #define LED2I 0xb
22 #define LED3I 0xb
23 #define UV_TASKLIST 0x80
24 #define GESTURE_TASKLIST 0x7
25 #define HOVER_TASKLIST 0x1
26 #define UV_IRQ_EN IE_ALS_EVRYSAMPLE
27 #define GESTURE_IRQ (IE_ALS_EVRYSAMPLE | IE_PS1_EVRYSAMPLE | IE_PS2_EVRYSAMPLE | IE_PS3_EVRYSAMPLE)
28 #define MEASRATE_FAST 320
29 #define MEASRATE_SLOW 32000
30 #define PS_HOVER_THRESHOLD 295
31 #define PS_THRESHOLD 275
32 #define SI1147_DEVICE_ID 0x47
33 
34 /*
35  The Si114x PGM toolkit functions uses a void* to pass hardware parameters
36  through to the lower level i2c functions. The struct below is passed down
37  to the low level i2c functions using that pointer.
38 */
39 static si114x_i2c_t si114x_i2c;
40 static si114x_i2c_t *si114x_handle = &si114x_i2c;
41 
42 
43 /* Function Prototypes */
44 static gesture_t ProcessSi1147Samples(Si114x_Sample_TypeDef *samples);
45 
46 /**************************************************************************/
56 int Si1147_Detect_Device(I2C_TypeDef *i2c, uint8_t addr)
57 {
58  uint8_t data;
59  si114x_handle->addr = addr;
60  si114x_handle->i2c = i2c;
62 
63  if (data == SI1147_DEVICE_ID)
64  {
65  return 1;
66  }
67  return 0;
68 }
69 
70 /**************************************************************************/
82 int Si1147_SetInterruptOutputEnable(I2C_TypeDef *i2c, uint8_t addr, int enable)
83 {
84  int retval;
85  si114x_handle->addr = addr;
86  si114x_handle->i2c = i2c;
87  if (enable)
88  {
89  retval = Si114xWriteToRegister(si114x_handle, REG_INT_CFG, ICG_INTOE);
90  }
91  else
92  {
93  retval = Si114xWriteToRegister(si114x_handle, REG_INT_CFG, 0);
94  }
95  return retval;
96 }
97 
98 /**************************************************************************/
111 int Si1147_GetInterruptOutputEnable(I2C_TypeDef *i2c, uint8_t addr, int *enable)
112 {
113  int retval = 0;
114  si114x_handle->addr = addr;
115  si114x_handle->i2c = i2c;
116  *enable = Si114xReadFromRegister(si114x_handle, REG_INT_CFG);
117  return retval;
118 }
119 
120 /**************************************************************************/
137 int Si1147_MeasureUVAndObjectPresent(I2C_TypeDef *i2c, uint8_t addr, uint16_t *uvIndex, int *objectDetect)
138 {
139  uint16_t data;
140  int retval = 0;
141  int gestureMode;
142  *objectDetect = 0;
143  si114x_handle->addr = addr;
144  si114x_handle->i2c = i2c;
145  Si1147_GetInterruptOutputEnable(i2c,addr,&gestureMode);
146  if ( !gestureMode ) /* Force only if not already running swipe detection. */
147  {
149  while ((Si114xReadFromRegister(si114x_handle, REG_IRQ_STATUS) & 1) == 0)
150  ; /*wait for measurement data */
151  }
152  data = Si114xReadFromRegister(si114x_handle, REG_AUX_DATA0); /*read sample data from si114x */
153  data |= Si114xReadFromRegister(si114x_handle, REG_AUX_DATA1) << 8;
154  /*round to nearest*/
155  *uvIndex = data + 50;
156  *uvIndex /= 100;
157 
158  if ( !gestureMode ) /* Check for object only if not already running swipe detection. */
159  {
160  data = Si114xReadFromRegister(si114x_handle, REG_PS1_DATA0); /*read sample data from si114x */
161  data |= Si114xReadFromRegister(si114x_handle, REG_PS1_DATA1) << 8;
162  if (data > PS_HOVER_THRESHOLD)
163  {
164  *objectDetect = 1;
165  }
166  }
167  /*clear irq*/
168  Si114xWriteToRegister(si114x_handle, REG_IRQ_STATUS, 0xff);
169 
170  return retval;
171 }
172 
173 /**************************************************************************/
181 static void readPSData(HANDLE si114x_handle, Si114x_Sample_TypeDef *sample)
182 {
183  /*read sample data from si114x */
184  sample->ps1 = Si114xReadFromRegister(si114x_handle, REG_PS1_DATA0);
185  sample->ps1 |= Si114xReadFromRegister(si114x_handle, REG_PS1_DATA1) << 8;
186 
187  sample->ps2 = Si114xReadFromRegister(si114x_handle, REG_PS2_DATA0);
188  sample->ps2 |= Si114xReadFromRegister(si114x_handle, REG_PS2_DATA1) << 8;
189 
190  sample->ps3 = Si114xReadFromRegister(si114x_handle, REG_PS3_DATA0);
191  sample->ps3 |= Si114xReadFromRegister(si114x_handle, REG_PS3_DATA1) << 8;
192 }
193 
194 
195 /**************************************************************************/
208 gesture_t Si1147_NewSample(I2C_TypeDef *i2c, uint8_t addr, uint32_t timestamp)
209 {
210  Si114x_Sample_TypeDef sample;
211  si114x_handle->addr = addr;
212  si114x_handle->i2c = i2c;
213  sample.timestamp = timestamp;
214  /*read sample data from si114x */
215  readPSData(si114x_handle, &sample);
216  /*clear irq*/
217  Si114xWriteToRegister(si114x_handle, REG_IRQ_STATUS, Si114xReadFromRegister(si114x_handle, REG_IRQ_STATUS));
218  /*look for gestures */
219  return ProcessSi1147Samples(&sample);
220 }
221 
222 
223 /**************************************************************************/
233 static gesture_t ProcessSi1147Samples(Si114x_Sample_TypeDef *samples)
234 {
235  u16 ps[3];
236 
237  static u32 ps_entry_time[3] = { 0, 0, 0 };
238  static u32 ps_exit_time[3] = { 0, 0, 0 };
239 
240  static u8 ps_state[3] = { 0, 0, 0 };
241 
242  u8 array_counter;
243  u32 diff_x ;
244  u32 diff_y1 ;
245  u32 diff_y2 ;
246  u32 ps_time[3] ;
247  u32 ps_avg;
248  gesture_t ret = NONE; /*gesture result return value */
249  /*save new samples into ps array */
250  ps[0] = samples->ps1;
251  ps[1] = samples->ps2;
252  ps[2] = samples->ps3;
253 
254  /* Check state of all three measurements */
255  for (array_counter = 0; array_counter < 3; array_counter++)
256  {
257  /* If measurement higher than the ps_threshold value, */
258  /* record the time of entry and change the state to look for the exit time */
259  if (ps[array_counter] >= PS_THRESHOLD)
260  {
261  if (ps_state[array_counter] == 0)
262  {
263  ps_state[array_counter] = 1;
264  ps_entry_time[array_counter] = samples->timestamp;
265  }
266  }
267  else
268  {
269  if (ps_state[array_counter] == 1)
270  {
271  ps_state[array_counter] = 0;
272  ps_exit_time[array_counter] = samples->timestamp;
273  }
274  }
275  }
276 
277  /* If there is no object in front of the board, look at history to see if a gesture occured */
278  if ((ps[0] < PS_THRESHOLD) && (ps[1] < PS_THRESHOLD) && (ps[2] < PS_THRESHOLD))
279  {
280  /* If the ps_max values are high enough and there exit entry and exit times, */
281  /* then begin processing gestures */
282  if ((ps_entry_time[0] != 0) && (ps_entry_time[1] != 0) && (ps_entry_time[2] != 0)
283  && (ps_exit_time[0] != 0) && (ps_exit_time[1] != 0) && (ps_exit_time[2] != 0))
284  {
285  /* Make sure no timestamps overflowed, indicated possibility if any of them are close to overflowing */
286  if ((ps_exit_time[0] > 0xFC000000L) || (ps_exit_time[1] > 0xFC000000L) || (ps_exit_time[2] > 0xFC000000L)
287  || (ps_entry_time[0] > 0xFC000000L) || (ps_entry_time[1] > 0xFC000000L) || (ps_entry_time[2] > 0xFC000000L))
288  { /* If any of them are close to overflowing, overflow them all so they all have the same reference */
289  ps_exit_time[0] += 0x1FFFFFFFL;
290  ps_exit_time[1] += 0x1FFFFFFFL;
291  ps_exit_time[2] += 0x1FFFFFFFL;
292 
293  ps_entry_time[0] += 0x1FFFFFFFL;
294  ps_entry_time[1] += 0x1FFFFFFFL;
295  ps_entry_time[2] += 0x1FFFFFFFL;
296  }
297 
298  /* Calculate the midpoint (between entry and exit times) of each waveform */
299  /* the order of these midpoints helps determine the gesture */
300  ps_time[0] = (ps_exit_time[0] - ps_entry_time[0]) / 2;
301  ps_time[0] = ps_time[0] + ps_entry_time[0];
302 
303  ps_time[1] = (ps_exit_time[1] - ps_entry_time[1]) / 2;
304  ps_time[1] = ps_time[1] + ps_entry_time[1];
305 
306  ps_time[2] = (ps_exit_time[2] - ps_entry_time[2]) / 2;
307  ps_time[2] = ps_time[2] + ps_entry_time[2];
308 
309  /* The diff_x and diff_y values help determine a gesture by comparing the */
310  /* LED measurements that are on a single axis */
311  if (ps_time[1] > ps_time[2])
312  {
313  diff_x = ps_time[1] - ps_time[2];
314  }
315  else
316  {
317  diff_x = ps_time[2] - ps_time[1];
318  }
319  if( ps_time[0] > ps_time[1] )
320  {
321  diff_y1 = ps_time[0] - ps_time[1];
322  }
323  else
324  {
325  diff_y1 = ps_time[1] - ps_time[0];
326  }
327 
328  if( ps_time[0] > ps_time[2] )
329  {
330  diff_y2 = ps_time[0] - ps_time[2];
331  }
332  else
333  {
334  diff_y2 = ps_time[2] - ps_time[0];
335  }
336 
337 
338  /* Take the average of all three midpoints to make a comparison point for each midpoint */
339  ps_avg = (u32) ps_time[0] + (u32) ps_time[1] + (u32) ps_time[2];
340  ps_avg = ps_avg / 3;
341 
342  if ((ps_exit_time[0] - ps_entry_time[0]) > 10 || (ps_exit_time[1] - ps_entry_time[1]) > 10 || (ps_exit_time[2] - ps_entry_time[2]) > 10)
343  {
344  if( ( (ps_time[0] < ps_time[1]) && (diff_y1 > diff_x) ) || ( (ps_time[0] <= ps_time[2]) && (diff_y2 > diff_x) ) )
345  { /* An up gesture occured if the bottom LED had its midpoint first */
346  ret = UP;
347  }
348  else if ( ( (ps_time[0] < ps_time[1]) && (diff_y1 > diff_x) ) || ( (ps_time[0] > ps_time[2]) && (diff_y2 > diff_x) ) )
349  { /* A down gesture occured if the bottom LED had its midpoint last */
350  ret = DOWN;
351  }
352  else if((ps_time[0] < ps_time[1]) && (ps_time[2] < ps_time[1]) && (diff_x > ((diff_y1+diff_y2)/2)))
353  { /* A left gesture occured if the left LED had its midpoint last */
354  ret = LEFT;
355  }
356  else if( (ps_time[0] < ps_time[2]) && (ps_time[1] < ps_time[2]) && (diff_x > ((diff_y1+diff_y2)/2)))
357  { /* A right gesture occured if the right LED had midpoint later than the right LED */
358  ret = RIGHT;
359  }
360  }
361  }
362  for (array_counter = 0; array_counter < 3; array_counter++)
363  {
364  ps_exit_time[array_counter] = 0;
365  ps_entry_time[array_counter] = 0;
366  }
367  }
368 
369  return ret;
370 }
371 
372 
373 /**************************************************************************/
386 int Si1147_ConfigureDetection(I2C_TypeDef *i2c, uint8_t addr, int lowpower)
387 {
388  s16 retval = 0;
389  SI114X_CAL_S si114x_cal;
390  si114x_handle->addr = addr;
391  si114x_handle->i2c = i2c;
392 
393 
394  /* Note that the Si114xReset() actually performs the following functions: */
395  /* 1. Pauses all prior measurements */
396  /* 2. Clear i2c registers that need to be cleared */
397  /* 3. Clears irq status to make sure INT* is negated */
398  /* 4. Delays 10 ms */
399  /* 5. Sends HW Key */
400  retval += Si114xReset(si114x_handle);
401 
402  retval += Si114xWriteToRegister(si114x_handle, REG_PS_LED21, (LED1I << 4) + LED2I);
403  retval += Si114xWriteToRegister(si114x_handle, REG_PS_LED3, LED3I);
404 
405 
406 
407  /* UV Coefficients */
408  si114x_get_calibration(si114x_handle, &si114x_cal, 0);
409  si114x_set_ucoef(si114x_handle, 0, &si114x_cal);
410 
411 
412 
413  retval += Si114xParamSet(si114x_handle, PARAM_CH_LIST, GESTURE_TASKLIST | UV_TASKLIST);
414 
415  retval += Si114xWriteToRegister(si114x_handle, REG_IRQ_ENABLE, GESTURE_IRQ);
416 
417  retval += Si114xParamSet(si114x_handle, PARAM_PS_ADC_MISC, 0x24); /* PS_ADC_MISC to high signal range */
418  retval += Si114xParamSet(si114x_handle, PARAM_PS1_ADC_MUX, 0x00); /* PS1_ADCMUX, PS2_ADCMUX, PS3_ADCMUX to small photodiode */
419  retval += Si114xParamSet(si114x_handle, PARAM_PS2_ADC_MUX, 0x00);
420  retval += Si114xParamSet(si114x_handle, PARAM_PS3_ADC_MUX, 0x00);
421 
422  /* Configure the ALS IR channel for the same settings as PS */
423 
424  retval += Si114xParamSet(si114x_handle, PARAM_ALSIR_ADC_MISC, RANGE_EN);
425  retval += Si114xParamSet(si114x_handle, PARAM_ALSVIS_ADC_MISC, RANGE_EN);
426 
427  if (!lowpower)
428  {
429  /* Set up how often the device wakes up to make measurements (10ms) */
430  retval += Si114xWriteToRegister(si114x_handle, REG_MEAS_RATE_MSB, (MEASRATE_FAST & 0xff00) >> 8);
431  retval += Si114xWriteToRegister(si114x_handle, REG_MEAS_RATE_LSB, MEASRATE_FAST & 0x00ff);
432  /* Enable Autonomous Operation */
433  retval += Si114xPsAlsAuto(si114x_handle);
434 
435  }
436 
437  /* If nothing went wrong after all of this time, the value */
438  /* returned will be 0. Otherwise, it will be some negative */
439  /* number */
440  return retval;
441 }
SI114X_CAL_S Data Structure.
#define UV_TASKLIST
Si114x function prototypes, structure and bit definitions.
unsigned short int u16
Definition: bmp280.h:283
int16_t Si114xParamSet(HANDLE si114x_handle, uint8_t address, uint8_t value)
Writes a byte to an Si113x/4x Parameter.
Driver for the Si1147 Proximity sensor.
int Si1147_MeasureUVAndObjectPresent(I2C_TypeDef *i2c, uint8_t addr, uint16_t *uvIndex, int *objectDetect)
Reads the UV measurement data and checks for object in proximity to the Si1147.
unsigned int u32
Definition: bmp280.h:284
int16_t Si114xWriteToRegister(HANDLE si114x_handle, uint8_t address, uint8_t data)
Writes to Si114x Register.
Definition: si1147_i2c.c:205
int16_t si114x_set_ucoef(HANDLE si114x_handle, uint8_t *input_ucoef, SI114X_CAL_S *si114x_cal)
Initializes the Si113x/46/47/48 UCOEF Registers.
signed short int s16
Definition: bmp280.h:277
int16_t Si114xPsAlsForce(HANDLE si114x_handle)
Sends a PSALSFORCE command to the Si113x/4x.
unsigned char u8
Definition: bmp280.h:282
int Si1147_GetInterruptOutputEnable(I2C_TypeDef *i2c, uint8_t addr, int *enable)
Get the enable status of the Si1147 interrupt pin.
int16_t Si114xReadFromRegister(HANDLE si114x_handle, uint8_t address)
Reads from Si114x register.
Definition: si1147_i2c.c:219
gesture_t Si1147_NewSample(I2C_TypeDef *i2c, uint8_t addr, uint32_t timestamp)
Reads new measurement data and processes a new sample. This function should be called every time an i...
int Si1147_SetInterruptOutputEnable(I2C_TypeDef *i2c, uint8_t addr, int enable)
Enables or disables the Si1147 interrupt pin.
int Si1147_ConfigureDetection(I2C_TypeDef *i2c, uint8_t addr, int lowpower)
Initializes and configures the Si1147 sensor.
int16_t si114x_get_calibration(HANDLE si114x_handle, SI114X_CAL_S *si114x_cal, uint8_t security)
Populates the SI114X_CAL_S structure.
Swipe algorithm for Si114x.
static void * si114x_handle
Si114x PGM toolkit functions uses a void* to pass hardware parameters through to the lower level i2c ...
int16_t Si114xPsAlsAuto(HANDLE si114x_handle)
Sends a PSALSAUTO command to the Si113x/4x.
int Si1147_Detect_Device(I2C_TypeDef *i2c, uint8_t addr)
Detects whether Si1147 is on the i2c bus.
gesture_t
int16_t Si114xReset(HANDLE si114x_handle)
Resets the Si113x/4x, clears any interrupts and initializes the HW_KEY register.