Communication between nrf52840 and nrf9160 on nrf9160DK over lpuart

Hello,

I'm attempting to establish communication between an nRF52840 and an nRF9160 on the nRF9160DK using LPUART. Initially, I tried using the interrupt-driven mode, but the uart_fifo_fill function only sends the packet once and then sends 0 bytes on both sides.

Next, I switched to the async mode API for LPUART by disabling the interrupt-driven mode. However, when I attempt to use uart_tx, it returns EBUSY.

Best Regards

Youssef

Parents
  • Hi Youssef,

    Can you share more about your implementation, what you are doing?

    Generally, async UART is the best option in most cases. You should enable HW counting though, which uses a TIMER and PPI (NRF_HW_ASYNC). There are also some examples using LPUART, like Low Power UART and the Connectivity bridge.

    Einar

  • i have tried to use samples lpuart and connectivity bridge but the same problem.

    My .overlay of nrf52 and nrf91 are based on hci_lpuart sample and lte_ble_getway sample :

    nrf9160dk_nrf52840.overlay :

    /* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */

    #include <nrf9160dk_nrf52840_reset_on_if5.dtsi>
    #include <nrf9160dk_uart1_on_if0_3.dtsi>

    &pinctrl {
        uart0_default_alt: uart0_default_alt {
            group1 {
                psels = <NRF_PSEL(UART_TX, 0, 5)>;
            };
        };

        uart0_sleep_alt: uart0_sleep_alt {
            group1 {
                psels = <NRF_PSEL(UART_TX, 0, 5)>;
                low-power-enable;
            };
        };

        uart1_default_alt: uart1_default_alt {
            group1 {
                psels = <NRF_PSEL(UART_TX, 0, 17)>,
                    <NRF_PSEL(UART_RX, 0, 20)>;
            };
        };

        uart1_sleep_alt: uart1_sleep_alt {
            group1 {
                psels = <NRF_PSEL(UART_TX, 0, 17)>,
                    <NRF_PSEL(UART_RX, 0, 20)>;
                low-power-enable;
            };
        };

    };

    &uart1 {
        current-speed = <1000000>;
        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";
            req-pin = <15>; /* <&interface_to_nrf9160 2 0>; */
            rdy-pin = <22>; /* <&interface_to_nrf9160 3 0>; */
        };
    };

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

    &gpiote {
        interrupts = <6 NRF_DEFAULT_IRQ_PRIORITY>;
    };

    /* Disabling uart rx pin to get low power */
    &uart0 {
        pinctrl-0 = <&uart0_default_alt>;
        pinctrl-1 = <&uart0_sleep_alt>;
        pinctrl-names = "default", "sleep";
        disable-rx;
    };

    nrf9160dk_nrf9160_ns.overlay :

    #include <nrf9160dk_nrf52840_reset_on_if5.dtsi>

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

    &gpiote {
        interrupts = <49 NRF_DEFAULT_IRQ_PRIORITY>;
    };

    &uart2 {
        current-speed = <1000000>;
        status = "okay";
        /delete-property/ hw-flow-control;

        pinctrl-0 = <&uart2_default_alt>;
        pinctrl-1 = <&uart2_sleep_alt>;
        pinctrl-names = "default", "sleep";
        lpuart: nrf-sw-lpuart {
            compatible = "nordic,nrf-sw-lpuart";
            status = "okay";
            req-pin = <21>; /* <&interface_to_nrf52840 3 0>; */
            rdy-pin = <19>; /* <&interface_to_nrf52840 2 0>; */
        };
    };

    &pinctrl {
        uart2_default_alt: uart2_default_alt {
            group1 {
                psels = <NRF_PSEL(UART_TX, 0, 18)>,
                    <NRF_PSEL(UART_RX, 0, 17)>;
            };
        };

        uart2_sleep_alt: uart2_sleep_alt {
            group1 {
                psels = <NRF_PSEL(UART_TX, 0, 18)>,
                    <NRF_PSEL(UART_RX, 0, 17)>;
                low-power-enable;
            };
        };

    };

    nrf9160dk_nrf9160_ns.conf :

    CONFIG_NRF_SW_LPUART=y
    CONFIG_NRF_SW_LPUART_INT_DRIVEN=n # to use async mode but when i use interrupt it is
    activated

    CONFIG_UART_2_ASYNC=y
    CONFIG_UART_2_INTERRUPT_DRIVEN=n
    CONFIG_UART_2_NRF_HW_ASYNC=y
    CONFIG_UART_2_NRF_HW_ASYNC_TIMER=2
    CONFIG_UART_2_NRF_TX_BUFFER_SIZE=256

    nrf9160dk_nrf52840.conf :

    # Override prj.conf defaults

    CONFIG_GPIO=y
    CONFIG_MAIN_STACK_SIZE=1024
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512
    CONFIG_BT_MAX_CONN=16
    CONFIG_BT_TINYCRYPT_ECC=n
    CONFIG_BT_CTLR_DTM_HCI=y
    CONFIG_BT_CTLR_ASSERT_HANDLER=n

    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
    CONFIG_NRF_SW_LPUART=y
    CONFIG_NRF_SW_LPUART_INT_DRIVEN=n

     main.c of nrf9160dk_nrf52840 :

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


    uint8_t tx_buffer[12] = "Hello World!";
    uint8_t rx_buffer[12];

    static void uart_callback(const struct device *dev,void *user_data)
    {
        // Gérer les événements UART ici
        if(uart_irq_update(dev) && uart_irq_is_pending(dev))
        {
            if(uart_irq_rx_ready(dev))
            {
                uint8_t buffer[1];
                uart_fifo_read(dev, buffer, 1);
                printk("Caractère reçu: %c\n", buffer[0]);
            }
            if(uart_irq_tx_ready(dev))
            {
                // Gérer les événements de transmission ici
                int ret = uart_fifo_fill(dev, "Hello World!", 12);
                if(ret <= 0)
                {
                    printk("Erreur de transmission : err : %d \n",ret);
                }else{
                    printk("%d octets transmis \n",ret);
                }

                while (uart_irq_tx_complete(dev) == 0);
                printk("Transmission terminée\n");
                uart_irq_tx_disable(dev);
            }
        }
    }

    void uart_cb(const struct device *uart_dev,
                                 struct uart_event *evt, void *user_data)
    {

        switch (evt->type) {
            case UART_TX_DONE:
                printk("Transmission terminée\n");
                break;
           
            case UART_TX_ABORTED:
                printk("Transmission annulée\n");
            case UART_RX_RDY:
                printk("Caractère reçu: %c\n", evt->data.rx.buf[0]);
                break;
           
            case UART_RX_BUF_REQUEST:
                break;

            case UART_RX_BUF_RELEASED:
                break;

            case UART_RX_DISABLED:
                break;
           
            default:
                break;
        }
    }
    int main(void)
    {
        const struct device *uart_dev = DEVICE_DT_GET(DT_NODELABEL(lpuart));

        if (!uart_dev) {
            printk("Impossible de trouver le périphérique UART\n");
            return;
        }
        if(device_is_ready(uart_dev) == false)
        {
            printk("Périphérique UART non prêt\n");
            return -1;
        }
        // to use interrupt mode
        /*uart_irq_callback_set(uart_dev, &uart_callback);
        uart_irq_rx_enable(uart_dev);

        while (1) {
            // Votre code principal ici
            uart_irq_tx_enable(uart_dev);
            k_sleep(K_MSEC(5000));
        }*/
        int ret = uart_callback_set(uart_dev,&uart_cb,NULL);
        if(ret < 0)
        {
            printk("Erreur de configuration de la callback , ret : %d\n",ret);
            return -1;
        }
        ret = uart_rx_enable(uart_dev,rx_buffer,sizeof(rx_buffer),SYS_FOREVER_US);
        if(ret < 0)
        {
            printk("Erreur de configuration de la réception , ret : %d\n",ret);
            return -1;
        }
        while (true)
        {
            ret = uart_tx(uart_dev,tx_buffer,sizeof(tx_buffer),SYS_FOREVER_US);
            if(ret < 0)
            {
                printk("Erreur de transmission , ret : %d\n",ret);
            }
            k_sleep(K_MSEC(5000));
        }
       
        return 0;
    }

    Best regards

    Youssef

  • Hi,

    That is a good point. There are a couple of other reasons you might get this as well. The simplest in that case is to check with a debugger and backtrack why you got the UART_RX_DISABLED event. If you use UARTE, the relevant implementation is in zephyr/drivers/serial/uart_nrfx_uarte.c. And you can set a breakpoint in notify_rx_disable() first to verify that it originates there. Then backtrack and see where notify_rx_disable() is called from, and so on.

  • Hi,

    I have a question: how can I determine whether I'm using UARTE or UART? In my configuration, I have enabled UART1, not UARTE1.

    Best regards,

    Youssef

  • Hi Youssef,

    My comment about UARTE was unessary. Async UART only makes sense with UARTE (as that is where you have DMA). So I expect you use that. You can check in the device tree file for your board, where most likely ouar uart1 is set to compatible with "nordic,nrf-uarte" (note the "e" in the end). But you can also just check with the debugger to see which driver you end up in to be sure (you should anyway do that to figure out the issue you are debugging now).

  • Hi Einar,

    You're right, the buffer is being filled with 100 bytes, which I didn't expect.

    How can I provide a new buffer each time the current one is filled?

    Best regards,

    Youssef

  • Hi Einar,

    It works, but I'm experiencing an unexpected delay between receiving packets from the other chip.

    For example, the nRF91 sends packets every 2000ms, but I receive them approximately every 10 seconds.

    Best regards

    Youssef

Reply Children
Related