Hello, I am using:
NCS v1.5.1 and the sample code from ~/ncs/v1.5.1/zephyr/drivers/sensor/max30101/ (max30101.c, max30101.h)
nRF5340dk
MAX30101 from Sparkfun www.sparkfun.com/.../16474
Sorry for the newbie question but I am a newer programmer and have been trying to figure this out for a long time. It *should* be simple.
The sample that comes with NCS for sensor max30101 is incomplete and only gets readings from one channel (GREEN) but I am trying to figure out how to get readings from the other two (IR, RED).
The readings for those channels are always the same value. IR is always at the maximum value (doesn't change) and RED is always 0.
The second and third channels keep on throwing an error: "Inactive sensor channel" which is thrown if fifo_chan >= 3. I can verify from debugging that fifo_chan for those channels is always gets set to 3 for some reason.
Why do I keep on getting no readings for my other second and third channels?
Why does fifo_chan keep on getting set to 3 for the second and third channels?
Am I doing something wrong?
This is my main.c
#include <zephyr.h> #include <sys/printk.h> #include <drivers/sensor.h> #include <stdio.h> void main(void) { struct sensor_value green; // begin what I added struct sensor_value ir; struct sensor_value red; // end what I added const struct device *dev = device_get_binding(DT_LABEL(DT_INST(0, max_max30101))); if (dev == NULL) { printf("Could not get max30101 device\n"); return; } while (1) { sensor_sample_fetch(dev); printf("\n==============================================================================\n"); sensor_channel_get(dev, SENSOR_CHAN_GREEN, &green); printf("GREEN=%d\n", green.val1); // begin what I added sensor_channel_get(dev, SENSOR_CHAN_IR, &ir); printf("IR=%d\n", ir.val1); sensor_channel_get(dev, SENSOR_CHAN_RED, &red); printf("RED=%d\n", red.val1); printf("\n"); // end what I added k_sleep(K_MSEC(5000)); } }
This is the code from max30101.c. I added one line for debugging (line 81) and verified that led_chan is set correctly but I still keep on getting fifo_chan set to 3.
/* * Copyright (c) 2017, NXP * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT max_max30101 #include <logging/log.h> #include "max30101.h" LOG_MODULE_REGISTER(MAX30101, CONFIG_SENSOR_LOG_LEVEL); static int max30101_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct max30101_data *data = dev->data; const struct max30101_config *config = dev->config; uint8_t buffer[MAX30101_MAX_BYTES_PER_SAMPLE]; uint32_t fifo_data; int fifo_chan; int num_bytes; int i; /* Read all the active channels for one sample */ num_bytes = data->num_channels * MAX30101_BYTES_PER_CHANNEL; if (i2c_burst_read(data->i2c, config->i2c_addr, MAX30101_REG_FIFO_DATA, buffer, num_bytes)) { LOG_ERR("Could not fetch sample"); return -EIO; } fifo_chan = 0; for (i = 0; i < num_bytes; i += 3) { /* Each channel is 18-bits */ fifo_data = (buffer[i] << 16) | (buffer[i + 1] << 8) | (buffer[i + 2]); fifo_data &= MAX30101_FIFO_DATA_MASK; /* Save the raw data */ data->raw[fifo_chan++] = fifo_data; } return 0; } static int max30101_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct max30101_data *data = dev->data; enum max30101_led_channel led_chan; int fifo_chan; switch (chan) { case SENSOR_CHAN_RED: led_chan = MAX30101_LED_CHANNEL_RED; break; case SENSOR_CHAN_IR: led_chan = MAX30101_LED_CHANNEL_IR; break; case SENSOR_CHAN_GREEN: led_chan = MAX30101_LED_CHANNEL_GREEN; break; default: LOG_ERR("Unsupported sensor channel"); return -ENOTSUP; } /* Check if the led channel is active by looking up the associated fifo * channel. If the fifo channel isn't valid, then the led channel * isn't active. */ fifo_chan = data->map[led_chan]; // begin what I added LOG_ERR("led_chan: %d. fifo_chan: %d. MAX30101_MAX_NUM_CHANNELS: %d ", led_chan, fifo_chan, MAX30101_MAX_NUM_CHANNELS); // end what I added if (fifo_chan >= MAX30101_MAX_NUM_CHANNELS) { LOG_ERR("Inactive sensor channel\n"); return -ENOTSUP; } /* TODO: Scale the raw data to standard units */ val->val1 = data->raw[fifo_chan]; val->val2 = 0; return 0; } static const struct sensor_driver_api max30101_driver_api = { .sample_fetch = max30101_sample_fetch, .channel_get = max30101_channel_get, }; static int max30101_init(const struct device *dev) { const struct max30101_config *config = dev->config; struct max30101_data *data = dev->data; uint8_t part_id; uint8_t mode_cfg; uint32_t led_chan; int fifo_chan; /* Get the I2C device */ data->i2c = device_get_binding(config->i2c_label); if (!data->i2c) { LOG_ERR("Could not find I2C device"); return -EINVAL; } /* Check the part id to make sure this is MAX30101 */ if (i2c_reg_read_byte(data->i2c, config->i2c_addr, MAX30101_REG_PART_ID, &part_id)) { LOG_ERR("Could not get Part ID"); return -EIO; } if (part_id != MAX30101_PART_ID) { LOG_ERR("Got Part ID 0x%02x, expected 0x%02x", part_id, MAX30101_PART_ID); return -EIO; } /* Reset the sensor */ if (i2c_reg_write_byte(data->i2c, config->i2c_addr, MAX30101_REG_MODE_CFG, MAX30101_MODE_CFG_RESET_MASK)) { return -EIO; } /* Wait for reset to be cleared */ do { if (i2c_reg_read_byte(data->i2c, config->i2c_addr, MAX30101_REG_MODE_CFG, &mode_cfg)) { LOG_ERR("Could read mode cfg after reset"); return -EIO; } } while (mode_cfg & MAX30101_MODE_CFG_RESET_MASK); /* Write the FIFO configuration register */ if (i2c_reg_write_byte(data->i2c, config->i2c_addr, MAX30101_REG_FIFO_CFG, config->fifo)) { return -EIO; } /* Write the mode configuration register */ if (i2c_reg_write_byte(data->i2c, config->i2c_addr, MAX30101_REG_MODE_CFG, config->mode)) { return -EIO; } /* Write the SpO2 configuration register */ if (i2c_reg_write_byte(data->i2c, config->i2c_addr, MAX30101_REG_SPO2_CFG, config->spo2)) { return -EIO; } /* Write the LED pulse amplitude registers */ if (i2c_reg_write_byte(data->i2c, config->i2c_addr, MAX30101_REG_LED1_PA, config->led_pa[0])) { return -EIO; } if (i2c_reg_write_byte(data->i2c, config->i2c_addr, MAX30101_REG_LED2_PA, config->led_pa[1])) { return -EIO; } if (i2c_reg_write_byte(data->i2c, config->i2c_addr, MAX30101_REG_LED3_PA, config->led_pa[2])) { return -EIO; } #ifdef CONFIG_MAX30101_MULTI_LED_MODE uint8_t multi_led[2]; /* Write the multi-LED mode control registers */ multi_led[0] = (config->slot[1] << 4) | (config->slot[0]); multi_led[1] = (config->slot[3] << 4) | (config->slot[2]); if (i2c_reg_write_byte(data->i2c, config->i2c_addr, MAX30101_REG_MULTI_LED, multi_led[0])) { return -EIO; } if (i2c_reg_write_byte(data->i2c, config->i2c_addr, MAX30101_REG_MULTI_LED + 1, multi_led[1])) { return -EIO; } #endif /* Initialize the channel map and active channel count */ data->num_channels = 0U; for (led_chan = 0U; led_chan < MAX30101_MAX_NUM_CHANNELS; led_chan++) { data->map[led_chan] = MAX30101_MAX_NUM_CHANNELS; } /* Count the number of active channels and build a map that translates * the LED channel number (red/ir/green) to the fifo channel number. */ for (fifo_chan = 0; fifo_chan < MAX30101_MAX_NUM_CHANNELS; fifo_chan++) { led_chan = (config->slot[fifo_chan] & MAX30101_SLOT_LED_MASK)-1; if (led_chan < MAX30101_MAX_NUM_CHANNELS) { data->map[led_chan] = fifo_chan; data->num_channels++; } } return 0; } static struct max30101_config max30101_config = { .i2c_label = DT_INST_BUS_LABEL(0), .i2c_addr = DT_INST_REG_ADDR(0), .fifo = (CONFIG_MAX30101_SMP_AVE << MAX30101_FIFO_CFG_SMP_AVE_SHIFT) | #ifdef CONFIG_MAX30101_FIFO_ROLLOVER_EN MAX30101_FIFO_CFG_ROLLOVER_EN_MASK | #endif (CONFIG_MAX30101_FIFO_A_FULL << MAX30101_FIFO_CFG_FIFO_FULL_SHIFT), #if defined(CONFIG_MAX30101_HEART_RATE_MODE) .mode = MAX30101_MODE_HEART_RATE, .slot[0] = MAX30101_SLOT_RED_LED1_PA, .slot[1] = MAX30101_SLOT_DISABLED, .slot[2] = MAX30101_SLOT_DISABLED, .slot[3] = MAX30101_SLOT_DISABLED, #elif defined(CONFIG_MAX30101_SPO2_MODE) .mode = MAX30101_MODE_SPO2, .slot[0] = MAX30101_SLOT_RED_LED1_PA, .slot[1] = MAX30101_SLOT_IR_LED2_PA, .slot[2] = MAX30101_SLOT_DISABLED, .slot[3] = MAX30101_SLOT_DISABLED, #else .mode = MAX30101_MODE_MULTI_LED, .slot[0] = CONFIG_MAX30101_SLOT1, .slot[1] = CONFIG_MAX30101_SLOT2, .slot[2] = CONFIG_MAX30101_SLOT3, .slot[3] = CONFIG_MAX30101_SLOT4, #endif .spo2 = (CONFIG_MAX30101_ADC_RGE << MAX30101_SPO2_ADC_RGE_SHIFT) | (CONFIG_MAX30101_SR << MAX30101_SPO2_SR_SHIFT) | (MAX30101_PW_18BITS << MAX30101_SPO2_PW_SHIFT), .led_pa[0] = CONFIG_MAX30101_LED1_PA, .led_pa[1] = CONFIG_MAX30101_LED2_PA, .led_pa[2] = CONFIG_MAX30101_LED3_PA, }; static struct max30101_data max30101_data; DEVICE_DT_INST_DEFINE(0, max30101_init, device_pm_control_nop, &max30101_data, &max30101_config, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &max30101_driver_api);
This is the output:
*** Booting Zephyr OS build v2.4.99-ncs2 *** ============================================================================== GREEN=291 IR=29473 RED=0 [00:00:00.403,747] [1B][1;31m<err> MAX30101: led_chan: 2. fifo_chan: 0. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:00.404,724] [1B][1;31m<err> MAX30101: led_chan: 1. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:00.404,724] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m [00:00:00.405,578] [1B][1;31m<err> MAX30101: led_chan: 0. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:00.405,578] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m ============================================================================== GREEN=131 IR=29473 RED=0 [00:00:05.414,306] [1B][1;31m<err> MAX30101: led_chan: 2. fifo_chan: 0. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:05.415,252] [1B][1;31m<err> MAX30101: led_chan: 1. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:05.415,283] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m [00:00:05.416,137] [1B][1;31m<err> MAX30101: led_chan: 0. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:05.416,137] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m ============================================================================== GREEN=337 IR=29473 RED=0 [00:00:10.424,835] [1B][1;31m<err> MAX30101: led_chan: 2. fifo_chan: 0. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:10.425,781] [1B][1;31m<err> MAX30101: led_chan: 1. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:10.425,811] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m [00:00:10.426,666] [1B][1;31m<err> MAX30101: led_chan: 0. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:10.426,666] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m ============================================================================== GREEN=267 IR=29473 RED=0 [00:00:15.435,363] [1B][1;31m<err> MAX30101: led_chan: 2. fifo_chan: 0. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:15.436,309] [1B][1;31m<err> MAX30101: led_chan: 1. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:15.436,309] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m [00:00:15.437,194] [1B][1;31m<err> MAX30101: led_chan: 0. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:15.437,194] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m ============================================================================== GREEN=246 IR=29473 RED=0 [00:00:20.445,861] [1B][1;31m<err> MAX30101: led_chan: 2. fifo_chan: 0. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:20.446,838] [1B][1;31m<err> MAX30101: led_chan: 1. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:20.446,838] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m [00:00:20.447,723] [1B][1;31m<err> MAX30101: led_chan: 0. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:20.447,723] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m ============================================================================== GREEN=301 IR=29473 RED=0 [00:00:25.456,390] [1B][1;31m<err> MAX30101: led_chan: 2. fifo_chan: 0. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:25.457,366] [1B][1;31m<err> MAX30101: led_chan: 1. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:25.457,366] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m [00:00:25.458,251] [1B][1;31m<err> MAX30101: led_chan: 0. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:25.458,251] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m ============================================================================== GREEN=143 IR=29473 RED=0 [00:00:30.466,949] [1B][1;31m<err> MAX30101: led_chan: 2. fifo_chan: 0. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:30.467,895] [1B][1;31m<err> MAX30101: led_chan: 1. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:30.467,895] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m [00:00:30.468,780] [1B][1;31m<err> MAX30101: led_chan: 0. fifo_chan: 3. MAX30101_MAX_NUM_CHANNELS: 3 [1B][0m [00:00:30.468,780] [1B][1;31m<err> MAX30101: Inactive sensor channel [1B][0m
Please help. I have gone through documentation for several weeks and my brain is numb at this point.