I am trying to read the values of UV, VIS and IR from the SI1145 (I2C device), but I get wrong results in a dark room with low level of light. I made the SI1145 component similar to Arduino's library for this Adafuit's sensor.
I am coding on Visual Studio with ESP-IDF v.5.3.0
Any suggestions to read properly the sensor?? Thank you so much.
I attach an image with the results: And here is my code:
i2c_config component:
- i2c_config.h:
Code: Select all
#ifndef _I2C_CONFIG_H
#define _I2C_CONFIG_H
#define I2C_MASTER_SCL_IO CONFIG_I2C_MASTER_SCL_IO /* GPIO number used for I2C master clock */
#define I2C_MASTER_SDA_IO CONFIG_I2C_MASTER_SDA_IO /* GPIO number used for I2C master data */
#define I2C_MASTER_NUM 1 /* I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ 100000 /* I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0 /* I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /* I2C master doesn't need buffer */
#define I2C_MASTER_TIMEOUT_MS 1000
#define ACK_CHECK_EN 0x1 /* I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /* I2C master will not check ack from slave */
#define ACK_VAL 0x0 /* I2C ack value */
#define NACK_VAL 0x1 /* I2C nack value */
void i2c_master_init();
#endif /* _I2C_CONFIG_H */Code: Select all
#include "driver/i2c.h"
#include "i2c_config.h"
void i2c_master_init()
{
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
i2c_param_config(I2C_MASTER_NUM, &conf);
i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}- si1145.h:
Code: Select all
#ifndef _SI1145_H_
#define _SI1145_H_
/* ADDRESS */
#define SI1145_ADDR 0x60
/* REGISTERS */
#define SI1145_REG_PART_ID 0x00
#define SI1145_REG_REV_ID 0x01
#define SI1145_REG_SEQ_ID 0x02
#define SI1145_REG_INTCFG 0x03
#define SI1145_REG_INTCFG_INTOE 0x01
#define SI1145_REG_INTCFG_INTMODE 0x02
#define SI1145_REG_IRQEN 0x04
#define SI1145_REG_IRQEN_ALSEVERYSAMPLE 0x01
#define SI1145_REG_IRQEN_PS1EVERYSAMPLE 0x04
#define SI1145_REG_IRQEN_PS2EVERYSAMPLE 0x08
#define SI1145_REG_IRQEN_PS3EVERYSAMPLE 0x10
#define SI1145_REG_IRQMODE1 0x05
#define SI1145_REG_IRQMODE2 0x06
#define SI1145_REG_HWKEY 0x07
#define SI1145_REG_MEASRATE0 0x08
#define SI1145_REG_MEASRATE1 0x09
#define SI1145_REG_PSRATE 0x0A
#define SI1145_REG_PSLED21 0x0F
#define SI1145_REG_PSLED3 0x10
#define SI1145_REG_UCOEF0 0x13
#define SI1145_REG_UCOEF1 0x14
#define SI1145_REG_UCOEF2 0x15
#define SI1145_REG_UCOEF3 0x16
#define SI1145_REG_PARAMWR 0x17
#define SI1145_REG_COMMAND 0x18
#define SI1145_REG_RESPONSE 0x20
#define SI1145_REG_IRQSTAT 0x21
#define SI1145_REG_IRQSTAT_ALS 0x01
#define SI1145_REG_ALSVISDATA0 0x22
#define SI1145_REG_ALSVISDATA1 0x23
#define SI1145_REG_ALSIRDATA0 0x24
#define SI1145_REG_ALSIRDATA1 0x25
#define SI1145_REG_PS1DATA0 0x26
#define SI1145_REG_PS1DATA1 0x27
#define SI1145_REG_PS2DATA0 0x28
#define SI1145_REG_PS2DATA1 0x29
#define SI1145_REG_PS3DATA0 0x2A
#define SI1145_REG_PS3DATA1 0x2B
#define SI1145_REG_UVINDEX0 0x2C
#define SI1145_REG_UVINDEX1 0x2D
#define SI1145_REG_PARAMRD 0x2E
#define SI1145_REG_CHIPSTAT 0x30
/* PARAMETERS */
#define SI1145_PARAM_I2CADDR 0x00
#define SI1145_PARAM_CHLIST 0x01
#define SI1145_PARAM_CHLIST_ENUV 0x80
#define SI1145_PARAM_CHLIST_ENAUX 0x40
#define SI1145_PARAM_CHLIST_ENALSIR 0x20
#define SI1145_PARAM_CHLIST_ENALSVIS 0x10
#define SI1145_PARAM_CHLIST_ENPS1 0x01
#define SI1145_PARAM_CHLIST_ENPS2 0x02
#define SI1145_PARAM_CHLIST_ENPS3 0x04
#define SI1145_PARAM_PSLED12SEL 0x02
#define SI1145_PARAM_PSLED12SEL_PS2NONE 0x00
#define SI1145_PARAM_PSLED12SEL_PS2LED1 0x10
#define SI1145_PARAM_PSLED12SEL_PS2LED2 0x20
#define SI1145_PARAM_PSLED12SEL_PS2LED3 0x40
#define SI1145_PARAM_PSLED12SEL_PS1NONE 0x00
#define SI1145_PARAM_PSLED12SEL_PS1LED1 0x01
#define SI1145_PARAM_PSLED12SEL_PS1LED2 0x02
#define SI1145_PARAM_PSLED12SEL_PS1LED3 0x04
#define SI1145_PARAM_PSLED3SEL 0x03
#define SI1145_PARAM_PSENCODE 0x05
#define SI1145_PARAM_ALSENCODE 0x06
#define SI1145_PARAM_PS1ADCMUX 0x07
#define SI1145_PARAM_PS2ADCMUX 0x08
#define SI1145_PARAM_PS3ADCMUX 0x09
#define SI1145_PARAM_PSADCOUNTER 0x0A
#define SI1145_PARAM_PSADCGAIN 0x0B
#define SI1145_PARAM_PSADCMISC 0x0C
#define SI1145_PARAM_PSADCMISC_RANGE 0x20
#define SI1145_PARAM_PSADCMISC_PSMODE 0x04
#define SI1145_PARAM_ALSIRADCMUX 0x0E
#define SI1145_PARAM_AUXADCMUX 0x0F
#define SI1145_PARAM_ALSVISADCOUNTER 0x10
#define SI1145_PARAM_ALSVISADCGAIN 0x11
#define SI1145_PARAM_ALSVISADCMISC 0x12
#define SI1145_PARAM_ALSVISADCMISC_VISRANGE 0x20
#define SI1145_PARAM_ALSIRADCOUNTER 0x1D
#define SI1145_PARAM_ALSIRADCGAIN 0x1E
#define SI1145_PARAM_ALSIRADCMISC 0x1F
#define SI1145_PARAM_ALSIRADCMISC_RANGE 0x20
#define SI1145_PARAM_ADCCOUNTER_511CLK 0x70
#define SI1145_PARAM_ADCMUX_SMALLIR 0x00
#define SI1145_PARAM_ADCMUX_LARGEIR 0x03
/* COMMANDS */
#define SI1145_PARAM_QUERY 0x80
#define SI1145_PARAM_SET 0xA0
#define SI1145_NOP 0x00
#define SI1145_RESET 0x01
#define SI1145_BUSADDR 0x02
#define SI1145_PS_FORCE 0x05
#define SI1145_ALS_FORCE 0x06
#define SI1145_PSALS_FORCE 0x07
#define SI1145_PS_PAUSE 0x09
#define SI1145_ALS_PAUSE 0x0A
#define SI1145_PSALS_PAUSE 0xB
#define SI1145_PS_AUTO 0x0D
#define SI1145_ALS_AUTO 0x0E
#define SI1145_PSALS_AUTO 0x0F
#define SI1145_GET_CAL 0x12
static const char *TAG_SI1145 = "SI1145";
void si1145_read_register_16(uint8_t reg, uint16_t *data);
void si1145_read_register(uint8_t reg, uint8_t *data);
void si1145_write_register(uint8_t reg, uint8_t value);
void si1145_write_command(uint8_t command);
void si1145_write_param(uint8_t param, uint8_t value);
void si1145_reset();
void si1145_configure(void);
#endif /*_SI1145_H_*/Code: Select all
#include <stdio.h>
#include "driver/i2c.h"
#include "esp_log.h"
#include "i2c_config.h"
#include "SI1145.h"
void si1145_read_register_16(uint8_t reg, uint16_t *data)
{
uint8_t read_data[2] = {0, 0};
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, SI1145_ADDR << 1 | 0, ACK_CHECK_EN);
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
vTaskDelay(0.02 / portTICK_PERIOD_MS);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
vTaskDelay(90 / portTICK_PERIOD_MS);
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
// i2c_master_write_byte(cmd, (SI1145_ADDR << 1) | I2C_MASTER_WRITE, true);
// i2c_master_write_byte(cmd, reg, true);
// i2c_master_start(cmd);
i2c_master_write_byte(cmd, (SI1145_ADDR << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, &read_data[0], 0x00); //I2C_MASTER_ACK
i2c_master_read_byte(cmd, &read_data[1], 0x01); //I2C_MASTER_NACK
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
vTaskDelay(pdMS_TO_TICKS(100));
*data = ((uint16_t)(read_data[0] << 8)) | ((uint16_t)(read_data[1] & 0xFF));
}
void si1145_read_register(uint8_t reg, uint8_t *data)
{
uint8_t read_data = 0;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (SI1145_ADDR << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, reg, true);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (SI1145_ADDR << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, &read_data, I2C_MASTER_LAST_NACK);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
vTaskDelay(pdMS_TO_TICKS(100));
*data = read_data;
}
void si1145_write_register(uint8_t reg, uint8_t value)
{
uint8_t data[2] = {reg, value};
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (SI1145_ADDR << 1) | I2C_MASTER_WRITE, true);
i2c_master_write(cmd, data, sizeof(data), true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
vTaskDelay(pdMS_TO_TICKS(100));
}
void si1145_write_command(uint8_t command)
{
si1145_write_register(SI1145_REG_COMMAND, command);
}
void si1145_write_param(uint8_t param, uint8_t value)
{
uint8_t value_read = 0;
si1145_write_register(SI1145_REG_PARAMWR, value);
si1145_write_command(param | SI1145_PARAM_SET);
si1145_read_register(SI1145_REG_PARAMRD, &value_read);
}
void si1145_reset()
{
si1145_write_register(SI1145_REG_MEASRATE0, 0);
si1145_write_register(SI1145_REG_MEASRATE1, 0);
si1145_write_register(SI1145_REG_IRQEN, 0);
si1145_write_register(SI1145_REG_IRQMODE1, 0);
si1145_write_register(SI1145_REG_IRQMODE2, 0);
si1145_write_register(SI1145_REG_INTCFG, 0);
si1145_write_register(SI1145_REG_IRQSTAT, 0xFF);
si1145_write_command(SI1145_RESET);
vTaskDelay(pdMS_TO_TICKS(10));
si1145_write_register(SI1145_REG_HWKEY, 0x17);
vTaskDelay(pdMS_TO_TICKS(10));
}
void si1145_configure(void)
{
si1145_reset();
/* Enable UV Index mesurements coefficients */
si1145_write_register(SI1145_REG_UCOEF0, 0x29);
si1145_write_register(SI1145_REG_UCOEF1, 0x89);
si1145_write_register(SI1145_REG_UCOEF2, 0x02);
si1145_write_register(SI1145_REG_UCOEF3, 0x00);
/* Enable UV sensor */
si1145_write_param(SI1145_PARAM_CHLIST, SI1145_PARAM_CHLIST_ENUV | SI1145_PARAM_CHLIST_ENALSIR | SI1145_PARAM_CHLIST_ENALSVIS | SI1145_PARAM_CHLIST_ENPS1);
/* Enable interrupt on every sample */
si1145_write_register(SI1145_REG_INTCFG, SI1145_REG_INTCFG_INTOE);
si1145_write_register(SI1145_REG_IRQEN, SI1145_REG_IRQEN_ALSEVERYSAMPLE);
/* ********* PROX SENSE 1 ********* */
/* Program LED Current */
si1145_write_register(SI1145_REG_PSLED21, 0x03); // 20mA for LED 1 only
si1145_write_param(SI1145_PARAM_PS1ADCMUX, SI1145_PARAM_ADCMUX_LARGEIR);
// prox sensor #1 uses LED #1
si1145_write_param(SI1145_PARAM_PSLED12SEL, SI1145_PARAM_PSLED12SEL_PS1LED1);
// fastest clocks, clock div 1
si1145_write_param(SI1145_PARAM_PSADCGAIN, 0);
// take 511 clocks to measure
si1145_write_param(SI1145_PARAM_PSADCOUNTER, SI1145_PARAM_ADCCOUNTER_511CLK);
// in prox mode, high range
si1145_write_param(SI1145_PARAM_PSADCMISC, SI1145_PARAM_PSADCMISC_RANGE | SI1145_PARAM_PSADCMISC_PSMODE);
si1145_write_param(SI1145_PARAM_ALSIRADCMUX, SI1145_PARAM_ADCMUX_SMALLIR);
// fastest clocks, clock div 1
si1145_write_param(SI1145_PARAM_ALSIRADCGAIN, 0);
// take 511 clocks to measure
si1145_write_param(SI1145_PARAM_ALSIRADCOUNTER, SI1145_PARAM_ADCCOUNTER_511CLK);
// in high range mode
si1145_write_param(SI1145_PARAM_ALSIRADCMISC, SI1145_PARAM_ALSIRADCMISC_RANGE);
// fastest clocks, clock div 1
si1145_write_param(SI1145_PARAM_ALSVISADCGAIN, 0);
// take 511 clocks to measure
si1145_write_param(SI1145_PARAM_ALSVISADCOUNTER, SI1145_PARAM_ADCCOUNTER_511CLK);
// in high range mode (not normal signal)
si1145_write_param(SI1145_PARAM_ALSVISADCMISC, SI1145_PARAM_ALSVISADCMISC_VISRANGE);
/* ********************************************* */
/* Measurement rate for auto */
si1145_write_register(SI1145_REG_MEASRATE0, 0xFF); // 255 * 31.25uS = 8ms
/* auto run */
si1145_write_command(SI1145_PSALS_AUTO);
ESP_LOGI(TAG_SI1145, "Config Si1145 complete");
}- main.c:
Code: Select all
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/i2c.h"
#include "i2c_config.h"
#include "SI1145.h"
static const char *TAG = "SI1145_test";
void app_main(void)
{
i2c_master_init();
vTaskDelay(pdMS_TO_TICKS(100));
si1145_configure();
vTaskDelay(pdMS_TO_TICKS(100));
while (1)
{
uint16_t uv_index, visible, ir;
// Read UV, VIS and IR
si1145_read_register_16(SI1145_REG_UVINDEX0, &uv_index);
ESP_LOGI(TAG, "UV Index: %f", (((float)uv_index) / 100));
vTaskDelay(pdMS_TO_TICKS(1000));
si1145_read_register_16(SI1145_REG_ALSVISDATA0, &visible);
ESP_LOGI(TAG, "Visible Light: %d", (int)visible);
vTaskDelay(pdMS_TO_TICKS(1000));
si1145_read_register_16(SI1145_REG_ALSIRDATA0, &ir);
ESP_LOGI(TAG, "IR Light: %d", (int)ir);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}