From 687d1040ac698d76b9e40de19906b27b59e31f49 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Fri, 13 Mar 2020 11:32:14 +0100 Subject: [PATCH] Sensor: ADXL345: Add ADXL345 driver Add support for Analog Devices ADXL345 3-axis I2C accelerometer. Signed-off-by: Kamil Rakoczy --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 2 + drivers/sensor/adxl345/CMakeLists.txt | 8 + drivers/sensor/adxl345/Kconfig | 10 ++ drivers/sensor/adxl345/adxl345.c | 192 +++++++++++++++++++++++ drivers/sensor/adxl345/adxl345.h | 59 +++++++ dts/bindings/sensor/adi,adxl345.yaml | 8 + tests/drivers/build_all/dts_fixup.h | 6 + tests/drivers/build_all/sensors_a_h.conf | 1 + 9 files changed, 287 insertions(+) create mode 100644 drivers/sensor/adxl345/CMakeLists.txt create mode 100644 drivers/sensor/adxl345/Kconfig create mode 100644 drivers/sensor/adxl345/adxl345.c create mode 100644 drivers/sensor/adxl345/adxl345.h create mode 100644 dts/bindings/sensor/adi,adxl345.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 594de34a7c5..e25ea66e6a7 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 add_subdirectory_ifdef(CONFIG_ADT7420 adt7420) +add_subdirectory_ifdef(CONFIG_ADXL345 adxl345) add_subdirectory_ifdef(CONFIG_ADXL362 adxl362) add_subdirectory_ifdef(CONFIG_ADXL372 adxl372) add_subdirectory_ifdef(CONFIG_AK8975 ak8975) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index bf8897934fe..41ab58d3c73 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -31,6 +31,8 @@ comment "Device Drivers" source "drivers/sensor/adt7420/Kconfig" +source "drivers/sensor/adxl345/Kconfig" + source "drivers/sensor/adxl362/Kconfig" source "drivers/sensor/adxl372/Kconfig" diff --git a/drivers/sensor/adxl345/CMakeLists.txt b/drivers/sensor/adxl345/CMakeLists.txt new file mode 100644 index 00000000000..44286560d96 --- /dev/null +++ b/drivers/sensor/adxl345/CMakeLists.txt @@ -0,0 +1,8 @@ +# +# Copyright (c) 2020 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_ADXL345 adxl345.c) diff --git a/drivers/sensor/adxl345/Kconfig b/drivers/sensor/adxl345/Kconfig new file mode 100644 index 00000000000..68ba21a87ee --- /dev/null +++ b/drivers/sensor/adxl345/Kconfig @@ -0,0 +1,10 @@ +# ADXL345, 3-Axis, +/-16g Digital Accelerometer + +# Copyright (c) 2020 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config ADXL345 + bool "ADXL345 Three Axis I2C accelerometer" + depends on I2C + help + Enable driver for ADXL345 Three-Axis Digital Accelerometer. diff --git a/drivers/sensor/adxl345/adxl345.c b/drivers/sensor/adxl345/adxl345.c new file mode 100644 index 00000000000..607e6552e03 --- /dev/null +++ b/drivers/sensor/adxl345/adxl345.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2020 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "adxl345.h" + +LOG_MODULE_REGISTER(ADXL345, CONFIG_SENSOR_LOG_LEVEL); + +static int adxl345_read_sample(struct device *dev, + struct adxl345_sample *sample) +{ + struct adxl345_dev_data *data = dev->driver_data; + s16_t raw_x, raw_y, raw_z; + u8_t axis_data[6]; + + int rc = i2c_burst_read(data->i2c_master, + data->i2c_addr, + ADXL345_X_AXIS_DATA_0_REG, + axis_data, + 6); + + if (rc < 0) { + LOG_ERR("Samples read failed with rc=%d\n", rc); + return rc; + } + + raw_x = axis_data[0] | (axis_data[1] << 8); + raw_y = axis_data[2] | (axis_data[3] << 8); + raw_z = axis_data[4] | (axis_data[5] << 8); + + sample->x = raw_x; + sample->y = raw_y; + sample->z = raw_z; + + return 0; +} + +static void adxl345_accel_convert(struct sensor_value *val, unsigned int sample) +{ + if (sample & BIT(9)) { + sample |= ADXL345_COMPLEMENT; + } + + val->val1 = (sample * 1000) / 32; + val->val2 = 0; +} + +static int adxl345_sample_fetch(struct device *dev, enum sensor_channel chan) +{ + struct adxl345_dev_data *data = dev->driver_data; + struct adxl345_sample sample; + u8_t samples_count; + int rc; + + data->sample_number = 0; + rc = i2c_reg_read_byte(dev, data->i2c_addr, ADXL345_FIFO_STATUS_REG, + &samples_count); + if (rc < 0) { + LOG_ERR("Failed to read FIFO status rc = %d\n", rc); + return rc; + } + + __ASSERT_NO_MSG(samples_count < ADXL345_MAX_FIFO_SIZE); + + for (u8_t s = 0; s < samples_count; s++) { + rc = adxl345_read_sample(dev, &sample); + if (rc < 0) { + LOG_ERR("Failed to fetch sample rc=%d\n", rc); + return rc; + } + data->bufx[s] = sample.x; + data->bufy[s] = sample.y; + data->bufz[s] = sample.z; + } + + return samples_count; +} + +static int adxl345_channel_get(struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct adxl345_dev_data *data = dev->driver_data; + + if (data->sample_number > 32) { + data->sample_number = 0; + } + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + adxl345_accel_convert(val, data->bufx[data->sample_number]); + data->sample_number++; + break; + case SENSOR_CHAN_ACCEL_Y: + adxl345_accel_convert(val, data->bufy[data->sample_number]); + data->sample_number++; + break; + case SENSOR_CHAN_ACCEL_Z: + adxl345_accel_convert(val, data->bufz[data->sample_number]); + data->sample_number++; + break; + case SENSOR_CHAN_ACCEL_XYZ: + adxl345_accel_convert(val++, data->bufx[data->sample_number]); + adxl345_accel_convert(val++, data->bufy[data->sample_number]); + adxl345_accel_convert(val, data->bufz[data->sample_number]); + data->sample_number++; + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api adxl345_api_funcs = { + .sample_fetch = adxl345_sample_fetch, + .channel_get = adxl345_channel_get, +}; + +static int adxl345_init(struct device *dev) +{ + int rc; + struct adxl345_dev_data *data = dev->driver_data; + const struct adxl345_dev_config *cfg = dev->config->config_info; + u8_t dev_id; + + data->sample_number = 0; + data->i2c_master = device_get_binding(cfg->i2c_master_name); + data->i2c_addr = cfg->i2c_addr; + + if (!data->i2c_master) { + LOG_ERR("Failed to get I2C master\n"); + return -ENODEV; + } + + rc = i2c_reg_read_byte(dev, data->i2c_addr, ADXL345_DEVICE_ID_REG, + &dev_id); + if (rc < 0 || dev_id != ADXL345_PART_ID) { + LOG_ERR("Read PART ID failed: 0x%x\n", rc); + return -ENODEV; + } + + rc = i2c_reg_write_byte(dev, data->i2c_addr, ADXL345_FIFO_CTL_REG, + ADXL345_FIFO_STREAM_MODE); + if (rc < 0) { + LOG_ERR("FIFO enable failed\n"); + return -EIO; + } + + rc = i2c_reg_write_byte(dev, data->i2c_addr, ADXL345_DATA_FORMAT_REG, + ADXL345_RANGE_16G); + if (rc < 0) { + LOG_ERR("Data format set failed\n"); + return -EIO; + } + + rc = i2c_reg_write_byte(dev, data->i2c_addr, ADXL345_RATE_REG, + ADXL345_RATE_25HZ); + if (rc < 0) { + LOG_ERR("Rate setting failed\n"); + return -EIO; + } + + rc = i2c_reg_write_byte(dev, data->i2c_addr, ADXL345_POWER_CTL_REG, + ADXL345_ENABLE_MEASURE_BIT); + if (rc < 0) { + LOG_ERR("Enable measure bit failed\n"); + return -EIO; + } + + return 0; +} + +static struct adxl345_dev_data adxl345_data; + +static const struct adxl345_dev_config adxl345_config = { + .i2c_master_name = DT_INST_0_ADI_ADXL345_BUS_NAME, + .i2c_addr = DT_INST_0_ADI_ADXL345_BASE_ADDRESS, +}; + +DEVICE_AND_API_INIT(adxl345, DT_INST_0_ADI_ADXL345_LABEL, adxl345_init, + &adxl345_data, &adxl345_config, POST_KERNEL, + CONFIG_SENSOR_INIT_PRIORITY, &adxl345_api_funcs); diff --git a/drivers/sensor/adxl345/adxl345.h b/drivers/sensor/adxl345/adxl345.h new file mode 100644 index 00000000000..d0dda231682 --- /dev/null +++ b/drivers/sensor/adxl345/adxl345.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ADX345_ADX345_H_ +#define ZEPHYR_DRIVERS_SENSOR_ADX345_ADX345_H_ + +#include +#include +#include +#include +#include + +#define ADXL345_DEVICE_ID_REG 0x00 +#define ADXL345_RATE_REG 0x2c +#define ADXL345_POWER_CTL_REG 0x2d +#define ADXL345_DATA_FORMAT_REG 0x31 +#define ADXL345_X_AXIS_DATA_0_REG 0x32 +#define ADXL345_FIFO_CTL_REG 0x38 +#define ADXL345_FIFO_STATUS_REG 0x39 + +#define ADXL345_PART_ID 0xe5 + +#define ADXL345_RANGE_2G 0x0 +#define ADXL345_RANGE_4G 0x1 +#define ADXL345_RANGE_8G 0x2 +#define ADXL345_RANGE_16G 0x3 +#define ADXL345_RATE_25HZ 0x8 +#define ADXL345_ENABLE_MEASURE_BIT (1 << 3) +#define ADXL345_FIFO_STREAM_MODE (1 << 7) +#define ADXL345_FIFO_COUNT_MASK 0x3f +#define ADXL345_COMPLEMENT 0xfc00 + +#define ADXL345_MAX_FIFO_SIZE 32 + +struct adxl345_dev_data { + unsigned int sample_number; + struct device *i2c_master; + u8_t i2c_addr; + + s16_t bufx[ADXL345_MAX_FIFO_SIZE]; + s16_t bufy[ADXL345_MAX_FIFO_SIZE]; + s16_t bufz[ADXL345_MAX_FIFO_SIZE]; +}; + +struct adxl345_sample { + s16_t x; + s16_t y; + s16_t z; +}; + +struct adxl345_dev_config { + const char *i2c_master_name; + u16_t i2c_addr; +}; + +#endif /* ZEPHYR_DRIVERS_SENSOR_ADX345_ADX345_H_ */ diff --git a/dts/bindings/sensor/adi,adxl345.yaml b/dts/bindings/sensor/adi,adxl345.yaml new file mode 100644 index 00000000000..63cb7efe48b --- /dev/null +++ b/dts/bindings/sensor/adi,adxl345.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: ADXL345 3-axis I2C accelerometer + +compatible: "adi,adxl345" + +include: i2c-device.yaml diff --git a/tests/drivers/build_all/dts_fixup.h b/tests/drivers/build_all/dts_fixup.h index 804be5bb2d5..59a1deab5e1 100644 --- a/tests/drivers/build_all/dts_fixup.h +++ b/tests/drivers/build_all/dts_fixup.h @@ -460,6 +460,12 @@ #define DT_INST_0_ASAHI_KASEI_AK8975_BUS_NAME "" #endif +#ifndef DT_INST_0_ADI_ADXL345_LABEL +#define DT_INST_0_ADI_ADXL345_LABEL "" +#define DT_INST_0_ADI_ADXL345_BUS_NAME "" +#define DT_INST_0_ADI_ADXL345_BASE_ADDRESS 0 +#endif + #endif /* CONFIG_HAS_DTS_I2C */ #ifndef DT_ADXL372_DEV_NAME diff --git a/tests/drivers/build_all/sensors_a_h.conf b/tests/drivers/build_all/sensors_a_h.conf index 4cb97060532..e5309753e40 100644 --- a/tests/drivers/build_all/sensors_a_h.conf +++ b/tests/drivers/build_all/sensors_a_h.conf @@ -28,3 +28,4 @@ CONFIG_FXOS8700=y CONFIG_HMC5883L=y CONFIG_HP206C=y CONFIG_HTS221=y +CONFIG_ADXL345=y