Contiki 3.x
tsl2563.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, Zolertia - http://www.zolertia.com
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 /*---------------------------------------------------------------------------*/
31 /**
32  * \addtogroup zoul-tsl2563-sensor
33  * @{
34  *
35  * \file
36  * Driver for the external TSL2563 light sensor
37  *
38  * \author
39  * Antonio Lignan <alinan@zolertia.com>
40  * Toni Lozano <tlozano@zolertia.com>
41  */
42 /*---------------------------------------------------------------------------*/
43 #include "contiki.h"
44 #include "dev/i2c.h"
45 #include "dev/gpio.h"
46 #include "dev/zoul-sensors.h"
47 #include "lib/sensors.h"
48 #include "tsl2563.h"
49 /*---------------------------------------------------------------------------*/
50 #define DEBUG 0
51 #if DEBUG
52 #define PRINTF(...) printf(__VA_ARGS__)
53 #else
54 #define PRINTF(...)
55 #endif
56 /*---------------------------------------------------------------------------*/
57 #define TSL2563_INT_PORT_BASE GPIO_PORT_TO_BASE(I2C_INT_PORT)
58 #define TSL2563_INT_PIN_MASK GPIO_PIN_MASK(I2C_INT_PIN)
59 /*---------------------------------------------------------------------------*/
60 static uint8_t enabled;
61 static uint8_t gain;
62 static uint8_t timming;
63 /*---------------------------------------------------------------------------*/
64 void (*tsl2563_int_callback)(uint8_t value);
65 /*---------------------------------------------------------------------------*/
66 static uint16_t
67 calculate_lux(uint8_t *buf)
68 {
69  uint32_t ch0, ch1, chscale = 0;
70  uint32_t ratio = 0;
71  uint32_t lratio, tmp = 0;
72  uint16_t buffer[2];
73 
74  /* The calculations below assume the integration time is 402ms and the gain
75  * is 16x (nominal), if not then it is required to normalize the reading
76  * before converting to lux
77  */
78 
79  buffer[0] = (buf[1] << 8 | (buf[0]));
80  buffer[1] = (buf[3] << 8 | (buf[2]));
81 
82  switch(timming) {
83  case TSL2563_TIMMING_INTEG_402MS:
84  chscale = (1 << CH_SCALE);
85  break;
86  case TSL2563_TIMMING_INTEG_101MS:
87  chscale = CHSCALE_TINT1;
88  break;
89  case TSL2563_TIMMING_INTEG_13_7MS:
90  chscale = CHSCALE_TINT0;
91  break;
92  }
93 
94  if(!gain) {
95  chscale = chscale << 4;
96  }
97 
98  ch0 = (buffer[0] * chscale) >> CH_SCALE;
99  ch1 = (buffer[1] * chscale) >> CH_SCALE;
100 
101  if(ch0 > 0) {
102  ratio = (ch1 << CH_SCALE);
103  ratio = ratio / ch0;
104  }
105 
106  lratio = (ratio + 1) >> 1;
107 
108  if((lratio >= 0) && (lratio <= K1T)) {
109  tmp = (ch0 * B1T) - (ch1 * M1T);
110  } else if(lratio <= K2T) {
111  tmp = (ch0 * B2T) - (ch1 * M2T);
112  } else if(lratio <= K3T) {
113  tmp = (ch0 * B3T) - (ch1 * M3T);
114  } else if(lratio <= K4T) {
115  tmp = (ch0 * B4T) - (ch1 * M4T);
116  } else if(lratio <= K5T) {
117  tmp = (ch0 * B5T) - (ch1 * M5T);
118  } else if(lratio <= K6T) {
119  tmp = (ch0 * B6T) - (ch1 * M6T);
120  } else if(lratio <= K7T) {
121  tmp = (ch0 * B7T) - (ch1 * M7T);
122  } else if(lratio > K8T) {
123  tmp = (ch0 * B8T) - (ch1 * M8T);
124  }
125 
126  if(tmp < 0) {
127  tmp = 0;
128  }
129 
130  tmp += (1 << (LUX_SCALE - 1));
131  return tmp >> LUX_SCALE;
132 }
133 /*---------------------------------------------------------------------------*/
134 static int
135 tsl2563_read_reg(uint8_t reg, uint8_t *buf, uint8_t regNum)
136 {
138  if(i2c_single_send(TSL2563_ADDR, reg) == I2C_MASTER_ERR_NONE) {
139  while(i2c_master_busy());
140  if(i2c_burst_receive(TSL2563_ADDR, buf, regNum) == I2C_MASTER_ERR_NONE) {
141  return TSL2563_SUCCESS;
142  }
143  }
144  return TSL2563_ERROR;
145 }
146 /*---------------------------------------------------------------------------*/
147 static int
148 tsl2563_write_reg(uint8_t *buf, uint8_t num)
149 {
150  if((buf == NULL) || (num <= 0)) {
151  PRINTF("TSL2563: invalid write values\n");
152  return TSL2563_ERROR;
153  }
154 
156  if(i2c_burst_send(TSL2563_ADDR, buf, num) == I2C_MASTER_ERR_NONE) {
157  return TSL2563_SUCCESS;
158  }
159  return TSL2563_ERROR;
160 }
161 /*---------------------------------------------------------------------------*/
162 static int
163 tsl2563_on(void)
164 {
165  uint8_t buf[2];
166  buf[0] = (TSL2563_COMMAND + TSL2563_CONTROL);
167  buf[1] = TSL2563_CONTROL_POWER_ON;
168 
169  if(tsl2563_write_reg(buf, 2) == I2C_MASTER_ERR_NONE) {
170  if(i2c_single_receive(TSL2563_ADDR, &buf[0]) == I2C_MASTER_ERR_NONE) {
171  if((buf[0] & 0x0F) == TSL2563_CONTROL_POWER_ON) {
172  PRINTF("TSL2563: powered on\n");
173  return TSL2563_SUCCESS;
174  }
175  }
176  }
177 
178  PRINTF("TSL2563: failed to power on\n");
179  return TSL2563_ERROR;
180 }
181 /*---------------------------------------------------------------------------*/
182 static int
183 tsl2563_id_register(uint8_t *buf)
184 {
185  if(tsl2563_read_reg((TSL2563_COMMAND + TSL2563_ID_REG),
186  buf, 1) == TSL2563_SUCCESS) {
187  PRINTF("TSL2563: partnum/revnum 0x%02X\n", *buf);
188  return TSL2563_SUCCESS;
189  }
190 
191  return TSL2563_ERROR;
192 }
193 /*---------------------------------------------------------------------------*/
194 static int
195 tsl2563_off(void)
196 {
197  uint8_t buf[2];
198  buf[0] = (TSL2563_COMMAND + TSL2563_CONTROL);
199  buf[1] = TSL2563_CONTROL_POWER_OFF;
200 
201  if(tsl2563_write_reg(buf, 2) == I2C_MASTER_ERR_NONE) {
202  PRINTF("TSL2563: powered off\n");
203  return TSL2563_SUCCESS;
204  }
205 
206  PRINTF("TSL2563: failed to power off\n");
207  return TSL2563_ERROR;
208 }
209 /*---------------------------------------------------------------------------*/
210 static int
211 tsl2563_clear_interrupt(void)
212 {
213  uint8_t buf = (TSL2563_COMMAND + TSL2563_CLEAR_INTERRUPT);
214  if(tsl2563_write_reg(&buf, 1) != I2C_MASTER_ERR_NONE) {
215  PRINTF("TSL2563: failed to clear the interrupt\n");
216  return TSL2563_ERROR;
217  }
218  return TSL2563_SUCCESS;
219 }
220 /*---------------------------------------------------------------------------*/
221 static int
222 tsl2563_read_sensor(uint16_t *lux)
223 {
224  uint8_t buf[4];
225 
226  /* This is hardcoded to use word write/read operations */
227  if(tsl2563_read_reg((TSL2563_COMMAND + TSL2563_D0LOW),
228  &buf[0], 2) == TSL2563_SUCCESS) {
229  if(tsl2563_read_reg((TSL2563_COMMAND + TSL2563_D1LOW),
230  &buf[2], 2) == TSL2563_SUCCESS) {
231 
232  PRINTF("TSL2563: CH0 0x%02X%02X CH1 0x%02X%02X\n", buf[1], buf[0],
233  buf[3], buf[2]);
234  *lux = calculate_lux(buf);
235  return TSL2563_SUCCESS;
236  }
237  }
238  PRINTF("TSL2563: failed to read\n");
239  return TSL2563_ERROR;
240 }
241 /*---------------------------------------------------------------------------*/
242 PROCESS(tsl2563_int_process, "TSL2563 interrupt process handler");
243 /*---------------------------------------------------------------------------*/
244 PROCESS_THREAD(tsl2563_int_process, ev, data)
245 {
247  PROCESS_BEGIN();
248 
249  while(1) {
250  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
251  tsl2563_clear_interrupt();
252  tsl2563_int_callback(0);
253  }
254  PROCESS_END();
255 }
256 /*---------------------------------------------------------------------------*/
257 static void
258 tsl2563_interrupt_handler(uint8_t port, uint8_t pin)
259 {
260  /* There's no alert/interruption flag to check, clear the interruption by
261  * writting to the CLEAR bit in the COMMAND register
262  */
263  process_poll(&tsl2563_int_process);
264 }
265 /*---------------------------------------------------------------------------*/
266 static int
267 configure(int type, int value)
268 {
269  uint8_t buf[3];
270 
271  if((type != TSL2563_ACTIVE) && (type != TSL2563_INT_OVER) &&
272  (type != TSL2563_INT_BELOW) && (type != TSL2563_INT_DISABLE) &&
273  (type != TSL2563_TIMMING_CFG)) {
274  PRINTF("TSL2563: invalid start value\n");
275  return TSL2563_ERROR;
276  }
277 
278  /* As default the power-on values of the sensor are gain 1X, 402ms integration
279  * time (not nominal), with manual control disabled
280  */
281 
282  if(type == TSL2563_ACTIVE) {
283  if(value) {
284  i2c_init(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SCL_PORT, I2C_SCL_PIN,
285  I2C_SCL_NORMAL_BUS_SPEED);
286 
287  /* Initialize interrupts handlers */
288  tsl2563_int_callback = NULL;
289 
290  /* Power on the sensor and check for the part number */
291  if(tsl2563_on() == TSL2563_SUCCESS) {
292  if(tsl2563_id_register(&buf[0]) == TSL2563_SUCCESS) {
293  if((buf[0] & TSL2563_ID_PARTNO_MASK) == TSL2563_EXPECTED_PARTNO) {
294 
295  /* Read the timming/gain configuration */
296  if(tsl2563_read_reg((TSL2563_COMMAND + TSL2563_TIMMING),
297  &buf[0], 1) == TSL2563_SUCCESS) {
298  gain = buf[0] & TSL2563_TIMMING_GAIN;
299  timming = buf[0] & TSL2563_TIMMING_INTEG_MASK;
300  PRINTF("TSL2563: enabled, timming %u gain %u\n", timming, gain);
301 
302  /* Restart the over interrupt threshold */
303  buf[0] = (TSL2563_COMMAND + TSL2563_THRHIGHLOW);
304  buf[1] = 0xFF;
305  buf[2] = 0xFF;
306 
307  if(tsl2563_write_reg(buf, 3) != TSL2563_SUCCESS) {
308  PRINTF("TSL2563: failed to clear over interrupt\n");
309  return TSL2563_ERROR;
310  }
311 
312  /* Restart the below interrupt threshold */
313  buf[0] = (TSL2563_COMMAND + TSL2563_THRLOWLOW);
314  buf[1] = 0x00;
315  buf[2] = 0x00;
316 
317  if(tsl2563_write_reg(buf, 3) != TSL2563_SUCCESS) {
318  PRINTF("TSL2563: failed to clear below interrupt\n");
319  return TSL2563_ERROR;
320  }
321 
322  /* Clear any pending interrupt */
323  if(tsl2563_clear_interrupt() == TSL2563_SUCCESS) {
324  enabled = 1;
325  return TSL2563_SUCCESS;
326  }
327  }
328  }
329  }
330  }
331  return TSL2563_ERROR;
332  } else {
333  if(tsl2563_off() == TSL2563_SUCCESS) {
334  PRINTF("TSL2563: stopped\n");
335  enabled = 0;
336  return TSL2563_SUCCESS;
337  }
338  return TSL2563_ERROR;
339  }
340  }
341 
342  if(!enabled) {
343  PRINTF("TSL2563: sensor not started\n");
344  return TSL2563_ERROR;
345  }
346 
347  if(type == TSL2563_INT_DISABLE) {
348 
349  /* Ensure the GPIO doesn't generate more interrupts, this may affect others
350  * I2C digital sensors using the bus and sharing this pin, so an user may
351  * comment the line below
352  */
353  GPIO_DISABLE_INTERRUPT(TSL2563_INT_PORT_BASE, TSL2563_INT_PIN_MASK);
354 
355  /* This also wipes out the persistance value, to be reconfigured when
356  * enabling back the interruption
357  */
358  buf[0] = (TSL2563_COMMAND + TSL2563_INTERRUPT);
359  buf[1] = TSL2563_INTR_DISABLED;
360 
361  if(tsl2563_write_reg(buf, 2) != TSL2563_SUCCESS) {
362  PRINTF("TSL2563: failed to disable the interrupt\n");
363  return TSL2563_ERROR;
364  }
365  return TSL2563_SUCCESS;
366  }
367 
368  /* Configure the timming and gain */
369  if(type == TSL2563_TIMMING_CFG) {
370  if((value != TSL2563_G16X_402MS) && (value != TSL2563_G1X_402MS) &&
371  (value != TSL2563_G1X_101MS) && (value != TSL2563_G1X_13_7MS)) {
372  PRINTF("TSL2563: invalid timming configuration values\n");
373  return TSL2563_ERROR;
374  }
375 
376  buf[0] = (TSL2563_COMMAND + TSL2563_TIMMING);
377  buf[1] = value;
378 
379  if(tsl2563_write_reg(buf, 2) == TSL2563_SUCCESS) {
380  if(value == TSL2563_G16X_402MS) {
381  gain = 1;
382  }
383 
384  switch(value) {
385  case TSL2563_G16X_402MS:
386  case TSL2563_G1X_402MS:
387  timming = TSL2563_TIMMING_INTEG_402MS;
388  break;
389  case TSL2563_G1X_101MS:
390  timming = TSL2563_TIMMING_INTEG_101MS;
391  break;
392  case TSL2563_G1X_13_7MS:
393  timming = TSL2563_TIMMING_INTEG_13_7MS;
394  break;
395  }
396 
397  PRINTF("TSL2563: new timming %u gain %u\n", timming, gain);
398  return TSL2563_SUCCESS;
399  }
400  PRINTF("TSL2563: failed to configure timming\n");
401  return TSL2563_ERROR;
402  }
403 
404  /* From here we handle the interrupt configuration, it requires the interrupt
405  * callback handler to have been previously set using the TSL2563_REGISTER_INT
406  * macro
407  */
408 
409  buf[1] = ((uint8_t *)&value)[0];
410  buf[2] = ((uint8_t *)&value)[1];
411 
412  if(type == TSL2563_INT_OVER) {
413  buf[0] = (TSL2563_COMMAND + TSL2563_THRHIGHLOW);
414  } else if(type == TSL2563_INT_BELOW) {
415  buf[0] = (TSL2563_COMMAND + TSL2563_THRLOWLOW);
416  }
417 
418  if(tsl2563_write_reg(buf, 3) != TSL2563_SUCCESS) {
419  PRINTF("TSL2563: failed to set interrupt level\n");
420  return TSL2563_ERROR;
421  }
422 
423  /* Now configure the interruption register (level interrupt, 2 integration
424  * cycles after threshold has been reached (roughly 804ms if timming is 402ms)
425  */
426  buf[0] = (TSL2563_COMMAND + TSL2563_INTERRUPT);
427  buf[1] = (TSL2563_INTR_LEVEL << TSL2563_INTR_SHIFT);
428  buf[1] += TSL2563_INT_PERSIST_2_CYCLES;
429 
430  if(tsl2563_write_reg(buf, 2) != TSL2563_SUCCESS) {
431  PRINTF("TSL2563: failed to enable interrupt\n");
432  return TSL2563_ERROR;
433  }
434 
435  /* Configure the interrupts pins */
436  GPIO_SOFTWARE_CONTROL(TSL2563_INT_PORT_BASE, TSL2563_INT_PIN_MASK);
437  GPIO_SET_INPUT(TSL2563_INT_PORT_BASE, TSL2563_INT_PIN_MASK);
438 
439  /* Pull-up resistor, detect falling edge */
440  GPIO_DETECT_EDGE(TSL2563_INT_PORT_BASE, TSL2563_INT_PIN_MASK);
441  GPIO_TRIGGER_SINGLE_EDGE(TSL2563_INT_PORT_BASE, TSL2563_INT_PIN_MASK);
442  GPIO_DETECT_FALLING(TSL2563_INT_PORT_BASE, TSL2563_INT_PIN_MASK);
443  gpio_register_callback(tsl2563_interrupt_handler, I2C_INT_PORT, I2C_INT_PIN);
444 
445  /* Spin process until an interrupt is received */
446  process_start(&tsl2563_int_process, NULL);
447 
448  /* Enable interrupts */
449  GPIO_ENABLE_INTERRUPT(TSL2563_INT_PORT_BASE, TSL2563_INT_PIN_MASK);
450 
451  /* The RE-Mote revision A has this pin shared and with a pull-down resistor,
452  * for other platforms (like the firefly), change to enable pull-up internal
453  * resistor instead if no external pull-up is present.
454  */
455  ioc_set_over(I2C_INT_PORT, I2C_INT_PIN, IOC_OVERRIDE_PUE);
456  nvic_interrupt_enable(I2C_INT_VECTOR);
457 
458  PRINTF("TSL2563: Interrupt configured\n");
459  return TSL2563_SUCCESS;
460 }
461 /*---------------------------------------------------------------------------*/
462 static int
463 status(int type)
464 {
465  switch(type) {
466  case SENSORS_ACTIVE:
467  case SENSORS_READY:
468  return enabled;
469  }
470  return 0;
471 }
472 /*---------------------------------------------------------------------------*/
473 static int
474 value(int type)
475 {
476  uint16_t lux;
477 
478  if(!enabled) {
479  PRINTF("TSL2563: sensor not started\n");
480  return TSL2563_ERROR;
481  }
482 
483  if(type == TSL2563_VAL_READ) {
484  if(tsl2563_read_sensor(&lux) != TSL2563_ERROR) {
485  return lux;
486  }
487  PRINTF("TSL2563: fail to read\n");
488  }
489  return TSL2563_ERROR;
490 }
491 /*---------------------------------------------------------------------------*/
492 SENSORS_SENSOR(tsl2563, TSL2563_SENSOR, value, configure, status);
493 /*---------------------------------------------------------------------------*/
494 /** @} */
#define GPIO_TRIGGER_SINGLE_EDGE(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to trigger an interrupt on single edge (controlled by G...
Definition: gpio.h:178
uint8_t i2c_master_busy(void)
Return the busy state of I2C module.
Definition: i2c.c:141
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
#define GPIO_ENABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Enable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:202
#define GPIO_SET_INPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to input.
Definition: gpio.h:93
#define CHSCALE_TINT1
322/81 * 2^CH_SCALE
Definition: tsl2563.h:136
#define IOC_OVERRIDE_PUE
Pull Up Enable.
Definition: ioc.h:223
#define GPIO_DETECT_EDGE(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to detect edge.
Definition: gpio.h:155
void i2c_master_enable(void)
Enable master I2C module.
Definition: i2c.c:91
#define CHSCALE_TINT0
322/11 * 2^CH_SCALE
Definition: tsl2563.h:135
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define GPIO_DETECT_FALLING(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to trigger an interrupt on falling edge.
Definition: gpio.h:194
Implementation of a generic module controlling Zoul sensors.
void i2c_init(uint8_t port_sda, uint8_t pin_sda, uint8_t port_scl, uint8_t pin_scl, uint32_t bus_speed)
Initialize the I2C peripheral and pins.
Definition: i2c.c:49
#define PROCESS_EXITHANDLER(handler)
Specify an action when a process exits.
Definition: process.h:254
uint8_t i2c_burst_send(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to send multiple bytes to a slave.
Definition: i2c.c:188
uint8_t i2c_single_receive(uint8_t slave_addr, uint8_t *data)
Perform all operations to receive a byte from a slave.
Definition: i2c.c:172
#define NULL
The null pointer.
uint8_t i2c_burst_receive(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to receive multiple bytes from a slave.
Definition: i2c.c:218
uint8_t i2c_single_send(uint8_t slave_addr, uint8_t data)
Perform all operations to send a byte to a slave.
Definition: i2c.c:159
#define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be software controlled with PIN_MASK of port with PORT_BASE. ...
Definition: gpio.h:259
Header file for the external TSL2563 Sensor Driver.
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
void nvic_interrupt_enable(uint32_t intr)
Enables interrupt intr.
Definition: nvic.c:64
#define GPIO_DISABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Disable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:210
#define CH_SCALE
scale channel values by 2^10
Definition: tsl2563.h:134
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition: ioc.c:54
void gpio_register_callback(gpio_callback_t f, uint8_t port, uint8_t pin)
Register GPIO callback.
Definition: gpio.c:56
#define LUX_SCALE
scale by 2^14
Definition: tsl2563.h:132
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120