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?