monoZ docs
MZ_Addon_Si1133.c
Go to the documentation of this file.
1/*
2 * MZ_Addon_Si1133.c
3 *
4 * Created on: Aug 26, 2021
5 * Author: SKM
6 */
7
8/*
9 * This is a sample implementation of the Si1133 driver as per data sheet.
10 * Please refer Si1133 data sheet for details
11 */
12
13#include "MZ_Addon_Si1133.h"
14#include "MZ_error_handler.h"
15#include "stm32l4xx_hal.h"
17
18#define X_ORDER_MASK 0x0070
19#define Y_ORDER_MASK 0x0007
20#define SIGN_MASK 0x0080
21#define GET_X_ORDER(m) ( ((m) & X_ORDER_MASK) >> 4)
22#define GET_Y_ORDER(m) ( ((m) & Y_ORDER_MASK) )
23#define GET_SIGN(m) ( ((m) & SIGN_MASK) >> 7)
24
25#define UV_INPUT_FRACTION 15
26#define UV_OUTPUT_FRACTION 12
27#define UV_NUMCOEFF 2
28
29#define ADC_THRESHOLD 16000
30#define INPUT_FRACTION_HIGH 7
31#define INPUT_FRACTION_LOW 15
32#define LUX_OUTPUT_FRACTION 12
33#define NUMCOEFF_LOW 9
34#define NUMCOEFF_HIGH 4
35
36/* I2C transmit and Receive API has been integrated here */
37#define UV_I2C_SEND(ADDRESS,LEN,TIME) MZ_I2C_Master_Transmit(MZ_ADDONUV_I2C_INSTANCE,SLAVE_ADD,(uint8_t *) ADDRESS,LEN,TIME)
38#define UV_I2C_GET(ADDRESS,LEN,TIME) MZ_I2C_Master_Receive(MZ_ADDONUV_I2C_INSTANCE,SLAVE_ADD,(uint8_t *) ADDRESS,LEN,TIME)
39#define SI1133_CONFIRM_COUNT (5)
40
41/*
42 * @brief
43 * Coefficients for lux calculation
44 */
46{
47 { { 0, 209 },
48 { 1665, 93 },
49 { 2064, 65 },
50 { -2671, 234 } },
51 { { 0, 0 },
52 { 1921, 29053 },
53 { -1022, 36363 },
54 { 2320, 20789 },
55 { -367, 57909 },
56 { -1774, 38240 },
57 { -608, 46775 },
58 { -1503, 51831 },
59 { -1886, 58928 } }
60};
61
62/*
63 * @brief
64 * Coefficients for UV index calculation
65 */
66
68{
69 { 1281, 30902 },
70 { -638, 46301 }
71};
72
73static Si1133_error SI1133_Write_Reg(Si1133_register w_addr, uint8_t data)
74{
75 uint8_t _Buff[2];
76 _Buff[0] = (uint8_t)w_addr;
77 _Buff[1] = data;
78
79 // Write the write register address and value in the slave memory
80 if(MZ_OK == UV_I2C_SEND(_Buff,2,1000))
81 {
82 return SI_OK;
83 }
84 return SI_FAIL;
85}
86
87static Si1133_error SI1133_Write_Reg_block(Si1133_register w_addr, uint8_t len, uint8_t *data)
88{
89 uint8_t _Buff[2];
90
91 if (len > 2) {
92 return SI_FAIL;
93 }
94
95 _Buff[0] = (uint8_t)w_addr;
96 memcpy(&_Buff[1], data, len);
97
98 // Write the write register address and value in the slave memory
99 if(MZ_OK == UV_I2C_SEND(_Buff,len+1,1000))
100 {
101 return SI_OK;
102 }
103 return SI_FAIL;
104}
105
107{
108 uint8_t _Buf = (uint8_t)r_addr;
109
110 // Write the read register address in the slave memory
111 if(MZ_OK == UV_I2C_SEND(&_Buf,1,1000))
112 {
113 // Read the value on that register
114 if(MZ_OK == UV_I2C_GET(&_Buf,1,1000))
115 {
116 *buf = _Buf;
117 return SI_OK;
118 }
119 }
120 return SI_FAIL;
121}
122
123static Si1133_error SI1133_Read_Reg_block(Si1133_register r_addr, uint8_t len, uint8_t *buf)
124{
125 uint8_t _Buf = (uint8_t)r_addr;
126
127 // Write the read register address in the slave memory
128 if(MZ_OK == UV_I2C_SEND(&_Buf,1,1000))
129 {
130 // Read the value on that register
131 if(MZ_OK == UV_I2C_GET(buf,len,1000))
132 {
133 return SI_OK;
134 }
135 }
136 return SI_FAIL;
137}
138
140{
141 Si1133_error _ret;
142
143 /* Delay 30 ms for sensor power-up time */
144 HAL_Delay(30);
145
146 /* Perform the Reset Command */
148
149 /*
150 * Delay for 10 ms. This delay is needed to allow the Si1133 to perform
151 * internal reset sequence.
152 */
153 HAL_Delay(10);
154
155 return _ret;
156}
157
159{
160 Si1133_error _ret;
161 uint8_t response;
162
163 /*
164 * This loops until the Si1133 is known to be in its sleep state
165 * or if an i2c error occurs
166 */
167 for(uint8_t count = 0; count < SI1133_CONFIRM_COUNT; count++)
168 {
169 _ret = SI1133_Read_Reg(SI1133_REG_RESPONSE0, &response);
170 /* If read fail or any error stop and return */
171 if (SI_OK != _ret) { return _ret; }
172
173 /* If sleep complete return */
174 if((response & (uint8_t)SI1133_RSP0_CHIPSTAT_MASK) == (uint8_t)SI1133_RSP0_SLEEP )
175 {
176 return SI_OK;
177 }
178 }
179
180 /* If not sleep in time then return fail */
181 return SI_FAIL;
182}
183
185{
186 uint8_t response;
187 uint8_t response_initial;
188
189 Si1133_error _ret;
190
191 /* Get the response register contents */
192 _ret = SI1133_Read_Reg(SI1133_REG_RESPONSE0, &response_initial);
193 if (SI_OK != _ret) { return _ret; }
194
195 response_initial = response_initial & (uint8_t)SI1133_RSP0_COUNTER_MASK;
196
197 /* Make sure the response register is consistent */
198 for(uint8_t count = 0; count < SI1133_CONFIRM_COUNT; count++)
199 {
201 /* If the sensor is not going to sleep or any error stop and return */
202 if (SI_OK != _ret) { return _ret; }
203
204 /* Skip if the command is RESET COMMAND COUNTER */
205 if (command == (uint8_t)SI1133_CMD_RESET_CMD_CTR) { break; }
206
207 /* Read the response register again */
208 _ret = SI1133_Read_Reg(SI1133_REG_RESPONSE0, &response);
209 /* If read fail or any error stop and return */
210 if (SI_OK != _ret) { return _ret; }
211
212 /* Check if the value is same as previous value once */
213 if ((response & (uint8_t)SI1133_RSP0_COUNTER_MASK) == response_initial)
214 {
215 break;
216 }
217 else
218 {
219 /* store the new value to check */
220 response_initial = response & (uint8_t)SI1133_RSP0_COUNTER_MASK;
221 }
222 }
223
224 /* Send the command */
225 _ret = SI1133_Write_Reg(SI1133_REG_COMMAND, command);
226 /* If write fail or any error stop and return */
227 if (SI_OK != _ret) { return _ret; }
228
229 /* Expect a change in the response register */
230 uint8_t count = 0;
231 for(uint8_t count = 0; count < SI1133_CONFIRM_COUNT; count++)
232 {
233 /* Skip if the command is RESET COMMAND COUNTER */
234 if ( command == (uint8_t)SI1133_CMD_RESET_CMD_CTR ) { break; }
235
236 _ret = SI1133_Read_Reg(SI1133_REG_RESPONSE0, &response);
237 /* If read fail or any error stop and return */
238 if (SI_OK != _ret) { return _ret; }
239
240 /* Check if response change once to confirm writing */
241 if ((response & (uint8_t)SI1133_RSP0_COUNTER_MASK) != response_initial)
242 {
243 break;
244 }
245 }
246
247 if (count >= SI1133_CONFIRM_COUNT)
248 {
249 return SI_FAIL;
250 }
251
252 return SI_OK;
253}
254
255#if 0
256static Si1133_error SI1133_reset_cmd_counter(void)
257{
259}
260#endif
262{
264}
265#if 0
266static Si1133_error SI1133_start_measurement(void)
267{
269}
270#endif
272{
274}
275
277{
278 Si1133_error _ret;
279 uint8_t param_Buff[2];
280 uint8_t response_initial;
281 uint8_t response;
282
284 /* If the sensor is not going to sleep or any error stop and return */
285 if (SI_OK != _ret) { return _ret; }
286
287 /* Get the response register contents */
288 _ret = SI1133_Read_Reg(SI1133_REG_RESPONSE0, &response_initial);
289 if (SI_OK != _ret) { return _ret; }
290
291 response_initial = response_initial & (uint8_t)SI1133_RSP0_COUNTER_MASK;
292
293 param_Buff[0] = value;
294 param_Buff[1] = 0x80 + ((uint8_t)address & 0x3F);
295
296 _ret = SI1133_Write_Reg_block(SI1133_REG_HOSTIN0, 2, param_Buff);
297 if (SI_OK != _ret) { return _ret; }
298
299 /* Wait for command to finish */
300 uint8_t count = 0;
301 for(; count < SI1133_CONFIRM_COUNT; count++)
302 {
303 _ret = SI1133_Read_Reg(SI1133_REG_RESPONSE0, &response);
304 /* If read fail or any error stop and return */
305 if (SI_OK != _ret) { return _ret; }
306
307 /* Check if response change once to confirm writing */
308 if ((response & (uint8_t)SI1133_RSP0_COUNTER_MASK) != response_initial)
309 {
310 break;
311 }
312 }
313
314 if (count >= SI1133_CONFIRM_COUNT)
315 {
316 return SI_FAIL;
317 }
318
319 return SI_OK;
320}
321
322static int32_t SI1133_calculate_polynomial_helper (int32_t input,
323 int8_t fraction,
324 uint16_t mag,
325 int8_t shift)
326{
327 int32_t value;
328
329 if ( shift < 0 ) {
330 value = ( (input << fraction) / mag) >> -shift;
331 } else {
332 value = ( (input << fraction) / mag) << shift;
333 }
334
335 return value;
336}
337
338static int32_t SI1133_calculate_polynomial(int32_t x,
339 int32_t y,
340 uint8_t input_fraction,
341 uint8_t output_fraction,
342 uint8_t num_coeff,
343 const Si1133_coeff *kp)
344{
345 uint8_t info, x_order, y_order, counter;
346 int8_t sign, shift;
347 uint16_t mag;
348 int32_t output = 0, x1, x2, y1, y2;
349
350 for ( counter = 0; counter < num_coeff; counter++ ) {
351 info = kp->info;
352 x_order = GET_X_ORDER(info);
353 y_order = GET_Y_ORDER(info);
354
355 shift = ( (uint16_t) kp->info & 0xff00) >> 8;
356 shift ^= 0x00ff;
357 shift += 1;
358 shift = -shift;
359
360 mag = kp->mag;
361
362 if ( GET_SIGN(info) ) {
363 sign = -1;
364 } else {
365 sign = 1;
366 }
367
368 if ( (x_order == 0) && (y_order == 0) ) {
369 output += sign * mag << output_fraction;
370 } else {
371 if ( x_order > 0 ) {
372 x1 = SI1133_calculate_polynomial_helper(x, input_fraction, mag, shift);
373 if ( x_order > 1 ) {
374 x2 = SI1133_calculate_polynomial_helper(x, input_fraction, mag, shift);
375 } else {
376 x2 = 1;
377 }
378 } else {
379 x1 = 1;
380 x2 = 1;
381 }
382
383 if ( y_order > 0 ) {
384 y1 = SI1133_calculate_polynomial_helper(y, input_fraction, mag, shift);
385 if ( y_order > 1 ) {
386 y2 = SI1133_calculate_polynomial_helper(y, input_fraction, mag, shift);
387 } else {
388 y2 = 1;
389 }
390 } else {
391 y1 = 1;
392 y2 = 1;
393 }
394
395 output += sign * x1 * x2 * y1 * y2;
396 }
397
398 kp++;
399 }
400
401 if ( output < 0 ) {
402 output = -output;
403 }
404
405 return output;
406}
407
408static int32_t SI1133_get_uv (int32_t uv)
409{
410 int32_t uvi;
411
413
414 return uvi;
415}
416
417static int32_t SI1133_get_lux (int32_t vis_high, int32_t vis_low, int32_t ir)
418{
419 int32_t lux;
420
421 if ( (vis_high > ADC_THRESHOLD) || (ir > ADC_THRESHOLD) )
422 {
423 lux = SI1133_calculate_polynomial(vis_high,
424 ir,
428 &(Si1133_lk.coeff_high[0]));
429 }
430 else
431 {
432 lux = SI1133_calculate_polynomial(vis_low,
433 ir,
437 &(Si1133_lk.coeff_low[0]) );
438 }
439
440 return lux;
441}
442
443/* --- PUBLIC FUNCTION --- */
445{
446 Si1133_error _ret;
447
448 /* Allow some time for the part to power up */
449 HAL_Delay(5);
450
451 _ret = SI1133_reset();
452
453 HAL_Delay(10);
454
468
470
471 return _ret;
472}
473
475{
476 Si1133_error _ret;
477
479 _ret += SI1133_pause_measurement();
480 _ret += SI1133_wait_until_sleep();
481
482 return _ret;
483}
484
486{
487 uint8_t buffer[13];
488 Si1133_error _ret;
489 Si1133_samples sample;
490 Si1133_samples *samples = &sample;
491
493
494 samples->irq_status = buffer[0];
495
496 samples->ch0 = buffer[1] << 16;
497 samples->ch0 |= (buffer[2] << 8);
498 samples->ch0 |= buffer[3];
499 if ( samples->ch0 & 0x800000 ) {
500 samples->ch0 |= 0xFF000000;
501 }
502
503 samples->ch1 = buffer[4] << 16;
504 samples->ch1 |= buffer[5] << 8;
505 samples->ch1 |= buffer[6];
506 if ( samples->ch1 & 0x800000 ) {
507 samples->ch1 |= 0xFF000000;
508 }
509
510 samples->ch2 = buffer[7] << 16;
511 samples->ch2 |= buffer[8] << 8;
512 samples->ch2 |= buffer[9];
513 if ( samples->ch2 & 0x800000 ) {
514 samples->ch2 |= 0xFF000000;
515 }
516
517 samples->ch3 = buffer[10] << 16;
518 samples->ch3 |= buffer[11] << 8;
519 samples->ch3 |= buffer[12];
520 if ( samples->ch3 & 0x800000 ) {
521 samples->ch3 |= 0xFF000000;
522 }
523
524 memcpy(_s1,&sample,sizeof(Si1133_samples));
525
526 return _ret;
527}
528
530{
531 return SI1133_Read_Reg(SI1133_REG_PART_ID, hardware_id);
532}
533
534Si1133_error SI1133_measure_lux_uv (float *lux, float *uvi)
535{
536 Si1133_samples _samples;
537 Si1133_error _ret;
538 uint8_t response;
539
540 /* Force measurement */
542
543 /* Go to sleep while the sensor does the conversion */
544 HAL_Delay(200);
545
546 /* Check if the measurement finished, if not then wait */
547 _ret += SI1133_Read_Reg(SI1133_REG_IRQ_STATUS, &response);
548 while ( response != 0x0F ) {
549 HAL_Delay(5);
550 _ret += SI1133_Read_Reg(SI1133_REG_IRQ_STATUS, &response);
551 }
552
553 /* Get the results */
554 memset(&_samples,0,sizeof(_samples));
555 _ret += SI1133_measure(&_samples);
556
557 /* Convert the readings to lux */
558 *lux = (float) SI1133_get_lux(_samples.ch1, _samples.ch3, _samples.ch2);
559 *lux = *lux / (float) (1 << LUX_OUTPUT_FRACTION);
560
561 /* Convert the readings to UV index */
562 *uvi = SI1133_get_uv(_samples.ch0);
563 *uvi = *uvi / (float)(1 << UV_OUTPUT_FRACTION);
564
565 return _ret;
566}
567
568
569Si1133_error SI1133_get_measurement (float *lux, float *uvi)
570{
571 Si1133_samples samples;
572 uint32_t _ret;
573
574 /* Get the results */
575 _ret = SI1133_measure(&samples);
576
577 /* Convert the readings to lux */
578 *lux = (float)SI1133_get_lux(samples.ch1, samples.ch3, samples.ch2);
579 *lux = *lux / (float)(1 << LUX_OUTPUT_FRACTION);
580
581 /* Convert the readings to UV index */
582 *uvi = (float)SI1133_get_uv(samples.ch0);
583 *uvi = *uvi / (float)(1 << UV_OUTPUT_FRACTION);
584
585 return _ret;
586}
587
589{
590 float lux, uvi;
591 (void)SI1133_measure_lux_uv(&lux, &uvi);
592 return lux;
593}
594
596{
597 float lux, uvi;
598 (void)SI1133_measure_lux_uv(&lux, &uvi);
599 return uvi;
600}
601
602
static Si1133_error SI1133_pause_measurement(void)
#define UV_INPUT_FRACTION
#define GET_X_ORDER(m)
Si1133_error SI1133_deinit(void)
#define GET_Y_ORDER(m)
#define SI1133_CONFIRM_COUNT
#define INPUT_FRACTION_HIGH
static Si1133_error SI1133_measure(Si1133_samples *_s1)
#define UV_NUMCOEFF
static Si1133_error SI1133_Write_Reg(Si1133_register w_addr, uint8_t data)
static int32_t SI1133_calculate_polynomial_helper(int32_t input, int8_t fraction, uint16_t mag, int8_t shift)
Si1133_error SI1133_measure_lux_uv(float *lux, float *uvi)
#define UV_I2C_SEND(ADDRESS, LEN, TIME)
float SI1133_get_uv_index(void)
const Si1133_coeff Si1133_uk[2]
static Si1133_error SI1133_Write_Reg_block(Si1133_register w_addr, uint8_t len, uint8_t *data)
#define UV_OUTPUT_FRACTION
Si1133_error SI1133_get_measurement(float *lux, float *uvi)
#define LUX_OUTPUT_FRACTION
const Si1133_LuxCoeff Si1133_lk
Si1133_error SI1133_init(void)
#define NUMCOEFF_HIGH
#define GET_SIGN(m)
#define UV_I2C_GET(ADDRESS, LEN, TIME)
static Si1133_error SI1133_send_cmd(Si1133_command command)
#define NUMCOEFF_LOW
static Si1133_error SI1133_wait_until_sleep(void)
static Si1133_error SI1133_force_measurement(void)
static Si1133_error SI1133_set_parameter(Si1133_parameter address, uint8_t value)
static int32_t SI1133_calculate_polynomial(int32_t x, int32_t y, uint8_t input_fraction, uint8_t output_fraction, uint8_t num_coeff, const Si1133_coeff *kp)
#define ADC_THRESHOLD
#define INPUT_FRACTION_LOW
static int32_t SI1133_get_lux(int32_t vis_high, int32_t vis_low, int32_t ir)
static int32_t SI1133_get_uv(int32_t uv)
Si1133_error SI1133_get_hardware_id(uint8_t *hardware_id)
static Si1133_error SI1133_Read_Reg(Si1133_register r_addr, uint8_t *buf)
static Si1133_error SI1133_reset(void)
float SI1133_get_light_level(void)
static Si1133_error SI1133_Read_Reg_block(Si1133_register r_addr, uint8_t len, uint8_t *buf)
Si1133_register
@ SI1133_REG_IRQ_STATUS
Interrupt status.
@ SI1133_REG_COMMAND
Initiated action in Sensor when specific codes written here.
@ SI1133_REG_IRQ_ENABLE
Interrupt enable
@ SI1133_REG_PART_ID
Part ID.
@ SI1133_REG_HOSTIN0
Host 0 -Data for parameter table on PARAM_SET write to COMMAND register.
@ SI1133_REG_RESPONSE0
Chip state and error status.
Si1133_error
@ SI_OK
@ SI_FAIL
@ SI1133_RSP0_CHIPSTAT_MASK
Chip state mask in Response0 register.
@ SI1133_RSP0_SLEEP
Sleep state indicator bit mask in Response0 register.
@ SI1133_RSP0_COUNTER_MASK
Command counter and error indicator mask in Response0 register.
Si1133_command
@ SI1133_CMD_RESET
Forces a Reset.
@ SI1133_CMD_PAUSE_CH
Pauses autonomous measurements.
@ SI1133_CMD_FORCE_CH
Initiates a set of measurements specified in CHAN_LIST parameter.
@ SI1133_CMD_RESET_CMD_CTR
Resets the command counter.
@ SI1133_CMD_START
Starts autonomous measurements.
Si1133_parameter
@ SI1133_PARAM_ADCPOST2
ADC resolution, shift and threshold settings for Channel 2.
@ SI1133_PARAM_ADCSENS1
ADC sensitivity setting for Channel 1.
@ SI1133_PARAM_ADCSENS3
ADC sensitivity setting for Channel 3.
@ SI1133_PARAM_ADCCONFIG3
ADC config for Channel 3
@ SI1133_PARAM_ADCCONFIG1
ADC config for Channel 1.
@ SI1133_PARAM_CH_LIST
Channel list.
@ SI1133_PARAM_ADCCONFIG2
ADC config for Channel 2.
@ SI1133_PARAM_ADCSENS0
ADC sensitivity setting for Channel 0.
@ SI1133_PARAM_ADCSENS2
ADC sensitivity setting for Channel 2.
@ SI1133_PARAM_ADCCONFIG0
ADC config for Channel 0.
@ SI1133_PARAM_ADCPOST0
ADC resolution, shift and threshold settings for Channel 0.
@ SI1133_PARAM_ADCPOST3
ADC resolution, shift and threshold settings for Channel 3.
@ SI1133_PARAM_ADCPOST1
ADC resolution, shift and threshold settings for Channel 1.
Si1133_samples
monoZ Error Handler
@ MZ_OK
mzUint8 buf[10]
Si1133_coeff coeff_low[9]
Low amplitude coeffs
Si1133_coeff coeff_high[4]
High amplitude coeffs.
uint16_t mag
Magnitude.
int16_t info
Info.