diff options
Diffstat (limited to 'lib/chibios-contrib/os/various/devices_lib/sensors/tsl2591.c')
-rw-r--r-- | lib/chibios-contrib/os/various/devices_lib/sensors/tsl2591.c | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/lib/chibios-contrib/os/various/devices_lib/sensors/tsl2591.c b/lib/chibios-contrib/os/various/devices_lib/sensors/tsl2591.c new file mode 100644 index 000000000..c0bbee0ce --- /dev/null +++ b/lib/chibios-contrib/os/various/devices_lib/sensors/tsl2591.c | |||
@@ -0,0 +1,272 @@ | |||
1 | /* | ||
2 | TSL2591 for ChibiOS/RT - Copyright (C) 2016 Stephane D'Alu | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * | ||
19 | * DOC: http://ams.com/eng/content/download/389383/1251117/221235 | ||
20 | */ | ||
21 | |||
22 | #define I2C_HELPERS_AUTOMATIC_DRV TRUE | ||
23 | |||
24 | #include "hal.h" | ||
25 | #include "i2c_helpers.h" | ||
26 | #include "tsl2591.h" | ||
27 | |||
28 | /*===========================================================================*/ | ||
29 | /* Driver local definitions. */ | ||
30 | /*===========================================================================*/ | ||
31 | |||
32 | #define TSL2591_LUX_DF (408.0F) | ||
33 | #define TSL2591_LUX_COEFB (1.64F) // CH0 coefficient | ||
34 | #define TSL2591_LUX_COEFC (0.59F) // CH1 coefficient A | ||
35 | #define TSL2591_LUX_COEFD (0.86F) // CH2 coefficient B | ||
36 | |||
37 | /* I2C registers */ | ||
38 | #define TSL2591_REG_ENABLE 0x00 | ||
39 | #define TSL2591_REG_CONFIG 0x01 /**< @brief gain and integration */ | ||
40 | #define TSL2591_REG_AILTL 0x04 | ||
41 | #define TSL2591_REG_AILTH 0x05 | ||
42 | #define TSL2591_REG_AIHTL 0x06 | ||
43 | #define TSL2591_REG_AIHTH 0x07 | ||
44 | #define TSL2591_REG_NPAILTL 0x08 | ||
45 | #define TSL2591_REG_NPAILTH 0x09 | ||
46 | #define TSL2591_REG_NPAIHTL 0x0A | ||
47 | #define TSL2591_REG_NPAIHTH 0x0B | ||
48 | #define TSL2591_REG_PERSIST 0x0C | ||
49 | #define TSL2591_REG_PID 0x11 /**< @brief Package ID */ | ||
50 | #define TSL2591_REG_ID 0x12 /**< @brief Device ID */ | ||
51 | #define TSL2591_REG_STATUS 0x13 /**< @brief Device status */ | ||
52 | #define TSL2591_REG_C0DATAL 0x14 /**< @brief CH0 ADC low data byte */ | ||
53 | #define TSL2591_REG_C0DATAH 0x15 /**< @brief CH0 ADC high data byte */ | ||
54 | #define TSL2591_REG_C1DATAL 0x16 /**< @brief CH1 ADC low data byte */ | ||
55 | #define TSL2591_REG_C1DATAH 0x17 /**< @brief CH1 ADC high data byte */ | ||
56 | |||
57 | #define TSL2591_REG_COMMAND 0x80 /**< @brief Select command register */ | ||
58 | #define TSL2591_REG_NORMAL 0x20 /**< @brief Normal opearation */ | ||
59 | #define TSL2591_REG_SPECIAL 0x60 /**< @brief Special function */ | ||
60 | |||
61 | #define TSL2591_ID_TSL2591 0x50 | ||
62 | |||
63 | #define TSL2591_VISIBLE (2) // channel 0 - channel 1 | ||
64 | #define TSL2591_INFRARED (1) // channel 1 | ||
65 | #define TSL2591_FULLSPECTRUM (0) // channel 0 | ||
66 | |||
67 | #define TSL2591_ENABLE_POWERON (0x01) | ||
68 | #define TSL2591_ENABLE_POWEROFF (0x00) | ||
69 | #define TSL2591_ENABLE_AEN (0x02) | ||
70 | #define TSL2591_ENABLE_AIEN (0x10) | ||
71 | |||
72 | #define TSL2591_CONTROL_RESET (0x80) | ||
73 | |||
74 | |||
75 | /*===========================================================================*/ | ||
76 | /* Driver exported variables. */ | ||
77 | /*===========================================================================*/ | ||
78 | |||
79 | /*===========================================================================*/ | ||
80 | /* Driver local variables and types. */ | ||
81 | /*===========================================================================*/ | ||
82 | |||
83 | /*===========================================================================*/ | ||
84 | /* Driver local functions. */ | ||
85 | /*===========================================================================*/ | ||
86 | |||
87 | static inline uint32_t | ||
88 | calculateIlluminance(TSL2591_integration_time_t integration_time, | ||
89 | TSL2591_gain_t gain, | ||
90 | uint16_t broadband, uint16_t ir) { | ||
91 | uint16_t atime, again; | ||
92 | |||
93 | /* Check for overflow conditions first */ | ||
94 | if ((broadband == 0xFFFF) | (ir == 0xFFFF)) { | ||
95 | return 0xFFFFFFFF; /* Signal overflow */ | ||
96 | } | ||
97 | |||
98 | switch (integration_time) { | ||
99 | case TSL2591_INTEGRATIONTIME_100MS : atime = 100; break; | ||
100 | case TSL2591_INTEGRATIONTIME_200MS : atime = 200; break; | ||
101 | case TSL2591_INTEGRATIONTIME_300MS : atime = 300; break; | ||
102 | case TSL2591_INTEGRATIONTIME_400MS : atime = 400; break; | ||
103 | case TSL2591_INTEGRATIONTIME_500MS : atime = 500; break; | ||
104 | case TSL2591_INTEGRATIONTIME_600MS : atime = 600; break; | ||
105 | } | ||
106 | |||
107 | switch (gain) { | ||
108 | case TSL2591_GAIN_1X : again = 1; break; | ||
109 | case TSL2591_GAIN_25X : again = 25; break; | ||
110 | case TSL2591_GAIN_415X : again = 415; break; | ||
111 | case TSL2591_GAIN_10000X : again = 10000; break; | ||
112 | } | ||
113 | |||
114 | // cpl = (ATIME * AGAIN) / DF | ||
115 | float cpl = ((float)(atime * again)) / ((float)TSL2591_LUX_DF); | ||
116 | float lux1 = ( ((float)broadband) - (TSL2591_LUX_COEFB * (float)ir) ) / cpl; | ||
117 | float lux2 = ( (TSL2591_LUX_COEFC * (float)broadband) - | ||
118 | (TSL2591_LUX_COEFD * (float)ir ) ) / cpl; | ||
119 | |||
120 | return (uint32_t) (lux1 > lux2 ? lux1 : lux2); | ||
121 | } | ||
122 | |||
123 | static inline msg_t | ||
124 | _readChannel(TSL2591_drv *drv, uint16_t *broadband, uint16_t *ir) { | ||
125 | msg_t msg; | ||
126 | if (((msg = i2c_reg_recv16_le( | ||
127 | TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_C0DATAL, | ||
128 | broadband)) < MSG_OK) || | ||
129 | ((msg = i2c_reg_recv16_le( | ||
130 | TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_C1DATAL, | ||
131 | ir )) < MSG_OK)) | ||
132 | return msg; | ||
133 | |||
134 | return MSG_OK; | ||
135 | } | ||
136 | |||
137 | /*===========================================================================*/ | ||
138 | /* Driver exported functions. */ | ||
139 | /*===========================================================================*/ | ||
140 | |||
141 | void | ||
142 | TSL2591_init(TSL2591_drv *drv, TSL2591_config *config) { | ||
143 | drv->config = config; | ||
144 | drv->gain = TSL2591_GAIN_1X; | ||
145 | drv->integration_time = TSL2591_INTEGRATIONTIME_100MS; | ||
146 | drv->state = SENSOR_INIT; | ||
147 | } | ||
148 | |||
149 | msg_t | ||
150 | TSL2591_check(TSL2591_drv *drv) { | ||
151 | uint8_t id; | ||
152 | |||
153 | msg_t msg; | ||
154 | if ((msg = i2c_reg_recv8(TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | | ||
155 | TSL2591_REG_ID, &id)) < MSG_OK) | ||
156 | return msg; | ||
157 | |||
158 | if (id != TSL2591_ID_TSL2591) | ||
159 | return SENSOR_NOTFOUND; | ||
160 | |||
161 | return MSG_OK; | ||
162 | } | ||
163 | |||
164 | msg_t | ||
165 | TSL2591_start(TSL2591_drv *drv) { | ||
166 | struct __attribute__((packed)) { | ||
167 | uint8_t reg; | ||
168 | uint8_t conf; | ||
169 | } tx_config = { | ||
170 | TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_CONFIG, | ||
171 | (uint8_t)(drv->integration_time | drv->gain) }; | ||
172 | |||
173 | struct __attribute__((packed)) { | ||
174 | uint8_t reg; | ||
175 | uint8_t conf; | ||
176 | } tx_start = { | ||
177 | TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_ENABLE, | ||
178 | TSL2591_ENABLE_POWERON }; | ||
179 | |||
180 | msg_t msg; | ||
181 | |||
182 | if (((msg = i2c_send((uint8_t*)&tx_config, sizeof(tx_config))) < MSG_OK) || | ||
183 | ((msg = i2c_send((uint8_t*)&tx_start, sizeof(tx_start ))) < MSG_OK)) { | ||
184 | drv->state = SENSOR_ERROR; | ||
185 | return msg; | ||
186 | } | ||
187 | |||
188 | drv->state = SENSOR_STARTED; | ||
189 | return MSG_OK; | ||
190 | } | ||
191 | |||
192 | msg_t | ||
193 | TSL2591_stop(TSL2591_drv *drv) { | ||
194 | struct __attribute__((packed)) { | ||
195 | uint8_t reg; | ||
196 | uint8_t conf; | ||
197 | } tx_stop = { | ||
198 | TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_ENABLE, | ||
199 | TSL2591_ENABLE_POWEROFF }; | ||
200 | |||
201 | return i2c_send((uint8_t*)&tx_stop, sizeof(tx_stop)); | ||
202 | } | ||
203 | |||
204 | msg_t | ||
205 | TSL2591_setIntegrationTime(TSL2591_drv *drv, | ||
206 | TSL2591_integration_time_t time) { | ||
207 | struct __attribute__((packed)) { | ||
208 | uint8_t reg; | ||
209 | uint8_t conf; | ||
210 | } tx = { TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_CONFIG, | ||
211 | (uint8_t)(time | drv->gain) }; | ||
212 | |||
213 | msg_t msg; | ||
214 | if ((msg = i2c_send((uint8_t*)&tx, sizeof(tx))) < MSG_OK) | ||
215 | return msg; | ||
216 | |||
217 | drv->integration_time = time; | ||
218 | |||
219 | return MSG_OK; | ||
220 | } | ||
221 | |||
222 | msg_t | ||
223 | TSL2591_setGain(TSL2591_drv *drv, | ||
224 | TSL2591_gain_t gain) { | ||
225 | struct __attribute__((packed)) { | ||
226 | uint8_t reg; | ||
227 | uint8_t conf; | ||
228 | } tx = { TSL2591_REG_COMMAND | TSL2591_REG_NORMAL | TSL2591_REG_CONFIG, | ||
229 | (uint8_t)(drv->integration_time | gain) }; | ||
230 | |||
231 | msg_t msg; | ||
232 | if ((msg = i2c_send((uint8_t*)&tx, sizeof(tx))) < MSG_OK) | ||
233 | return msg; | ||
234 | |||
235 | drv->gain = gain; | ||
236 | |||
237 | return MSG_OK; | ||
238 | } | ||
239 | |||
240 | unsigned int | ||
241 | TSL2591_getAcquisitionTime(TSL2591_drv *drv) { | ||
242 | switch (drv->integration_time) { | ||
243 | case TSL2591_INTEGRATIONTIME_100MS : return 100; | ||
244 | case TSL2591_INTEGRATIONTIME_200MS : return 200; | ||
245 | case TSL2591_INTEGRATIONTIME_300MS : return 300; | ||
246 | case TSL2591_INTEGRATIONTIME_400MS : return 400; | ||
247 | case TSL2591_INTEGRATIONTIME_500MS : return 500; | ||
248 | case TSL2591_INTEGRATIONTIME_600MS : return 600; | ||
249 | } | ||
250 | return -1; | ||
251 | } | ||
252 | |||
253 | |||
254 | msg_t | ||
255 | TSL2591_readIlluminance(TSL2591_drv *drv, | ||
256 | unsigned int *illuminance) { | ||
257 | uint16_t broadband; | ||
258 | uint16_t ir; | ||
259 | |||
260 | /* Read channels */ | ||
261 | msg_t msg; | ||
262 | if ((msg = _readChannel(drv, &broadband, &ir)) < MSG_OK) | ||
263 | return msg; | ||
264 | |||
265 | /* Calculate illuminance */ | ||
266 | *illuminance = | ||
267 | calculateIlluminance(drv->integration_time, drv->gain, | ||
268 | broadband, ir); | ||
269 | /* Ok */ | ||
270 | return SENSOR_OK; | ||
271 | } | ||
272 | |||