This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to fully configure i2c sensor working with NCS bluetooth?

We are in the process to add spectral sensor to zephyr based BLE sample, but following the tutorial to add overlay or copying other sensor configurations not helped much. Either it causes device tree error or some configuration error or label not registered.

Please help find any suitable guide to know all modifications needed to make new sensor visible for main script in BLE.

Thank you.

Parents Reply Children
  • I tried using BME680 to build BMI160 sensor support for NRF5340. Whatever overlay name such as NRF5340PDK/DK_NRF5340_CPUAPP/NS I try the BOSCH_BMI160 not declared error repeats.

    I have modified files for BMI160 said following : 

    1. https://devzone.nordicsemi.com/f/nordic-q-a/65900/change-sda-and-scl-pin-for-i2c1-on-nrf5340

    2. https://devzone.nordicsemi.com/f/nordic-q-a/66230/how-to-add-new-i2c-based-sensor-device-to-ncs-v1-3-0-zephyr-drivers-sensor

    But it throws error : DT_N_INST_)_BOSCH_BMI160_P_LABEL undeclared in expansion of macro 'UTIL_CAT'

    How to bypass I2C SCK with custom generated clock frequency (greater than 1 MHz) from GPIO to read sensor values?

  • I tried all possibilities modifying; 

    DTS->Bindings, Devicetree.h, drivers, overlay, board.dts, but no progress in adding adxl345 sensor to custom 52840 board nor BMI160 to NRF52840 development kit.

    device_get_binding(DT_LABEL(DT_INST(0,adi_adxl345) is always NULL and DT_NODE_HAS_STATUS(ADXL345,okay) is always NULL.

    Driver->adxl345->cmake

     

    # Copyright (c) 2019 Brett Witherspoon
    #
    # SPDX-License-Identifier: Apache-2.0
    
    cmake_minimum_required(VERSION 3.13.1)
    
    find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
    project(adxl345)
    
    target_sources(app PRIVATE src/main.c)
    

    Driver -> adxl_345.c

    /*
     * Copyright (c) 2020 Antmicro <www.antmicro.com>
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #define DT_DRV_COMPAT adi_adxl345
    
    #include <drivers/sensor.h>
    #include <init.h>
    #include <drivers/gpio.h>
    #include <drivers/i2c.h>
    #include <logging/log.h>
    #include <sys/__assert.h>
    
    #include "adxl345.h"
    
    LOG_MODULE_REGISTER(ADXL345, CONFIG_SENSOR_LOG_LEVEL);
    
    static int adxl345_read_sample(const struct device *dev,
    			       struct adxl345_sample *sample)
    {
    	struct adxl345_dev_data *data = dev->data;
    	int16_t raw_x, raw_y, raw_z;
    	uint8_t axis_data[6];
    
    	int rc = i2c_burst_read(data->i2c_master,
    				data->i2c_addr,
    				ADXL345_X_AXIS_DATA_0_REG,
    				axis_data,
    				6);
    
    	if (rc < 0) {
    		LOG_ERR("Samples read failed with rc=%d\n", rc);
    		return rc;
    	}
    
    	raw_x = axis_data[0] | (axis_data[1] << 8);
    	raw_y = axis_data[2] | (axis_data[3] << 8);
    	raw_z = axis_data[4] | (axis_data[5] << 8);
    
    	sample->x = raw_x;
    	sample->y = raw_y;
    	sample->z = raw_z;
    
    	return 0;
    }
    
    static void adxl345_accel_convert(struct sensor_value *val, int16_t sample)
    {
    	if (sample & BIT(9)) {
    		sample |= ADXL345_COMPLEMENT;
    	}
    
    	val->val1 = (sample * 1000) / 32;
    	val->val2 = 0;
    }
    
    static int adxl345_sample_fetch(const struct device *dev,
    				enum sensor_channel chan)
    {
    	struct adxl345_dev_data *data = dev->data;
    	struct adxl345_sample sample;
    	uint8_t samples_count;
    	int rc;
    
    	data->sample_number = 0;
    	rc = i2c_reg_read_byte(data->i2c_master, data->i2c_addr,
    		ADXL345_FIFO_STATUS_REG, &samples_count);
    	if (rc < 0) {
    		LOG_ERR("Failed to read FIFO status rc = %d\n", rc);
    		return rc;
    	}
    
    	__ASSERT_NO_MSG(samples_count <= ARRAY_SIZE(data->bufx));
    
    	for (uint8_t s = 0; s < samples_count; s++) {
    		rc = adxl345_read_sample(dev, &sample);
    		if (rc < 0) {
    			LOG_ERR("Failed to fetch sample rc=%d\n", rc);
    			return rc;
    		}
    		data->bufx[s] = sample.x;
    		data->bufy[s] = sample.y;
    		data->bufz[s] = sample.z;
    	}
    
    	return samples_count;
    }
    
    static int adxl345_channel_get(const struct device *dev,
    			       enum sensor_channel chan,
    			       struct sensor_value *val)
    {
    	struct adxl345_dev_data *data = dev->data;
    
    	if (data->sample_number >= ARRAY_SIZE(data->bufx)) {
    		data->sample_number = 0;
    	}
    
    	switch (chan) {
    	case SENSOR_CHAN_ACCEL_X:
    		adxl345_accel_convert(val, data->bufx[data->sample_number]);
    		data->sample_number++;
    		break;
    	case SENSOR_CHAN_ACCEL_Y:
    		adxl345_accel_convert(val, data->bufy[data->sample_number]);
    		data->sample_number++;
    		break;
    	case SENSOR_CHAN_ACCEL_Z:
    		adxl345_accel_convert(val, data->bufz[data->sample_number]);
    		data->sample_number++;
    		break;
    	case SENSOR_CHAN_ACCEL_XYZ:
    		adxl345_accel_convert(val++, data->bufx[data->sample_number]);
    		adxl345_accel_convert(val++, data->bufy[data->sample_number]);
    		adxl345_accel_convert(val,   data->bufz[data->sample_number]);
    		data->sample_number++;
    		break;
    	default:
    		return -ENOTSUP;
    	}
    
    	return 0;
    }
    
    static const struct sensor_driver_api adxl345_api_funcs = {
    	.sample_fetch = adxl345_sample_fetch,
    	.channel_get = adxl345_channel_get,
    };
    
    static int adxl345_init(const struct device *dev)
    {
            printf("-------------------------- Entered init --------------------");
    	int rc;
    	struct adxl345_dev_data *data = dev->data;
    	const struct adxl345_dev_config *cfg = dev->config;
    	uint8_t dev_id;
    
    	data->sample_number = 0;
    	data->i2c_master = device_get_binding(cfg->i2c_master_name);
    	data->i2c_addr = cfg->i2c_addr;
    
    	if (!data->i2c_master) {
    		LOG_ERR("Failed to get I2C master\n");
    		return -ENODEV;
    	}
            printf("I@C Address = %x \n",data->i2c_addr);
    	rc = i2c_reg_read_byte(data->i2c_master, data->i2c_addr,
    		ADXL345_DEVICE_ID_REG, &dev_id);
    	if (rc < 0 || dev_id != ADXL345_PART_ID) {
    		LOG_ERR("Read PART ID failed: 0x%x\n", rc);
    		return -ENODEV;
    	}
    
    	rc = i2c_reg_write_byte(data->i2c_master, data->i2c_addr,
    		ADXL345_FIFO_CTL_REG, ADXL345_FIFO_STREAM_MODE);
    	if (rc < 0) {
    		LOG_ERR("FIFO enable failed\n");
    		return -EIO;
    	}
    
    	rc = i2c_reg_write_byte(data->i2c_master, data->i2c_addr,
    		ADXL345_DATA_FORMAT_REG, ADXL345_RANGE_16G);
    	if (rc < 0) {
    		LOG_ERR("Data format set failed\n");
    		return -EIO;
    	}
    
    	rc = i2c_reg_write_byte(data->i2c_master, data->i2c_addr,
    		ADXL345_RATE_REG, ADXL345_RATE_25HZ);
    	if (rc < 0) {
    		LOG_ERR("Rate setting failed\n");
    		return -EIO;
    	}
    
    	rc = i2c_reg_write_byte(data->i2c_master, data->i2c_addr,
    		ADXL345_POWER_CTL_REG, ADXL345_ENABLE_MEASURE_BIT);
    	if (rc < 0) {
    		LOG_ERR("Enable measure bit failed\n");
    		return -EIO;
    	}
    
    	return 0;
    }
    
    static struct adxl345_dev_data adxl345_data;
    static const struct adxl345_dev_config adxl345_config = {
    #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
    	.i2c_master_name = DT_INST_BUS_LABEL(0),
    	.i2c_addr = 0x53,
    #else
    #error "BUS MACRO NOT DEFINED IN DTS"
    #endif
    
    };
    DEVICE_AND_API_INIT(adxl345, DT_INST_LABEL(0), adxl345_init,
    		    &adxl345_data, &adxl345_config, POST_KERNEL,
    		    CONFIG_SENSOR_INIT_PRIORITY, &adxl345_api_funcs);
    

    Drivers->adxl345->Kconfig

    # ADXL345, 3-Axis, +/-16g Digital Accelerometer
    
    # Copyright (c) 2020 Antmicro <www.antmicro.com>
    # SPDX-License-Identifier: Apache-2.0
    config ADXL345
    	bool "ADXL345 Three Axis I2C accelerometer"
    	depends on I2C
    	help
    	  Enable driver for ADXL345 Three-Axis Digital Accelerometer.
    

    2. ncs->nrf->samples->bluetooth->mesh->adxl345->

    nrf52840dk_nrf52840.overlay overlay file:

    /*
     * Copyright (c) 2020, Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    &i2c0 {
    	compatible = "nordic,nrf-twim";
    	status = "okay";
    	sda-pin = <17>;
    	scl-pin = <13>;
    	clock-frequency = <I2C_BITRATE_FAST>;
    	adxl345@53 {
    		compatible = "adi,adxl345";
    		label = "ADXL345";
    		reg = <0x53>;
    		status = "okay";
    	};
    };
    
    
    

    # Copyright (c) 2019 Brett Witherspoon
    #
    # SPDX-License-Identifier: Apache-2.0
    
    cmake_minimum_required(VERSION 3.13.1)
    
    find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
    project(adxl345)
    
    target_sources(app PRIVATE src/main.c)
    

    sample.yaml

    sample:
      name: adxl345 sample
      description: ADXL345 accelerometer sample application
    tests:
      sample.sensor.adxl345:
        harness: sensor
        tags: sensors
        depends_on: i2c
        platform_allow: nrf52840dk_nrf52840
    

    Proj.conf

    CONFIG_STDOUT_CONSOLE=y
    CONFIG_I2C=y
    CONFIG_SENSOR=y
    CONFIG_ADXL345=y
    
    CONFIG_USE_SEGGER_RTT=y
    CONFIG_RTT_CONSOLE=y
    CONFIG_LOG_BACKEND_UART=y
    CONFIG_SERIAL=y
    CONFIG_UART_CONSOLE=n
    CONFIG_PRINTK=y
    CONFIG_CONSOLE=y
    
    
    

    main.c

    /*
     * Copyright (c) 2019 Brett Witherspoon
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr.h>
    #include <stdio.h>
    #include <device.h>
    #include <drivers/sensor.h>
    #include <drivers/gpio.h>
    #include <drivers/i2c.h>
    K_SEM_DEFINE(sem, 0, 1);
    #define adxl_sdo 20
    #define adxl_cs  15
    static void trigger_handler(const struct device *dev,
    			    struct sensor_trigger *trig)
    {
    	switch (trig->type) {
    	case SENSOR_TRIG_DATA_READY:
    		if (sensor_sample_fetch(dev) < 0) {
    			printf("Sample fetch error\n");
    			return;
    		}
    		k_sem_give(&sem);
    		break;
    	case SENSOR_TRIG_THRESHOLD:
    		printf("Threshold trigger\n");
    		break;
    	default:
    		printf("Unknown trigger\n");
    	}
    }
    const struct device *gpio_dev;
    void i2c_init(){
      gpio_pin_configure(gpio_dev,adxl_sdo,GPIO_PULL_DOWN);
      gpio_pin_configure(gpio_dev,adxl_cs,GPIO_PULL_DOWN);
      gpio_pin_set(gpio_dev,adxl_sdo,0);
      gpio_pin_set(gpio_dev,adxl_cs,1);
    
    }
    void main(void)
    {
    	struct sensor_value accel[3];
            if(DT_NODE_HAS_STATUS(ADXL345,okay)){
            printf("Device found\n");
            }
    	const struct device *dev = device_get_binding(DT_LABEL(DT_INST(0, adi_adxl345)));
    	if (dev == NULL) {
    		printf("Device get binding device\n");
    		return;
    	}
    
    	while (true) {
    
    			if (sensor_sample_fetch(dev) < 0) {
    				printf("Sample fetch error\n");
    				return;
    			}
    
    
    		if (sensor_channel_get(dev, SENSOR_CHAN_ACCEL_X, &accel[0]) < 0) {
    			printf("Channel get error\n");
    			return;
    		}
    
    		if (sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Y, &accel[1]) < 0) {
    			printf("Channel get error\n");
    			return;
    		}
    
    		if (sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Z, &accel[2]) < 0) {
    			printf("Channel get error\n");
    			return;
    		}
    
    		printf("x: %.1f, y: %.1f, z: %.1f (m/s^2)\n",
    		       sensor_value_to_double(&accel[0]),
    		       sensor_value_to_double(&accel[1]),
    		       sensor_value_to_double(&accel[2]));
    	}
    }
    

    Above is my project configuration files.

    I am trying to read ADXL345 accelerometer value from NRF52840 custom board. The device is not getting detected. Similar configuration I have used for BMI160 with NRF52840 development kit but there also device binding is NULL.

    Please help me find the missing modifications for getting the sensor working.

  • Also, how to configure any GPIO PIN as INPUT or OUTPUT with Zephyr.

    device_get_bindig('GPIO_0') is successful, but gpio_pin_configure(dev,20,GPIO_OUTPUT_ACTIVE/GPIO_OUTPUT_LOW/GPIO_OUTPUT) and gpio_pin_set(dev,20,1) is not working.

    I am trying to set pin number 20 in NRF52840. But it is not working. I am unable to find any suitable example to fix this issue. Please help out.

  • For a start, you can try changing i2c0 to either i2c1 or i2c2. There are conflicting memory addresses between i2c0 and uart0, so you should use a different i2c peripheral instance.

  • I am using NRF52840- zephyr (i2c_burst_read) and BMP388 sensor using I2C. I am successfully able to setup register enabling required feature and able to read the sensor data from I2C. However, the data read from data register doesn't change. The hexadecimal value read from arduino with same sensor board is completely different from that read in nrf52840 over i2c. Please help me know if I am missing ay fundamental understanding reading data value over i2c. I am reading register 0x04 with Length 6. Arduino reads the same address with length 6 and gets different value from register and it is changing but nrf52840 gets different value and unchanging. (I have used i2c1 in board overlay)

Related