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

Task watchdog preventing BLE connection on ncs 1.6.0 but not rc2

Hello everyone,

I am having an odd problem. I am using an SoC based on the nRF52832 (the ISP1507-AX). So far I had been using ncs v1.6.0-rc2 during development. Recently I have been trying to use v1.6.0. However, when the watchdog module is used, the BLE connection is impossible (using the mobile nRF Connect App, there is some delay before disconnection):

  

The thing is, this only happens on 1.6.0 and NOT on 1.6.0-rc2. I haven't tried other releases so far.

Thus, I constructed a sample reproducing the error. This very vaguely resemble the architecture I've been using. Am I doing something wrong ? And why would it not happen on 1.6.0-rc2 ?

Attached you'll find all files.

Here is the main.c:

/* Standard and Zephyr libraries */
#include <zephyr.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <soc.h>
#include <sys/byteorder.h>
#include <sys/util.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/sensor.h>

/* Bluetooth Stack Libraries */
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>
#include <bluetooth/services/bas.h>
#include <bluetooth/services/dis.h>
#include <bluetooth/services/hrs.h>

/* Settings librairy for DIS */
#include <settings/settings.h>

/* Watchdog and task_wdt */
#include <drivers/watchdog.h>
#include <sys/reboot.h>
#include <task_wdt/task_wdt.h>

/* Logging module */
#include <logging/log.h>
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);

/**************************************************************************
 * DECLARATIONS
 *************************************************************************/

void sensor_stop(void);
void sensor_start(void);

/**************************************************************************
 * BLUETOOTH FUNCTIONS
 *************************************************************************/

/** Device Name as defined in the prj.conf */
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
/** device name length */
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)

static const struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	BT_DATA_BYTES(BT_DATA_UUID16_ALL,
		      BT_UUID_16_ENCODE(BT_UUID_HRS_VAL),
		      BT_UUID_16_ENCODE(BT_UUID_BAS_VAL),
		      BT_UUID_16_ENCODE(BT_UUID_DIS_VAL))
};

static void connected(struct bt_conn *conn, uint8_t err)
{
	if (err) {
		LOG_ERR("Connection failed (err 0x%02x)", err);
	} else {
		LOG_INF("Connected\n");
        sensor_start();
	}
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
	LOG_INF("Disconnected (reason 0x%02x)", reason);
    sensor_stop();
}

static struct bt_conn_cb conn_callbacks = {
	.connected = connected,
	.disconnected = disconnected,
};

static void bt_ready(void)
{
	int err;

	LOG_INF("Bluetooth initialized");

	err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
	if (err) {
		LOG_ERR("Advertising failed to start (err %d)", err);
		return;
	}

	LOG_INF("Advertising successfully started");
}

static void bas_notify(void)
{
	uint8_t battery_level = bt_bas_get_battery_level();

	battery_level--;

	if (!battery_level) {
		battery_level = 100U;
	}

	bt_bas_set_battery_level(battery_level);
}

static void hrs_notify(uint8_t heartrate)
{
	bt_hrs_notify(heartrate);
}

static void ble_init(void)
{
    int err;

	err = bt_enable(NULL);
	if (err) {
		LOG_ERR("Bluetooth init failed (err %d)", err);
		return;
	}

	bt_ready();

	bt_conn_cb_register(&conn_callbacks);
}

/**************************************************************************
 * WATCHDOG FUNCTIONS
 *************************************************************************/

#define WATCHDOG_ACTIVE

/**
 * If the devicetree has a watchdog node, we get the watchdog device
 * from there. Otherwise, the task watchdog will be used without a
 * hardware watchdog fallback.
 */
#if DT_NODE_HAS_STATUS(DT_ALIAS(watchdog0), okay)
#define WDT_NODE DT_ALIAS(watchdog0)
#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_watchdog)
#define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nordic_nrf_watchdog)
#endif

static void watchdog_main_init(void)
{
#ifdef WDT_NODE
    const struct device *hw_wdt_dev = DEVICE_DT_GET(WDT_NODE);
#else
    const struct device *hw_wdt_dev = NULL;
#endif

    if (!device_is_ready(hw_wdt_dev))
    {
        LOG_INF("Hardware watchdog %s is not ready; ignoring it.\n",
                log_strdup(hw_wdt_dev->name));
        hw_wdt_dev = NULL;
    }
    task_wdt_init(hw_wdt_dev);
}

void task_wdt_callback(int channel_id, void *user_data)
{
    LOG_ERR("Task watchdog channel %d callback, thread: %s\n",
            channel_id, log_strdup(k_thread_name_get((k_tid_t)user_data)));
    /*
	 * If the issue could be resolved, call task_wdt_feed(channel_id) here
	 * to continue operation.
	 *
	 * Otherwise we can perform some cleanup and reset the device.
	 */
    LOG_ERR("Resetting device...\n");

    sys_reboot(SYS_REBOOT_COLD);
}

/**************************************************************************
 * UPDATE VALUES FUNCTIONS
 *************************************************************************/

#define START_DELAY_MS              1000
#define SENSOR_SAMPLING_TIME_MS     1000
#define WATCHDOG_PROCESS_TIMEOUT_MS 10000

static K_SEM_DEFINE(sensor_ok, 0, 1);
static K_SEM_DEFINE(sensor_init_ok, 0, 1);

static void sensor_timer_handler(struct k_timer *dummy)
{
    k_sem_give(&sensor_ok);
}

K_TIMER_DEFINE(sensor_timer, sensor_timer_handler, NULL);

int sensor_init(void)
{
    int status = 0;

    /* Indicate to the processing thread that initialization is finished */
    k_sem_give(&sensor_init_ok);

    return status;
}

#ifdef WATCHDOG_ACTIVE
/** ID for the process watchdog */
static int processor_wdt_id;
#endif /* WATCHDOG_ACTIVE */

void sensor_stop(void)
{
    k_timer_stop(&sensor_timer);

#ifdef WATCHDOG_ACTIVE
    task_wdt_delete(processor_wdt_id);
#endif /* WATCHDOG_ACTIVE */

    LOG_INF("Sensor stopped.\n");
}

void sensor_start(void)
{
    /* start periodic timer that expires once every "samplingTime" */
    k_timer_start(&sensor_timer, K_MSEC(START_DELAY_MS),
                  K_MSEC(SENSOR_SAMPLING_TIME_MS));

#ifdef WATCHDOG_ACTIVE
    processor_wdt_id = task_wdt_add(WATCHDOG_PROCESS_TIMEOUT_MS,
                                        task_wdt_callback,
                                        (void *)k_current_get());
#endif /* WATCHDOG_ACTIVE */

    LOG_INF("Sensor started.\n");
}

void sensor_process_thread(void)
{
    /* Wait for the sensor to be initialized before starting the thread loop. */
    k_sem_take(&sensor_init_ok, K_FOREVER);

    static uint8_t sensor_data = 90;

    while (1)
    {
        /* Semaphore is available every sampling time */
        k_sem_take(&sensor_ok, K_FOREVER);

        /* Notify new sensor value */
	    sensor_data++;
	    if (sensor_data == 160U) {
		    sensor_data = 90U;
	    }
        hrs_notify(sensor_data);

#ifdef WATCHDOG_ACTIVE
        task_wdt_feed(processor_wdt_id);
#endif /* WATCHDOG_ACTIVE */
    }
}

/* Defines the processor thread with its stacksize and priority. */
K_THREAD_DEFINE(sensor_producer_thread_id, 512,
                sensor_process_thread, NULL, NULL,
                NULL, 5, 0, 0);

/**************************************************************************
 * MAIN
 *************************************************************************/

void main(void)
{
    watchdog_main_init();

    sensor_init();

    ble_init();

    while(1)
    {
        bas_notify();
        k_sleep(K_MSEC(5000));
    }
}

Here is the prj.conf:

# Deactivate DEBUG/LOG for production builds
CONFIG_DEBUG=y
CONFIG_SERIAL=y
# Logging
CONFIG_LOG=y

# segger RTT console
CONFIG_USE_SEGGER_RTT=y
CONFIG_RTT_CONSOLE=y
CONFIG_UART_CONSOLE=n

# Unused Peripherals
CONFIG_SPI=n

# Activate the BLE layer, set as peripheral
CONFIG_BT=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_DEBUG_SERVICE=y
CONFIG_BT_SMP=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_CTLR=y
CONFIG_BT_CTLR_PHY_2M=y
CONFIG_BT_GATT_CLIENT=y
# Set up the Services
CONFIG_BT_DIS=y
CONFIG_BT_DIS_PNP=n
CONFIG_BT_BAS=y
CONFIG_BT_HRS=y

# Set up device appearance
# Appearance 833 is Heart Rate Belt
CONFIG_BT_DEVICE_APPEARANCE=833

# WATCHDOG MODULE 
CONFIG_WATCHDOG=y
CONFIG_WDT_DISABLE_AT_BOOT=y
CONFIG_TASK_WDT=y
CONFIG_THREAD_NAME=y

Here is the CMakeLists.txt:

# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.13.1)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(peripheral_hr)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE
  ${app_sources}
  )

zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)

You just have to comment out or not the define at line 133 to reproduce the behavior. I have tested on this SoC based on the nRF52832 because I don't have other boards on hand.

watchdog_ble_pblm.zip

Thank you very much in advance for any help.

Best regards,

Parents
  • Hello,

    Thank you for your time.

    I managed to test and reproduce the problem with an nrf52dk_nrf52832 board. I just had to increase the stack size of the thread defined in line 263 from 512 to 1024 or I would get an MPU fault when subscribing to notifications.

    But, the problem is the same, if the watchdog (as defined in this sample) is active, connection to the device is impossible.

Reply
  • Hello,

    Thank you for your time.

    I managed to test and reproduce the problem with an nrf52dk_nrf52832 board. I just had to increase the stack size of the thread defined in line 263 from 512 to 1024 or I would get an MPU fault when subscribing to notifications.

    But, the problem is the same, if the watchdog (as defined in this sample) is active, connection to the device is impossible.

Children
No Data
Related