How to add i2c sensor driver correctly on nrf connect SDK?

Hi,

I'm trying to move project from nrf52 SDK to new NCS.

I'm using custom board with nrf52832. There're some problems when working on i2c communication with LSM6DSL.

The project I'm testing is copied from "ncs\v2.5.1\zephyr\samples\sensor\lsm6dsl", so the main code and prj.conf are all same as usual.

When I build and run the code to my board, just showed "sensor: device not ready."

Here are my other files currently, please help me to fix with it

for .dtsi file:

/*
 * Copyright (c) 2022 Nordic Semiconductor
 * SPDX-License-Identifier: Apache-2.0
 */

 &pinctrl {
	uart0_default: uart0_default {
		group1 {
			psels = <NRF_PSEL(UART_TX, 0, 6)>,
				<NRF_PSEL(UART_RX, 0, 8)>,
				<NRF_PSEL(UART_RTS, 0, 9)>,
				<NRF_PSEL(UART_CTS, 0, 7)>;
		};
	};

	uart0_sleep: uart0_sleep {
		group1 {
			psels = <NRF_PSEL(UART_TX, 0, 6)>,
				<NRF_PSEL(UART_RX, 0, 8)>,
				<NRF_PSEL(UART_RTS, 0, 9)>,
				<NRF_PSEL(UART_CTS, 0, 7)>;
			low-power-enable;
		};
	};

	i2c0_default: i2c0_default {
		group1 {
			psels = <NRF_PSEL(TWIM_SDA, 0, 11)>,
				<NRF_PSEL(TWIM_SCL, 0, 12)>;
			// bias-pull-up;
		};
	};

	i2c0_sleep: i2c0_sleep {
		group1 {
			psels = <NRF_PSEL(TWIM_SDA, 0, 11)>,
				<NRF_PSEL(TWIM_SCL, 0, 12)>;
			low-power-enable;
		};
	};

    pwm0_default: pwm0_default {
		group1 {
			psels = <NRF_PSEL(PWM_OUT0, 0, 3)>,
                <NRF_PSEL(PWM_OUT1, 0, 4)>,
                <NRF_PSEL(PWM_OUT2, 0, 5)>;
			nordic,invert;
		};
	};

	pwm0_sleep: pwm0_sleep {
		group1 {
			psels = <NRF_PSEL(PWM_OUT0, 0, 3)>,
                <NRF_PSEL(PWM_OUT1, 0, 4)>,
                <NRF_PSEL(PWM_OUT2, 0, 5)>;
			low-power-enable;
		};
	};

};

for dts file:

// Copyright (c) 2024 Nordic Semiconductor ASA
// SPDX-License-Identifier: Apache-2.0

/dts-v1/;
#include <nordic/nrf52832_qfaa.dtsi>
#include "custom_nrf52832-pinctrl.dtsi"

/ {
	model = "custom_nrf52832";
	compatible = "private,custom-nrf52832";

	chosen {
		zephyr,sram = &sram0;
		zephyr,flash = &flash0;
		zephyr,code-partition = &slot0_partition;
		zephyr,console = &uart0;
		zephyr,shell-uart = &uart0;
		zephyr,uart-mcumgr = &uart0;
	};

	leds {
		compatible = "gpio-leds";
		ledR: led_0 {
			gpios = <&gpio0 3 (GPIO_ACTIVE_LOW)>;
			label = "Red led R";
		};
		ledG: led_1 {
			gpios = <&gpio0 4 (GPIO_ACTIVE_LOW)>;
			label = "Green led G";
		};
		ledB: led_2 {
			gpios = <&gpio0 5 (GPIO_ACTIVE_LOW)>;
			label = "Blue led B";
		};
	};

	buttons {
		compatible = "gpio-keys";
		buttonC: button_0 {
			gpios = <&gpio0 27 0>;
			label = "Push button switch 0";
		};
	};

	pwmleds {
		compatible = "pwm-leds";
		pwm_ledR: pwm_led_0 {
			pwms = <&pwm0 0 PWM_MSEC(1) PWM_POLARITY_NORMAL>;
			label = "pwm led R";
		};
		pwm_ledG: pwm_led_1 {
			pwms = <&pwm0 1 PWM_MSEC(1) PWM_POLARITY_NORMAL>;
			label = "pwm led G";
		};
		pwm_ledB: pwm_led_2 {
			pwms = <&pwm0 2 PWM_MSEC(1) PWM_POLARITY_NORMAL>;
			label = "pwm led B";
		};
	};

	/* These aliases are provided for compatibility with samples */
	aliases {
		led0 = &ledR;
		led1 = &ledG;
		led2 = &ledB;
		pwm-led0 = &pwm_ledR;
		pwm-led1 = &pwm_ledG;
		pwm-led2 = &pwm_ledB;
		sw0 = &buttonC;
		bootloader-led0 = &ledR;
		mcuboot-button0 = &buttonC;
		mcuboot-led0 = &ledR;
		watchdog0 = &wdt0;
	};
};

&flash0 {
	partitions {
		compatible = "fixed-partitions";
		#address-cells = <1>;
		#size-cells = <1>;

		boot_partition: partition@0 {
			label = "mcuboot";
			reg = <0x0 0xc000>;
		};
		slot0_partition: partition@c000 {
			label = "image-0";
			reg = <0xc000 0x32000>;
		};
		slot1_partition: partition@3e000 {
			label = "image-1";
			reg = <0x3e000 0x32000>;
		};
		scratch_partition: partition@70000 {
			label = "image-scratch";
			reg = <0x70000 0xa000>;
		};
		storage_partition: partition@7a000 {
			label = "storage";
			reg = <0x7a000 0x6000>;
		};
	};
};


&gpio0 {
	status = "okay";
};

&gpiote {
	status = "okay";
};

&uart0 {
	status = "okay";
	current-speed = <115200>;
	pinctrl-0 = <&uart0_default>;
	pinctrl-1 = <&uart0_sleep>;
	pinctrl-names = "default", "sleep";
};

&i2c0 {
	status = "okay";
	pinctrl-0 = <&i2c0_default>;
	pinctrl-1 = <&i2c0_sleep>;
	pinctrl-names = "default", "sleep";
	lsm6dsl@6a {
		compatible = "st,lsm6dsl";
		reg = <0x6a>;
		label = "GSENSOR";
	};
};

&pwm0 {
	status = "okay";
	pinctrl-0 = <&pwm0_default>;
	pinctrl-1 = <&pwm0_sleep>;
	pinctrl-names = "default", "sleep";
};

for board_defconfig:

# Copyright (c) 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

CONFIG_SOC_SERIES_NRF52X=y
CONFIG_SOC_NRF52832_QFAA=y
CONFIG_BOARD_CUSTOM_NRF52832=y

# Enable MPU
CONFIG_ARM_MPU=y

# Enable hardware stack protection
CONFIG_HW_STACK_PROTECTION=y

# Enable RTT
CONFIG_USE_SEGGER_RTT=y

# enable GPIO
CONFIG_GPIO=y

# enable uart driver
CONFIG_SERIAL=y

# enable console
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=n
CONFIG_RTT_CONSOLE=y

CONFIG_PINCTRL=y

  • Good to know that you are able to initializing the sensor now and be to get the device node pointer in the applicaiton. 

    ekidsalan123 said:
    but I can't correctly set the sensor, could you help with that?

    You need to be a bit more descriptive than can't correct set the sensor. 

    -Which API are you using to set the sensor?

    - What error are you getting?

    - Have you seen any activity on the I2C pins? Did you use any logic analyzer or oscillscope to see any activity on the I2C pins?

  • Hello,

    Good news is that I'm able to get data from my sensor. It works in simple main.c like this:

    /*
     * Copyright (c) 2018 STMicroelectronics
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/sensor.h>
    #include <stdio.h>
    #include <zephyr/sys/util.h>
    #include <zephyr/drivers/i2c.h>
    #include "lsm6dsl_reg.h"
    #include "Gsensor.h"
    
    int main()
    {
    	lsm6dsl_init();
    
    	int32_t get_x, get_y, get_z, get_a, get_b, get_c;
    
    	int ret;
    
    	if (!gpio_is_ready_dt(&lsm6dsl_int1)) {
    		printk("Error: lsm6dsl_int1 device %s is not ready\n",
    		       lsm6dsl_int1.port->name);
    		return 0;
    	}
    
    	ret = gpio_pin_configure_dt(&lsm6dsl_int1, GPIO_INPUT);
    	if (ret != 0) {
    		printk("Error %d: failed to configure %s pin %d\n",
    		       ret, lsm6dsl_int1.port->name, lsm6dsl_int1.pin);
    		return 0;
    	}
    
    	ret = gpio_pin_interrupt_configure_dt(&lsm6dsl_int1,
    					      GPIO_INT_EDGE_TO_ACTIVE);
    	if (ret != 0) {
    		printk("Error %d: failed to configure interrupt on %s pin %d\n",
    			ret, lsm6dsl_int1.port->name, lsm6dsl_int1.pin);
    		return 0;
    	}
    
    	gpio_init_callback(&int1_cb_data, lsm6dsl_int1_handler, BIT(lsm6dsl_int1.pin));
    	gpio_add_callback(lsm6dsl_int1.port, &int1_cb_data);
    	printk("Set up lsm6dsl_int1 at %s pin %d\n", lsm6dsl_int1.port->name, lsm6dsl_int1.pin);
    
    
    
    	while(1)
    	{
    		k_msleep(1000);
    		lsm6dsl_get_6d_value(&get_x, &get_y, &get_z, &get_a, &get_b, &get_c);
    	}
    	return 0;
    }
     

    I'm using API from ST, the following code is about sensor initial.

    Something in Gsensor.c:

    int32_t LSM6DSL_Write_Byte(uint8_t LSM6DSL_reg, uint8_t value)
    {
    	int ret;
    	uint8_t config[2] = {LSM6DSL_reg, value};
    	ret = i2c_write_dt(&dev_LSM6DSL, config, sizeof(config));
    	return ret;
    }
    
    uint8_t LSM6DSL_ReadOneByte(uint8_t LSM6DSL_reg)
    {
    	int ret;
    	uint8_t readback_reg[1] = {0};
    	uint8_t sensor_regs[1] = {LSM6DSL_reg};
    	ret = i2c_write_read_dt(&dev_LSM6DSL, &sensor_regs[0], 1, &readback_reg[0], 1);
    	return readback_reg[0];
    }
    
    int LSM6DSL_ReadNumBytes(uint8_t LSM6DSL_reg, uint8_t * DataBuf, uint8_t number)
    {
    	int ret;
    	ret = i2c_burst_read_dt(&dev_LSM6DSL, LSM6DSL_reg, DataBuf, number);
    	return ret;
    }
    
    int32_t readReg4Lsm6dsl(void* handle, uint8_t reg, uint8_t * data, uint16_t len)
    {
        return LSM6DSL_ReadNumBytes(reg, data, len);
    }
    
    int32_t writeReg4Lsm6dsl(void* handle, uint8_t reg, uint8_t * data, uint16_t len)
    {
        return LSM6DSL_Write_Byte(reg, data[0]);
    }
    
    void wakeup_init()
    {
        lsm6dsl_wkup_dur_set(&dev_ctx, 0);
        lsm6dsl_wkup_threshold_set(&dev_ctx, 0x09);
    
        lsm6dsl_xl_hp_path_internal_set(&dev_ctx, LSM6DSL_USE_HPF);
        
        lsm6dsl_int1_route_t int_1_reg;
        lsm6dsl_pin_int1_route_get(&dev_ctx, &int_1_reg);
    
        int_1_reg.int1_wu = PROPERTY_ENABLE;
        lsm6dsl_pin_int1_route_set(&dev_ctx, int_1_reg);
        
        lsm6dsl_int2_route_t int_2_reg;
        lsm6dsl_pin_int2_route_get(&dev_ctx, &int_2_reg);
    
        int_2_reg.int2_wu = PROPERTY_ENABLE;
        lsm6dsl_pin_int2_route_set(&dev_ctx, int_2_reg); 
    }
    
    void lsm6dsl_init()
    {
        if(!device_is_ready(dev_LSM6DSL.bus))
        {
            printk("I2C bus %s is not ready!\n\r", dev_LSM6DSL.bus->name);
        }
    
        uint8_t WhoAmI = 0xff;
        uint8_t rst = 0xff;
    
        // LSM6DSL driver init
        dev_ctx.write_reg   = writeReg4Lsm6dsl;
        dev_ctx.read_reg    = readReg4Lsm6dsl;
        dev_ctx.handle      = &dev_LSM6DSL;
    
        lsm6dsl_device_id_get(&dev_ctx, &WhoAmI);
        printk("-------------------- whoamI. %x\n", WhoAmI);
    
        lsm6dsl_reset_set(&dev_ctx, PROPERTY_ENABLE);
        do
        {
            lsm6dsl_reset_get(&dev_ctx, &rst);
        }
        while (rst);
        printk("-------------------- rst. %x\n", rst);
    
        //lsm6dsl_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);
        //lsm6dsl_fifo_mode_set(&dev_ctx, LSM6DSL_STREAM_MODE);
    
        lsm6dsl_xl_data_rate_set(&dev_ctx, LSM6DSL_XL_ODR_416Hz);
        lsm6dsl_gy_data_rate_set(&dev_ctx, LSM6DSL_GY_ODR_416Hz);
    
        lsm6dsl_xl_full_scale_set(&dev_ctx, LSM6DSL_2g);
        lsm6dsl_gy_full_scale_set(&dev_ctx, LSM6DSL_2000dps);
    
        //Filter
        //lsm6dsl_xl_filter_analog_set(&dev_ctx, LSM6DSL_XL_ANA_BW_400Hz);
        // lsm6dsl_xl_lp1_bandwidth_set(&dev_ctx, LSM6DSL_XL_LP1_ODR_DIV_4);
        lsm6dsl_xl_lp2_bandwidth_set(&dev_ctx, LSM6DSL_XL_LOW_NOISE_LP_ODR_DIV_400);  //low pass filter for acc
        lsm6dsl_gy_band_pass_set(&dev_ctx, LSM6DSL_HP_DISABLE_LP1_AGGRESSIVE);
    
        wakeup_init();
    }

    But there's still another problems. I want to add this LSM6DSL I2C driver code to NRF Connect SDK's  BLE Peripheral UART sample code.

    I had added these code to prj.conf:

    CONFIG_STDOUT_CONSOLE=y
    CONFIG_I2C=y
    # CONFIG_SPI=y
    CONFIG_SENSOR=y
    CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y
    CONFIG_CBPRINTF_FP_SUPPORT=y

    If I add lsm6dsl_init(); to main.c like following, it won't work and the log shows as below:

    Any idea about what I'm missing when porting the code? 

    log

    Process: JLink.exe
    [00:00:00.044,067] <err> LSM6DSL: GPIO device not ready
    [00:00:00.044,128] <err> LSM6DSL: Failed to initialize interrupt.
    *** Booting nRF Connect SDK v2.5.1 ***
    [00:00:22.628,692] <inf> fs_nvs: 6 Sectors of 4096 bytes
    [00:00:22.628,784] <inf> fs_nvs: alloc wra: 0, fd0
    [00:00:22.628,784] <inf> fs_nvs: data wra: 0, 1c
    [00:00:22.629,180] <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
                                                c5 93 ba a9 14 4d 8d 05  30 4e 9b 92 d7 71 1e e8 |.....M.. 0N...q..
                                                aa 02 50 3c                                      |..P<             
    [00:00:22.636,260] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
    [00:00:22.636,291] <inf> bt_hci_core: HW Variant: nRF52x (0x0002)
    [00:00:22.636,383] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 197.47763 Build 2370639017
    [00:00:22.637,115] <inf> bt_hci_core: No ID address. App must call settings_load()
    [00:00:22.637,145] <inf> peripheral_uart: Bluetooth initialized
    [00:00:22.638,671] <inf> bt_hci_core: Identity: FF:98:1B:A5:7C:BE (random)
    [00:00:22.638,763] <inf> bt_hci_core: HCI: version 5.4 (0x0d) revision 0x1102, manufacturer 0x0059
    [00:00:22.638,793] <inf> bt_hci_core: LMP: version 5.4 (0x0d) subver 0x1102

  • It might be something missing in your dts or overlay file. This LSM6DSL sensor has been discussed a lot in this forum and successfully being used with NCS. Have you searched in the forum to find some threads like this that discuss this? The thing is we do not have that sensor with us, so it is hard for us to test your code.

Related