SHT4x interface with nRF52840

Hi,

I am trying to integrate Sensirion SHT40 sensor with nRF52840. I am using the sensor sample app from 2.9.0 SDK. I am building with 2.6.1 SDK with toolchain 2.6.1.  The build is ok, but when the app starts, it just get stuck as I can see in the console as follows.

[00:00:00.003,143] <inf> ieee802154_nrf5: nRF5 802154 radio initialized
[00:00:00.003,173] <dbg> temp_nrf5_mpsl: temp_nrf5_mpsl_init:
[00:00:00.009,490] <inf> fs_nvs: 8 Sectors of 4096 bytes
[00:00:00.

Then I added CONFIG_COAP_CLIENT=y to prj.conf and I get the following.

[00:00:00.[00:00[00:00:00.003,326] <dbg> temp_nrf5_mpsl: temp_nrf5_mpsl_init:
[00:00:00.009,643] <inf> fs_nvs: 8 Sectors of 4096 bytes
[00:00:00.009,643] <inf> fs_nvs: alloc wra: 0, e00
[00:00:00.009,674] <inf> fs_nvs: data wra: 0, 810
*** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
ASSERTION FAIL @ WEST_TOPDIR/zephyr/kernel/thread.c:601
        invalid priority (15); allowed range: 14 to -16
[00:00:00.038,909] <dbg> temp_nrf5_mpsl: temp_nrf5_mpsl_sample_fetch: sample: 96
[00:00:00.038,940] <dbg> temp_nrf5_mpsl: temp_nrf5_mpsl_channel_get: Temperature:24,0
[00:00:00.039,031] <err> os: r0/a1:  0x00000004  r1/a2:  0x00000259  r2/a3:  0x00000009
[00:00:00.039,062] <err> os: r3/a4:  0x20001a40 r12/ip:  0x00000014 r14/lr:  0x00022321
[00:00:00.039,062] <err> os:  xpsr:  0x41000000
[00:00:00.039,093] <err> os: s[ 0]:  0x00000001  s[ 1]:  0x20003f10  s[ 2]:  0x20002bf8  s[ 3]:  0x0003b379
[00:00:00.039,093] <err> os: s[ 4]:  0x00000000  s[ 5]:  0x00000000  s[ 6]:  0x000539d0  s[ 7]:  0x20015744
[00:00:00.039,123] <err> os: s[ 8]:  0x20002bf8  s[ 9]:  0x0003ac5d  s[10]:  0x000539d0  s[11]:  0x20015744
[00:00:00.039,154] <err> os: s[12]:  0x0000000e  s[13]:  0x00022317  s[14]:  0x000539d0  s[15]:  0x0000000f
[00:00:00.039,154] <err> os: fpscr:  0x0000000e
[00:00:00.039,154] <err> os: Faulting instruction address (r15/pc): 0x0003ac4a
[00:00:00.039,215] <err> os: >>> ZEPHYR FATAL ERROR 4: Kernel panic on CPU 0
[00:00:00.039,245] <err> os: Current thread: 0x20003f10 (main)

I have attached my prj.conf and overlay file.

87304.prj.conf

6366.nrf52840dk_nrf52840.overlay

I haven't modified any thread priority. I tried searching for where this priorities are assigned, but couldn't find that either.

Please help.

Cheers,

Kaushalya

Parents
  • Hello Kaushalya,

    The log shows you are reading the temperature from the nRF52's TEMP peripheral, not the external sht40 sensor. Maybe you selected the wrong sensor device in your app?

    Regarding the assertion, it appears to be raised for the main thread if I'm the crash log correctly, but I don't see why this would happen when enabling the CONFIG_COAP_CLIENT symbol. Please check the generated configuration file (.config) for your application located in the build directory and check if the CONFIG_MAIN_THREAD_PRIORITY is set to '0' in both cases.

    Cheers,

    Vidar

  • Hi Vidar,

    Many thanks for lookin into this. 

    Thats interesting observation that I am using Temp peripheral. How do we enable Temp peripheral? 

    What I have done in my case is

    1. Enable Sensirion SHT4x node under I2C node in the device tree as follows. 

     

    &pinctrl {
    	i2c0_default: i2c0_default {
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA, 1, 15)>,
    				<NRF_PSEL(TWIM_SCL, 1, 13)>;
    		};
    	};
    
    	i2c0_sleep: i2c0_sleep {
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA, 1, 15)>,
    				<NRF_PSEL(TWIM_SCL, 1, 13)>;
    			low-power-enable;
    		};
    	};
    };
    
    &i2c0 {
    	status = "okay";
    	clock-frequency = <I2C_BITRATE_FAST>;
    	sht4x@44 {
    		status = "okay";
    		compatible = "sensirion,sht4x";
    		reg = <0x44>;
    		repeatability = <2>;
    	};
    };

    2. Access it from coap_client.c as follows.

    const struct device *const sht = DEVICE_DT_GET_ANY(sensirion_sht4x);
    struct sensor_value temp, hum;
    
    #if !DT_HAS_COMPAT_STATUS_OKAY(sensirion_sht4x)		// Feature 17
    #error "No sensirion,sgp40 compatible node found in the device tree"
    #endif
    .
    .
    void ADCscan () {
    	if (sensor_sample_fetch(sht)) {
    		LOG_INF("Failed to fetch sample from SHT4X device\n");
    		return;
    	}
    	sensor_channel_get(sht, SENSOR_CHAN_AMBIENT_TEMP, &temp);
    	sensor_channel_get(sht, SENSOR_CHAN_HUMIDITY, &hum);
    
    	LOG_INF("SHT4X: %.2f Temp. [C] ; %0.2f RH [%%]",
    		sensor_value_to_float(&temp),
    		sensor_value_to_float(&hum));
     
        .
        .
    }
    
    int main () {
    	if (!device_is_ready(sht)) {
    		LOG_INF("Device %s is not ready.\n", sht->name);
    		return 0;
    	}
    	ADCscan ();
    	.
    	.
    }

    Is there anything you see I have not done correctly here for getting data from SHT40? I get both temperature and humidity readings in my case and both values seems to change with environmental conditions. Furthermore I can see the I2C signals on bus as well. So seems like the data is originating from the SGT40 sensor.

     CONFIG_MAIN_THREAD_PRIORITY is set to '0' in both cases.

    I checked that in both cases of CONFIG_COAP_CLIENT, the CONFIG_MAIN_THREAD_PRIORITY  is 0, but when CONFIG_COAP_CLIENT is enabled it crashes as before.

    This is my .config file.

    5734..config.zip

  • Strangely enough, when I restarted my computer, the above SGP40 issue disappeared !! Now I can kconfig and see the SGP40 driver enable is active.

    Now I get the following errors when try to fetch data from SGP40.

    [00:00:00.003,173] <inf> ieee802154_nrf5: nRF5 802154 radio initialized
    [00:00:00.003,204] <dbg> temp_nrf5_mpsl: temp_nrf5_mpsl_init:
    
    
    [00:00:00.253,540] <err> SGP40: Failed to read data sample.
    [00:00:00.253,601] <err> SGP40: Selftest failed!
    [00:00:00.260,437] <inf> fs_nvs: 8 Sectors of 4096 bytes
    [00:00:00.260,467] <inf> fs_nvs: alloc wra: 0, e98
    [00:00:00.260,467] <inf> fs_nvs: data wra: 0, 550
    *** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
    [00:00:00.281,524] <dbg> temp_nrf5_mpsl: temp_nrf5_mpsl_sample_fetch: sample: 115
    [00:00:00.281,555] <dbg> temp_nrf5_mpsl: temp_nrf5_mpsl_channel_get: Temperature:28,750000
    [00:00:00.281,677] <err> coap_client: Device sgp40@59 is not ready.
    

    My code snippet is like this.

    .
    .
    static void ADCscan_fn () {
    
    int16_t temp16, hum16;
    
    	// 17. SHT40 functionality
    	if (sensor_sample_fetch(sht)) {
    		LOG_INF("Failed to fetch sample from SHT4X device\n");
    		return;
    	}
    
    	sensor_channel_get(sht, SENSOR_CHAN_AMBIENT_TEMP, &temp);
    	sensor_channel_get(sht, SENSOR_CHAN_HUMIDITY, &hum);
    
    #if CONFIG_APP_USE_HEATER
    	struct sensor_value heater_p;
    	struct sensor_value heater_d;
    
    	heater_p.val1 = CONFIG_APP_HEATER_PULSE_POWER;
    	heater_d.val1 = CONFIG_APP_HEATER_PULSE_DURATION;
    	sensor_attr_set(sht, SENSOR_CHAN_ALL,
    			SENSOR_ATTR_SHT4X_HEATER_POWER, &heater_p);
    	sensor_attr_set(sht, SENSOR_CHAN_ALL,
    			SENSOR_ATTR_SHT4X_HEATER_DURATION, &heater_d);
    #endif
    
    	LOG_INF("SHT4X: %.2f Temp. [C] ; %0.2f RH [%%]", sensor_value_to_float(&temp), sensor_value_to_float(&hum));
    
    	#if CONFIG_APP_USE_HEATER
    	/*
    	 * Conditions in which it makes sense to activate the heater
    	 * are application/environment specific.
    	 *
    	 * The heater should not be used above SHT4X_HEATER_MAX_TEMP (65 °C)
    	 * as stated in the datasheet.
    	 *
    	 * The temperature data will not be updated here for obvious reasons.
    	 **/
    	if (hum.val1 > CONFIG_APP_HEATER_HUMIDITY_THRESH &&
    			temp.val1 < SHT4X_HEATER_MAX_TEMP) {
    		printf("Activating heater.\n");
    
    		if (sht4x_fetch_with_heater(sht)) {
    			printf("Failed to fetch sample from SHT4X device\n");
    			return 0;
    		}
    
    		sensor_channel_get(sht, SENSOR_CHAN_HUMIDITY, &hum);
    	}
    #endif
    
    #if CONFIG_APP_USE_COMPENSATION
    		comp_t.val1 = temp.val1; /* Temp [°C] */
    		comp_rh.val1 = hum.val1; /* RH [%] */
    		sensor_attr_set(sgp,
    				SENSOR_CHAN_GAS_RES,
    				SENSOR_ATTR_SGP40_TEMPERATURE,
    				&comp_t);
    		sensor_attr_set(sgp,
    				SENSOR_CHAN_GAS_RES,
    				SENSOR_ATTR_SGP40_HUMIDITY,
    				&comp_rh);
    #endif
    
    	if (sensor_sample_fetch(sgp)) {
    		LOG_INF("Failed to fetch sample from SGP40 device.\n");
    		return;
    	}
    
    	sensor_channel_get(sgp, SENSOR_CHAN_GAS_RES, &aq);
    	LOG_INF("SGP40: %d Gas [a.u.]\n", aq.val1);
    	// -----------------------
    
        .
        .
    	k_work_schedule (&ADC_scan_work, K_MSEC(30000));	// schedule for next cycle
    }
    
    .
    .
    int main(void)
    {
    	int ret;
    
    	if (!device_is_ready(sht)) {
    		LOG_ERR("Device %s is not ready.\n", sht->name);
    		return 0;
    	}
    	if (!device_is_ready(sgp)) {
    		LOG_ERR("Device %s is not ready.\n", sgp->name);
    		return 0;
    	}
    	k_work_schedule (&ADC_scan_work, K_NO_WAIT);	// just to test Sensiron SHT40/SGP40
        .
        .
    }
    

    1. From the console it seems a SGP40 read cycle and a self test has happened before checking device ready. But device read status check happens first thing in the main (). I tried debugging into it and also fount that device ready status check happened first and then main () returns as a fail of that. 

    2. Why is "device_is_ready(sgp)" fails?

    Cheers,

    Kaushalya

  • Strangely enough, when I restarted my computer, the above SGP40 issue disappeared !! Now I can kconfig and see the SGP40 driver enable is active.

    I am now continuing the rest of the tests.

    Cheers,

    Kaushalya

  • ok now I can see the self test command correctly send to SGP40 using a logic analyzer. But the read of the result seems to fail with return code -5.

    Any idea?

  • -5 translates to -EIO. Since this happens while you're attempting to read from the sensor, I suspect the sensor is responding with a NACK.

    I haven't worked with this sensor before, but I had a look at the datasheet and the driver implementation, and I'm wondering if the delay between writing the test command and reading back the result is sufficient. Section 3.3 of the datasheet says it should be 320 ms, but it is 250 ms in the code: https://github.com/zephyrproject-rtos/zephyr/commit/0d7cb32c58dce7396315c7c6fb7f67749e5ee1b3#diff-0b4f8ce909416f09b98d94dafd9f360d5243bfa41a913d8eba3ce394ca2cb143R21 

    Could you try to increase this delay and see if it helps?

  • ok managed to solve it by increasing the SGP40 test wait time from 250mS to 400mS. But this is not a good way of solving this as I am modifying the files in the SDK. I cant think of any way to do it in my code as this initialization is happening even before my code is executed.

    I can see from SGP40 datasheet Figure 9 shows that the wait from send self test command to read the result should be 320mS, but the 'SGP40_TEST_WAIT_MS' is 250mS. This explains why it works when I increase this time to 400mS. If this is correct, probably this is a bug in the driver code timing definitions.

    Any thoughts?

Reply
  • ok managed to solve it by increasing the SGP40 test wait time from 250mS to 400mS. But this is not a good way of solving this as I am modifying the files in the SDK. I cant think of any way to do it in my code as this initialization is happening even before my code is executed.

    I can see from SGP40 datasheet Figure 9 shows that the wait from send self test command to read the result should be 320mS, but the 'SGP40_TEST_WAIT_MS' is 250mS. This explains why it works when I increase this time to 400mS. If this is correct, probably this is a bug in the driver code timing definitions.

    Any thoughts?

Children
  • I'm not sure if you saw my previous comment. Anyway, this does appear to be an obvious bug. If you want, you can submit a PR to Zephyr to fix the delay. 

    Is self-testing something you want to be performed on every boot? The datasheet suggests using during production tests. If not, you can remove the  enable-selftest; property from the node in your DT and reduce the startup time of your app.

Related