drivers: sensor: bme680: Add SPI interface
This enables the SPI interface for the BME680 sensor driver. Signed-off-by: Leonard Pollak <leonardp@tr-host.de>
This commit is contained in:
parent
4e804bfa73
commit
35b55175cc
7 changed files with 308 additions and 28 deletions
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
# Copyright (c) 2018 Bosch Sensortec GmbH
|
||||
# Copyright (c) 2022, Leonard Pollak
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources(bme680.c)
|
||||
zephyr_library_sources(bme680.c bme680_i2c.c bme680_spi.c)
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
# BME680 temperature, pressure, humidity and gas sensor configuration options
|
||||
|
||||
# Copyright (c) 2018 Bosch Sensortec GmbH
|
||||
# Copyright (c) 2022, Leonard Pollak
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menuconfig BME680
|
||||
bool "BME680 sensor"
|
||||
depends on I2C
|
||||
depends on I2C || SPI
|
||||
help
|
||||
Enable driver for BME680 I2C-based based temperature, pressure, humidity and gas sensor.
|
||||
Enable driver for BME680 I2C- or SPI- based temperature, pressure, humidity and gas sensor.
|
||||
|
||||
if BME680
|
||||
|
||||
|
|
|
@ -11,33 +11,49 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT bosch_bme680
|
||||
|
||||
#include "bme680.h"
|
||||
#include <drivers/gpio.h>
|
||||
#include <drivers/i2c.h>
|
||||
#include <init.h>
|
||||
#include <kernel.h>
|
||||
#include <sys/byteorder.h>
|
||||
#include <sys/__assert.h>
|
||||
#include <drivers/sensor.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
|
||||
#include "bme680.h"
|
||||
|
||||
LOG_MODULE_REGISTER(bme680, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
static int bme680_reg_read(const struct device *dev, uint8_t start,
|
||||
uint8_t *buf, int size)
|
||||
|
||||
#if BME680_BUS_SPI
|
||||
static inline bool bme680_is_on_spi(const struct device *dev)
|
||||
{
|
||||
const struct bme680_config *config = dev->config;
|
||||
|
||||
return i2c_burst_read_dt(&config->bus, start, buf, size);
|
||||
return config->bus_io == &bme680_bus_io_spi;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int bme680_bus_check(const struct device *dev)
|
||||
{
|
||||
const struct bme680_config *config = dev->config;
|
||||
|
||||
return config->bus_io->check(&config->bus);
|
||||
}
|
||||
|
||||
static int bme680_reg_write(const struct device *dev, uint8_t reg, uint8_t val)
|
||||
static inline int bme680_reg_read(const struct device *dev,
|
||||
uint8_t start, uint8_t *buf, int size)
|
||||
{
|
||||
const struct bme680_config *config = dev->config;
|
||||
|
||||
return i2c_reg_write_byte_dt(&config->bus, reg, val);
|
||||
return config->bus_io->read(dev, start, buf, size);
|
||||
}
|
||||
|
||||
static inline int bme680_reg_write(const struct device *dev, uint8_t reg,
|
||||
uint8_t val)
|
||||
{
|
||||
const struct bme680_config *config = dev->config;
|
||||
|
||||
return config->bus_io->write(dev, reg, val);
|
||||
}
|
||||
|
||||
static void bme680_calc_temp(struct bme680_data *data, uint32_t adc_temp)
|
||||
|
@ -346,14 +362,23 @@ static int bme680_read_compensation(const struct device *dev)
|
|||
static int bme680_init(const struct device *dev)
|
||||
{
|
||||
struct bme680_data *data = dev->data;
|
||||
const struct bme680_config *config = dev->config;
|
||||
int err;
|
||||
|
||||
if (!device_is_ready(config->bus.bus)) {
|
||||
LOG_ERR("I2C master %s not ready", config->bus.bus->name);
|
||||
return -EINVAL;
|
||||
err = bme680_bus_check(dev);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Bus not ready for '%s'", dev->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if BME680_BUS_SPI
|
||||
if (bme680_is_on_spi(dev)) {
|
||||
err = bme680_reg_read(dev, BME680_REG_MEM_PAGE, &data->mem_page, 1);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
err = bme680_reg_read(dev, BME680_REG_CHIP_ID, &data->chip_id, 1);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
|
@ -410,12 +435,39 @@ static const struct sensor_driver_api bme680_api_funcs = {
|
|||
.channel_get = bme680_channel_get,
|
||||
};
|
||||
|
||||
static struct bme680_data bme680_data;
|
||||
/* Initializes a struct bme680_config for an instance on a SPI bus. */
|
||||
#define BME680_CONFIG_SPI(inst) \
|
||||
{ \
|
||||
.bus.spi = SPI_DT_SPEC_INST_GET( \
|
||||
inst, BME680_SPI_OPERATION, 0), \
|
||||
.bus_io = &bme680_bus_io_spi, \
|
||||
}
|
||||
|
||||
static const struct bme680_config bme680_config = {
|
||||
.bus = I2C_DT_SPEC_INST_GET(0)
|
||||
};
|
||||
/* Initializes a struct bme680_config for an instance on an I2C bus. */
|
||||
#define BME680_CONFIG_I2C(inst) \
|
||||
{ \
|
||||
.bus.i2c = I2C_DT_SPEC_INST_GET(inst), \
|
||||
.bus_io = &bme680_bus_io_i2c, \
|
||||
}
|
||||
|
||||
DEVICE_DT_INST_DEFINE(0, bme680_init, NULL, &bme680_data,
|
||||
&bme680_config, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
|
||||
&bme680_api_funcs);
|
||||
/*
|
||||
* Main instantiation macro, which selects the correct bus-specific
|
||||
* instantiation macros for the instance.
|
||||
*/
|
||||
#define BME680_DEFINE(inst) \
|
||||
static struct bme680_data bme680_data_##inst; \
|
||||
static const struct bme680_config bme680_config_##inst = \
|
||||
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
|
||||
(BME680_CONFIG_SPI(inst)), \
|
||||
(BME680_CONFIG_I2C(inst))); \
|
||||
DEVICE_DT_INST_DEFINE(inst, \
|
||||
bme680_init, \
|
||||
NULL, \
|
||||
&bme680_data_##inst, \
|
||||
&bme680_config_##inst, \
|
||||
POST_KERNEL, \
|
||||
CONFIG_SENSOR_INIT_PRIORITY, \
|
||||
&bme680_api_funcs);
|
||||
|
||||
/* Create the struct device for every status "okay" node in the devicetree. */
|
||||
DT_INST_FOREACH_STATUS_OKAY(BME680_DEFINE)
|
||||
|
|
|
@ -10,8 +10,51 @@
|
|||
|
||||
#include <zephyr/types.h>
|
||||
#include <device.h>
|
||||
#include <devicetree.h>
|
||||
#include <drivers/spi.h>
|
||||
#include <drivers/i2c.h>
|
||||
|
||||
#define DT_DRV_COMPAT bosch_bme680
|
||||
|
||||
#define BME680_BUS_SPI DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
|
||||
#define BME680_BUS_I2C DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
|
||||
|
||||
union bme680_bus {
|
||||
#if BME680_BUS_SPI
|
||||
struct spi_dt_spec spi;
|
||||
#endif
|
||||
#if BME680_BUS_I2C
|
||||
struct i2c_dt_spec i2c;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef int (*bme680_bus_check_fn)(const union bme680_bus *bus);
|
||||
typedef int (*bme680_reg_read_fn)(const struct device *dev,
|
||||
uint8_t start, uint8_t *buf, int size);
|
||||
typedef int (*bme680_reg_write_fn)(const struct device *dev,
|
||||
uint8_t reg, uint8_t val);
|
||||
|
||||
struct bme680_bus_io {
|
||||
bme680_bus_check_fn check;
|
||||
bme680_reg_read_fn read;
|
||||
bme680_reg_write_fn write;
|
||||
};
|
||||
|
||||
#if BME680_BUS_SPI
|
||||
#define BME680_SPI_OPERATION (SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL \
|
||||
| SPI_MODE_CPHA | SPI_OP_MODE_MASTER)
|
||||
extern const struct bme680_bus_io bme680_bus_io_spi;
|
||||
#endif
|
||||
|
||||
#if BME680_BUS_I2C
|
||||
extern const struct bme680_bus_io bme680_bus_io_i2c;
|
||||
#endif
|
||||
|
||||
struct bme680_config {
|
||||
union bme680_bus bus;
|
||||
const struct bme680_bus_io *bus_io;
|
||||
};
|
||||
|
||||
#define BME680_CHIP_ID 0x61
|
||||
|
||||
#define BME680_LEN_FIELD 15
|
||||
|
@ -44,6 +87,12 @@
|
|||
#define BME680_MSK_RANGE_SW_ERR 0xf0
|
||||
#define BME680_MSK_HEATR_STAB 0x10
|
||||
|
||||
#define BME680_SPI_READ_BIT 0x80
|
||||
#define BME680_SPI_WRITE_MSK 0x7f
|
||||
|
||||
#define BME680_MEM_PAGE1 0x00
|
||||
#define BME680_MEM_PAGE0 0x10
|
||||
|
||||
#if defined CONFIG_BME680_TEMP_OVER_1X
|
||||
#define BME680_TEMP_OVER (1 << 5)
|
||||
#elif defined CONFIG_BME680_TEMP_OVER_2X
|
||||
|
@ -163,10 +212,10 @@ struct bme680_data {
|
|||
int32_t t_fine;
|
||||
|
||||
uint8_t chip_id;
|
||||
};
|
||||
|
||||
struct bme680_config {
|
||||
struct i2c_dt_spec bus;
|
||||
#if BME680_BUS_SPI
|
||||
uint8_t mem_page;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* __ZEPHYR_DRIVERS_SENSOR_BME680_H__ */
|
||||
|
|
43
drivers/sensor/bme680/bme680_i2c.c
Normal file
43
drivers/sensor/bme680/bme680_i2c.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017 Intel Corporation
|
||||
* Copyright (c) 2017 IpTronix S.r.l.
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2022, Leonard Pollak
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bus-specific functionality for BME680s accessed via I2C.
|
||||
*/
|
||||
|
||||
#include "bme680.h"
|
||||
|
||||
#if BME680_BUS_I2C
|
||||
static int bme680_bus_check_i2c(const union bme680_bus *bus)
|
||||
{
|
||||
return device_is_ready(bus->i2c.bus) ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static int bme680_reg_read_i2c(const struct device *dev,
|
||||
uint8_t start, uint8_t *buf, int size)
|
||||
{
|
||||
const struct bme680_config *config = dev->config;
|
||||
|
||||
return i2c_burst_read_dt(&config->bus.i2c, start, buf, size);
|
||||
}
|
||||
|
||||
static int bme680_reg_write_i2c(const struct device *dev,
|
||||
uint8_t reg, uint8_t val)
|
||||
{
|
||||
const struct bme680_config *config = dev->config;
|
||||
|
||||
return i2c_reg_write_byte_dt(&config->bus.i2c, reg, val);
|
||||
}
|
||||
|
||||
const struct bme680_bus_io bme680_bus_io_i2c = {
|
||||
.check = bme680_bus_check_i2c,
|
||||
.read = bme680_reg_read_i2c,
|
||||
.write = bme680_reg_write_i2c,
|
||||
};
|
||||
#endif /* BME680_BUS_I2C */
|
124
drivers/sensor/bme680/bme680_spi.c
Normal file
124
drivers/sensor/bme680/bme680_spi.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017 Intel Corporation
|
||||
* Copyright (c) 2017 IpTronix S.r.l.
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2022, Leonard Pollak
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bus-specific functionality for BME680s accessed via SPI.
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
#include "bme680.h"
|
||||
|
||||
#if BME680_BUS_SPI
|
||||
|
||||
LOG_MODULE_DECLARE(bme680, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
static int bme680_bus_check_spi(const union bme680_bus *bus)
|
||||
{
|
||||
return spi_is_ready(&bus->spi) ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static inline int bme680_set_mem_page(const struct device *dev, uint8_t addr)
|
||||
{
|
||||
const struct bme680_config *config = dev->config;
|
||||
struct bme680_data *data = dev->data;
|
||||
uint8_t page;
|
||||
int err = 0;
|
||||
|
||||
if (addr > 0x7f) {
|
||||
page = BME680_MEM_PAGE1;
|
||||
} else {
|
||||
page = BME680_MEM_PAGE0;
|
||||
}
|
||||
|
||||
if (data->mem_page != page) {
|
||||
|
||||
data->mem_page = page;
|
||||
uint8_t cmd[] = { BME680_REG_MEM_PAGE & BME680_SPI_WRITE_MSK, data->mem_page };
|
||||
const struct spi_buf tx_buf = {
|
||||
.buf = cmd,
|
||||
.len = sizeof(cmd)
|
||||
};
|
||||
const struct spi_buf_set tx = {
|
||||
.buffers = &tx_buf,
|
||||
.count = 1
|
||||
};
|
||||
|
||||
err = spi_write_dt(&config->bus.spi, &tx);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bme680_reg_write_spi(const struct device *dev,
|
||||
uint8_t reg, uint8_t val)
|
||||
{
|
||||
const struct bme680_config *config = dev->config;
|
||||
int err;
|
||||
uint8_t cmd[] = { reg & BME680_SPI_WRITE_MSK, val };
|
||||
const struct spi_buf tx_buf = {
|
||||
.buf = cmd,
|
||||
.len = sizeof(cmd)
|
||||
};
|
||||
const struct spi_buf_set tx = {
|
||||
.buffers = &tx_buf,
|
||||
.count = 1
|
||||
};
|
||||
|
||||
err = bme680_set_mem_page(dev, reg);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = spi_write_dt(&config->bus.spi, &tx);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bme680_reg_read_spi(const struct device *dev,
|
||||
uint8_t start, uint8_t *buf, int size)
|
||||
{
|
||||
const struct bme680_config *config = dev->config;
|
||||
int err;
|
||||
uint8_t addr;
|
||||
const struct spi_buf tx_buf = {
|
||||
.buf = &addr,
|
||||
.len = 1
|
||||
};
|
||||
const struct spi_buf_set tx = {
|
||||
.buffers = &tx_buf,
|
||||
.count = 1
|
||||
};
|
||||
struct spi_buf rx_buf[2];
|
||||
const struct spi_buf_set rx = {
|
||||
.buffers = rx_buf,
|
||||
.count = ARRAY_SIZE(rx_buf)
|
||||
};
|
||||
|
||||
rx_buf[0].buf = NULL;
|
||||
rx_buf[0].len = 1;
|
||||
|
||||
addr = start | BME680_SPI_READ_BIT;
|
||||
rx_buf[1].buf = buf;
|
||||
rx_buf[1].len = size;
|
||||
|
||||
err = bme680_set_mem_page(dev, start);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = spi_transceive_dt(&config->bus.spi, &tx, &rx);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
const struct bme680_bus_io bme680_bus_io_spi = {
|
||||
.check = bme680_bus_check_spi,
|
||||
.read = bme680_reg_read_spi,
|
||||
.write = bme680_reg_write_spi,
|
||||
};
|
||||
#endif /* BME680_BUS_SPI */
|
Loading…
Add table
Add a link
Reference in a new issue