-
Notifications
You must be signed in to change notification settings - Fork 8.2k
drivers: sensor: Add support for BH1750 ambient light sensor #43086
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| zephyr_library() | ||
|
|
||
| zephyr_library_sources(bh1750.c) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # BH1750 ambient light sensor configuration options | ||
|
|
||
| # Copyright (c) 2022 Michal Morsisko | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| config BH1750 | ||
| bool "BH1750 ambient light sensor" | ||
| default y | ||
| depends on DT_HAS_ROHM_BH1750_ENABLED | ||
| select I2C | ||
| help | ||
| Enable driver for BH1750 ambient light sensor. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,222 @@ | ||
| /* | ||
| * Copyright (c) 2022, Michal Morsisko | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| #define DT_DRV_COMPAT rohm_bh1750 | ||
|
|
||
| #include <zephyr/drivers/sensor.h> | ||
| #include <zephyr/drivers/i2c.h> | ||
| #include <zephyr/logging/log.h> | ||
| #include <zephyr/kernel.h> | ||
| #include <zephyr/devicetree.h> | ||
| #include <zephyr/sys/byteorder.h> | ||
| #include <zephyr/sys/__assert.h> | ||
|
|
||
| LOG_MODULE_REGISTER(BH1750, CONFIG_SENSOR_LOG_LEVEL); | ||
|
|
||
| #define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10 | ||
| #define BH1750_CONTINUOUS_HIGH_RES_MODE_2 0x11 | ||
| #define BH1750_CONTINUOUS_LOW_RES_MODE 0x13 | ||
| #define BH1750_ONE_TIME_HIGH_RES_MODE 0x20 | ||
| #define BH1750_ONE_TIME_HIGH_RES_MODE_2 0x21 | ||
| #define BH1750_ONE_TIME_LOW_RES_MODE 0x23 | ||
| #define BH1750_MTREG_HIGH_BYTE 0x40 | ||
| #define BH1750_MTREG_LOW_BYTE 0x60 | ||
| #define BH1750_MTREG_HIGH_BYTE_MASK 0xE0 | ||
| #define BH1750_MTREG_LOW_BYTE_MASK 0x1F | ||
|
|
||
| #define BH1750_DEFAULT_MTREG 69U | ||
| #define BH1750_LOW_RES_MODE_MAX_WAIT 24U | ||
| #define BH1750_HIGH_RES_MODE_MAX_WAIT 180U | ||
| #define BH1750_LOW_RES_MODE_TYPICAL_WAIT 16U | ||
| #define BH1750_HIGH_RES_MODE_TYPICAL_WAIT 120U | ||
|
|
||
| #define BH1750_LOW_RES_DTS_ENUM 0U | ||
| #define BH1750_HIGH_RES_DTS_ENUM 1U | ||
| #define BH1750_HIGH_RES_2_DTS_ENUM 2U | ||
|
|
||
| struct bh1750_dev_config { | ||
| struct i2c_dt_spec bus; | ||
| uint8_t resolution; | ||
| uint8_t mtreg; | ||
| }; | ||
|
|
||
| struct bh1750_data { | ||
| uint16_t sample; | ||
| }; | ||
|
|
||
| static int bh1750_opcode_read(const struct device *dev, uint8_t opcode, | ||
| uint16_t *val) | ||
| { | ||
| const struct bh1750_dev_config *cfg = dev->config; | ||
| int rc; | ||
|
|
||
| rc = i2c_burst_read_dt(&cfg->bus, opcode, (uint8_t *)val, 2); | ||
| if (rc < 0) { | ||
| return rc; | ||
| } | ||
|
|
||
| *val = sys_be16_to_cpu(*val); | ||
| return 0; | ||
| } | ||
|
|
||
| static int bh1750_opcode_write(const struct device *dev, uint8_t opcode) | ||
| { | ||
| const struct bh1750_dev_config *cfg = dev->config; | ||
|
|
||
| return i2c_write_dt(&cfg->bus, &opcode, 1); | ||
| } | ||
|
|
||
| static int bh1750_mtreg_write(const struct device *dev, uint8_t mtreg) | ||
| { | ||
| int rc; | ||
| uint8_t high_byte = mtreg & BH1750_MTREG_HIGH_BYTE_MASK; | ||
| uint8_t low_byte = mtreg & BH1750_MTREG_LOW_BYTE_MASK; | ||
|
|
||
| rc = bh1750_opcode_write(dev, BH1750_MTREG_HIGH_BYTE | (high_byte >> 5)); | ||
| if (rc < 0) { | ||
| LOG_ERR("%s, Failed to write high byte of mtreg!", | ||
| dev->name); | ||
| return rc; | ||
| } | ||
|
|
||
| rc = bh1750_opcode_write(dev, BH1750_MTREG_LOW_BYTE | low_byte); | ||
| if (rc < 0) { | ||
| LOG_ERR("%s, Failed to write low byte of mtreg!", | ||
| dev->name); | ||
| return rc; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static uint8_t bh1750_get_mode_from_dts_device(const struct device *dev) | ||
| { | ||
| const struct bh1750_dev_config *cfg = dev->config; | ||
|
|
||
| if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) { | ||
| return BH1750_ONE_TIME_HIGH_RES_MODE_2; | ||
| } else if (cfg->resolution == BH1750_HIGH_RES_DTS_ENUM) { | ||
| return BH1750_ONE_TIME_HIGH_RES_MODE; | ||
| } else { | ||
| return BH1750_ONE_TIME_LOW_RES_MODE; | ||
| } | ||
| } | ||
|
|
||
| static int bh1750_get_wait_time_from_dts_device(const struct device *dev) | ||
| { | ||
| const struct bh1750_dev_config *cfg = dev->config; | ||
|
|
||
| if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) { | ||
| return BH1750_HIGH_RES_MODE_MAX_WAIT; | ||
| } else if (cfg->resolution == BH1750_HIGH_RES_DTS_ENUM) { | ||
| return BH1750_HIGH_RES_MODE_MAX_WAIT; | ||
| } else { | ||
| return BH1750_LOW_RES_MODE_MAX_WAIT; | ||
| } | ||
| } | ||
|
|
||
| static int bh1750_sample_fetch(const struct device *dev, | ||
| enum sensor_channel chan) | ||
| { | ||
| const struct bh1750_dev_config *cfg = dev->config; | ||
| struct bh1750_data *drv_data = dev->data; | ||
| const int max_wait = bh1750_get_wait_time_from_dts_device(dev); | ||
| const uint8_t mode = bh1750_get_mode_from_dts_device(dev); | ||
| int rc; | ||
| int wait_time; | ||
|
|
||
| if (chan != SENSOR_CHAN_ALL && | ||
| chan != SENSOR_CHAN_LIGHT) { | ||
| return -ENOTSUP; | ||
| } | ||
|
|
||
| /* Start the measurement */ | ||
| rc = bh1750_opcode_write(dev, mode); | ||
| if (rc < 0) { | ||
| LOG_ERR("%s, Failed to start measurement!", | ||
| dev->name); | ||
| return rc; | ||
| } | ||
|
|
||
| /* Calculate measurement time */ | ||
| wait_time = (max_wait * (cfg->mtreg * 10000 / BH1750_DEFAULT_MTREG)) / 10000; | ||
|
|
||
| /* Wait for the measurement to be stored in the sensor memory */ | ||
| k_msleep(wait_time); | ||
|
|
||
| /* Fetch result */ | ||
| rc = bh1750_opcode_read(dev, mode, &drv_data->sample); | ||
| if (rc < 0) { | ||
| LOG_ERR("%s: Failed to read measurement result!", | ||
| dev->name); | ||
| return rc; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static int bh1750_channel_get(const struct device *dev, | ||
| enum sensor_channel chan, | ||
| struct sensor_value *val) | ||
| { | ||
| const struct bh1750_dev_config *cfg = dev->config; | ||
| struct bh1750_data *drv_data = dev->data; | ||
| uint32_t tmp; | ||
|
|
||
| if (chan != SENSOR_CHAN_ALL && | ||
| chan != SENSOR_CHAN_LIGHT) { | ||
| return -ENOTSUP; | ||
| } | ||
|
|
||
| /* See datasheet (Technical note 11046EDT01), page 11 | ||
| * https://www.mouser.com/datasheet/2/348/Rohm_11162017_ROHMS34826-1-1279292.pdf | ||
| * for more information how to convert raw sample to lx | ||
| */ | ||
| tmp = (drv_data->sample * 1000 / 12) * (BH1750_DEFAULT_MTREG * 100 / cfg->mtreg); | ||
|
|
||
| if (cfg->resolution == BH1750_HIGH_RES_2_DTS_ENUM) { | ||
| tmp /= 2; | ||
| } | ||
|
|
||
| val->val1 = tmp / 10000; | ||
| val->val2 = (tmp % 10000) * 100; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static const struct sensor_driver_api bh1750_driver_api = { | ||
| .sample_fetch = bh1750_sample_fetch, | ||
| .channel_get = bh1750_channel_get | ||
| }; | ||
|
|
||
| static int bh1750_init(const struct device *dev) | ||
| { | ||
| const struct bh1750_dev_config *cfg = dev->config; | ||
|
|
||
| if (!device_is_ready(cfg->bus.bus)) { | ||
| LOG_ERR("I2C dev %s not ready", cfg->bus.bus->name); | ||
| return -ENODEV; | ||
| } | ||
|
|
||
| if (cfg->mtreg != BH1750_DEFAULT_MTREG) { | ||
| bh1750_mtreg_write(dev, cfg->mtreg); | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| #define DEFINE_BH1750(_num) \ | ||
| static struct bh1750_data bh1750_data_##_num; \ | ||
| static const struct bh1750_dev_config bh1750_config_##_num = { \ | ||
| .bus = I2C_DT_SPEC_INST_GET(_num), \ | ||
| .mtreg = DT_INST_PROP(_num, mtreg), \ | ||
| .resolution = DT_INST_PROP(_num, resolution) \ | ||
| }; \ | ||
| SENSOR_DEVICE_DT_INST_DEFINE(_num, bh1750_init, NULL, \ | ||
| &bh1750_data_##_num, &bh1750_config_##_num, POST_KERNEL, \ | ||
| CONFIG_SENSOR_INIT_PRIORITY, &bh1750_driver_api); | ||
|
|
||
| DT_INST_FOREACH_STATUS_OKAY(DEFINE_BH1750) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # Copyright (c) 2022, Michal Morsisko | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| description: Rohm BH1750 ambient light sensor. | ||
|
|
||
| compatible: "rohm,bh1750" | ||
|
|
||
| include: [sensor-device.yaml, i2c-device.yaml] | ||
|
|
||
| properties: | ||
| resolution: | ||
| type: int | ||
| default: 1 | ||
| description: | | ||
| Resolution of the measurement result | ||
| 0 = low resolution | ||
| 1 = high resolution | ||
| 2 = high resolution 2 | ||
| The default mode number 1 is mentioned | ||
| in the datasheet as recommended by the | ||
| sensor manufacturer. One should pick | ||
| other mode, if higher or lower resolution | ||
| is desired. | ||
| enum: | ||
| - 0 | ||
| - 1 | ||
| - 2 | ||
| mtreg: | ||
| type: int | ||
| default: 69 | ||
| description: | | ||
| Duration of single measurement process. | ||
| The greater the value, the longer the duration | ||
| and greater accuracy. After sensor power-on | ||
| mtreg register is set to default value of | ||
| this property (chosen by sensor manufacturer): 69. | ||
| Valid values are in range 31-254 (inclusive). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.