Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Restart after system off if the sensor driver is not suspended (Zephyr OS)

Hello, 

I'm working with LIS3DH sensor and I want to wakeup nRF52832 from system off by an interrupt from the sensor (not added the interrupt configuration yet). I'm using Zephyr OS v3.1.99 on a nRF52 DK, and I've merged two examples : nRF5x System Off demo and LIS2DH: Motion Sensor Monitor. The problem is, whenever I put the chip in system off mode, It will reset immediately, but if I suspend the sensor driver using pm_device_action_run(), it won't reset anymore. I don't know what's going on, can someone explain the reason?

This is the main.c :

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

#include <stdio.h>
#include <zephyr/zephyr.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/pm/pm.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/policy.h>
#include <hal/nrf_gpio.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/init.h>

static void fetch_and_display(const struct device *sensor)
{
	static unsigned int count;
	struct sensor_value accel[3];
	struct sensor_value temperature;
	const char *overrun = "";
	int rc = sensor_sample_fetch(sensor);

	++count;
	if (rc == -EBADMSG) {
		/* Sample overrun.  Ignore in polled mode. */
		if (IS_ENABLED(CONFIG_LIS2DH_TRIGGER)) {
			overrun = "[OVERRUN] ";
		}
		rc = 0;
	}
	if (rc == 0) {
		rc = sensor_channel_get(sensor,
					SENSOR_CHAN_ACCEL_XYZ,
					accel);
	}
	if (rc < 0) {
		printf("ERROR: Update failed: %d\n", rc);
	} else {
		printf("#%u @ %u ms: %sx %f , y %f , z %f",
		       count, k_uptime_get_32(), overrun,
		       sensor_value_to_double(&accel[0]),
		       sensor_value_to_double(&accel[1]),
		       sensor_value_to_double(&accel[2]));
	}

	if (IS_ENABLED(CONFIG_LIS2DH_MEASURE_TEMPERATURE)) {
		if (rc == 0) {
			rc = sensor_channel_get(sensor, SENSOR_CHAN_DIE_TEMP, &temperature);
			if (rc < 0) {
				printf("\nERROR: Unable to read temperature:%d\n", rc);
			} else {
				printf(", t %f\n", sensor_value_to_double(&temperature));
			}
		}

	} else {
		printf("\n");
	}
}

#ifdef CONFIG_LIS2DH_TRIGGER
static void trigger_handler(const struct device *dev,
			    const struct sensor_trigger *trig)
{
	fetch_and_display(dev);
}
#endif


void main(void)
{
	const struct device *sensor = DEVICE_DT_GET_ANY(st_lis2dh);

	if (sensor == NULL) {
		printf("No device found\n");
		return;
	}
	if (!device_is_ready(sensor)) {
		printf("Device %s is not ready\n", sensor->name);
		return;
	}


#if CONFIG_LIS2DH_TRIGGER
	{
		struct sensor_trigger trig;
		int rc;

		trig.type = SENSOR_TRIG_DATA_READY;
		trig.chan = SENSOR_CHAN_ACCEL_XYZ;

		if (IS_ENABLED(CONFIG_LIS2DH_ODR_RUNTIME)) {
			struct sensor_value odr = {
				.val1 = 1,
			};

			rc = sensor_attr_set(sensor, trig.chan,
					     SENSOR_ATTR_SAMPLING_FREQUENCY,
					     &odr);
			if (rc != 0) {
				printf("Failed to set odr: %d\n", rc);
				return;
			}
			printf("Sampling at %u Hz\n", odr.val1);
		}

		rc = sensor_trigger_set(sensor, &trig, trigger_handler);
		if (rc != 0) {
			printf("Failed to set trigger: %d\n", rc);
			return;
		}

		printf("Waiting for triggers\n");
		while (true) {
			k_sleep(K_MSEC(2000));
		}
	}
#else /* CONFIG_LIS2DH_TRIGGER */
	printf("Polling at 0.5 Hz\n");

	fetch_and_display(sensor);

	pm_device_action_run(sensor, PM_DEVICE_ACTION_SUSPEND);

	printf("Going to sleep after 3 sec...\n");
	k_sleep(K_MSEC(3000));
	printf("Deep Sleep Starts now\n");

	pm_state_force(0u, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
	k_sleep(K_SECONDS(2U));

	while (true) {

	}
#endif /* CONFIG_LIS2DH_TRIGGER */
}

prj.conf :

CONFIG_STDOUT_CONSOLE=y
CONFIG_I2C=y
CONFIG_SENSOR=y
CONFIG_CBPRINTF_FP_SUPPORT=y
CONFIG_LIS2DH=y
CONFIG_LIS2DH_ACCEL_RANGE_2G=y
CONFIG_LIS2DH_OPER_MODE_LOW_POWER=y
CONFIG_LIS2DH_ODR_1=y
# CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD=y
CONFIG_PM=y
CONFIG_PM_DEVICE=y
CONFIG_GPIO=y

dts.overlay :

&i2c0 {
    lis3dh: lis3dh@19 {
        status = "okay";
        compatible = "st,lis2dh";
        reg = <0x19 >;
    };
};

Parents Reply Children
  • I turned on the log and I'm getting these errors :

    *** Booting Zephyr OS build v3.1.99-ncs1 ***
    Polling at 0.5 Hz
    #1 @ 266 ms: x -0.153216 , y -0.153216 , z 9.805824
    Going to sleep after 3 sec...
    [00:00:00.259,124] <inf> lis2dh: fs=2, odr=0x1 lp_en=0x8 scale=9576
    Deep Sleep Starts now
    [00:00:03.275,512] <err> os: ***** MPU FAULT *****
    [00:00:03.275,543] <err> os: Stacking error (context area might be not valid)
    [00:00:03.275,543] <err> os: Data Access Violation
    [00:00:03.275,573] <err> os: MMFAR Address: 0x200015f8
    [00:00:03.275,573] <err> os: r0/a1: 0x34f155bf r1/a2: 0x00c52802 r2/a3: 0x7d679934
    [00:00:03.275,604] <err> os: r3/a4: 0xc0ebe905 r12/ip: 0x5c1b1937 r14/lr: 0x0a8008e8
    [00:00:03.275,604] <err> os: xpsr: 0x2406de00
    [00:00:03.275,634] <err> os: Faulting instruction address (r15/pc): 0x8bc6d297
    [00:00:03.275,634] <err> os: >>> ZEPHYR FATAL ERROR 2: Stack overflow on CPU 0
    [00:00:03.275,665] <err> os: Current thread: 0x20000628 (unknown)
    [00:00:04.461,730] <err> fatal_error: Resetting system
    *** Booting Zephyr OS build v3.1.99-ncs1 ***
    Polling at 0.5 Hz
    #1 @ 266 ms: x -0.153216 , y -0.306432 , z 9.959040
    Going to sleep after 3 sec...




  • The crashlog indicates that you had a stack overflow in one of your threads. Please add CONFIG_DEBUG_THREAD_INFO=y to your prj.conf to get the name of the thread.

  • after enabling mentioned config this is the new log :


    [00:00:03.275,482] <err> os: ***** MPU FAULT *****
    [00:00:03.275,512] <err> os: Stacking error (context area might be not valid)
    [00:00:03.275,512] <err> os: Data Access Violation
    [00:00:03.275,512] <err> os: MMFAR Address: 0x20001678
    [00:00:03.275,543] <err> os: r0/a1: 0x088324ff r1/a2: 0x4eb7b419 r2/a3: 0xdc5f7d29
    [00:00:03.275,573] <err> os: r3/a4: 0x49e0b6dc r12/ip: 0xe53dc749 r14/lr: 0x2b23e114
    [00:00:03.275,573] <err> os: xpsr: 0xafd52000
    [00:00:03.275,573] <err> os: Faulting instruction address (r15/pc): 0x5db9d8f3
    [00:00:03.275,604] <err> os: >>> ZEPHYR FATAL ERROR 2: Stack overflow on CPU 0
    [00:00:03.275,634] <err> os: Current thread: 0x20000658 (idle)
    [00:00:04.461,700] <err> fatal_error: Resetting system

  • I'm not sure why you get a stack overflow in the 'idle' thread. Either way, please try to increase the stack size for this thread by adding CONFIG_IDLE_STACK_SIZE=<new stack size> to your prj.conf and see if it helps. The default is 320 bytes.

  • I increased the stack size and I'm facing these errors : 

    *** Booting Zephyr OS build v3.1.99-ncs1  ***
    Polling at 0.5 Hz
    #1 @ 266 ms: x -0.612864 , y 0.612864 , z 10.571904
    Going to sleep after 3 sec...
    [00:00:00.259,094] <inf> lis2dh: fs=2, odr=0x1 lp_en=0x8 scale=9576
    Deep Sleep Starts now
    [00:00:03.275,512] <err> i2c_nrfx_twi: Error on I2C line occurred for message 0
    [00:00:03.275,543] <err> lis2dh: failed to read reg_crtl1
    [00:00:03.275,573] <err> pm: Device lis3dh@19 did not enter suspended state (-5)
    *** Booting Zephyr OS build v3.1.99-ncs1  ***
    Polling at 0.5 Hz
    #1 @ 401 ms: x -0.766080 , y -0.153216 , z 9.499392
    Going to sleep after 3 sec...

    which is I think something related to the sensor driver, it might be running some code in the background in a thread, cause when I run k_sleep in the main thread, it logs : 
    [00:00:00.259,094] <inf> lis2dh: fs=2, odr=0x1 lp_en=0x8 scale=9576
    and after 3 seconds it might be still running, so putting device into deep sleep interrupt it's operation and the i2c and sensor driver face errors which indicate that it is better to suspend the driver (which suspend it's thread) so it won't face any error.

Related