L14-Click 1.0
STM32WLE5CC LoRaWAN Sensor Platform
Loading...
Searching...
No Matches
amb_tsl2591.c
Go to the documentation of this file.
1#include "amb_tsl2591.h"
2
3#ifdef SENSOR_AMB_TSL2591
4
5#include "i2c.h"
6#include "utils/mydefs.h"
7#include "mymems.h"
8#include <stdio.h>
9
10#define AMBIENT_ADDR (0x29 << 1) // Shifted for HAL
11#define TSL2591_COMMAND 0xA0 // Must be OR'd with register address
12#define REG_ENABLE 0x00
13#define REG_CONFIG 0x01
14#define REG_C0DATAL 0x14 // Channel 0 (Visible + IR)
15#define REG_C1DATAL 0x16 // Channel 1 (IR)
16
17#define THRESH_MAX 60000
18#define THRESH_MIN 500
19
20// First, we define the gain multipliers and the threshold for switching. The TSL2591 supports specific gain steps.
21typedef enum
22{
23 TSL2591_GAIN_LOW = 0x00, // 1x (Bright light)
24 TSL2591_GAIN_MED = 0x10, // 25x
25 TSL2591_GAIN_HIGH = 0x20, // 428x
26 TSL2591_GAIN_MAX = 0x30 // 9876x (Very dark)
28
29// Global or static variable to track state
31static int8_t _isAmbientSensor = 0; // indicator whether sensor is present
34
35int8_t amb_tsl2591_Is(I2C_HandleTypeDef *hi2c, int8_t tryInit) //
36{
37 if (!_isAmbientSensor && tryInit)
38 amb_tsl2591_Init(hi2c);
39 return _isAmbientSensor;
40}
41
42HAL_StatusTypeDef amb_tsl2591_IsOn(I2C_HandleTypeDef *hi2c, uint8_t *onOff)
43{
44 uint8_t data = 0;
45 HAL_StatusTypeDef status = HAL_ERROR;
46
48 {
49 status = HAL_I2C_Mem_Read(hi2c, AMBIENT_ADDR, TSL2591_COMMAND | REG_ENABLE, I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
50 if (status == HAL_OK)
51 if (onOff != NULL)
52 *onOff = data & 1; //(bit0 - powerOnOff);
53 }
54 return status;
55}
56
57HAL_StatusTypeDef amb_tsl2591_On(I2C_HandleTypeDef *hi2c)
58{
59 HAL_StatusTypeDef status = HAL_ERROR;
60 uint8_t data;
61
62 _amb_tsl2591Data.IsDataValid = 0;
64 {
65 do
66 {
67 // 1. Power on the sensor (Enable register)
68 // AIEN (Bit 4) = 0 (Interrupts off for now)
69 // AEN (Bit 1) = 1 (ALS Enable)
70 // PON (Bit 0) = 1 (Power ON)
71 data = 0x03;
72 status = HAL_I2C_Mem_Write(hi2c, AMBIENT_ADDR, TSL2591_COMMAND | REG_ENABLE, I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
73 if (status != HAL_OK)
74 break;
75
76 // 2. Set Initial Gain and Timing (Config register)
77 // We match our 'currentGain' variable (TSL2591_GAIN_MED = 0x10)
78 // And set Integration Time to 100ms (0x01)
79 // Result: 0x11
81 data = (uint8_t) _currentGain | 0x01;
82
83 status = HAL_I2C_Mem_Write(hi2c, AMBIENT_ADDR, TSL2591_COMMAND | REG_CONFIG, I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
84 if (status != HAL_OK)
85 break;
86 status = HAL_OK;
88 {
89 for (data = 0; data < 4; data++)
90 if (amb_tsl2591_Read(hi2c) == HAL_OK)
91 break; // calibration...., if value obtained, can finish
92 }
93 _memsMainBlock.Sens_AmbientStart++;
95 } while (0);
96 _isAmbientSensor = (status == HAL_OK);
97 }
98 return status;
99}
100
101HAL_StatusTypeDef amb_tsl2591_Off(I2C_HandleTypeDef *hi2c)
102{
103 HAL_StatusTypeDef status = HAL_ERROR;
104 uint8_t data;
105
107 do
108 {
109 // 1. Power on the sensor (Enable register)
110 // AIEN (Bit 4) = 0 (Interrupts off for now)
111 // AEN (Bit 1) = 0 (ALS Enable)
112 // PON (Bit 0) = 0 (Power ON)
113 data = 0x00;
114 status = HAL_I2C_Mem_Write(hi2c, AMBIENT_ADDR, TSL2591_COMMAND | REG_ENABLE, I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
115 if (status != HAL_OK)
116 break;
117 } while (0);
118 return status;
119}
120
121HAL_StatusTypeDef amb_tsl2591_Init(I2C_HandleTypeDef *hi2c)
122{
123 HAL_StatusTypeDef status = I2C_IsDeviceReadyMT(hi2c, AMBIENT_ADDR, 2, 2); // first check
124 if (status == HAL_OK)
125 do
126 {
128 // 1. turn on sensor and calibrate
129 if ((status = amb_tsl2591_On(hi2c)) != HAL_OK)
130 break;
131 // 2. turn off sensor
132 if ((status = amb_tsl2591_Off(hi2c)) != HAL_OK)
133 break;
134 } while (0);
135 _isAmbientSensor = (status == HAL_OK);
136 return status;
137}
138
139/**
140 * @brief This function checks the raw channel 0 value. If it is near the 16-bit limit (65535), it drops the gain. If it is too low, it boosts it.
141 */
142static HAL_StatusTypeDef ambient_AdjustGain(I2C_HandleTypeDef *hi2c, uint16_t rawCH0)
143{
145 HAL_StatusTypeDef status = HAL_OK;
146
147 // Thresholds: ~90% of max for "too bright", ~1% for "too dark"
148 if (rawCH0 > THRESH_MAX) // 60000) //
149 {
151 newGain = TSL2591_GAIN_HIGH;
153 newGain = TSL2591_GAIN_MED;
154 else if (_currentGain == TSL2591_GAIN_MED)
155 newGain = TSL2591_GAIN_LOW;
156 }
157 else if (rawCH0 < THRESH_MIN) ///500)
158 {
160 newGain = TSL2591_GAIN_MED;
161 else if (_currentGain == TSL2591_GAIN_MED)
162 newGain = TSL2591_GAIN_HIGH;
164 newGain = TSL2591_GAIN_MAX;
165 }
166
167 if (newGain != _currentGain) //
168 {
169 _currentGain = newGain;
170 uint8_t regVal = _currentGain | 0x01; // 0x01 is 100ms integration time
171 status = HAL_I2C_Mem_Write(hi2c, AMBIENT_ADDR, TSL2591_COMMAND | REG_CONFIG, I2C_MEMADD_SIZE_8BIT, &regVal, 1, 100);
172 }
173 return status;
174}
175
176/**
177 * @brief When calculating Lux, you must use the actual multiplier corresponding to the currentGain
178 */
179HAL_StatusTypeDef amb_tsl2591_Read(I2C_HandleTypeDef *hi2c) //
180{
181 uint8_t buffer[4];
182 HAL_StatusTypeDef status = HAL_ERROR;
183
184 if (_isAmbientSensor) //
185 {
186 do
187 {
188 uint8_t onOff = 0;
189 // 1.check, sensor is on
190 if ((status = amb_tsl2591_IsOn(hi2c, &onOff)) != HAL_OK)
191 break;
192
193 if (!onOff)
194 {
195 status = HAL_TIMEOUT;
196 break;
197 }
198
199 // Read raw values
200 if ((status = HAL_I2C_Mem_Read(hi2c, AMBIENT_ADDR, TSL2591_COMMAND | REG_C0DATAL, I2C_MEMADD_SIZE_8BIT, buffer, 4, 100)) != HAL_OK)
201 break;
202
203 uint16_t ch0 = (buffer[1] << 8) | buffer[0];
204 uint16_t ch1 = (buffer[3] << 8) | buffer[2];
205
206 // 1. Update gain for the NEXT reading
207 ambient_AdjustGain(hi2c, ch0);
208
209 // 2. Map current gain enum to actual multiplier for math
210 float multiplier;
211 switch (_currentGain)
212 //
213 {
214 case TSL2591_GAIN_LOW:
215 multiplier = 1.0f;
216 break;
217 case TSL2591_GAIN_MED:
218 multiplier = 25.0f;
219 break;
221 multiplier = 428.0f;
222 break;
223 case TSL2591_GAIN_MAX:
224 multiplier = 9876.0f;
225 break;
226 default:
227 multiplier = 1.0f;
228 }
229
230 // 3. Calculate Lux
231 float atime = 100.0f;
232 float cpl = (atime * multiplier) / 408.0f;
233 if (ch0 < THRESH_MIN || ch0 > THRESH_MAX)
234 {
235 status = HAL_BUSY;
236 break;
237 }
238 status = HAL_OK;
239 _amb_tsl2591Data.IsDataValid = 1;
240 _amb_tsl2591Data.Lux = ((float) ch0 - (2.0f * (float) ch1)) / cpl;
241 if (_amb_tsl2591Data.Lux < 0)
242 _amb_tsl2591Data.Lux = 0.0f;
243 } while (0);
244 }
245 return status;
246}
247
248void amb_tsl2591_LogData(char* buf)
249{
250 if (buf != NULL)
251 sprintf(buf, "|ambient lux:" PRIf_02 " ", PRIf_02D(_amb_tsl2591Data.Lux));
252}
253
254#endif
void amb_tsl2591_LogData(char *buf)
log data to buffer
#define REG_C0DATAL
Definition amb_tsl2591.c:14
#define AMBIENT_ADDR
Definition amb_tsl2591.c:10
static HAL_StatusTypeDef ambient_AdjustGain(I2C_HandleTypeDef *hi2c, uint16_t rawCH0)
This function checks the raw channel 0 value. If it is near the 16-bit limit (65535),...
#define REG_CONFIG
Definition amb_tsl2591.c:13
int8_t amb_tsl2591_Is(I2C_HandleTypeDef *hi2c, int8_t tryInit)
check if light sensor is present
Definition amb_tsl2591.c:35
#define THRESH_MIN
Definition amb_tsl2591.c:18
HAL_StatusTypeDef amb_tsl2591_Read(I2C_HandleTypeDef *hi2c)
When calculating Lux, you must use the actual multiplier corresponding to the currentGain.
HAL_StatusTypeDef amb_tsl2591_Off(I2C_HandleTypeDef *hi2c)
turn off sensor
HAL_StatusTypeDef amb_tsl2591_On(I2C_HandleTypeDef *hi2c)
turn on sensor, read value 4x to automatically configure the sensor.
Definition amb_tsl2591.c:57
#define TSL2591_COMMAND
Definition amb_tsl2591.c:11
#define THRESH_MAX
Definition amb_tsl2591.c:17
TSL2591_Gain_t
Definition amb_tsl2591.c:22
@ TSL2591_GAIN_MED
Definition amb_tsl2591.c:24
@ TSL2591_GAIN_HIGH
Definition amb_tsl2591.c:25
@ TSL2591_GAIN_LOW
Definition amb_tsl2591.c:23
@ TSL2591_GAIN_MAX
Definition amb_tsl2591.c:26
#define REG_ENABLE
Definition amb_tsl2591.c:12
HAL_StatusTypeDef amb_tsl2591_Init(I2C_HandleTypeDef *hi2c)
initialization of light sensor, and check if sensor is present or not Subsequently the sensor is turn...
HAL_StatusTypeDef amb_tsl2591_IsOn(I2C_HandleTypeDef *hi2c, uint8_t *onOff)
check if sensor is turned on or not
Definition amb_tsl2591.c:42
static TSL2591_Gain_t _currentGain
Definition amb_tsl2591.c:30
static int8_t _isAmbientSensor
Definition amb_tsl2591.c:31
amb_tsl2591_t _bck_amb_tsl2591Data
Snapshot copy of the last completed TSL2591 measurement; used for LoRaWAN transmission.
Definition amb_tsl2591.c:33
amb_tsl2591_t _amb_tsl2591Data
Live measurement data from the TSL2591 sensor; updated by amb_tsl2591_Read().
Definition amb_tsl2591.c:32
This file contains all the function prototypes for the i2c.c file.
HAL_StatusTypeDef I2C_IsDeviceReadyMT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout)
Wrapper around HAL_I2C_IsDeviceReady() that recovers from a busy bus. If the HAL I2C bus is in a BUSY...
Definition i2c.c:158
#define PRIf_02D(fData)
Expands to integer and fractional arguments for use with PRIf_02. Splits a float/double into the inte...
Definition mydefs.h:38
#define PRIf_02
printf format string for printing a float/double as integer with 2 decimal places....
Definition mydefs.h:30
mems_MainBlock_t _memsMainBlock
Global instance of the main flash control block; loaded by mems_ReadMainBlock().
Definition mymems.c:27
HAL_StatusTypeDef mems_WriteMainBlock()
writing the main block on flash. The main block is stored on address 0
Definition mymems.c:117
Measurement data produced by the TSL2591 ambient light sensor. Populated by amb_tsl2591_Read(); check...
Definition amb_tsl2591.h:32