als: Update ambient light sensor driver to use integers

Additionally separate calibration so later Aula one can be used
This commit is contained in:
CTCaer 2021-06-08 05:49:16 +03:00
parent a959196c2a
commit 1f4f41b6e6
2 changed files with 101 additions and 65 deletions

View file

@ -23,79 +23,117 @@
#include <soc/pinmux.h> #include <soc/pinmux.h>
#include <utils/util.h> #include <utils/util.h>
#define HOS_GAIN BH1730_GAIN_64X #define BH1730_DEFAULT_GAIN BH1730_GAIN_64X
#define HOS_ITIME 38 #define BH1730_DEFAULT_ICYCLE 38
void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime) #define BH1730_INTERNAL_CLOCK_NS 2800
#define BH1730_ADC_CALC_DELAY_US 2000 /* BH1730_INTERNAL_CLOCK_MS * 714 */
#define BH1730_ITIME_CYCLE_TO_US 2700 /* BH1730_INTERNAL_CLOCK_MS * 964 */
#define BH1730_DEFAULT_ITIME_MS 100
#define BH1730_LUX_MULTIPLIER 3600
#define BH1730_LUX_MULTIPLIER_AULA 1410
#define BH1730_LUX_MAX 100000
typedef struct _opt_win_cal_t
{ {
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain); u32 rc;
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - itime)); u32 cv;
u32 ci;
} opt_win_cal_t;
als_val->gain = gain; // Nintendo Switch Icosa/Iowa Optical Window calibration.
als_val->itime = itime; const opt_win_cal_t opt_win_cal_default[] = {
{ 500, 5002, 7502 },
{ 754, 2250, 2000 },
{ 1029, 1999, 1667 },
{ 1373, 884, 583 },
{ 1879, 309, 165 }
};
// Nintendo Switch Aula Optical Window calibration.
const opt_win_cal_t opt_win_cal_aula[] = {
{ 231, 9697, 30300 },
{ 993, 3333, 2778 },
{ 1478, 1621, 1053 },
{ 7500, 81, 10 }
};
const u32 als_gain_idx_tbl[4] = { 1, 2, 64, 128 };
void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle)
{
if (gain > BH1730_GAIN_128X)
gain = BH1730_GAIN_128X;
if (!cycle)
cycle = 1;
else if (cycle > 255)
cycle = 255;
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain);
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - cycle));
als_ctxt->gain = gain;
als_ctxt->cycle = cycle;
} }
void get_als_lux(als_table_t *als_val) void get_als_lux(als_ctxt_t *als_ctxt)
{ {
u32 data[2]; u32 data[2];
float pre_gain_lux; u32 visible_light;
float visible_light; u32 ir_light;
float ir_light; u64 lux = 0;
float light_ratio; u32 itime_us = BH1730_ITIME_CYCLE_TO_US * als_ctxt->cycle;
u8 adc_ready = 0; // Get visible and ir light raw data. Mode is continuous so waiting for new values doesn't matter.
u8 retries = 100;
const float als_gain_idx_tbl[4] = { 1.0, 2.0, 64.0, 128.0 };
const float als_norm_res = 100.0;
const float als_multiplier = 3.6;
const float als_tint = 2.7;
// Wait for ADC to prepare new data.
while (!(adc_ready & BH1730_CTL_ADC_VALID) && retries)
{
retries--;
adc_ready = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG));
}
// Get visible and ir light raw data.
data[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) + data[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) +
(i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8); (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8);
data[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) + data[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) +
(i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8); (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8);
als_val->over_limit = data[0] > 65534 || data[1] > 65534; visible_light = data[0];
als_val->vi_light = data[0]; ir_light = data[1];
als_val->ir_light = data[1];
if (!data[0] || !retries) als_ctxt->over_limit = visible_light > 65534 || ir_light > 65534;
als_ctxt->vi_light = visible_light;
als_ctxt->ir_light = ir_light;
if (!visible_light)
{ {
als_val->lux = 0.0; als_ctxt->lux = 0;
return; return;
} }
visible_light = (float)data[0]; // Set calibration parameters.
ir_light = (float)data[1]; u32 lux_multiplier = BH1730_LUX_MULTIPLIER;
light_ratio = (float)data[1] / (float)data[0]; u32 opt_win_cal_count = ARRAY_SIZE(opt_win_cal_default);
const opt_win_cal_t *opt_win_cal = opt_win_cal_default;
// The following are specific to the light filter Switch uses. // Apply optical window calibration coefficients.
if (light_ratio < 0.5) for (u32 i = 0; i < opt_win_cal_count; i++)
pre_gain_lux = visible_light * 5.002 - ir_light * 7.502; {
else if (light_ratio < 0.754) if (1000 * ir_light / visible_light < opt_win_cal[i].rc)
pre_gain_lux = visible_light * 2.250 - ir_light * 2.000; {
else if (light_ratio < 1.029) lux = ((u64)opt_win_cal[i].cv * data[0]) - (opt_win_cal[i].ci * data[1]);
pre_gain_lux = visible_light * 1.999 - ir_light * 1.667; break;
else if (light_ratio < 1.373) }
pre_gain_lux = visible_light * 0.884 - ir_light * 0.583; }
else if (light_ratio < 1.879)
pre_gain_lux = visible_light * 0.309 - ir_light * 0.165;
else pre_gain_lux = 0.0;
als_val->lux = (pre_gain_lux / als_gain_idx_tbl[als_val->gain]) * (als_norm_res / ((float)als_val->itime * als_tint)) * als_multiplier; lux *= BH1730_DEFAULT_ITIME_MS * lux_multiplier;
lux /= als_gain_idx_tbl[als_ctxt->gain] * itime_us;
lux /= 1000;
if (lux > BH1730_LUX_MAX)
lux = BH1730_LUX_MAX;
als_ctxt->lux = lux;
} }
u8 als_init(als_table_t *als_val) u8 als_power_on(als_ctxt_t *als_ctxt)
{ {
// Enable power to ALS IC. // Enable power to ALS IC.
max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000); max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000);
@ -109,12 +147,10 @@ u8 als_init(als_table_t *als_val)
// Initialize ALS. // Initialize ALS.
u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12)); u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12));
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0); i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0);
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), HOS_GAIN);
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - HOS_ITIME));
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN);
als_val->gain = HOS_GAIN; set_als_cfg(als_ctxt, BH1730_DEFAULT_GAIN, BH1730_DEFAULT_ICYCLE);
als_val->itime = HOS_ITIME;
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN);
return id; return id;
} }

View file

@ -48,18 +48,18 @@
#define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | (reg)) #define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | (reg))
#define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | (cmd)) #define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | (cmd))
typedef struct _als_table_t typedef struct _als_ctxt_t
{ {
float lux; u32 lux;
bool over_limit; bool over_limit;
u32 vi_light; u32 vi_light;
u32 ir_light; u32 ir_light;
u8 gain; u8 gain;
u8 itime; u8 cycle;
} als_table_t; } als_ctxt_t;
void set_als_cfg(als_table_t *als_val, u8 gain, u8 itime); void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle);
void get_als_lux(als_table_t *als_val); void get_als_lux(als_ctxt_t *als_ctxt);
u8 als_init(als_table_t *als_val); u8 als_power_on(als_ctxt_t *als_ctxt);
#endif /* __ALS_H_ */ #endif /* __ALS_H_ */