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

Zigbee and Serial communication issue

Hello Nordic!

I have been developing a Zigbee application and now, I need to connect via Serial communication with another device. I just need to listen to the port, not send any data. Unfortunately I don't have that device so I am simulating it with an Arduino Uno. It is configured as the original device at 19200baud, 8bit, 1 stop bit. First of al, is there any other better way to read data through RX/TX? Any other libraries instead of libuarte?

I found the libuarte example which I modified and make it work for my needs. It reads my Arduino via Serial communication correctly and I obtain the characters nicely. My problem occurs when I try to implement the libuarte code into mine. I have had several problems with the sdk_config file. But once the errors have faded out and the code have compiled, I have flashed it into the nrf52840DK board but the Zigbee and Serial communication suddenly stopped working. Could it be that they share some timer or some other peripheral?

I have tried changing the timer for the serial communication but achieved nothing. What may be causing this issue?

The modified code of the libuarte's example is as follows:

/**
 * Copyright (c) 2018 - 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 libuarte_example_main main.c
 * @{
 * @ingroup libuarte_example
 * @brief Libuarte Example Application main file.
 *
 * This file contains the source code for a sample application using libuarte.
 *
 */

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "nrf_libuarte_async.h"
#include "nrf_drv_clock.h"
#include <bsp.h>
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_queue.h"

NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 0, 0, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 3);

static uint8_t text[] = "UART example started.\r\n Loopback:\r\n";
static uint8_t text_size = sizeof(text);
static volatile bool m_loopback_phase;

typedef struct {
    uint8_t * p_data;
    uint32_t length;
} buffer_t;

NRF_QUEUE_DEF(buffer_t, m_buf_queue, 10, NRF_QUEUE_MODE_NO_OVERFLOW);

void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
{
    nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
    ret_code_t ret;

    switch (p_evt->type)
    {
        case NRF_LIBUARTE_ASYNC_EVT_ERROR:
            bsp_board_led_invert(0);
            break;
        case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
            ret = nrf_libuarte_async_tx(p_libuarte,p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
            if (ret == NRF_ERROR_BUSY)
            {
                buffer_t buf = {
                    .p_data = p_evt->data.rxtx.p_data,
                    .length = p_evt->data.rxtx.length,
                };

                ret = nrf_queue_push(&m_buf_queue, &buf);
                APP_ERROR_CHECK(ret);
            }
            else
            {
                APP_ERROR_CHECK(ret);
            }
            bsp_board_led_invert(1);
            m_loopback_phase = true;
            break;
        case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
            if (m_loopback_phase)
            {
                nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                if (!nrf_queue_is_empty(&m_buf_queue))
                {
                    buffer_t buf;
                    ret = nrf_queue_pop(&m_buf_queue, &buf);
                    APP_ERROR_CHECK(ret);
                    UNUSED_RETURN_VALUE(nrf_libuarte_async_tx(p_libuarte, buf.p_data, buf.length));
                }
            }
            bsp_board_led_invert(2);
            break;
        default:
            break;
    }
}

/**
 * @brief Function for main application entry.
 */
int main(void)
{
    bsp_board_init(BSP_INIT_LEDS);
    
    ret_code_t ret = nrf_drv_clock_init();
    APP_ERROR_CHECK(ret);
  
    nrf_drv_clock_lfclk_request(NULL);

    ret_code_t err_code = NRF_LOG_INIT(app_timer_cnt_get);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

    nrf_libuarte_async_config_t nrf_libuarte_async_config = {
            .tx_pin     = TX_PIN_NUMBER,
            .rx_pin     = RX_PIN_NUMBER,
            .baudrate   = NRF_UARTE_BAUDRATE_19200,
            .parity     = NRF_UARTE_PARITY_EXCLUDED,
            .hwfc       = NRF_UARTE_HWFC_DISABLED,
            .timeout_us = 100,
            .int_prio   = APP_IRQ_PRIORITY_LOW
    };

    err_code = nrf_libuarte_async_init(&libuarte, &nrf_libuarte_async_config, uart_event_handler, (void *)&libuarte);

    APP_ERROR_CHECK(err_code);

    nrf_libuarte_async_enable(&libuarte);

    err_code = nrf_libuarte_async_tx(&libuarte, text, text_size);
    APP_ERROR_CHECK(err_code);

    while (true)
    {
        NRF_LOG_FLUSH();
    }
}


/** @} */

Thanks to all in advance!

Cheers!

Parents
  • Hello,

    Perhaps you can look into the Zigbee CLI example found in:

    SDK_for_thread_and_zigbee_v4.1.0\examples\zigbee\experimental\cli\cli_agent_router, which is an example where a lot of the zigbee api is serialized.

    If you want to continue on the libuarte path, did you try writing something to the log? Try adding:

    NRF_LOG_INFO("starting application"); right after NRF_LOG_DEFAULT_BACKENDS_INIT(). Do you see the log anywhere? (RTT perhaps, if you are using UART for your application).

    If you see the log, does the log say anything when your application isn't working?

    BR,
    Edvin

  • Hello Edvin!

    Thanks for your quick reply!

    Could you specify a bit more what should I look at in the cli_agent_router example? The code is too short...

    About the log, I haven't had time to learn how to use the NRF_LOG so what I am using is the printf function to show some info via Debug Terminal (in Segger). May you link some information about how to use it? I guess it is more useful than the printf function that I am currently using.

    Anyway, I placed the printf function right under the NRF_LOG_DEFAULT_BACKENDS_INIT() call and it didn't show in the debug terminal... What could be causing this  issue?

    What I found is that the call to nrf_drv_clock_init() is failing, it is returning 0x85 error code. I will debug a bit more this...

    EDIT: I just found out that the error code 0x0085 means that the module is already initialized. So I think I can either remove that call or remove the call to the APP_ERROR_CHECK function. Am I right? Unfortunately the code still fails in the call to NRF_LOG_DEFAULT_BACKENDS_INIT()... I will continue to investigate this issue...

    Thanks in advance!

  • It may not be clear what this does based on the main.c file, but check the test description:

    https://infocenter.nordicsemi.com/topic/sdk_tz_v4.1.0/zigbee_example_cli_agent.html?cp=7_3_3_8_5_1_3#zigbee_example_cli_agent_testing

     

    mazis said:
    I guess it is more useful than the printf function that I am currently using.

     The reason I asked about this is that it will print the error information in the log.

    Try to run any of the examples that are already using the log, e.g. ble_app_uart (NB: You need to flash the sofdevice manually if you are not using Segger Embedded Studio). Then either open JLink RTT Viewer, or if you are using Segger Embedded Studio, then change this define in sdk_config.h from 1 to 0:

    #define NRF_FPRINTF_FLAG_AUTOMATIC_CR_ON_LF_ENABLED 1
    to
    #define NRF_FPRINTF_FLAG_AUTOMATIC_CR_ON_LF_ENABLED 0

    and click "build and debug".

    Then look at how this is set up in that project, and try to do the same in your project. If you get the log up and running it is a useful tool for debugging, since the error handler will print errors in the log. Please define DEBUG in your preprocessor definitions to see extra logging information from the error handler. Let me know what IDE you are using if you don't know how to add preprocessor definitions.

    mazis said:
    Anyway, I placed the printf function right under the NRF_LOG_DEFAULT_BACKENDS_INIT() call and it didn't show in the debug terminal... What could be causing this  issue?

    I am not sure. printf doesn't use the NRF_LOG.

     

    mazis said:
    EDIT: I just found out that the error code 0x0085 means that the module is already initialized. So I think I can either remove that call or remove the call to the APP_ERROR_CHECK function. Am I right? Unfortunately the code still fails in the call to NRF_LOG_DEFAULT_BACKENDS_INIT()... I will continue to investigate this issue...

     Perhaps you are trying to use the UART for both NRF_LOG and printf (not possible). Try to set the RTT backend in sdk_config.h. If you don't know how to do it, see ble_app_uart's sdk_config.h file (since it uses the RTT backend for logging by default). 

  • Hello Edvin!

    I'm using Segger and I've got NRF_LOG working. I am going to change all my printf functions to NRF_LOG_INFO and NRF_LOG_ERROR. 

    I have been reading and understanding the cli_agent code but I have some doubts about it. The cli_agent uses the nrf_drv_uart libraries and macros. I just need to read the serial port and wait for a specific string to arrive. I thought about using interruptions for that, so I think I don't need to implement DMA. Am I right? Do you recommend using it anyway? What are the differences between the nrf_drv_uart and libuarte libraries?

    Thanks!

    Cheers!

Reply
  • Hello Edvin!

    I'm using Segger and I've got NRF_LOG working. I am going to change all my printf functions to NRF_LOG_INFO and NRF_LOG_ERROR. 

    I have been reading and understanding the cli_agent code but I have some doubts about it. The cli_agent uses the nrf_drv_uart libraries and macros. I just need to read the serial port and wait for a specific string to arrive. I thought about using interruptions for that, so I think I don't need to implement DMA. Am I right? Do you recommend using it anyway? What are the differences between the nrf_drv_uart and libuarte libraries?

    Thanks!

    Cheers!

Children
  • Hello,

    Sorry for the late reply. I have been out of office for the last 8 days. 

    Just to sort out a couple of things. If the NRF_LOG is using the UART backend, then I think you will have a hard time reading the UART, because it is occupied by the log module. But in this example, the log uses the RTT backend.

     

    mazis said:
    What are the differences between the nrf_drv_uart and libuarte libraries?

     the libuarte is tailored for fast UART transfers. If it is not very fast, I suggest you stick to the nrf_drv_uart. 

    I suggest you check out the ble_app_uart example from the SDK. This doesn't use Zigbee, but perhaps you can get some inspiration from the UART handler in that example.

    Alternatively, you can add the commands you need in the pool of CLI commands. Look at how it sets up the CLI commands. That is why I initially mentioned the CLI example.

    BR,
    Edvin

  • Hello Edvin!

    I finally made it, I have the Serial communication working but I still have some doubts...

    - I receive data via Serial correctly but sometimes I get some communication errors. The most frequent is the error code 1. What does it mean? Where can I find a table/list of the error codes and the associated explanation?

    - When I set the Serial communication, the BLE stops working. I remember seeing something about RTT in my sdk_config file, is this related?. What may be causing this issue? Right now it's not a big problem but I will need to implement BLE in the future so I need to fix this.

    - I also had to delete the APP_ERROR_HANDLER call in the APP_UART_COMMUNICATION_ERROR case in uart_event_handle() function when an error occurs because it was stopping my code. I will have to handle the errror codes manually. For me, there is no problem, but for the board? Is it better to use the error_handler or the error_check than to do it manually?

    Thanks for all your help. As you said, the ble_app_uart gave me the inspiration I needed. OOnce I've cleared my doubts, I will verify the answer and finish this thread.

    Thanks again!

    Cheers!

  • Hi Alejandro,

    Edvin is on leave so I am taking over this thread and will try to assist you. I am not an expert in Zigbee, but I have good understanding on the UART related issues which hopefully will be useful in this case.

    mazis said:
    - I receive data via Serial correctly but sometimes I get some communication errors. The most frequent is the error code 1. What does it mean? Where can I find a table/list of the error codes and the associated explanation?

    I think what you are seeing is somewhat similar to this error. There was a bug where the communication which does not translate the internal hardware error src to library specific error. Probably you should figure out what this error was and how to handle this specific error in your case. 

     

    mazis said:
    - I also had to delete the APP_ERROR_HANDLER call in the APP_UART_COMMUNICATION_ERROR case in uart_event_handle() function when an error occurs because it was stopping my code. I will have to handle the errror codes manually. For me, there is no problem, but for the board? Is it better to use the error_handler or the error_check than to do it manually?

    It is good idea that you handle this errors manually but I recommend you to do it inside the error_handler to make it architecturally same as before.

     

    mazis said:
    Thanks for all your help. As you said, the ble_app_uart gave me the inspiration I needed. OOnce I've cleared my doubts, I will verify the answer and finish this thread.

     Thanks for the kind words and again sorry for the late reply.

  • Hello Susheel!

    From what I read, the problem is that I am not reading the registers fast enough, right? I am not using the FIFO rergister, I don't know if that is relevant. Anyway, I will try to fix it as soon as possible. What do you think is the best approach to solve the issue?

    It is good idea that you handle this errors manually but I recommend you to do it inside the error_handler to make it architecturally same as before.

    What do you mean? Modify the SDK API error_handler function? Would you mind elaborate on this a bit more? I find it pretty interesting to me.

    Furthermore, did you see the last comment I posted? The one below me about the issue with Zigbee and BLE.

    Cheers!

  • mazis said:
    From what I read, the problem is that I am not reading the registers fast enough, right? I am not using the FIFO rergister, I don't know if that is relevant. Anyway, I will try to fix it as soon as possible. What do you think is the best approach to solve the issue?

     Use flow control if possible (change NRF_UARTE_HWFC_DISABLED to NRF_UARTE_HWFC_ENABLED)

    Also try with application uart priority APP_IRQ_PRIORITY_HIGH instead of APP_IRQ_PRIORITY_LOW.

    I think that you are doing a lot of uart post processing, which is causing the hardware FIFO to overflow causing overrun errors. Enabling hardware flow control will greatly reduce the chance of this overrun error. 

     

    mazis said:
    What do you mean? Modify the SDK API error_handler function? Would you mind elaborate on this a bit more? I find it pretty interesting to me.

     No need to change any SDK API, what I mean to say is that when you get any errors and your application is notified using NRF_DRV_UART_EVT_ERROR, then you need to handle it properly. Sometimes you might have to read an extra char from the FIFO to restart the state machine of the underlying driver. Please look at other examples in the SDK that handle this NRF_DRV_UART_EVT_ERROR event.

     

    mazis said:
    Furthermore, did you see the last comment I posted? The one below me about the issue with Zigbee and BLE.

    Not really, that is strange, can you repost the question about Zigbee and BLE? I do not find your specific question regarding the issue with this combo. 

Related