UART tx using thingy91

Hello,

I am using uart with thingy:91 to communicate between nrf52 SoC and nrf91 SiP, i am able to receive data from nrf52 but when i try to send data to nrf52 SoC the function uart_irq_tx_ready always returns 0 "UART TX is not ready", btw I am using uart0 for both nrf52 and nrf91 and for nrf91 I am using interrupt driven mode and for nrf52 I am using async api mode.

Here is my init code for nrf91 SiP and how i try to send data:

void uart_init(void)
{
    int ret;
  if (!uart_dev) {
    LOG_ERR("UART_0 failed");
    return;
  }
  ret = uart_irq_callback_user_data_set(uart_dev, uart_cb, NULL);
  if (ret < 0)
  {
    if (ret == -ENOTSUP)
    {
      LOG_ERR("Interrupt-driven UART API support not enabled\n");
    }
    else if (ret == -ENOSYS)
    {
      LOG_ERR("UART device does not support interrupt-driven API\n");
    }
    else
    {
      LOG_ERR("Error setting UART callback: %d\n", ret);
    }
    return 0;
  }
  uart_irq_rx_enable(uart_dev);
  LOG_INF("UART initialized");
}
void send_data_to_nrf52(int64_t timestamp_unix)
{
    int ret;
    uint8_t data[8];
    int64_to_uint8_array(data, timestamp_unix);
    LOG_DBG("Sending : %x | %x | %x | %x | %x | %x | %x | %x ", data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]);
    uart_irq_tx_enable(uart_dev);
    if (!uart_irq_update(uart_dev)) {
    LOG_DBG("uart_irq_update failed");
    return;
    }
    if(uart_irq_tx_ready(uart_dev) == 0) // the issue is here always 0
    {
        LOG_ERR("UART TX not ready");
        uart_irq_tx_enable(uart_dev);
    }
    // Enable TX interrupt
   
    ret = uart_fifo_fill(uart_dev, data, sizeof(data));
    if(ret == ENOSYS || ret == ENOTSUP)
    {
        LOG_ERR("UART device does not support interrupt-driven API , error code : %d",ret);
    }
    else
    {
        LOG_INF("Data sent to nrf52 , number of bytes sent : %d",ret);
    }
    uart_irq_tx_disable(uart_dev); // disable the tx interrupt
}
Parents
  • Hi Youssef

    Have you considered using the LPUART driver instead, since you are establishing communication between two Nordic devices? 

    This driver is optimized for lower power consumption, and should be easier to interface than accessing the serial drivers directly. 

    Best regards
    Torbjørn 

  • Hi Torbjørn,

    When I tried using LPUART with the Thingy91_nrf9160ns, I encountered a build error. The error message is as follows:

    C:/ncs/v2.5.0/deps/zephyr/include/zephyr/device.h:85:41: error: '__device_dts_ord_96' undeclared here (not in a function); did you mean '__device_dts_ord_16'?
       85 | #define DEVICE_NAME_GET(dev_id) _CONCAT(__device_, dev_id)
          |                                         ^~~~~~~~~
    C:/ncs/v2.5.0/deps/zephyr/include/zephyr/toolchain/common.h:132:26: note: in definition of macro '_DO_CONCAT'
      132 | #define _DO_CONCAT(x, y) x ## y
          |                          ^
    C:/ncs/v2.5.0/deps/zephyr/include/zephyr/device.h:85:33: note: in expansion of macro '_CONCAT'
       85 | #define DEVICE_NAME_GET(dev_id) _CONCAT(__device_, dev_id)
          |                                 ^~~~~~~
    C:/ncs/v2.5.0/deps/zephyr/include/zephyr/device.h:211:37: note: in expansion of macro 'DEVICE_NAME_GET'
      211 | #define DEVICE_DT_NAME_GET(node_id) DEVICE_NAME_GET(Z_DEVICE_DT_DEV_ID(node_id))
          |                                     ^~~~~~~~~~~~~~~
    C:/ncs/v2.5.0/deps/zephyr/include/zephyr/device.h:228:34: note: in expansion of macro 'DEVICE_DT_NAME_GET'
      228 | #define DEVICE_DT_GET(node_id) (&DEVICE_DT_NAME_GET(node_id))
          |                                  ^~~~~~~~~~~~~~~~~~
    C:/ncs/v2.5.0/deps/zephyr/drivers/console/uart_console.c:40:9: note: in expansion of macro 'DEVICE_DT_GET'
       40 |         DEVICE_DT_GET(DT_CHOSEN(zephyr_console))

    here is my thingy91_nrf9160ns.overlay file : 

    / {
        chosen {
            zephyr,bt-c2h-uart=&lpuart;
        };
    };

    &uart1 {

        status = "okay";

        current-speed = <115200>;

        pinctrl-0 = <&uart1_default_alt>;

        pinctrl-1 = <&uart1_sleep_alt>;

        pinctrl-names = "default", "sleep";

        lpuart: nrf-sw-lpuart {

            compatible = "nordic,nrf-sw-lpuart";

            status = "okay";

            label = "LPUART";

            req-pin = <24>;

            rdy-pin = <25>;

        };

    };



    &uart0 {

        status = "disabled";

    };



    &gpio0 {

        status = "okay";

    };



    &gpiote {

        interrupts = <49 NRF_DEFAULT_IRQ_PRIORITY>;

    };



    &pinctrl {

        uart1_default_alt: uart1_default_alt {

            group1 {

                psels = <NRF_PSEL(UART_RX, 0, 23)>,

                    <NRF_PSEL(UART_TX, 0, 22)>,

                    <NRF_PSEL(UART_CTS, 0, 13)>,

                    <NRF_PSEL(UART_RTS, 0, 14)>;

            };

        };



        uart1_sleep_alt: uart1_sleep_alt {

            group1 {
                psels = <NRF_PSEL(UART_RX, 0, 23)>,
                    <NRF_PSEL(UART_TX, 0, 22)>,
                    <NRF_PSEL(UART_CTS, 0, 13)>,
                    <NRF_PSEL(UART_RTS, 0, 14)>;
                low-power-enable;

            };

        };

    };

    main.c file (which is based on lpuart sample):


    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/logging/log.h>
    #include <zephyr/drivers/uart.h>

    LOG_MODULE_REGISTER(app);

    #define BUF_SIZE 64
    static K_MEM_SLAB_DEFINE(uart_slab, BUF_SIZE, 3, 4);

    static void uart_irq_handler(const struct device *dev, void *context)
    {
        uint8_t buf[] = {1, 2, 3, 4, 5};

        if (uart_irq_tx_ready(dev)) {
            (void)uart_fifo_fill(dev, buf, sizeof(buf));
            uart_irq_tx_disable(dev);
        }

        if (uart_irq_rx_ready(dev)) {
            uint8_t buf[10];
            int len = uart_fifo_read(dev, buf, sizeof(buf));

            if (len) {
                printk("read %d bytes\n", len);
            }
        }
    }

    static void interrupt_driven(const struct device *dev)
    {
        uint8_t c = 0xff;

        uart_irq_callback_set(dev, uart_irq_handler);
        uart_irq_rx_enable(dev);
        while (1) {
            uart_irq_tx_enable(dev);
            k_sleep(K_MSEC(500));

            uart_poll_out(dev, c);
            k_sleep(K_MSEC(100));
        }
    }

    static void uart_callback(const struct device *dev,
                  struct uart_event *evt,
                  void *user_data)
    {
        struct device *uart = user_data;
        int err;

        switch (evt->type) {
        case UART_TX_DONE:
            LOG_INF("Tx sent %d bytes", evt->data.tx.len);
            break;

        case UART_TX_ABORTED:
            LOG_ERR("Tx aborted");
            break;

        case UART_RX_RDY:
            LOG_INF("Received data %d bytes", evt->data.rx.len);
            break;

        case UART_RX_BUF_REQUEST:
        {
            uint8_t *buf;

            err = k_mem_slab_alloc(&uart_slab, (void **)&buf, K_NO_WAIT);
            __ASSERT(err == 0, "Failed to allocate slab");

            err = uart_rx_buf_rsp(uart, buf, BUF_SIZE);
            __ASSERT(err == 0, "Failed to provide new buffer");
            break;
        }

        case UART_RX_BUF_RELEASED:
            k_mem_slab_free(&uart_slab, (void *)evt->data.rx_buf.buf);
            break;

        case UART_RX_DISABLED:
            break;

        case UART_RX_STOPPED:
            break;
        }
    }

    static void async(const struct device *lpuart)
    {
        uint8_t txbuf[5] = {1, 2, 3, 4, 5};
        int err;
        uint8_t *buf;

        err = k_mem_slab_alloc(&uart_slab, (void **)&buf, K_NO_WAIT);
        __ASSERT(err == 0, "Failed to alloc slab");

        err = uart_callback_set(lpuart, uart_callback, (void *)lpuart);
        __ASSERT(err == 0, "Failed to set callback");

        err = uart_rx_enable(lpuart, buf, BUF_SIZE, 10000);
        __ASSERT(err == 0, "Failed to enable RX");

        while (1) {
            err = uart_tx(lpuart, txbuf, sizeof(txbuf), 10000);
            __ASSERT(err == 0, "Failed to initiate transmission");

            k_sleep(K_MSEC(500));

            uart_poll_out(lpuart, txbuf[0]);
            k_sleep(K_MSEC(100));
        }
    }

    int main(void)
    {
        const struct device *lpuart = DEVICE_DT_GET(DT_NODELABEL(lpuart));

        __ASSERT(device_is_ready(lpuart), "LPUART device not ready");

        if (IS_ENABLED(CONFIG_NRF_SW_LPUART_INT_DRIVEN)) {
            interrupt_driven(lpuart);
        } else {
            async(lpuart);
        }

        return 0;
    }

    and my thingy91_nrf9160ns.conf file :

    CONFIG_NRF_SW_LPUART=y
    CONFIG_NRF_SW_LPUART_INT_DRIVEN=y

    CONFIG_UART_1_ASYNC=y
    CONFIG_UART_1_INTERRUPT_DRIVEN=n
    CONFIG_UART_1_NRF_HW_ASYNC=y
    CONFIG_UART_1_NRF_HW_ASYNC_TIMER=2

     

    Best Regards

    Youssef

  • Hi Youssef

    It seems the issue is that you still have the UART console library enabled, even though you have disabled uart0 and removed the uart console chosen definition. 

    Could you try to disable the UART console by adding the following to your project configuration? 

    CONFIG_UART_CONSOLE=n

    Best regards
    Torbjørn

Reply Children
  • Hi Torbjørn,

    I have disabled the UART console, but I am still encountering the same issue.

    Here is my prj.conf file:

    CONFIG_GPIO=y
    CONFIG_SERIAL=y
    #CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_LOG=y
    CONFIG_COREDUMP_DEVICE=y
    CONFIG_DEBUG_COREDUMP=y
    CONFIG_DEBUG_COREDUMP_BACKEND_LOGGING=y
    CONFIG_FPU=y
    CONFIG_UART_CONSOLE=n

    i tried also to disable CONFIG_SERIAL but the same problem.

    Best regards

    Youssef

  • Now, when i have activated uart0, so status = "okay" there's no error, but when i tried to send data over lpuart, the function uart_irq_handler returns 5 for the first time then it returns 0 bytes.

    here's my callback :

    static void uart_irq_handler(const struct device *dev, void *context)
    {
        uint8_t buf[] = {1, 2, 3, 4, 5};
        printk("uart_irq_handler\n");
        if (uart_irq_tx_ready(dev)) {
            int ret = uart_fifo_fill(dev, buf, sizeof(buf));
            printk("fill %d bytes\n", ret);
            uart_irq_tx_disable(dev);
        }

        if (uart_irq_rx_ready(dev)) {
            uint8_t buf[10];
            int len = uart_fifo_read(dev, buf, sizeof(buf));

            if (len) {
                printk("read %d bytes\n", len);
            }else{
                printk("no data %d bytes\n",len);
            }
        }
    }

    it returns : fill 5 bytes , then fill 0 bytes

    Best regards,

    Youssef

  • Hi Youssef

    I believe you need CONFIG_UART_INTERRUPT_DRIVEN and CONFIG_NRF_SW_LPUART_INT_DRIVEN enabled if you want to use these functions. 

    In many cases I think the ASYNC interface is more convenient. Have you tried to use this instead? 

    Best regards
    Torbjørn

  • Hi Torbjørn,

    I have already set CONFIG_UART_INTERRUPT_DRIVEN  and CONFIG_NRF_SW_LPUART_INT_DRIVEN but the same issue,

    the first image shows that the lpuart sends 8 bytes as expected for the first try, but then it sends only 0 as shown in the second image

    Send 8 bytes for the first time

    Send 0 bytes

    I have tried to use uart1 and uart 0 with async but it doesn't work, does lpuart supports async mode ?

    Best regards

    Youssef

  • Hi Torbjørn,

    Following your suggestion, I tried using UART1 in async mode for communication between the nRF52 and nRF91. However, I encountered some issues:

    1. On the nRF52 side, whenever I send data, the callback jumps to the UART_TX_ABORT case instead of UART_TX_DONE.
    2. On the nRF91 side, when I send data over UART1, the callback correctly calls UART_TX_DONE, but nothing is received on the nRF52.

    Best regards

    Youssef

Related