Skip to content

Commit

Permalink
feat: sensor fetch and get api
Browse files Browse the repository at this point in the history
  • Loading branch information
Gergo Vari committed Dec 22, 2024
1 parent 937d132 commit 0f6bbcb
Showing 8 changed files with 328 additions and 12 deletions.
3 changes: 1 addition & 2 deletions drivers/rtc/rtc_ds3231.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2024 Gergo Vari <work@varigergo.hu>
* Copyright (c) 2024 Gergo Vari
*/

/* TODO: implement get_temp */
/* TODO: implement user mode? */
/* TODO: implement aging offset with calibration */
/* TODO: handle century bit, external storage? */
1 change: 1 addition & 0 deletions drivers/sensor/maxim/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@

# zephyr-keep-sorted-start
add_subdirectory_ifdef(CONFIG_DS18B20 ds18b20)
add_subdirectory_ifdef(CONFIG_DS3231 ds3231)
add_subdirectory_ifdef(CONFIG_MAX17055 max17055)
add_subdirectory_ifdef(CONFIG_MAX17262 max17262)
add_subdirectory_ifdef(CONFIG_MAX30101 max30101)
1 change: 1 addition & 0 deletions drivers/sensor/maxim/Kconfig
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@

# zephyr-keep-sorted-start
source "drivers/sensor/maxim/ds18b20/Kconfig"
source "drivers/sensor/maxim/ds3231/Kconfig"
source "drivers/sensor/maxim/max17055/Kconfig"
source "drivers/sensor/maxim/max17262/Kconfig"
source "drivers/sensor/maxim/max30101/Kconfig"
6 changes: 6 additions & 0 deletions drivers/sensor/maxim/ds3231/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_library()

zephyr_library_sources(ds3231.c)
#zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API bme280_decoder.c bme280_async.c)
13 changes: 13 additions & 0 deletions drivers/sensor/maxim/ds3231/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# DS3231 temperature sensor configuration options

# Copyright (c) 2024 Gergo Vari
# SPDX-License-Identifier: Apache-2.0

config DS3231
bool "DS3231 sensor"
default y
depends on DT_HAS_MAXIM_DS3231_ENABLED
depends on I2C
# select RTIO_WORKQ if SENSOR_ASYNC_API
help
Enable driver for DS3231 I2C-based temperature sensor.
284 changes: 284 additions & 0 deletions drivers/sensor/maxim/ds3231/ds3231.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
/* ds3231.c - Driver for Maxim DS3231 temperature sensor */

/*
* Copyright (c) 2024 Gergo Vari
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>
#include <zephyr/init.h>

#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/i2c.h>

#include <zephyr/sys/util.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/__assert.h>
#include <math.h>

#include "ds3231.h"

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(DS3231, CONFIG_SENSOR_LOG_LEVEL);

#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
#warning "DS3231 driver enabled without any devices"
#endif

struct drv_data {
struct k_sem lock;
const struct device *dev;
int32_t temp_int;
int32_t temp_frac;
};

struct drv_conf {
struct i2c_dt_spec i2c_bus;
};

static int i2c_get_registers(const struct device *dev, uint8_t start_reg, uint8_t *buf, const size_t buf_size)
{
struct drv_data *data = dev->data;
const struct drv_conf *config = dev->config;

/* FIXME: bad start_reg/buf_size values break i2c for that run */

(void)k_sem_take(&data->lock, K_FOREVER);
int err = i2c_burst_read_dt(&config->i2c_bus, start_reg, buf, buf_size);
k_sem_give(&data->lock);

return err;
}

/* Fetch and Get (will be deprecated) */

int ds3231_sample_fetch(const struct device *dev, enum sensor_channel chan)
{
struct drv_data *data = dev->data;
int err;

const size_t buf_size = 2;
uint8_t buf[buf_size];

err = i2c_get_registers(dev, DS3231_REG_TEMP_MSB, buf, buf_size);
if (err != 0) {
return err;
}

int16_t itemp = ( buf[0] << 8 | (buf[1] & 0xC0) );
double temp = ( (double)itemp / 256.0 );

data->temp_int = (int)temp;
data->temp_frac = (int)((temp - data->temp_int) * 100) / pow(10, -6);

return 0;
}

static int ds3231_channel_get(const struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct drv_data *data = dev->data;

switch (chan) {
case SENSOR_CHAN_AMBIENT_TEMP:
val->val1 = data->temp_int;
val->val2 = data->temp_frac;
break;
default:
return -ENOTSUP;
}

return 0;
}

/* Read and Decode */
/*
void ds3231_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
{
struct rtio_work_req *req = rtio_work_req_alloc();
if (req == NULL) {
LOG_ERR("RTIO work item allocation failed. Consider to increase "
"CONFIG_RTIO_WORKQ_POOL_ITEMS.");
rtio_iodev_sqe_err(iodev_sqe, -ENOMEM);
return;
}
rtio_work_req_submit(req, iodev_sqe, ds3231_submit_sync);
}
static int ds3231_decoder_get_frame_count(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
uint16_t *frame_count)
{
const struct ds3231_encoded_data *edata = (const struct ds3231_encoded_data *)buffer;
int32_t ret = -ENOTSUP;
if (chan_spec.chan_idx != 0) {
return ret;
}
switch (chan_spec.chan_type) {
case SENSOR_CHAN_AMBIENT_TEMP:
*frame_count = edata->has_temp ? 1 : 0;
break;
case SENSOR_CHAN_PRESS:
*frame_count = edata->has_press ? 1 : 0;
break;
case SENSOR_CHAN_HUMIDITY:
*frame_count = edata->has_humidity ? 1 : 0;
break;
default:
return ret;
}
if (*frame_count > 0) {
ret = 0;
}
return ret;
}
static int ds3231_decoder_get_size_info(struct sensor_chan_spec chan_spec, size_t *base_size,
size_t *frame_size)
{
switch (chan_spec.chan_type) {
case SENSOR_CHAN_AMBIENT_TEMP:
case SENSOR_CHAN_HUMIDITY:
case SENSOR_CHAN_PRESS:
*base_size = sizeof(struct sensor_q31_sample_data);
*frame_size = sizeof(struct sensor_q31_sample_data);
return 0;
default:
return -ENOTSUP;
}
}
static int ds3231_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
uint32_t *fit, uint16_t max_count, void *data_out)
{
const struct ds3231_encoded_data *edata = (const struct ds3231_encoded_data *)buffer;
if (*fit != 0) {
return 0;
}
struct sensor_q31_data *out = data_out;
out->header.base_timestamp_ns = edata->header.timestamp;
out->header.reading_count = 1;
switch (chan_spec.chan_type) {
case SENSOR_CHAN_AMBIENT_TEMP:
if (edata->has_temp) {
int32_t readq = edata->reading.comp_temp * pow(2, 31 - BME280_TEMP_SHIFT);
int32_t convq = BME280_TEMP_CONV * pow(2, 31 - BME280_TEMP_SHIFT);
out->readings[0].temperature =
(int32_t)((((int64_t)readq) << (31 - BME280_TEMP_SHIFT)) /
((int64_t)convq));
out->shift = BME280_TEMP_SHIFT;
} else {
return -ENODATA;
}
break;
case SENSOR_CHAN_PRESS:
if (edata->has_press) {
int32_t readq = edata->reading.comp_press;
int32_t convq = BME280_PRESS_CONV_KPA * pow(2, 31 - BME280_PRESS_SHIFT);
out->readings[0].pressure =
(int32_t)((((int64_t)readq) << (31 - BME280_PRESS_SHIFT)) /
((int64_t)convq));
out->shift = BME280_PRESS_SHIFT;
} else {
return -ENODATA;
}
break;
case SENSOR_CHAN_HUMIDITY:
if (edata->has_humidity) {
out->readings[0].humidity = edata->reading.comp_humidity;
out->shift = BME280_HUM_SHIFT;
} else {
return -ENODATA;
}
break;
default:
return -EINVAL;
}
*fit = 1;
return 1;
}
SENSOR_DECODER_API_DT_DEFINE() = {
.get_frame_count = ds3231_decoder_get_frame_count,
.get_size_info = ds3231_decoder_get_size_info,
.decode = ds3231_decoder_decode,
};
int ds3231_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder)
{
ARG_UNUSED(dev);
*decoder = &SENSOR_DECODER_NAME();
return 0;
}*/

static int init_i2c(const struct drv_conf *config, struct drv_data *data) {
k_sem_init(&data->lock, 1, 1);
if (!i2c_is_ready_dt(&config->i2c_bus)) {
LOG_ERR("I2C bus not ready.");
return -ENODEV;
}
return 0;
}

static int init(const struct device *dev)
{
int err = 0;

const struct drv_conf *config = dev->config;
struct drv_data *data = dev->data;

err = init_i2c(config, data);
if (err != 0) {
LOG_ERR("Failed to init I2C.");
return err;
}

return 0;
}


static DEVICE_API(sensor, driver_api) = {
.sample_fetch = ds3231_sample_fetch,
.channel_get = ds3231_channel_get,
/*
#ifdef CONFIG_SENSOR_ASYNC_API
.submit = ds3231_submit,
.get_decoder = ds3231_get_decoder,
#endif
*/
};

#define DS3231_DEFINE(inst) \
static struct drv_data drv_data_##inst; \
static const struct drv_conf drv_conf_##inst = { \
.i2c_bus = I2C_DT_SPEC_INST_GET(inst) \
}; \
SENSOR_DEVICE_DT_INST_DEFINE(inst, \
&init, \
NULL, \
&drv_data_##inst, \
&drv_conf_##inst, \
POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&driver_api);

DT_INST_FOREACH_STATUS_OKAY(DS3231_DEFINE)
21 changes: 21 additions & 0 deletions drivers/sensor/maxim/ds3231/ds3231.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2016, 2017 Intel Corporation
* Copyright (c) 2017 IpTronix S.r.l.
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_DRIVERS_SENSOR_DS3231_DS3231_H_
#define ZEPHYR_DRIVERS_SENSOR_DS3231_DS3231_H_

#define DT_DRV_COMPAT maxim_ds3231

/* Temperature registers */
#define DS3231_REG_TEMP_MSB 0x11
#define DS3231_REG_TEMP_LSB 0x12

/* Temperature bitmasks */
#define DS3231_BITS_TEMP_LSB GENMASK(7, 6) /* fractional portion */

#endif
11 changes: 1 addition & 10 deletions include/zephyr/drivers/rtc/rtc_ds3231.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2024 Gergo Vari <work@varigergo.hu>
* Copyright (c) 2024 Gergo Vari
*/

#define DT_DRV_COMPAT maxim_ds3231
@@ -38,11 +38,6 @@
/* Aging offset register */
#define DS3231_REG_AGING_OFFSET 0x10

/* Temperature registers */
#define DS3231_REG_TEMP_MSB 0x11
#define DS3231_REG_TEMP_LSB 0x12



/* *
*** BITMASKS ***
@@ -105,10 +100,6 @@
/* Aging offset bitmask */
#define DS3231_BITS_DATA BIT(6, 0)

/* Temperature bitmasks */
#define DS3231_BITS_TEMP_MSB GENMASK(6, 0) /* integer portion */
#define DS3231_BITS_TEMP_LSB GENMASK(7, 6) /* fractional portion */

/* Settings bitmasks */
#define DS3231_BITS_STS_OSC BIT(0)
#define DS3231_BITS_STS_INTCTRL BIT(1)

0 comments on commit 0f6bbcb

Please sign in to comment.