sensor: rm3100: Add ODR build-time setting through DTS property

Using pre-defined values displayed on datasheet's table 5-4 for
CMM Update Rates.

Please note that datasheet specifies these Update-Rates may have
up to 7% standard deviation, which may be significant for certain
applications.

Signed-off-by: Luis Ubieda <luisf@croxel.com>
This commit is contained in:
Luis Ubieda 2025-04-28 22:08:16 -04:00 committed by Benjamin Cabé
commit 4dfe251986
6 changed files with 157 additions and 7 deletions

View file

@ -12,6 +12,9 @@
#include <zephyr/rtio/rtio.h>
#include <zephyr/rtio/work.h>
#include <zephyr/sys/check.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/dt-bindings/sensor/rm3100.h>
#include "rm3100.h"
#include "rm3100_reg.h"
@ -130,6 +133,7 @@ static DEVICE_API(sensor, rm3100_driver_api) = {
static int rm3100_init(const struct device *dev)
{
struct rm3100_data *data = dev->data;
uint8_t val;
int err;
@ -145,6 +149,36 @@ static int rm3100_init(const struct device *dev)
}
LOG_DBG("RM3100 chip ID confirmed: 0x%02x", val);
uint16_t cycle_count[] = {
sys_be16_to_cpu(RM3100_CYCLE_COUNT_DEFAULT),
sys_be16_to_cpu(RM3100_CYCLE_COUNT_DEFAULT),
sys_be16_to_cpu(RM3100_CYCLE_COUNT_DEFAULT)
};
/** Setting ODR requires adjusting Cycle-count should it be 600-HZ ODR,
* because at default cycle-count, the max ODR is 440 Hz, which will
* override our setting.
*/
if (data->settings.odr == RM3100_DT_ODR_600) {
cycle_count[0] = sys_be16_to_cpu(RM3100_CYCLE_COUNT_HIGH_ODR);
cycle_count[1] = sys_be16_to_cpu(RM3100_CYCLE_COUNT_HIGH_ODR);
cycle_count[2] = sys_be16_to_cpu(RM3100_CYCLE_COUNT_HIGH_ODR);
}
err = rm3100_bus_write(dev, RM3100_REG_CCX_MSB,
(uint8_t *)cycle_count, sizeof(cycle_count));
if (err < 0) {
LOG_ERR("Failed to set cycle count: %d", err);
return err;
}
val = data->settings.odr;
err = rm3100_bus_write(dev, RM3100_REG_TMRC, &val, 1);
if (err < 0) {
LOG_ERR("Failed to set ODR: %d", err);
return err;
}
/** Enable Continuous measurement on all axis */
val = RM3100_CMM_ALL_AXIS;
@ -169,6 +203,9 @@ static int rm3100_init(const struct device *dev)
.iodev = &rm3100_bus_##inst, \
.ctx = &rm3100_rtio_ctx_##inst, \
}, \
.settings = { \
.odr = DT_INST_PROP(inst, odr), \
}, \
}; \
\
SENSOR_DEVICE_DT_INST_DEFINE(inst, rm3100_init, NULL, \

View file

@ -20,6 +20,7 @@ struct rm3100_encoded_data {
struct {
uint64_t timestamp;
uint8_t channels : 3;
uint16_t cycle_count;
} header;
union {
uint8_t payload[RM3100_TOTAL_BYTES];
@ -41,6 +42,9 @@ struct rm3100_data {
struct rtio_iodev *iodev;
struct rtio *ctx;
} rtio;
struct {
uint8_t odr;
} settings;
};
#endif /* ZEPHYR_DRIVERS_SENSOR_PNI_RM3100_H_ */

View file

@ -9,6 +9,7 @@
#include <zephyr/drivers/sensor_clock.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/dt-bindings/sensor/rm3100.h>
#include "rm3100.h"
uint8_t rm3100_encode_channel(enum sensor_channel chan)
@ -33,12 +34,19 @@ int rm3100_encode(const struct device *dev,
size_t num_channels,
uint8_t *buf)
{
const struct rm3100_data *data = dev->data;
struct rm3100_encoded_data *edata = (struct rm3100_encoded_data *)buf;
uint64_t cycles;
int err;
edata->header.channels = 0;
if (data->settings.odr == RM3100_DT_ODR_600) {
edata->header.cycle_count = RM3100_CYCLE_COUNT_HIGH_ODR;
} else {
edata->header.cycle_count = RM3100_CYCLE_COUNT_DEFAULT;
}
for (size_t i = 0; i < num_channels; i++) {
edata->header.channels |= rm3100_encode_channel(channels[i].chan_type);
}
@ -105,9 +113,11 @@ static int rm3100_decoder_get_frame_count(const uint8_t *buffer,
return -1;
}
static int rm3100_convert_raw_to_q31(uint32_t raw_reading, q31_t *out, int8_t *shift)
static int rm3100_convert_raw_to_q31(uint16_t cycle_count, uint32_t raw_reading,
q31_t *out, int8_t *shift)
{
int64_t value;
uint8_t divider;
raw_reading = sys_be24_to_cpu(raw_reading);
value = sign_extend(raw_reading, 23);
@ -115,9 +125,18 @@ static int rm3100_convert_raw_to_q31(uint32_t raw_reading, q31_t *out, int8_t *s
/** Convert to Gauss, assuming 1 LSB = 75 uT, given default Cycle-Counting (200).
* We can represent the largest sample (2^23 LSB) in Gauss with 11 bits.
*/
*shift = 11;
if (cycle_count == RM3100_CYCLE_COUNT_DEFAULT) {
*shift = 11;
divider = 75;
} else {
/** Otherwise, it's 1 LSB = 38 uT at Cycle-counting for 600 Hz ODR (100):
* 12-bits max value.
*/
*shift = 12;
divider = 38;
}
int64_t micro_tesla_scaled = ((int64_t)value << (31 - *shift)) / 75;
int64_t micro_tesla_scaled = ((int64_t)value << (31 - *shift)) / divider;
int64_t gauss_scaled = (int64_t)micro_tesla_scaled / 100;
*out = gauss_scaled;
@ -166,7 +185,8 @@ static int rm3100_decoder_decode(const uint8_t *buffer,
raw_reading = edata->magn.z;
}
rm3100_convert_raw_to_q31(raw_reading, &out->readings->value, &out->shift);
rm3100_convert_raw_to_q31(
edata->header.cycle_count, raw_reading, &out->readings->value, &out->shift);
*fit = 1;
return 1;
@ -182,9 +202,12 @@ static int rm3100_decoder_decode(const uint8_t *buffer,
out->header.base_timestamp_ns = edata->header.timestamp;
out->header.reading_count = 1;
rm3100_convert_raw_to_q31(edata->magn.x, &out->readings[0].x, &out->shift);
rm3100_convert_raw_to_q31(edata->magn.y, &out->readings[0].y, &out->shift);
rm3100_convert_raw_to_q31(edata->magn.z, &out->readings[0].z, &out->shift);
rm3100_convert_raw_to_q31(
edata->header.cycle_count, edata->magn.x, &out->readings[0].x, &out->shift);
rm3100_convert_raw_to_q31(
edata->header.cycle_count, edata->magn.y, &out->readings[0].y, &out->shift);
rm3100_convert_raw_to_q31(
edata->header.cycle_count, edata->magn.z, &out->readings[0].z, &out->shift);
*fit = 1;
return 1;

View file

@ -10,6 +10,13 @@
/* RM3100 register addresses */
#define RM3100_REG_CMM 0x01 /* Continuous measurement mode */
#define RM3100_REG_CCX_MSB 0x04 /* Cycle Count X LSB */
#define RM3100_REG_CCX_LSB 0x05 /* Cycle Count X MSB */
#define RM3100_REG_CCY_MSB 0x06 /* Cycle Count Y LSB */
#define RM3100_REG_CCY_LSB 0x07 /* Cycle Count Y MSB */
#define RM3100_REG_CCZ_MSB 0x08 /* Cycle Count Z LSB */
#define RM3100_REG_CCZ_LSB 0x09 /* Cycle Count Z MSB */
#define RM3100_REG_TMRC 0x0B /* Continuous Mode Update Rate */
#define RM3100_REG_MX 0x24 /* Measurement results X (3 bytes) */
#define RM3100_REG_MY 0x27 /* Measurement results Y (3 bytes) */
#define RM3100_REG_MZ 0x2A /* Measurement results Z (3 bytes) */
@ -21,4 +28,8 @@
#define RM3100_CMM_ALL_AXIS 0x71
#define RM3100_CYCLE_COUNT_DEFAULT 0x00C8 /* Default Cycle Count value */
#define RM3100_CYCLE_COUNT_HIGH_ODR 0x0064 /* Cycle count value required for 600 Hz ODR */
#endif /* ZEPHYR_DRIVERS_SENSOR_PNI_RM3100_REG_H_ */

View file

@ -7,7 +7,43 @@ description: |
The RM3100 can use either I2C or SPI as a communication bus.
This driver currently supports I2C only.
When setting the odr property in a .dts or .dtsi file you may include rm3100.h
and use the macros defined there.
Example:
#include <zephyr/dt-bindings/sensor/rm3100.h>
&i2c0 {
rm3100@20 {
compatible = "pni,rm3100";
reg = <0x20>;
odr = <RM3100_DT_ODR_600>;
};
};
compatible: "pni,rm3100"
include: [sensor-device.yaml, i2c-device.yaml]
properties:
odr:
type: int
default: 0x96
description: |
The output data rate (ODR) of the sensor in Hz.
Default is power-on setting.
enum:
- 0x92 # RM33100_DT_ODR_600
- 0x93 # RM33100_DT_ODR_300
- 0x94 # RM33100_DT_ODR_150
- 0x95 # RM33100_DT_ODR_75
- 0x96 # RM33100_DT_ODR_37_5
- 0x97 # RM33100_DT_ODR_18
- 0x98 # RM33100_DT_ODR_9
- 0x99 # RM33100_DT_ODR_4_5
- 0x9A # RM33100_DT_ODR_2_3
- 0x9B # RM33100_DT_ODR_1_2
- 0x9C # RM33100_DT_ODR_0_6
- 0x9D # RM33100_DT_ODR_0_3
- 0x9E # RM33100_DT_ODR_0_015
- 0x9F # RM33100_DT_ODR_0_0075

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 Intel Corporation
* Copyright (c) 2025 Croxel Inc.
* Copyright (c) 2025 CogniPilot Foundation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PNI_RM3100_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_PNI_RM3100_H_
/**
* @defgroup RM3100 PNI DT Options
* @ingroup sensor_interface
* @{
*/
/**
* @defgroup RM3100_ODR Output data rate options
* @{
*/
#define RM3100_DT_ODR_600 0x92
#define RM3100_DT_ODR_300 0x93
#define RM3100_DT_ODR_150 0x94
#define RM3100_DT_ODR_75 0x95
#define RM3100_DT_ODR_37_5 0x96
#define RM3100_DT_ODR_18 0x97
#define RM3100_DT_ODR_9 0x98
#define RM3100_DT_ODR_4_5 0x99
#define RM3100_DT_ODR_2_3 0x9A
#define RM3100_DT_ODR_1_2 0x9B
#define RM3100_DT_ODR_0_6 0x9C
#define RM3100_DT_ODR_0_3 0x9D
#define RM3100_DT_ODR_0_015 0x9E
#define RM3100_DT_ODR_0_0075 0x9F
/** @} */
/** @} */
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PNI_RM3100_H_ */