Skip to content

Commit 4a2f408

Browse files
committed
drivers: sensor: max30101: Enhanced sample_fetch to match datasheet
The max30101 allows to configure time slots in samples acquisition. It is now supported by adding matrix mapping for the slot/fifo indexing. When a channel is present multiple times, the resulting sample from the `sensor_channel_get` is averaging each entry. Added Die temperature sample acquisition with `CONFIG_MAX30101_DIS_TEMPERATURE` Kconfig. Signed-off-by: Logan Saint-Germain <[email protected]>
1 parent 4c540aa commit 4a2f408

File tree

4 files changed

+116
-52
lines changed

4 files changed

+116
-52
lines changed

drivers/sensor/maxim/max30101/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ menuconfig MAX30101
1313

1414
if MAX30101
1515

16+
config MAX30101_DIE_TEMPERATURE
17+
bool "Die temperature acquisition"
18+
1619
choice MAX30101_TRIGGER_MODE
1720
prompt "Trigger mode"
1821
default MAX30101_TRIGGER_NONE

drivers/sensor/maxim/max30101/max30101.c

Lines changed: 98 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static int max30101_sample_fetch(const struct device *dev,
2424
int i;
2525

2626
/* Read all the active channels for one sample */
27-
num_bytes = data->num_channels * MAX30101_BYTES_PER_CHANNEL;
27+
num_bytes = data->total_channels * MAX30101_BYTES_PER_CHANNEL;
2828
if (i2c_burst_read_dt(&config->i2c, MAX30101_REG_FIFO_DATA, buffer,
2929
num_bytes)) {
3030
LOG_ERR("Could not fetch sample");
@@ -36,12 +36,27 @@ static int max30101_sample_fetch(const struct device *dev,
3636
/* Each channel is 18-bits */
3737
fifo_data = (buffer[i] << 16) | (buffer[i + 1] << 8) |
3838
(buffer[i + 2]);
39-
fifo_data &= MAX30101_FIFO_DATA_MASK;
39+
fifo_data = (fifo_data & MAX30101_FIFO_DATA_MASK) >> config->data_shift;
4040

4141
/* Save the raw data */
4242
data->raw[fifo_chan++] = fifo_data;
4343
}
4444

45+
#if CONFIG_MAX30101_DIE_TEMPERATURE
46+
/* Read the die temperature */
47+
if (i2c_burst_read_dt(&config->i2c, MAX30101_REG_TINT, buffer, 2)) {
48+
LOG_ERR("Could not fetch die temperature");
49+
return -EIO;
50+
}
51+
52+
/* Save the raw data */
53+
data->die_temp[0] = buffer[0];
54+
data->die_temp[1] = buffer[1];
55+
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_TEMP_CFG, 1)) {
56+
return -EIO;
57+
}
58+
#endif /* CONFIG_MAX30101_DIE_TEMPERATURE */
59+
4560
return 0;
4661
}
4762

@@ -66,6 +81,13 @@ static int max30101_channel_get(const struct device *dev,
6681
led_chan = MAX30101_LED_CHANNEL_GREEN;
6782
break;
6883

84+
#if CONFIG_MAX30101_DIE_TEMPERATURE
85+
case SENSOR_CHAN_DIE_TEMP:
86+
val->val1 = data->die_temp[0];
87+
val->val2 = (1000000 * data->die_temp[1]) >> MAX30101_TEMP_FRAC_SHIFT;
88+
return 0;
89+
#endif /* CONFIG_MAX30101_DIE_TEMPERATURE */
90+
6991
default:
7092
LOG_ERR("Unsupported sensor channel");
7193
return -ENOTSUP;
@@ -75,14 +97,19 @@ static int max30101_channel_get(const struct device *dev,
7597
* channel. If the fifo channel isn't valid, then the led channel
7698
* isn't active.
7799
*/
78-
fifo_chan = data->map[led_chan];
79-
if (fifo_chan >= MAX30101_MAX_NUM_CHANNELS) {
100+
fifo_chan = data->num_channels[led_chan];
101+
if (!fifo_chan) {
80102
LOG_ERR("Inactive sensor channel");
81103
return -ENOTSUP;
82104
}
83105

106+
val->val1 = 0;
107+
for (fifo_chan = 0; fifo_chan < data->num_channels[led_chan]; fifo_chan++) {
108+
val->val1 += data->raw[data->map[led_chan][fifo_chan]];
109+
}
110+
84111
/* TODO: Scale the raw data to standard units */
85-
val->val1 = data->raw[fifo_chan];
112+
val->val1 /= data->num_channels[led_chan];
86113
val->val2 = 0;
87114

88115
return 0;
@@ -96,45 +123,9 @@ static DEVICE_API(sensor, max30101_driver_api) = {
96123
#endif
97124
};
98125

99-
static int max30101_init(const struct device *dev)
126+
static int max30101_configure(const struct device *dev)
100127
{
101128
const struct max30101_config *config = dev->config;
102-
struct max30101_data *data = dev->data;
103-
uint8_t part_id;
104-
uint8_t mode_cfg;
105-
uint32_t led_chan;
106-
107-
if (!device_is_ready(config->i2c.bus)) {
108-
LOG_ERR("Bus device is not ready");
109-
return -ENODEV;
110-
}
111-
112-
/* Check the part id to make sure this is MAX30101 */
113-
if (i2c_reg_read_byte_dt(&config->i2c, MAX30101_REG_PART_ID,
114-
&part_id)) {
115-
LOG_ERR("Could not get Part ID");
116-
return -EIO;
117-
}
118-
if (part_id != MAX30101_PART_ID) {
119-
LOG_ERR("Got Part ID 0x%02x, expected 0x%02x",
120-
part_id, MAX30101_PART_ID);
121-
return -EIO;
122-
}
123-
124-
/* Reset the sensor */
125-
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_MODE_CFG,
126-
MAX30101_MODE_CFG_RESET_MASK)) {
127-
return -EIO;
128-
}
129-
130-
/* Wait for reset to be cleared */
131-
do {
132-
if (i2c_reg_read_byte_dt(&config->i2c, MAX30101_REG_MODE_CFG,
133-
&mode_cfg)) {
134-
LOG_ERR("Could read mode cfg after reset");
135-
return -EIO;
136-
}
137-
} while (mode_cfg & MAX30101_MODE_CFG_RESET_MASK);
138129

139130
/* Write the FIFO configuration register */
140131
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_FIFO_CFG,
@@ -186,28 +177,80 @@ static int max30101_init(const struct device *dev)
186177
}
187178
}
188179

180+
#if CONFIG_MAX30101_DIE_TEMPERATURE
181+
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_TEMP_CFG, 1)) {
182+
return -EIO;
183+
}
184+
#endif /* CONFIG_MAX30101_DIE_TEMPERATURE */
185+
189186
#if CONFIG_MAX30101_TRIGGER
190187
if (max30101_init_interrupts(dev)) {
191188
LOG_ERR("Failed to initialize interrupts");
192189
return -EIO;
193190
}
194191
#endif
195192

196-
/* Initialize the channel map and active channel count */
197-
data->num_channels = 0U;
198-
for (led_chan = 0U; led_chan < MAX30101_MAX_NUM_CHANNELS; led_chan++) {
199-
data->map[led_chan] = MAX30101_MAX_NUM_CHANNELS;
193+
return 0;
194+
}
195+
196+
static int max30101_init(const struct device *dev)
197+
{
198+
const struct max30101_config *config = dev->config;
199+
struct max30101_data *data = dev->data;
200+
uint8_t part_id;
201+
uint8_t mode_cfg;
202+
uint32_t led_chan;
203+
204+
if (!device_is_ready(config->i2c.bus)) {
205+
LOG_ERR("Bus device is not ready");
206+
return -ENODEV;
207+
}
208+
209+
/* Check the part id to make sure this is MAX30101 */
210+
if (i2c_reg_read_byte_dt(&config->i2c, MAX30101_REG_PART_ID, &part_id)) {
211+
LOG_ERR("Could not get Part ID");
212+
return -EIO;
213+
}
214+
if (part_id != MAX30101_PART_ID) {
215+
LOG_ERR("Got Part ID 0x%02x, expected 0x%02x", part_id, MAX30101_PART_ID);
216+
return -EIO;
217+
}
218+
219+
/* Reset the sensor */
220+
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_MODE_CFG,
221+
MAX30101_MODE_CFG_RESET_MASK)) {
222+
return -EIO;
223+
}
224+
225+
/* Wait for reset to be cleared */
226+
do {
227+
if (i2c_reg_read_byte_dt(&config->i2c, MAX30101_REG_MODE_CFG, &mode_cfg)) {
228+
LOG_ERR("Could read mode cfg after reset");
229+
return -EIO;
230+
}
231+
} while (mode_cfg & MAX30101_MODE_CFG_RESET_MASK);
232+
233+
if (max30101_configure(dev)) {
234+
return -EIO;
200235
}
201236

202237
/* Count the number of active channels and build a map that translates
203238
* the LED channel number (red/ir/green) to the fifo channel number.
204239
*/
205240
for (int fifo_chan = 0; fifo_chan < MAX30101_MAX_NUM_CHANNELS; fifo_chan++) {
206241
led_chan = (config->slot[fifo_chan] & MAX30101_SLOT_LED_MASK) - 1;
207-
if (led_chan < MAX30101_MAX_NUM_CHANNELS) {
208-
data->map[led_chan] = fifo_chan;
209-
data->num_channels++;
242+
if (led_chan >= MAX30101_MAX_NUM_CHANNELS) {
243+
continue;
244+
}
245+
246+
for (int i = 0; i < MAX30101_MAX_NUM_CHANNELS; i++) {
247+
if (data->map[led_chan][i] == MAX30101_MAX_NUM_CHANNELS) {
248+
data->map[led_chan][i] = fifo_chan;
249+
data->num_channels[led_chan]++;
250+
break;
251+
}
210252
}
253+
data->total_channels++;
211254
}
212255

213256
return 0;
@@ -242,10 +285,15 @@ static int max30101_init(const struct device *dev)
242285
(DT_INST_ENUM_IDX(n, led_pw) << MAX30101_SPO2_PW_SHIFT), \
243286
.led_pa = DT_INST_PROP(n, led_pa), \
244287
.slot = MAX30101_SLOT_CFG(n), \
288+
.data_shift = MAX30101_FIFO_DATA_MAX_SHIFT - DT_INST_ENUM_IDX(n, led_pw), \
245289
IF_ENABLED(CONFIG_MAX30101_TRIGGER, \
246290
(.irq_gpio = GPIO_DT_SPEC_INST_GET_OR(n, irq_gpios, {0}),) \
247291
) }; \
248-
static struct max30101_data max30101_data_##n; \
292+
static struct max30101_data max30101_data_##n = { \
293+
.map = {{3, 3, 3}, {3, 3, 3}, {3, 3, 3}}, \
294+
.num_channels = {0, 0, 0}, \
295+
.total_channels = 0, \
296+
}; \
249297
SENSOR_DEVICE_DT_INST_DEFINE(n, max30101_init, NULL, &max30101_data_##n, \
250298
&max30101_config_##n, POST_KERNEL, \
251299
CONFIG_SENSOR_INIT_PRIORITY, &max30101_driver_api);

drivers/sensor/maxim/max30101/max30101.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555

5656
#define MAX30101_FIFO_DATA_BITS 18
5757
#define MAX30101_FIFO_DATA_MASK ((1 << MAX30101_FIFO_DATA_BITS) - 1)
58+
#define MAX30101_FIFO_DATA_MAX_SHIFT 3
59+
60+
#define MAX30101_TEMP_FRAC_SHIFT 4
5861

5962
#if CONFIG_MAX30101_TRIGGER
6063
#define MAX30101_SUPPORTED_INTERRUPTS 4 /* FIFO_FULL | PPG | ALC | TEMP */
@@ -121,15 +124,20 @@ struct max30101_config {
121124
uint8_t led_pa[MAX30101_MAX_NUM_CHANNELS];
122125
uint8_t mode;
123126
uint8_t slot[4];
127+
uint8_t data_shift;
124128
#if CONFIG_MAX30101_TRIGGER
125129
const struct gpio_dt_spec irq_gpio;
126130
#endif
127131
};
128132

129133
struct max30101_data {
130134
uint32_t raw[MAX30101_MAX_NUM_CHANNELS];
131-
uint8_t map[MAX30101_MAX_NUM_CHANNELS];
132-
uint8_t num_channels;
135+
uint8_t map[MAX30101_MAX_NUM_CHANNELS][MAX30101_MAX_NUM_CHANNELS];
136+
uint8_t num_channels[MAX30101_MAX_NUM_CHANNELS];
137+
uint8_t total_channels;
138+
#if CONFIG_MAX30101_DIE_TEMPERATURE
139+
uint8_t die_temp[2];
140+
#endif /* CONFIG_MAX30101_DIE_TEMPERATURE */
133141
#if CONFIG_MAX30101_TRIGGER
134142
const struct device *dev;
135143
struct gpio_callback gpio_cb;

drivers/sensor/maxim/max30101/max30101_trigger.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,13 @@ int max30101_trigger_set(const struct device *dev, const struct sensor_trigger *
113113
case SENSOR_TRIG_DATA_READY:
114114
switch (trig->chan) {
115115
case SENSOR_CHAN_DIE_TEMP:
116+
#if CONFIG_MAX30101_DIE_TEMPERATURE
116117
mask = MAX30101_INT_TEMP_MASK;
117118
index = MAX30101_TEMP_CB_INDEX;
119+
#else
120+
LOG_ERR("SENSOR_CHAN_DIE_TEMP needs CONFIG_MAX30101_DIE_TEMPERATURE");
121+
return -EINVAL;
122+
#endif /* CONFIG_MAX30101_DIE_TEMPERATURE */
118123
break;
119124

120125
case SENSOR_CHAN_LIGHT:

0 commit comments

Comments
 (0)