Last active
August 7, 2019 20:15
-
-
Save selimslab/b16c013ebbaafee461da2b91eb7bd9a5 to your computer and use it in GitHub Desktop.
TSL-2561 light sensor library for Nordic nRF 51822
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include < stdio.h > | |
#include "boards.h" | |
#include "app_util_platform.h" | |
#include "app_uart.h" | |
#include "app_error.h" | |
#include "nrf_drv_twi.h" | |
#include "nrf_delay.h" | |
#include "main.h" | |
/* Define version of GCC. */ | |
# | |
define GCC_VERSION(__GNUC__ * 10000\ + __GNUC_MINOR__ * 100\ + __GNUC_PATCHLEVEL__)# ifdef __GNUC_PATCHLEVEL__# | |
if GCC_VERSION < 50505# pragma GCC diagnostic push# pragma GCC diagnostic ignored "-Wmissing-braces" | |
// Hack to GCC 4.9.3 bug. Can be deleted after switch on using GCC 5.0.0 | |
# | |
endif# endif# ifdef __GNUC_PATCHLEVEL__# | |
if GCC_VERSION < 50505# pragma GCC diagnostic pop# endif# endif | |
/* Indicates if reading operation from device has ended. */ | |
static volatile bool is_read_done = true; | |
/* Indicates if setting mode operation has ended. */ | |
static volatile bool is_set_mode_done = false; | |
/* TWI instance. */ | |
static | |
const nrf_drv_twi_t twi_instance = NRF_DRV_TWI_INSTANCE(0); | |
bool device_found = false; | |
uint8_t CH0_LOW, CH0_HIGH, CH1_LOW, CH1_HIGH; | |
// these are for holding read values from channel registers | |
uint16_t ch0, ch1; | |
// to hold high and low bytes of a register together, | |
// for example ch0 holds together values in CH0_LOW and CH0_HIGH | |
uint8_t ch0low = TSL2561_Channel0Low; | |
uint8_t ch0high = TSL2561_Channel0High; | |
uint8_t ch1low = TSL2561_Channel1Low; | |
uint8_t ch1high = TSL2561_Channel1High; | |
/** | |
UART events handler. | |
*/ | |
static void uart_events_handler(app_uart_evt_t * p_event) { | |
switch (p_event - > evt_type) { | |
case APP_UART_COMMUNICATION_ERROR: | |
APP_ERROR_HANDLER(p_event - > data.error_communication); | |
break; | |
case APP_UART_FIFO_ERROR: | |
APP_ERROR_HANDLER(p_event - > data.error_code); | |
break; | |
default: | |
break; | |
} | |
} | |
/** | |
UART initialization. | |
*/ | |
static void uart_config(void) { | |
uint32_t err_code; | |
const app_uart_comm_params_t comm_params = { | |
RX_PIN_NUMBER, | |
TX_PIN_NUMBER, | |
RTS_PIN_NUMBER, | |
CTS_PIN_NUMBER, | |
APP_UART_FLOW_CONTROL_DISABLED, | |
false, | |
UART_BAUDRATE_BAUDRATE_Baud115200 | |
}; | |
APP_UART_FIFO_INIT( & comm_params, | |
UART_RX_BUF_SIZE, | |
UART_TX_BUF_SIZE, | |
uart_events_handler, | |
APP_IRQ_PRIORITY_LOW, | |
err_code); | |
APP_ERROR_CHECK(err_code); | |
} | |
/***************************** | |
this is the function that converts the raw data of sensor to SI units in lumens | |
iGain − gain, where 0:1X, 1:16X | |
integration_time − integration time, where 0:13.7mS, 1:100mS, 2:402mS, | |
function has different coefficients for T and CS packages | |
***************************/ | |
unsigned int CalculateLux(unsigned int iGain, unsigned int integration_time, int package_type) { | |
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− | |
// first, scale the channel values depending on the gain and integration time | |
// 16X, 402mS is nominal. | |
// scale if integration time is NOT 402 msec | |
unsigned long chScale; | |
unsigned long channel1; | |
unsigned long channel0; | |
switch (integration_time) { | |
case 0: // 13.7 msec | |
chScale = CHSCALE_TINT0; | |
break; | |
case 1: // 101 msec | |
chScale = CHSCALE_TINT1; | |
break; | |
default: // assume no scaling | |
chScale = (1 << CH_SCALE); | |
break; | |
} | |
// scale if gain is NOT 16X | |
if (!iGain) chScale = chScale << 4; // scale 1X to 16X | |
// scale the channel values | |
channel0 = (ch0 * chScale) >> CH_SCALE; | |
channel1 = (ch1 * chScale) >> CH_SCALE; | |
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− | |
// find the ratio of the channel values (Channel1/Channel0) | |
// protect against divide by zero | |
unsigned long ratio1 = 0; | |
if (channel0 != 0) ratio1 = (channel1 << (RATIO_SCALE + 1)) / channel0; | |
// round the ratio value | |
unsigned long ratio = (ratio1 + 1) >> 1; | |
// is ratio <= eachBreak ? | |
unsigned int b = 0, m = 0; | |
switch (package_type) { | |
case 0: // T package | |
if ((ratio >= 0) && (ratio <= K1T)) { | |
b = B1T; | |
m = M1T; | |
} else if (ratio <= K2T) { | |
b = B2T; | |
m = M2T; | |
} else if (ratio <= K3T) { | |
b = B3T; | |
m = M3T; | |
} else if (ratio <= K4T) { | |
b = B4T; | |
m = M4T; | |
} else if (ratio <= K5T) { | |
b = B5T; | |
m = M5T; | |
} else if (ratio <= K6T) { | |
b = B6T; | |
m = M6T; | |
} else if (ratio <= K7T) { | |
b = B7T; | |
m = M7T; | |
} else if (ratio > K8T) { | |
b = B8T; | |
m = M8T; | |
} | |
break; | |
case 1: // CS package | |
if ((ratio >= 0) && (ratio <= K1C)) { | |
b = B1C; | |
m = M1C; | |
} else if (ratio <= K2C) { | |
b = B2C; | |
m = M2C; | |
} else if (ratio <= K3C) { | |
b = B3C; | |
m = M3C; | |
} else if (ratio <= K4C) { | |
b = B4C; | |
m = M4C; | |
} else if (ratio <= K5C) { | |
b = B5C; | |
m = M5C; | |
} else if (ratio <= K6C) { | |
b = B6C; | |
m = M6C; | |
} else if (ratio <= K7C) { | |
b = B7C; | |
m = M7C; | |
} else if (ratio > K8C) { | |
b = B8C; | |
m = M8C; | |
} | |
break; | |
} | |
unsigned long temp; | |
temp = ((channel0 * b) - (channel1 * m)); | |
// do not allow negative lux value | |
if (temp < 0) temp = 0; | |
// round lsb (2^(LUX_SCALE−1)) | |
temp += (1 << (LUX_SCALE - 1)); | |
// strip off fractional portion | |
unsigned long lux = temp >> LUX_SCALE; | |
printf(" lux:%lu \n", lux); | |
return (lux); | |
} | |
// end of CalculateLux | |
// Function for setting active mode on TSL2561 device. | |
void enable_device(void) { | |
ret_code_t err_code; | |
/* Writing "0x03" on control register enables the device */ | |
uint8_t reg[2] = { | |
TSL2561_Control, | |
0x03 | |
}; | |
//Here we are enabling the sensor by writing the control register 0x03, | |
// or 3h in terms of datasheet | |
err_code = nrf_drv_twi_tx( & twi_instance, TSL2561_ADDRESS, reg, sizeof(reg), false); | |
//printf("device POWER ON"); | |
APP_ERROR_CHECK(err_code); | |
while (is_set_mode_done == false); | |
} | |
void read_register() { | |
ret_code_t err_code; | |
/*************WARNING********************* | |
below reading procedure works only using blocking mode, with no handler. but we have a twi_handler | |
**********************/ | |
//read channel 0 low byte | |
err_code = nrf_drv_twi_tx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & ch0low, sizeof(ch0low), true); | |
if (NRF_SUCCESS == err_code) | |
err_code = nrf_drv_twi_rx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & CH0_LOW, sizeof(CH0_LOW)); | |
APP_ERROR_CHECK(err_code); | |
//read channel 0 high byte | |
err_code = nrf_drv_twi_tx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & ch0high, sizeof(ch0high), true); | |
if (NRF_SUCCESS == err_code) | |
err_code = nrf_drv_twi_rx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & CH0_HIGH, sizeof(CH0_HIGH)); | |
APP_ERROR_CHECK(err_code); | |
// read channel 1 low byte | |
err_code = nrf_drv_twi_tx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & ch1low, sizeof(ch1low), true); | |
if (NRF_SUCCESS == err_code) | |
err_code = nrf_drv_twi_rx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & CH1_LOW, sizeof(CH1_LOW)); | |
APP_ERROR_CHECK(err_code); | |
//read channel 1 high byte | |
err_code = nrf_drv_twi_tx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & ch1high, sizeof(ch1high), true); | |
if (NRF_SUCCESS == err_code) | |
err_code = nrf_drv_twi_rx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & CH1_HIGH, sizeof(CH1_HIGH)); | |
APP_ERROR_CHECK(err_code); | |
// low and high bytes of a channel is got together here | |
ch0 = (CH0_HIGH << 8) | CH0_LOW; | |
ch1 = (CH1_HIGH << 8) | CH1_LOW; | |
CalculateLux(0, 0, 0); //T package, no gain, 13ms integration time | |
} | |
/** | |
TWI events handler. | |
*/ | |
void twi_handler(nrf_drv_twi_evt_t | |
const * p_event, void * p_context) { | |
ret_code_t err_code; | |
switch (p_event - > type) { | |
case NRF_DRV_TWI_EVT_DONE: //Transfer completed event | |
printf(" Connected to device \n\r"); | |
read_register(); | |
if ((p_event - > type == NRF_DRV_TWI_EVT_DONE) && | |
(p_event - > xfer_desc.type == NRF_DRV_TWI_XFER_TX)) { | |
if (is_set_mode_done != true) { | |
is_set_mode_done = true; | |
return; | |
} | |
is_read_done = false; | |
/* Read 4 bytes from the specified address. */ | |
err_code = nrf_drv_twi_rx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & CH0_LOW, sizeof(CH0_LOW)) | |
err_code = nrf_drv_twi_rx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & CH0_HIGH, sizeof(CH0_HIGH)); | |
err_code = nrf_drv_twi_rx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & CH1_LOW, sizeof(CH1_LOW)); | |
err_code = nrf_drv_twi_rx( & twi_instance, TSL2561_ADDRESS, (uint8_t * ) & CH1_HIGH, sizeof(CH1_HIGH)); | |
APP_ERROR_CHECK(err_code); | |
} else { | |
read_register(); | |
is_read_done = true; | |
} | |
break; | |
default: | |
printf(" \n\r Can't connect to device \n\r"); | |
break; | |
} | |
} | |
void twi_init(void) { | |
ret_code_t err_code; | |
const nrf_drv_twi_config_t tsl_twi_config = { /*Structure for TWI instance configuration */ | |
.scl = DEVICE_SCL_PIN, | |
.sda = DEVICE_SDA_PIN, | |
.frequency = NRF_TWI_FREQ_100K, | |
.interrupt_priority = APP_IRQ_PRIORITY_HIGH | |
}; | |
//Function for initializing the TWI instance | |
err_code = nrf_drv_twi_init( & twi_instance, & tsl_twi_config, twi_handler, NULL); | |
APP_ERROR_CHECK(err_code); | |
nrf_drv_twi_enable( & twi_instance); | |
read_register(); | |
// printf("\n\r Instance INITIALIZED \n\r"); | |
} | |
/** | |
Function for main application entry. | |
*/ | |
int main(void) { | |
uart_config(); // configures UART, just to see results via UART, all UART functions can be deleted before final application | |
twi_init(); | |
enable_device(); // Function for setting active mode on TSL2561 device | |
uint8_t reg = 0; | |
ret_code_t err_code; | |
while (true) { | |
nrf_delay_ms(1000); | |
// Start transaction with a slave with the specified address. | |
do { | |
__WFE(); // means 'Wait for event', used to save power while waiting | |
} while (is_read_done == false); | |
// By writing a 00h to control register, the device is powered down. | |
uint8_t reg[2] = { | |
TSL2561_Control, | |
0 | |
}; | |
err_code = nrf_drv_twi_tx( & twi_instance, TSL2561_ADDRESS, & reg, sizeof(reg), true); | |
APP_ERROR_CHECK(err_code); | |
is_read_done = false; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define MAIN_H | |
/* device addresses definition | |
The Slave and SMB Alert Addresses are 7 bits. A read/write bit shouldbe appended to | |
the slave address by the master device to properly communicate with the TSL256X device. | |
*/ | |
#define TSL2561_ADDRESS 0x29 | |
#define TSL2561_ADDR_FLOAT (0x39) | |
#define TSL2561_ADDR_HIGH (0x49) | |
#define TSL2561_Control 0x00 | |
#define TSL2561_Timing 0x01 | |
#define TSL2561_Interrupt 0x06 | |
#define TSL2561_Channel0Low 0x0C | |
#define TSL2561_Channel0High 0x0D | |
#define TSL2561_Channel1Low 0x0E | |
#define TSL2561_Channel1High 0x0F | |
// these are for the function that converts raw readings into SI units | |
#define LUX_SCALE 14 // scale by 2^14 | |
#define RATIO_SCALE 9 // scale ratio by 2^9 | |
#define CH_SCALE 10 // scale channel values by 2^10 | |
#define CHSCALE_TINT0 0x7517 // 322/11 * 2^CH_SCALE | |
#define CHSCALE_TINT1 0x0fe7 // 322/81 * 2^CH_SCALE | |
/****************** | |
coeffeficients for standalone circuit and chipscale packages, from the datasheet | |
*****************//// | |
#define K1T 0x0040 // 0.125 * 2^RATIO_SCALE | |
#define B1T 0x01f2 // 0.0304 * 2^LUX_SCALE | |
#define M1T 0x01be // 0.0272 * 2^LUX_SCALE | |
#define K2T 0x0080 // 0.250 * 2^RATIO_SCA | |
#define B2T 0x0214 // 0.0325 * 2^LUX_SCALE | |
#define M2T 0x02d1 // 0.0440 * 2^LUX_SCALE | |
#define K3T 0x00c0 // 0.375 * 2^RATIO_SCALE | |
#define B3T 0x023f // 0.0351 * 2^LUX_SCALE | |
#define M3T 0x037b // 0.0544 * 2^LUX_SCALE | |
#define K4T 0x0100 // 0.50 * 2^RATIO_SCALE | |
#define B4T 0x0270 // 0.0381 * 2^LUX_SCALE | |
#define M4T 0x03fe // 0.0624 * 2^LUX_SCALE | |
#define K5T 0x0138 // 0.61 * 2^RATIO_SCALE | |
#define B5T 0x016f // 0.0224 * 2^LUX_SCALE | |
#define M5T 0x01fc // 0.0310 * 2^LUX_SCALE | |
#define K6T 0x019a // 0.80 * 2^RATIO_SCALE | |
#define B6T 0x00d2 // 0.0128 * 2^LUX_SCALE | |
#define M6T 0x00fb // 0.0153 * 2^LUX_SCALE | |
#define K7T 0x029a // 1.3 * 2^RATIO_SCALE | |
#define B7T 0x0018 // 0.00146 * 2^LUX_SCALE | |
#define M7T 0x0012 // 0.00112 * 2^LUX_SCALE | |
#define K8T 0x029a // 1.3 * 2^RATIO_SCALE | |
#define B8T 0x0000 // 0.000 * 2^LUX_SCALE | |
#define M8T 0x0000 // 0.000 * 2^LUX_SCALE | |
#define K1C 0x0043 // 0.130 * 2^RATIO_SCALE | |
#define B1C 0x0204 // 0.0315 * 2^LUX_SCALE | |
#define M1C 0x01ad // 0.0262 * 2^LUX_SCALE | |
#define K2C 0x0085 // 0.260 * 2^RATIO_SCALE | |
#define B2C 0x0228 // 0.0337 * 2^LUX_SCALE | |
#define M2C 0x02c1 // 0.0430 * 2^LUX_SCALE | |
#define K3C 0x00c8 // 0.390 * 2^RATIO_SCALE | |
#define B3C 0x0253 // 0.0363 * 2^LUX_SCALE | |
#define M3C 0x0363 // 0.0529 * 2^LUX_SCALE | |
#define K4C 0x010a // 0.520 * 2^RATIO_SCALE | |
#define B4C 0x0282 // 0.0392 * 2^LUX_SCALE | |
#define M4C 0x03df // 0.0605 * 2^LUX_SCALE | |
#define K5C 0x014d // 0.65 * 2^RATIO_SCALE | |
#define B5C 0x0177 // 0.0229 * 2^LUX_SCALE | |
#define M5C 0x01dd // 0.0291 * 2^LUX_SCALE | |
#define K6C 0x019a // 0.80 * 2^RATIO_SCALE | |
#define B6C 0x0101 // 0.0157 * 2^LUX_SCALE | |
#define M6C 0x0127 // 0.0180 * 2^LUX_SCALE | |
#define K7C 0x029a // 1.3 * 2^RATIO_SCALE | |
#define B7C 0x0037 // 0.00338 * 2^LUX_SCALE | |
#define M7C 0x002b // 0.00260 * 2^LUX_SCALE | |
#define K8C 0x029a // 1.3 * 2^RATIO_SCALE | |
#define B8C 0x0000 // 0.000 * 2^LUX_SCALE | |
#define M8C 0x0000 // 0.000 * 2^LUX_SCALE | |
/*Pins to connect device. */ | |
#define DEVICE_SCL_PIN 7 | |
#define DEVICE_SDA_PIN 30 | |
/*UART buffer size. */ | |
#define UART_TX_BUF_SIZE 256 | |
#define UART_RX_BUF_SIZE 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment