Skip to content

Commit aeac04c

Browse files
committed
drivers: sensor: Add support for BH1750 ambient light sensor
This commit adds support for BH1750 ambient light sensor. The driver works using I2C peripheral in one-time mode. Signed-off-by: Michal morsisko <[email protected]>
1 parent 432ff20 commit aeac04c

File tree

7 files changed

+284
-0
lines changed

7 files changed

+284
-0
lines changed

drivers/sensor/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_subdirectory_ifdef(CONFIG_AMG88XX amg88xx)
99
add_subdirectory_ifdef(CONFIG_AMS_AS5600 ams_as5600)
1010
add_subdirectory_ifdef(CONFIG_AMS_IAQ_CORE ams_iAQcore)
1111
add_subdirectory_ifdef(CONFIG_APDS9960 apds9960)
12+
add_subdirectory_ifdef(CONFIG_BH1750 bh1750)
1213
add_subdirectory_ifdef(CONFIG_BMA280 bma280)
1314
add_subdirectory_ifdef(CONFIG_BMC150_MAGN bmc150_magn)
1415
add_subdirectory_ifdef(CONFIG_BME280 bme280)

drivers/sensor/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ source "drivers/sensor/ams_iAQcore/Kconfig"
5959

6060
source "drivers/sensor/apds9960/Kconfig"
6161

62+
source "drivers/sensor/bh1750/Kconfig"
63+
6264
source "drivers/sensor/bma280/Kconfig"
6365

6466
source "drivers/sensor/bmc150_magn/Kconfig"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
5+
zephyr_library_sources(bh1750.c)

drivers/sensor/bh1750/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# BH1750 ambient light sensor configuration options
2+
3+
# Copyright (c) 2022 Michal Morsisko
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config BH1750
7+
bool "BH1750 ambient light sensor"
8+
default y
9+
depends on DT_HAS_ROHM_BH1750_ENABLED
10+
select I2C
11+
help
12+
Enable driver for BH1750 ambient light sensor.

drivers/sensor/bh1750/bh1750.c

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/*
2+
* Copyright (c) 2022, Michal Morsisko
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT rohm_bh1750
8+
9+
#include <zephyr/drivers/sensor.h>
10+
#include <zephyr/drivers/i2c.h>
11+
#include <zephyr/logging/log.h>
12+
#include <zephyr/kernel.h>
13+
#include <zephyr/devicetree.h>
14+
#include <zephyr/sys/byteorder.h>
15+
#include <zephyr/sys/__assert.h>
16+
17+
LOG_MODULE_REGISTER(BH1750, CONFIG_SENSOR_LOG_LEVEL);
18+
19+
#define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10
20+
#define BH1750_CONTINUOUS_HIGH_RES_MODE_2 0x11
21+
#define BH1750_CONTINUOUS_LOW_RES_MODE 0x13
22+
#define BH1750_ONE_TIME_HIGH_RES_MODE 0x20
23+
#define BH1750_ONE_TIME_HIGH_RES_MODE_2 0x21
24+
#define BH1750_ONE_TIME_LOW_RES_MODE 0x23
25+
#define BH1750_MTREG_HIGH_BYTE 0x40
26+
#define BH1750_MTREG_LOW_BYTE 0x60
27+
#define BH1750_MTREG_HIGH_BYTE_MASK 0xE0
28+
#define BH1750_MTREG_LOW_BYTE_MASK 0x1F
29+
30+
#define BH1750_DEFAULT_MTREG 69U
31+
#define BH1750_LOW_RES_MODE_MAX_WAIT 24U
32+
#define BH1750_HIGH_RES_MODE_MAX_WAIT 180U
33+
#define BH1750_LOW_RES_MODE_TYPICAL_WAIT 16U
34+
#define BH1750_HIGH_RES_MODE_TYPICAL_WAIT 120U
35+
36+
#define BH1750_LOW_RES_DTS_ENUM 0U
37+
#define BH1750_HIGH_RES_DTS_ENUM 1U
38+
#define BH1750_HIGH_RES_2_DTS_ENUM 2U
39+
40+
struct bh1750_dev_config {
41+
struct i2c_dt_spec bus;
42+
uint8_t resolution;
43+
uint8_t mtreg;
44+
};
45+
46+
struct bh1750_data {
47+
uint16_t sample;
48+
};
49+
50+
static int bh1750_opcode_read(const struct device *dev, uint8_t opcode,
51+
uint16_t *val)
52+
{
53+
const struct bh1750_dev_config *cfg = dev->config;
54+
int rc;
55+
56+
rc = i2c_burst_read_dt(&cfg->bus, opcode, (uint8_t *)val, 2);
57+
if (rc < 0) {
58+
return rc;
59+
}
60+
61+
*val = sys_be16_to_cpu(*val);
62+
return 0;
63+
}
64+
65+
static int bh1750_opcode_write(const struct device *dev, uint8_t opcode)
66+
{
67+
const struct bh1750_dev_config *cfg = dev->config;
68+
69+
return i2c_write_dt(&cfg->bus, &opcode, 1);
70+
}
71+
72+
static int bh1750_mtreg_write(const struct device *dev, uint8_t mtreg)
73+
{
74+
int rc;
75+
uint8_t high_byte = mtreg & BH1750_MTREG_HIGH_BYTE_MASK;
76+
uint8_t low_byte = mtreg & BH1750_MTREG_LOW_BYTE_MASK;
77+
78+
rc = bh1750_opcode_write(dev, BH1750_MTREG_HIGH_BYTE | (high_byte >> 5));
79+
if (rc < 0) {
80+
LOG_ERR("%s, Failed to write high byte of mtreg!",
81+
dev->name);
82+
return rc;
83+
}
84+
85+
rc = bh1750_opcode_write(dev, BH1750_MTREG_LOW_BYTE | low_byte);
86+
if (rc < 0) {
87+
LOG_ERR("%s, Failed to write low byte of mtreg!",
88+
dev->name);
89+
return rc;
90+
}
91+
92+
return 0;
93+
}
94+
95+
static uint8_t bh1750_get_mode_from_dts_device(const struct device *dev)
96+
{
97+
const struct bh1750_dev_config *cfg = dev->config;
98+
99+
if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) {
100+
return BH1750_ONE_TIME_HIGH_RES_MODE_2;
101+
} else if (cfg->resolution == BH1750_HIGH_RES_DTS_ENUM) {
102+
return BH1750_ONE_TIME_HIGH_RES_MODE;
103+
} else {
104+
return BH1750_ONE_TIME_LOW_RES_MODE;
105+
}
106+
}
107+
108+
static int bh1750_get_wait_time_from_dts_device(const struct device *dev)
109+
{
110+
const struct bh1750_dev_config *cfg = dev->config;
111+
112+
if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) {
113+
return BH1750_HIGH_RES_MODE_MAX_WAIT;
114+
} else if (cfg->resolution == BH1750_HIGH_RES_DTS_ENUM) {
115+
return BH1750_HIGH_RES_MODE_MAX_WAIT;
116+
} else {
117+
return BH1750_LOW_RES_MODE_MAX_WAIT;
118+
}
119+
}
120+
121+
static int bh1750_sample_fetch(const struct device *dev,
122+
enum sensor_channel chan)
123+
{
124+
const struct bh1750_dev_config *cfg = dev->config;
125+
struct bh1750_data *drv_data = dev->data;
126+
const int max_wait = bh1750_get_wait_time_from_dts_device(dev);
127+
const uint8_t mode = bh1750_get_mode_from_dts_device(dev);
128+
int rc;
129+
int wait_time;
130+
131+
if (chan != SENSOR_CHAN_ALL &&
132+
chan != SENSOR_CHAN_LIGHT) {
133+
return -ENOTSUP;
134+
}
135+
136+
/* Start the measurement */
137+
rc = bh1750_opcode_write(dev, mode);
138+
if (rc < 0) {
139+
LOG_ERR("%s, Failed to start measurement!",
140+
dev->name);
141+
return rc;
142+
}
143+
144+
/* Calculate measurement time */
145+
wait_time = (max_wait * (cfg->mtreg * 10000 / BH1750_DEFAULT_MTREG)) / 10000;
146+
147+
/* Wait for the measurement to be stored in the sensor memory */
148+
k_msleep(wait_time);
149+
150+
/* Fetch result */
151+
rc = bh1750_opcode_read(dev, mode, &drv_data->sample);
152+
if (rc < 0) {
153+
LOG_ERR("%s: Failed to read measurement result!",
154+
dev->name);
155+
return rc;
156+
}
157+
158+
return 0;
159+
}
160+
161+
static int bh1750_channel_get(const struct device *dev,
162+
enum sensor_channel chan,
163+
struct sensor_value *val)
164+
{
165+
const struct bh1750_dev_config *cfg = dev->config;
166+
struct bh1750_data *drv_data = dev->data;
167+
uint32_t tmp;
168+
169+
if (chan != SENSOR_CHAN_ALL &&
170+
chan != SENSOR_CHAN_LIGHT) {
171+
return -ENOTSUP;
172+
}
173+
174+
/* See datasheet (Technical note 11046EDT01), page 11
175+
* https://www.mouser.com/datasheet/2/348/Rohm_11162017_ROHMS34826-1-1279292.pdf
176+
* for more information how to convert raw sample to lx
177+
*/
178+
tmp = (drv_data->sample * 1000 / 12) * (BH1750_DEFAULT_MTREG * 100 / cfg->mtreg);
179+
180+
if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) {
181+
tmp /= 2;
182+
}
183+
184+
val->val1 = tmp / 10000;
185+
val->val2 = (tmp % 10000) * 100;
186+
187+
return 0;
188+
}
189+
190+
static const struct sensor_driver_api bh1750_driver_api = {
191+
.sample_fetch = bh1750_sample_fetch,
192+
.channel_get = bh1750_channel_get
193+
};
194+
195+
static int bh1750_init(const struct device *dev)
196+
{
197+
const struct bh1750_dev_config *cfg = dev->config;
198+
199+
if (!device_is_ready(cfg->bus.bus)) {
200+
LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name);
201+
return -ENODEV;
202+
}
203+
204+
if (cfg->mtreg != BH1750_DEFAULT_MTREG) {
205+
bh1750_mtreg_write(dev, cfg->mtreg);
206+
}
207+
208+
return 0;
209+
}
210+
211+
#define DEFINE_BH1750(_num) \
212+
static struct bh1750_data bh1750_data_##_num; \
213+
static const struct bh1750_dev_config bh1750_config_##_num = { \
214+
.bus = I2C_DT_SPEC_INST_GET(_num), \
215+
.mtreg = DT_INST_PROP(_num, mtreg), \
216+
.resolution = DT_INST_PROP(_num, resolution) \
217+
}; \
218+
SENSOR_DEVICE_DT_INST_DEFINE(_num, bh1750_init, NULL, \
219+
&bh1750_data_##_num, &bh1750_config_##_num, POST_KERNEL, \
220+
CONFIG_SENSOR_INIT_PRIORITY, &bh1750_driver_api);
221+
222+
DT_INST_FOREACH_STATUS_OKAY(DEFINE_BH1750)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright (c) 2022, Michal Morsisko
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Rohm BH1750 ambient light sensor.
5+
6+
compatible: "rohm,bh1750"
7+
8+
include: [sensor-device.yaml, i2c-device.yaml]
9+
10+
properties:
11+
resolution:
12+
type: int
13+
default: 1
14+
description: |
15+
Resolution of the measurement result
16+
0 = low resolution
17+
1 = high resolution
18+
2 = high resolution 2
19+
The default mode number 1 is mentioned
20+
in the datasheet as recommended by the
21+
sensor manufacturer. One should pick
22+
other mode, if higher or lower resolution
23+
is desired.
24+
enum:
25+
- 0
26+
- 1
27+
- 2
28+
mtreg:
29+
type: int
30+
default: 69
31+
description: |
32+
Duration of single measurement process.
33+
The greater the value, the longer the duration
34+
and greater accuracy. After sensor power-on
35+
mtreg register is set to default value of
36+
this property (chosen by sensor manufacturer): 69.
37+
Valid values are in range 31-254 (inclusive).

tests/drivers/build_all/sensor/i2c.dtsi

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,3 +646,8 @@ test_i2c_as5600: as5600@64 {
646646
compatible = "ams,as5600";
647647
reg = <0x64>;
648648
};
649+
650+
test_i2c_bh1750: bh1750@65 {
651+
compatible = "rohm,bh1750";
652+
reg = <0x65>;
653+
};

0 commit comments

Comments
 (0)