Triyng to use a MPRLS 0015PA0000SAB sensor with nrf5340dk

Hello, I've been developing on a Nrf5340 board and I am trying to gather pressure sensor data from both a adafruit mprls pressure sensor breakout board on i2c and then a Honeywell mprls0015PA0000SAB sensor that is running on the SPI bus. I've been able to get the adafruit sensor board and read data from that board but I have been having many troubles trying to configure the honeywell board and get my project to actually build. 

This is my main.c file:

/*
 * Copyright (c) 2024 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/printk.h>

/* Configuration Macros */
#define SLEEP_TIME_MS 1000
#define ADC_SAMPLE_INTERVAL_MS 50
#define I2C_CONFIG_REG 0x8C
#define PRESSURE_SENSOR_ADDR DT_NODELABEL(mprls)
#define SPIOP      SPI_WORD_SET(8) | SPI_TRANSFER_MSB

/* ADC Specification */
static const struct adc_dt_spec adc_channel = ADC_DT_SPEC_GET(DT_PATH(zephyr_user));

/* Logging Module */
LOG_MODULE_REGISTER(ImprovedSensorApp, LOG_LEVEL_DBG);

/* Function Prototypes */
static int initialize_i2c_sensor(const struct i2c_dt_spec *dev_i2c);
static int initialize_adc(const struct adc_dt_spec *adc_channel, struct adc_sequence *sequence, int16_t *buf);
static int initialize_spi_sensor(const struct spi_dt_spec *dev_spit);
static int read_adc_value(const struct adc_dt_spec *adc_channel, struct adc_sequence *sequence, int16_t *buf);
static float calculate_pressure(uint8_t *data_buffer);
static float calculate_spi_pressure(uint8_t *spi_data);

int main(void) {
    /* I2C Initialization */
    uint8_t Sensor_I2C[3];
    Sensor_I2C[0] = 0xAA;      //Output Measurement
    Sensor_I2C[1] = 0x00;     
    Sensor_I2C[2] = 0x00; 
    struct adc_sequence sequence;
    int16_t adc_buf;
    if (initialize_adc(&adc_channel, &sequence, &adc_buf) < 0) {
        return -1;
    }
    static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(PRESSURE_SENSOR_ADDR);
    if (initialize_i2c_sensor(&dev_i2c) < 0) {
        return -1;
    }

    static const struct spi_dt_spec dev_spi = SPI_DT_SPEC_GET(DT_NODELABEL(mprls_spi), SPIOP, 0);


        if (initialize_spi_sensor(&dev_spi) < 0) {
            return -1;
        }


    printk("Start reading Sensor\n");
    while (1) {
        /* ADC Reading */
        int adc_mv = read_adc_value(&adc_channel, &sequence, &adc_buf);
        if (adc_mv >= 0) {
            printk(">");
			printk("var1:");
		    printk("%d mV", adc_mv);
			printk("\r\n");
        }

        /* I2C Sensor Reading */
        uint8_t i2c_rx_buffer[4];
        uint8_t config[2] = {0xAA, 0x8C};  // Replace this with the correct command for your sensor
        int ret = i2c_write_dt(&dev_i2c, config, sizeof(config));

        // Assuming 3 bytes for pressure data
        ret = i2c_read_dt(&dev_i2c, i2c_rx_buffer, sizeof(i2c_rx_buffer));
        printk("I2C raw data: %02x %02x %02x %02x\n", i2c_rx_buffer[0], i2c_rx_buffer[1], i2c_rx_buffer[2], i2c_rx_buffer[3]);

        if (ret != 0) {
            printk("Failed to read from sensor (%d)\n", ret);
        } else {
            float pressure = calculate_pressure(i2c_rx_buffer);
            printk(">");
			printk("var2:");
			printk("%.2f Psi", pressure);
			printk("\r\n");
            printk("Pressure: %.2f kPa\n", pressure);
        }
        uint8_t spi_tx_buffer[1] = {0x00}; // Command to request pressure data (adjust as needed)
        uint8_t spi_rx_buffer[3] = {0}; // Buffer for received pressure data
        struct spi_buf tx_buf = {
            .buf = spi_tx_buffer,
            .len = sizeof(spi_tx_buffer),
        };
        struct spi_buf rx_buf = {
            .buf = spi_rx_buffer,
            .len = sizeof(spi_rx_buffer),
        };
        struct spi_buf_set tx_set = {
            .buffers = &tx_buf,
            .count = 1,
        };
        struct spi_buf_set rx_set = {
            .buffers = &rx_buf,
            .count = 1,
        };

        ret = spi_transceive_dt(&dev_spi, &tx_set, &rx_set);

        if (ret != 0) {
            printk("Failed to read from SPI sensor (%d)\n", ret);
        } else {
            float pressure = calculate_spi_pressure(spi_rx_buffer);
            printk(">SPI Pressure: %.2f kPa\n", pressure);
        }

        /* Sleep */
        k_sleep(K_MSEC(ADC_SAMPLE_INTERVAL_MS));
    }

    return 0;
}

/* Initialize the I2C Sensor */
static int initialize_i2c_sensor(const struct i2c_dt_spec *dev_i2c) {
    if (!device_is_ready(dev_i2c->bus)) {
        printk("I2C bus %s is not ready!\n", dev_i2c->bus->name);
        return -1;
    }
    uint8_t config[2] = {I2C_CONFIG_REG, 0x8C};
    int ret = i2c_write_dt(dev_i2c, config, sizeof(config));
    if (ret != 0) {
        printk("Failed to configure I2C sensor (addr: 0x%x, reg: 0x%x)\n", dev_i2c->addr, config[0]);
        return -1;
    }
    printk("I2C Sensor initialized successfully.\n");
    return 0;
}

static int initialize_spi_sensor(const struct spi_dt_spec *dev_spi) {
    const struct device *mprls = DEVICE_DT_GET(DT_NODELABEL(mprls_spi));
    if (!device_is_ready(mprls)) {
        printk("MPRLS device not ready\n");
        return -ENODEV;
    }

    if (!spi_is_ready_dt(dev_spi)) {
        printk("SPI device not ready\n");
        return -1;
    }

    printk("SPI Sensor initialized successfully.\n");
    return 0;
}


/* Initialize the ADC */
static int initialize_adc(const struct adc_dt_spec *adc_channel, struct adc_sequence *sequence, int16_t *buf) {
    if (!adc_is_ready_dt(adc_channel)) {
        LOG_ERR("ADC controller device %s is not ready", adc_channel->dev->name);
        return -1;
    }
    int err = adc_channel_setup_dt(adc_channel);
    if (err < 0) {
        LOG_ERR("Failed to setup ADC channel (%d)", err);
        return -1;
    }

    /* Configure ADC sequence */
        sequence->options = NULL;
        sequence->channels = BIT(adc_channel->channel_id);
        sequence->buffer = buf;
        sequence->buffer_size = sizeof(int16_t); // Single sample
        sequence->resolution = adc_channel->resolution;
        sequence->oversampling = 0;
    printk("ADC initialized successfully.\n");
    return 0;
}

/* Read ADC Value */
static int read_adc_value(const struct adc_dt_spec *adc_channel, struct adc_sequence *sequence, int16_t *buf) {
    int err = adc_read(adc_channel->dev, sequence);
    if (err < 0) {
        LOG_ERR("ADC read failed (%d)", err);
        return err;
    }
    int val_mv = buf[0];
    err = adc_raw_to_millivolts_dt(adc_channel, &val_mv);
    if (err < 0) {
        LOG_WRN("Raw ADC value: %d (conversion to mV not available)", buf[0]);
    }
    return val_mv;
}

/* Calculate Pressure from Sensor Data */
static float calculate_pressure(uint8_t *data_buffer) {
    int raw_value = (data_buffer[1] << 16) | data_buffer[2] << 8 | data_buffer[3]; // Assuming 16-bit raw data
    float double_pressure = (float)raw_value;
    float calculated_pressure = (((double_pressure - 1677722)*25)/13421772)+(0);
    return calculated_pressure;
}

static float calculate_spi_pressure(uint8_t *spi_data) {
    int raw_value = (spi_data[1] << 16) | (spi_data[2] << 8) | spi_data[2];
    float double_pressure = (float)raw_value;
    float calculated_pressure = (((double_pressure - 1677722)*25)/13421772)+(0);
    return calculated_pressure;
}


And this is the nrf5340dk_nrf5340_cpuadd_ns.overlay file
/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * Copyright (c) 2022 Nordic Semiconductor ASA
 *
 
	Includes code to activate the ADC and the I2C drivers. Overlay details are typically mirrored in the prj.conf file
 
 */
&uart1 {status = "disabled";};
 / {
	zephyr,user {
		io-channels = <&adc 0>;			// We're using channel 0, but we can specify more
	};
};

&adc {
	#address-cells = <1>;		// 
	#size-cells = <0>;			//
	status = "okay";			//
	channel@0 {					// We're using channel 0
		reg = <0>;
		zephyr,gain = "ADC_GAIN_1";
		zephyr,reference = "ADC_REF_INTERNAL"; //Use an intenral reference, there are several to choose from. 
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;	// 10us. fSAMPLE < 1/(tACQ + tconv), where tconv depends on resolution
		zephyr,input-positive = <NRF_SAADC_AIN0>; /* P0.04 for nRF5340 */
		zephyr,resolution = <12>; //can also be 8/10/12
	};
};

// Device tree shows this as i2c1 node for the nRF53DK

&i2c1 {
	mprls: mprls@18{
		compatible = "i2c-device";
		reg = < 0x18 >; //This must be a 7 bit address, not a 8 bit one. If comm is an issue, this could be it
		label = "mprls";
		pinctrl-0 = <&i2c1_default>;
		pinctrl-1 = <&i2c1_sleep>;
		int_gpios = <&gpio0 27 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
		status = "okay";
		zephyr,concat-buf-size = <128>; //fixes an old issue in which burst read/write runs out of memory 
	};
};

&spi0 {
    compatible = "nordic,nrf-spim";
    status = "okay";
    pinctrl-0 = <&spi0_default>;
    pinctrl-1 = <&spi0_sleep>;
    pinctrl-names = "default", "sleep";
    cs-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;

    mprls_spi: mprls_spi@0 {
        compatible = "honeywell,mprls_spi";
        reg = <0>;                          // Chip-select index
        spi-max-frequency = <1000000>;      // Maximum SPI clock frequency (1 MHz)
        duplex = <0>;                    // Ensure duplex is explicitly defined
    };
};

&pinctrl {
    spi0_default: spi0_default {
        group1 {
            psels = <NRF_PSEL(SPIM_SCK, 0, 8)>,					 
                    <NRF_PSEL(SPIM_MOSI, 0, 9)>,
                    <NRF_PSEL(SPIM_MISO, 0, 10)>;
        };
    };
    spi0_sleep: spi0_sleep {
        group1 {
            psels = <NRF_PSEL(SPIM_SCK, 0, 8)>,
                    <NRF_PSEL(SPIM_MOSI, 0, 9)>,
                    <NRF_PSEL(SPIM_MISO, 0, 10)>;
            low-power-enable;
        };
    };
};


I've managed to get the project to build pretty far to the point where it's generating build files but near the end I will get an error that says "undefined reference to '__device_dts_ord_146'

Im pretty stuck at this point and not sure what my next steps are to figuring this out. In order to get mrpls_spi to work I did go into the zephyr project folders and added a yaml specifically for that board and made the file honeywell,mprls_spi.yaml there was already a honeywell,mpr.yaml file but it had specified that it only worked on the i2c bus and not the spi one which was my reason for doing that. Im not sure if I have to create a new driver for the sensor or if there's just something wrong im doing with the configuration?

Parents Reply Children
No Data
Related