NRF52840:Thread communication debugging is restarted

Hi Nordic Team: 

I'm using the coap server example. I created a test task that will always send UDP messages. During the test, I found that the device would restart. Here is the test code I modified, along with the log for RTT when an abnormal restart occurs.I really hope to get your help.Thank you. 

OS: Windows 10

HW: NRF52840 DK    

NCS Version:nRF Connect SDK v2.1.0

/*
 * Copyright (c) 2020 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include <zephyr/kernel.h>
#include <dk_buttons_and_leds.h>
#include <zephyr/logging/log.h>
#include <zephyr/net/openthread.h>
/*UDP*/
#include <openthread/message.h>
#include <openthread/udp.h>
#include <openthread/ip6.h>
#include <openthread/link.h>

#include <openthread/thread.h>

#include "ot_coap_utils.h"

LOG_MODULE_REGISTER(coap_server, CONFIG_COAP_SERVER_LOG_LEVEL);

#define OT_CONNECTION_LED DK_LED1
#define PROVISIONING_LED DK_LED3
#define LIGHT_LED DK_LED4

static struct k_work provisioning_work;

static struct k_timer led_timer;
static struct k_timer provisioning_timer;

static void on_light_request(uint8_t command)
{
	static uint8_t val;

	switch (command) {
	case THREAD_COAP_UTILS_LIGHT_CMD_ON:
		dk_set_led_on(LIGHT_LED);
		val = 1;
		break;

	case THREAD_COAP_UTILS_LIGHT_CMD_OFF:
		dk_set_led_off(LIGHT_LED);
		val = 0;
		break;

	case THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE:
		val = !val;
		dk_set_led(LIGHT_LED, val);
		break;

	default:
		break;
	}
}

static void activate_provisioning(struct k_work *item)
{
	ARG_UNUSED(item);

	ot_coap_activate_provisioning();

	k_timer_start(&led_timer, K_MSEC(100), K_MSEC(100));
	k_timer_start(&provisioning_timer, K_SECONDS(5), K_NO_WAIT);

	LOG_INF("Provisioning activated");
}

static void deactivate_provisionig(void)
{
	k_timer_stop(&led_timer);
	k_timer_stop(&provisioning_timer);

	if (ot_coap_is_provisioning_active()) {
		ot_coap_deactivate_provisioning();
		LOG_INF("Provisioning deactivated");
	}
}

static void on_provisioning_timer_expiry(struct k_timer *timer_id)
{
	ARG_UNUSED(timer_id);

	deactivate_provisionig();
}

static void on_led_timer_expiry(struct k_timer *timer_id)
{
	static uint8_t val = 1;

	ARG_UNUSED(timer_id);

	dk_set_led(PROVISIONING_LED, val);
	val = !val;
}

static void on_led_timer_stop(struct k_timer *timer_id)
{
	ARG_UNUSED(timer_id);

	dk_set_led_off(PROVISIONING_LED);
}

static void on_button_changed(uint32_t button_state, uint32_t has_changed)
{
	uint32_t buttons = button_state & has_changed;

	if (buttons & DK_BTN4_MSK) {
		k_work_submit(&provisioning_work);
	}
}
void dk_set_led_toggle(uint8_t led_idx);
static void on_thread_state_changed(uint32_t flags, void *context)
{
	struct openthread_context *ot_context = context;

	if (flags & OT_CHANGED_THREAD_ROLE) {
		switch (otThreadGetDeviceRole(ot_context->instance)) {
		case OT_DEVICE_ROLE_CHILD:
		case OT_DEVICE_ROLE_ROUTER:
		case OT_DEVICE_ROLE_LEADER:
			dk_set_led_on(OT_CONNECTION_LED);
			break;

		case OT_DEVICE_ROLE_DISABLED:
		case OT_DEVICE_ROLE_DETACHED:
		default:
			dk_set_led_off(OT_CONNECTION_LED);
			deactivate_provisionig();
			break;
		}
	}
}
struct k_thread my_thread_data;
#define MY_STACK_SIZE   (2048)
#define MY_PRIOTITY		(5)
K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE);

typedef struct BACnet_IP6_Address {
    uint8_t address[16];
    uint16_t port;
} BACNET_IP6_ADDRESS;
 static uint8_t Ttest_data[384];
static otUdpSocket sUdpSocket;
static otMessage *   ot_message;
const otMessageInfo *OTMessageInfo = NULL;
static uint8_t udp_buf[32];
static uint16_t ot_message_len = 16;
void handleUdpReceive(void *aContext, otMessage *aMessage,
                      const otMessageInfo *aMessageInfo)
{
    OT_UNUSED_VARIABLE(aContext);
    OT_UNUSED_VARIABLE(aMessage);
    OT_UNUSED_VARIABLE(aMessageInfo);
    OTMessageInfo = aMessageInfo;
    ot_message_len = otMessageGetLength(aMessage);
    otMessageRead(aMessage, 0, udp_buf, ot_message_len);
    dk_set_led_toggle(PROVISIONING_LED);
}
void initUdp(otInstance *aInstance)
{
    otSockAddr  listenSockAddr;
    memset(&sUdpSocket, 0, sizeof(sUdpSocket));
    memset(&listenSockAddr, 0, sizeof(listenSockAddr));

    listenSockAddr.mPort    = 0x1234;
    otUdpOpen(aInstance, &sUdpSocket, handleUdpReceive, aInstance);
    otUdpBind(aInstance, &sUdpSocket, &listenSockAddr, OT_NETIF_THREAD);

}

static void ot_udp_init(void)
{
    otInstance * aInstance = openthread_get_default_instance(); 
    initUdp(aInstance);
}

int bip6_send_mpdu(BACNET_IP6_ADDRESS *dest, uint8_t *mtu, uint16_t mtu_len)
{
    static uint32_t otFreeCount = 0;
    otError       error = OT_ERROR_NONE; 
    otMessageInfo messageInfo;
    otInstance * aInstance = openthread_get_default_instance(); 

    otMessage *   ot_message = NULL;

    otBufferInfo mesInfo;
    otMessageGetBufferInfo(aInstance, &mesInfo);

    otMessageSettings aSentting = {.mLinkSecurityEnabled = false, .mPriority = OT_MESSAGE_PRIORITY_HIGH};
    memset(&messageInfo, 0, sizeof(messageInfo));
    memcpy(&messageInfo.mPeerAddr.mFields.m8[0], &dest->address[0], 16);
    messageInfo.mPeerPort = dest->port;
    /* send the packet */
    do {
        ot_message = otUdpNewMessage(aInstance, NULL);
        if (ot_message == NULL) {
            break;
        }
        error = otMessageAppend(ot_message, mtu, mtu_len);
        if (error != OT_ERROR_NONE) {
            break;
        }
        error = otUdpSend(aInstance, &sUdpSocket, ot_message, &messageInfo);
    } while(0);

    
    if (error != OT_ERROR_NONE && ot_message != NULL)
    {
        //NRF_LOG_INFO("**OT Free:%d\n", ++otFreeCount);
        otMessageFree(ot_message);
        return 0;
    } else {
        //NRF_LOG_INFO("**OT Send:%d err:%d %x\n", ++otFreeCount, error, ot_message);
        
    }
    if (error != OT_ERROR_NONE) {
        return 0;
    }
    return mtu_len;

}
void thread_send_test(void)
{
    static uint32_t cnt = 0;
    uint8_t len = 0;
    otIp6Address  broadcastAddr;    
    BACNET_IP6_ADDRESS dest = {{0}};   
    len = sprintf(Ttest_data, "Tsend cnt:%d\n", ++cnt);
    memset(&broadcastAddr, 0x00, sizeof(broadcastAddr));
    otIp6AddressFromString("FF03::1", &broadcastAddr);
    dest.port = 0x1234;
    memcpy(&dest.address[0], &broadcastAddr.mFields.m8[0], sizeof(broadcastAddr));
    bip6_send_mpdu(&dest, Ttest_data, len);
    //DEBUG_PRINTF("Tsend cnt:%d\n", cnt);
    
}

static void ot_app(int unused1, int unused2, int unused3)
{
	ot_udp_init();
    while (1)
    {        
		thread_send_test();
		k_sleep(K_MSEC(50));
    }
}

void main(void)
{
	int ret;

	LOG_INF("Start CoAP-server sample");

	k_timer_init(&led_timer, on_led_timer_expiry, on_led_timer_stop);
	k_timer_init(&provisioning_timer, on_provisioning_timer_expiry, NULL);

	k_work_init(&provisioning_work, activate_provisioning);

	ret = ot_coap_init(&deactivate_provisionig, &on_light_request);
	if (ret) {
		LOG_ERR("Could not initialize OpenThread CoAP");
		goto end;
	}

	ret = dk_leds_init();
	if (ret) {
		LOG_ERR("Could not initialize leds, err code: %d", ret);
		goto end;
	}

	ret = dk_buttons_init(on_button_changed);
	if (ret) {
		LOG_ERR("Cannot init buttons (error: %d)", ret);
		goto end;
	}

	openthread_set_state_changed_cb(on_thread_state_changed);
	openthread_start(openthread_get_default_context());

	k_tid_t my_tid = k_thread_create(&my_thread_data, my_stack_area, K_THREAD_STACK_SIZEOF(my_stack_area), ot_app, NULL, NULL, NULL, MY_PRIOTITY, 0, K_NO_WAIT);
end:
	return;
}

  • Hello,

    This could be a stack overflow for the thread named openthread. Try to increase the stack size for that thread.

    To get an overview of the stack usage for all threads you can enable the Zephyr Thread Analyzer to get reports on the stack usage for each thread.

    An additional note: In your attached code on line 112 there is a declaration of dk_set_led_toggle() but I can't find the implementation.

    Kind Regards,
    Maria

  • Hi,

    Thank you for your reply. May I ask where I should modify the size of the Thread? I used Zephyr Thread Analyzer but I don't know how to print out the log. dk_set_led_toggle() is a flashing check that you can directly delete without affecting the test.

  • Hello,

    Increase the stack size for openthread by setting CONFIG_OPENTHREAD_THREAD_STACK_SIZE in your prj.conf. It is either 6240 or 3168 by default depending on whether  CONFIG_OPENTHREAD_COMMISSIONER or CONFIG_OPENTHREAD_JOINER are set or not.

    You can print the thread analyzer log in a serial terminal by including the following lines in your prj.conf:

    # Thread analyzer
    CONFIG_THREAD_ANALYZER=y
    CONFIG_THREAD_ANALYZER_USE_PRINTK=y
    CONFIG_THREAD_ANALYZER_AUTO=y
    CONFIG_THREAD_ANALYZER_AUTO_INTERVAL=5
    CONFIG_THREAD_NAME=y

    The lines above will enable the thread analyzer to print a report regularly to the terminal.

    Best Regards,
    Maria

Related