NRF52840:The thread Data sending and receiving is disconnected

Hi Nordic Team: 

I use this example "freertos_coap_server", when the communication is abnormal, the network communication can be restored only after power failure and restart. Based on this example, I

changed the transmission protocol to udp. main.c is the only file I changed.This makes it easy to repeat the problem of abnormal test communication.I really hope to get your help.Thank you. 

OS: Windows 10, IDE: Segger Embedded Studio for ARM 5.32, HW: NRF52840 DK   

Segger project file is in   examples\thread\freertos_coap_server\pca10056\blank\ses   

NRF5_SDK_version:V4.2.0     

/**
 * Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
/** @file
 *
 * @defgroup freertos_coap_server_example_main main.c
 * @{
 * @ingroup freertos_coap_server_example
 *
 * @brief Thread CoAP server example with FreeRTOS Application main file.
 *
 * This file contains the source code for a sample application using Thread CoAP server and FreeRTOS.
 *
 */
#include "FreeRTOS.h"
#include "nrf_drv_clock.h"
#include "task.h"

#define NRF_LOG_MODULE_NAME APP
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
NRF_LOG_MODULE_REGISTER();

#include "app_timer.h"
#include "bsp_thread.h"
#include "thread_coap_utils.h"
#include "thread_utils.h"

#include <openthread/instance.h>
#include <openthread/thread.h>

#define THREAD_STACK_TASK_STACK_SIZE     (( 1024 * 8 ) / sizeof(StackType_t))   /**< FreeRTOS task stack size is determined in multiples of StackType_t. */
#define LOG_TASK_STACK_SIZE              ( 1024 / sizeof(StackType_t))          /**< FreeRTOS task stack size is determined in multiples of StackType_t. */
#define THREAD_STACK_TASK_PRIORITY       2
#define LOG_TASK_PRIORITY                1
#define LED1_TASK_PRIORITY               1
#define LED2_TASK_PRIORITY               1
#define LED1_BLINK_INTERVAL              427
#define LED2_BLINK_INTERVAL              472
#define LOG_TASK_INTERVAL                100

typedef struct
{
    TaskHandle_t thread_stack_task;   /**< Thread stack task handle */
    TaskHandle_t led1_task;           /**< LED1 task handle*/
    TaskHandle_t led2_task;           /**< LED2 task handle*/
    TaskHandle_t ot_app;
#if NRF_LOG_ENABLED
    TaskHandle_t logger_task;         /**< Definition of Logger thread. */
#endif
} application_t;

application_t m_app =
{
    .thread_stack_task = NULL,
    .led1_task         = NULL,
    .led2_task         = NULL,
    .ot_app         = NULL,
#if NRF_LOG_ENABLED
    .logger_task       = NULL,
#endif
};

/***************************************************************************************************
 * @section CoAP
 **************************************************************************************************/

static inline void light_on(void)
{
    vTaskResume(m_app.led1_task);
    vTaskResume(m_app.led2_task);
}


static inline void light_off(void)
{
    vTaskSuspend(m_app.led1_task);
    LEDS_OFF(BSP_LED_2_MASK);

    vTaskSuspend(m_app.led2_task);
    LEDS_OFF(BSP_LED_3_MASK);
}


static inline void light_toggle(void)
{
    if (!thread_coap_utils_light_is_led_blinking())
    {
        light_on();
    }
    else
    {
        light_off();
    }
}


static void on_light_change(thread_coap_utils_light_command_t command)
{
    switch (command)
    {
        case THREAD_COAP_UTILS_LIGHT_CMD_ON:
            light_on();
            break;

        case THREAD_COAP_UTILS_LIGHT_CMD_OFF:
            light_off();
            break;

        case THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE:
            light_toggle();
            break;

        default:
            ASSERT(false);
            break;
    }
}

/***************************************************************************************************
 * @section Signal handling
 **************************************************************************************************/

void otTaskletsSignalPending(otInstance * p_instance)
{
    if (m_app.thread_stack_task == NULL)
    {
        return;
    }

    UNUSED_RETURN_VALUE(xTaskNotifyGive(m_app.thread_stack_task));
}


void otSysEventSignalPending(void)
{
    static BaseType_t xHigherPriorityTaskWoken;

    if (m_app.thread_stack_task == NULL)
    {
        return;
    }

    vTaskNotifyGiveFromISR(m_app.thread_stack_task, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

/***************************************************************************************************
 * @section State change handling
 **************************************************************************************************/

 static void thread_state_changed_callback(uint32_t flags, void * p_context)
{
    if (flags & OT_CHANGED_THREAD_ROLE)
    {
        switch(otThreadGetDeviceRole(p_context))
        {
            case OT_DEVICE_ROLE_CHILD:
            case OT_DEVICE_ROLE_ROUTER:
            case OT_DEVICE_ROLE_LEADER:
                break;

            case OT_DEVICE_ROLE_DISABLED:
            case OT_DEVICE_ROLE_DETACHED:
            default:
                thread_coap_utils_provisioning_enable_set(false);
                break;
        }
    }

    NRF_LOG_INFO("State changed! Flags: 0x%08x Current role: %d\r\n", flags, otThreadGetDeviceRole(p_context));
}

/***************************************************************************************************
 * @section Buttons
 **************************************************************************************************/

static void bsp_event_handler(bsp_event_t event)
{
    switch (event)
    {
        case BSP_EVENT_KEY_3:
            thread_coap_utils_provisioning_enable_set(true);
            break;

        default:
            return;
    }
}

/***************************************************************************************************
 * @section Initialization
 **************************************************************************************************/

 /**@brief Function for initializing the Application Timer Module
 */
static void timer_init(void)
{
    uint32_t error_code = app_timer_init();
    APP_ERROR_CHECK(error_code);
}


/**@brief Function for initializing the Thread Board Support Package
 */
static void thread_bsp_init(void)
{
    uint32_t error_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
    APP_ERROR_CHECK(error_code);

    error_code = bsp_thread_init(thread_ot_instance_get());
    APP_ERROR_CHECK(error_code);
}


/**@brief Function for initializing the Thread Stack
 */
static void thread_instance_init(void)
{
    thread_configuration_t thread_configuration =
    {
        .radio_mode        = THREAD_RADIO_MODE_RX_ON_WHEN_IDLE,
        .autocommissioning = true,
    };

    thread_init(&thread_configuration);
    //thread_cli_init();
    thread_state_changed_callback_set(thread_state_changed_callback);
}


/**@brief Function for initializing the Constrained Application Protocol Module
 */
static void thread_coap_init(void)
{
    thread_coap_utils_configuration_t thread_coap_configuration =
    {
        .coap_server_enabled               = true,
        .coap_client_enabled               = false,
        .configurable_led_blinking_enabled = true,
    };

    thread_coap_utils_init(&thread_coap_configuration);
}


/**@brief Function for initializing the nrf log module.
 */
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}


/**@brief Function for initializing the clock.
 */
static void clock_init(void)
{
    ret_code_t err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);
}


static void thread_stack_task(void * arg)
{
    UNUSED_PARAMETER(arg);

    while (1)
    {
        thread_process();
        UNUSED_RETURN_VALUE(ulTaskNotifyTake(pdTRUE, portMAX_DELAY));
    }
}

/***************************************************************************************************
 * @section Leds
 **************************************************************************************************/

static void led1_task(void * pvParameter)
{
    UNUSED_PARAMETER(pvParameter);

    while (1)
    {
        LEDS_INVERT(BSP_LED_2_MASK);
        vTaskDelay(LED1_BLINK_INTERVAL);
    }
}


static void led2_task(void * pvParameter)
{
    UNUSED_PARAMETER(pvParameter);

    while (1)
    {
        LEDS_INVERT(BSP_LED_3_MASK);
        vTaskDelay(LED2_BLINK_INTERVAL);
    }
}

#if NRF_LOG_ENABLED
static void logger_thread(void * pvParameter)
{
    UNUSED_PARAMETER(pvParameter);

    while (true)
    {
        if (!(NRF_LOG_PROCESS()))
        {
            /* No more logs, let's sleep and wait for any */
            //thread_coap_utils_multicast_light_request_send2(0, 1);
            vTaskDelay(LOG_TASK_INTERVAL);
        }
    }
}
#endif //NRF_LOG_ENABLED

/***************************************************************************************************
 * @section Main
 **************************************************************************************************/
#include <openthread/message.h>
#include <openthread/udp.h>
#include <openthread/ip6.h>
#include <openthread/link.h>
typedef struct BACnet_IP6_Address {
    uint8_t address[16];
    uint16_t port;
} BACNET_IP6_ADDRESS;
 /*UDP*/
 static uint8_t Ttest_data[384];
 /* Set Extended Pan ID to DEAD00BEEF00CAFE */
static const uint8_t thread_extPanId[OT_EXT_PAN_ID_SIZE] = {0xDE, 0xAD, 0x00, 0xBE, 0xEF, 0x00, 0xCA, 0xFE};//dafult
/* Set network key to 00112233445566778899aabbccddeeff */
static const uint8_t thread_network_key[OT_MASTER_KEY_SIZE] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
/*broadcast addr */
static const char UDP_DEST_ADDR[] = "ff03::1";
static otUdpSocket sUdpSocket;
static otMessage *   ot_message;
const otMessageInfo *OTMessageInfo = NULL;
static uint8_t udp_buf[384];
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);
    nrf_gpio_pin_toggle(LED_1);
}
otError       udp_error = OT_ERROR_GENERIC;
void initUdp(otInstance *aInstance)
{
    otSockAddr  listenSockAddr;
    otError       error = OT_ERROR_NONE;
    memset(&sUdpSocket, 0, sizeof(sUdpSocket));
    memset(&listenSockAddr, 0, sizeof(listenSockAddr));

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

}

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

otError setNetworkConfiguration(void)
{
    static char          aNetworkName[16] = {0};
    otOperationalDataset aDataset;
    const otExtAddress *ot_Extaddr;
    otInstance * aInstance = thread_ot_instance_get(); 
    
    memset(&aDataset, 0, sizeof(otOperationalDataset));
    memset(aNetworkName, 0x00, sizeof(aNetworkName));

    ot_Extaddr = otLinkGetExtendedAddress(aInstance);
    /*
     * Fields that can be configured in otOperationDataset to override defaults:
     *     Network Name, Mesh Local Prefix, Extended PAN ID, PAN ID, Delay Timer,
     *     Channel, Channel Mask Page 0, Network Key, PSKc, Security Policy
     */
    aDataset.mActiveTimestamp                      = 1;
    aDataset.mComponents.mIsActiveTimestampPresent = true;

    /* Set Channel to 15 */
    aDataset.mChannel                      = 11;
    aDataset.mComponents.mIsChannelPresent = true;

    /* Set Pan ID to 2222 */
    aDataset.mPanId                      = (otPanId)0xabcc;
    aDataset.mComponents.mIsPanIdPresent = true;

    /* Set Extended Pan ID to C0DE1AB5C0DE1AB5 */
    memcpy(aDataset.mExtendedPanId.m8, thread_extPanId, sizeof(aDataset.mExtendedPanId));
    aDataset.mComponents.mIsExtendedPanIdPresent = true;

    /* Set network key to 1234C0DE1AB51234C0DE1AB51234C0DE */
    memcpy(aDataset.mMasterKey.m8, thread_network_key, sizeof(aDataset.mMasterKey));
    aDataset.mComponents.mIsMasterKeyPresent = true;

    /* Set Network Name to OTCodelab */
    //size_t length = strlen(aNetworkName);
    size_t length = sprintf(aNetworkName, "%s-%02x%02x", "WNGTTEST", ot_Extaddr->m8[6], ot_Extaddr->m8[7]);
    ASSERT(length <= OT_NETWORK_NAME_MAX_SIZE);
    memcpy(aDataset.mNetworkName.m8, aNetworkName, length);
    aDataset.mComponents.mIsNetworkNamePresent = true;

    /* Set the router selection jitter to override the 2 minute default.
       CLI cmd > routerselectionjitter 20
       Warning: For demo purposes only - not to be used in a real product */
//    uint8_t jitterValue = 100;
//    otThreadSetRouterSelectionJitter(aInstance, jitterValue);
    return otDatasetSetActive(aInstance, &aDataset);
}

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 = thread_ot_instance_get(); 

    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;
        }
        CRITICAL_REGION_ENTER();
        error = otUdpSend(&sUdpSocket, ot_message, &messageInfo);
        CRITICAL_REGION_EXIT();
    } 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(void * pvParameter)
{
    UNUSED_PARAMETER(pvParameter);
    static bool flag = true;
    while (1)
    {
        thread_send_test();
        vTaskDelay(50);
    }
}

int main(void)
{
    log_init();
    clock_init();
    timer_init();

    thread_instance_init();

    //thread_coap_init();
    thread_bsp_init();
    //thread_coap_utils_light_command_handler_set(on_light_change);
    ot_udp_init();
    NRF_LOG_INFO("APP\n");
    // Start thread stack execution.
    if (pdPASS != xTaskCreate(thread_stack_task, "THR", THREAD_STACK_TASK_STACK_SIZE, NULL, THREAD_STACK_TASK_PRIORITY, &m_app.thread_stack_task))
    {
        APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
    }

    // Start execution.
    //if (pdPASS != xTaskCreate(led1_task, "LED1", configMINIMAL_STACK_SIZE, NULL, LED1_TASK_PRIORITY, &m_app.led1_task))
    //{
    //    APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
    //}

    //// Start execution.
    //if (pdPASS != xTaskCreate(led2_task, "LED2", configMINIMAL_STACK_SIZE, NULL, LED2_TASK_PRIORITY, &m_app.led2_task))
    //{
    //    APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
    //}

#if NRF_LOG_ENABLED
    // Start execution.
    if (pdPASS != xTaskCreate(logger_thread, "LOGGER", LOG_TASK_STACK_SIZE, NULL, LOG_TASK_PRIORITY, &m_app.logger_task))
    {
        APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
    }
#endif

    // Start execution.
    if (pdPASS != xTaskCreate(ot_app, "OTAPP", THREAD_STACK_TASK_STACK_SIZE, NULL, LED2_TASK_PRIORITY, &m_app.led2_task))
    {
        APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
    }
    /* Start FreeRTOS scheduler. */
    vTaskStartScheduler();

    while (true)
    {
        /* FreeRTOS should not be here... FreeRTOS goes back to the start of stack
         * in vTaskStartScheduler function. */
    }
}

void HardFault_Handler(void)
{
    //xTaskStackShowCurrentTask();
    NVIC_SystemReset();
    while(1);
}

/**
 *@}
 **/

Parents Reply
  • The freertos examples are normally packed with tight stack size but it should be ok to be able to create new tasks. 

    I was only trying to rule out that this is not a stack overflow error and it looks based on your stack size (8192 bytes) that it has enough stack space. 

    I do not know what other changes you made affects this behavior.

    If this sample works ok without your task and no other changes were made, and also if this is not a stack overflow, then it has to be the task itself that might be causing the deadlock/race condition?

Children
  • Have you tried to test my modified example? Is it because my semaphore is not properly handled. How should I use the otTaskletsSignalPending and otSysEventSignalPending functions?Thank you for your reply.

  • I am here looking at the freertos perspective and I do not see anything wrong in the usage of otTaskletsSignalPending and/or otSysEventSignalPending .

    In regards to the example, you have made quite a lot of changes to the example we have provided so it is not easy for me to tell why you are seeing those disconnects.  I see that you might be using a bit too much stack to be allocated for your tasks that you create, maybe they are causing some overflow?

  • Do you think the problem I fed back was caused by the stack overflow? I really can't find any task with stack overflow. In this example, I only modified main.c, and I changed the Coap protocol to UDP protocol, which is the main modification point. Can you give me a debugging direction? I don't know how to solve this problem. We are nearing the end of the project schedule, and this problem has been bothering us.Thank you for your reply.

  • If it were me, I would try to understand the reason for the disconnect first using a sniffer trace of air packets.

    After understanding the reason of the disconnect, I would debug which side of the node did not respond to which procedure or packets.

    Using SystemView from segger after adding below configs to proj.conf will give you more direction on what is happening with the threads/contexts on your system.

    CONFIG_THREAD_NAME=y
    CONFIG_THREAD_MONITOR=y
    
    CONFIG_LOG_MODE_DEFERRED=y
    CONFIG_HEAP_MEM_POOL_SIZE=1024
    
    CONFIG_TRACING=y
    CONFIG_SEGGER_SYSTEMVIEW=y 
    

    Enable CONFIG_STACK_SENTINEL to get a hint from the system on possible stack overflows.

  • I used the example of the software kit in nrF5_sdk_for_thread_and_zigbee_v2.0_AF27F76.zip, and I used the sniffer-tracking to catch the air package in the attached two screenshots. From these two screenshots, we can determine that the Thread stops sending when it occurs for 114352 consecutive times using UDP. The MLE protocol continued to send some packets, and finally the MLE packet stopped sending. Can this information help you with debugging?

Related