can't seem to see Rx for either UART0 or UART2

Hello,

I'm trying to see serial data (polling async method) coming from a single-wire signal.  I have verified via an oscilloscope that there is indeed data on that wire.  However I when I plug the wire into the GPIO Rx (for both UART0 and UART2), I see nothing triggering the callback that RX is ready.  There is no flow control

Here are the specifics:

From Uart.C:

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:
            //printk("Tx sent %d bytes\n", evt->data.tx.len);
            break;

        case UART_TX_ABORTED:
            printk("Error: Tx aborted\n\r");
            break;

        case UART_RX_RDY: {
            struct uart_event_rx *pRX = &evt->data.rx;
            size_t length = 0;
            size_t offset = 0;

            struct event_item event = { 0 };
            event.data = NULL;
            event.uart = uart;
            offset =  pRX->offset;
            length = pRX->len;
            printk("Received %d bytes (%s)\n\r", pRX->len, (const char *)&pRX->buf[offset]);
#if 0
            event.data = k_calloc(length, 1);
            memcpy(event.data, (char *)&pRX->buf[offset],  length - 1);
            //printk("Received data %d bytes  (%s)\n", length - 1, (char *)event.data);
            err = k_msgq_put(&event_msgq, &event, K_NO_WAIT);
            if (err) {
                /* Failed to put event into queue */
                k_free(event.data);
            }
#endif
            break;
        }
        case UART_RX_BUF_REQUEST:
        {
            uint8_t *buf;
            //printk("allocating memory\n");
            err = k_mem_slab_alloc(&uart_slab, (void **)&buf, K_NO_WAIT);
            __ASSERT(err == 0, "Failed to allocate slab");

            //printk("setting up buffer response.\n");
            err = uart_rx_buf_rsp(uart, buf, BUF_SIZE);
            __ASSERT(err == 0, "Failed to provide new buffer");
            break;
        }

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

        case UART_RX_DISABLED:
            printk("Rx Disabled.\n");
            break;

        case UART_RX_STOPPED:
            printk("Rx Stopped.\n");
            break;
    }
}

From prj.conf:

CONFIG_THREAD_MONITOR=y
CONFIG_NRF_MODEM_LIB=y                # implies CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_NRF_MODEM_LIB_SYS_INIT=n       # The application will take care of initializing Modem in main.c

CONFIG_NETWORKING=y
CONFIG_NET_SOCKETS=y                  # Will provide BSD name support. e.g. setsockopt() instead of nrf_setsockopt()
CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_NET_NATIVE=n                   # We are using socket offload, so set this to no

CONFIG_BUILD_WITH_TFM=y

# Memory size for k_malloc()
CONFIG_HEAP_MEM_POOL_SIZE=4096
# 4096 is the default
CONFIG_MAIN_STACK_SIZE=8192           

CONFIG_MODEM_KEY_MGMT=y               # Application wants to make calls to store keys
CONFIG_LTE_LINK_CONTROL=y             # Enable the API's to setup and configure the LTE link
CONFIG_LTE_AUTO_INIT_AND_CONNECT=n    # The application will take care of initializing the LTE stuff in main.c

CONFIG_NEWLIB_LIBC=y                  # Use the "new" libc
CONFIG_SAMPLE_TFM_MBEDTLS=y

CONFIG_CJSON_LIB=y
CONFIG_HTTP_CLIENT=y

# MbedTLS and security
CONFIG_NORDIC_SECURITY_BACKEND=y            # Required when commenting out BUILD_WITH_TFM
CONFIG_MBEDTLS_VANILLA_BACKEND=y
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y
CONFIG_NET_SOCKETS_OFFLOAD_TLS=n
CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=8192
CONFIG_MBEDTLS_HEAP_SIZE=44000
CONFIG_MBEDTLS_TLS_LIBRARY=y
CONFIG_MBEDTLS_PKCS1_V15=y
CONFIG_MBEDTLS_RSA_C=y
CONFIG_MBEDTLS=y                              # Required when commenting out CONFIG_NORDIC_SECURITY_BACKEND

CONFIG_LOG=n
CONFIG_USE_SEGGER_RTT=y
CONFIG_RTT_CONSOLE=y
CONFIG_UART_CONSOLE=n

# Event management which handles network-related events (like ip address change, or net iface up/down for examples)
# CONFIG_NET_MGMT=y
# CONFIG_NET_MGMT_EVENT=y
# CONFIG_NET_SOCKETS_NET_MGMT=y

From the conf and overlay files:

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

&uart2 {
compatible = "nordic,nrf-uarte";
	reg = < 0xa000 0x1000 >;
	interrupts = < 0xa 0x1 >;
	status = "okay";
	label = "UART_2";
	current-speed = < 0x1C200 >;
	tx-pin = < 0x00 >;
	rx-pin = < 0x01 >;
	/delete-property/ rts-pin;
	/delete-property/ cts-pin;
	/delete-property/ hw-flow-control;
};

&uart1 {
	status = "disabled";
};

// &gpiote {
//	interrupts = <13 NRF_DEFAULT_IRQ_PRIORITY>;
// };

CONFIG_TFM_SECURE_UART1=n
CONFIG_UART_ASYNC_API=y
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_NRFX_TIMER2=y
CONFIG_RESET_ON_FATAL_ERROR=n
CONFIG_TRUSTED_EXECUTION_NONSECURE=y

And for UART2 What is the GPIO config?  In one part it reads Rx is PIN 0.  In another part it reads Tx is PIN 1.

Please help.

Thanks

/Loren

Parents Reply Children
  • I certainly can!  I have another question, lol. Could you please explain the difference between SPM and TFM?  It seems that I have to use TFM for mbedtls functionality.  And according to the documentation you can use TFM instead of SPM.  Can you use both?

  • The SPM and TFM are two different implementations of separating the secure and non-secure domains. You can read about them here and here. You can not use both, but I don't see why that would be desirable.

    TF-M is fairly new, so I will have to look into how to set UART2 as non-secure using TFM.

  • Thanks Oivind.  Just to reiterate, MY project is using TFM (required for mbedtls), so I CANNOT have a spm.conf, correct?

  • Correct, please disregard that part of my original reply. I misread the config file you posted and thought you were commenting out "BUILD_WITH_TFM" (in order to use SPM).

    So see if using different pins works for UART0, and I'll look into how to configure UART2 as non-secure with TFM.

  • Hi Oivind,

    Still no success.

    My interpretations for things are as follows:

    nrf9160 has 2 uarts: UART1 and UART2.  It seems that UART1 by default is mapped to VCOM0, and UART2 by default is mapped to VCOM2.  Is this correct?

    What I did was built for the nrf9160_nrf52840 and in the overlay:

    /*
    &vcom2_pins_routing {
            status = "disabled";
    };
    */
    
    &vcom0_pins_routing {
            status = "disabled";
    };

    So to (hopefully) disable the VCOM0 and give control back to UART1.  Is this correct?

    Then on the 9160 side, I have the following in the 9160_9160_ns overlay:

    /* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */
    
    &uart0 {
    compatible = "nordic,nrf-uarte";
        status = "okay";
        label = "UART_0";
    	current-speed = < 115200 >;
    	tx-pin = < 10 >;
    	rx-pin = < 11 >;
    };
    
    /*
    &uart2 {
    compatible = "nordic,nrf-uarte";
        status = "okay";
        label = "UART_2";
    	current-speed = < 115200 >;
    	tx-pin = < 24 >;
    	rx-pin = < 23 >;
    };
    */
    
    &uart1 {
    compatible = "nordic,nrf-uarte";
        status = "okay";
        label = "UART_1";
    	current-speed = < 115200 >;
    	tx-pin = < 29 >;
    	rx-pin = < 28 >;
    };
    

    Is this overlay correct?

    Inside the nrf9160_9160_ns.conf I have:

    CONFIG_TFM_SECURE_UART1=n
    CONFIG_UART_ASYNC_API=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
    CONFIG_NRFX_TIMER2=y
    CONFIG_RESET_ON_FATAL_ERROR=n
    CONFIG_TRUSTED_EXECUTION_NONSECURE=y

    Is this conf correct?

    Lastly, my uart.c:

    #include <string.h>
    #include <zephyr.h>
    #include <drivers/uart.h>
    
    #define BUF_SIZE 4096
    static K_MEM_SLAB_DEFINE(uart_slab, BUF_SIZE, 3, 4);
    
    struct event_item {
        uint8_t id;
        void* data;
        void* uart;
    };
    
    K_MSGQ_DEFINE(event_msgq, sizeof(struct event_item), 10, 4);
    
    #define WORKQ_THREAD_STACK_SIZE 2048
    #define WORKQ_THREAD_PRIORITY   5
    
    static void data_handler_thread_fn(void)
    {
    	struct event_item event;
        int err = 0;
    
    	while (true) {
    		k_msgq_get(&event_msgq, &event, K_FOREVER);
    
    		switch (event.id) {
            case 0: {
                //printk("Thread data %d bytes  (%s)\n", strlen((char *)event.data), (char *)event.data);
                struct device *uart = event.uart;
                err = uart_tx(uart, (char *)event.data, strlen((char *)event.data), 10);
                __ASSERT(err == 0, "Failed to initiate transmission");
                break;
            }
    		default:
    			break;
    		}
    
    		k_free(event.data);
    	}
    }
    
    K_THREAD_DEFINE(data_handler, WORKQ_THREAD_STACK_SIZE,
        data_handler_thread_fn, NULL, NULL, NULL,
        K_PRIO_PREEMPT(WORKQ_THREAD_PRIORITY), 0, 0);
    
    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:
                //printk("Tx sent %d bytes\n", evt->data.tx.len);
                break;
    
            case UART_TX_ABORTED:
                printk("Error: Tx aborted\n\r");
                break;
    
            case UART_RX_RDY: {
                struct uart_event_rx *pRX = &evt->data.rx;
                size_t length = 0;
                size_t offset = 0;
                struct event_item event = { 0 };
                event.data = NULL;
                event.uart = uart;
                offset =  pRX->offset;
                length = pRX->len;
                char *buffer = k_calloc(length, 1);
                strncpy(buffer, (const char *)&pRX->buf[offset], length - 1);
                printk("Received %d bytes (%s)\n\r", pRX->len, buffer);
                k_free(buffer);
    #if 0
                event.data = k_calloc(length, 1);
                memcpy(event.data, (char *)&pRX->buf[offset],  length - 1);
                //printk("Received data %d bytes  (%s)\n", length - 1, (char *)event.data);
                err = k_msgq_put(&event_msgq, &event, K_NO_WAIT);
                if (err) {
                    /* Failed to put event into queue */
                    k_free(event.data);
                }
    #endif
                break;
            }
            case UART_RX_BUF_REQUEST:
            {
                uint8_t *buf;
                //printk("allocating memory\n");
                err = k_mem_slab_alloc(&uart_slab, (void **)&buf, K_NO_WAIT);
                __ASSERT(err == 0, "Failed to allocate slab");
    
                //printk("setting up buffer response.\n");
                err = uart_rx_buf_rsp(uart, buf, BUF_SIZE);
                __ASSERT(err == 0, "Failed to provide new buffer");
                break;
            }
    
            case UART_RX_BUF_RELEASED:
                //printk("Releasing memory");
                k_mem_slab_free(&uart_slab, (void **)&evt->data.rx_buf.buf);
                break;
    
            case UART_RX_DISABLED:
                printk("Rx Disabled.\n");
                break;
    
            case UART_RX_STOPPED:
                printk("Rx Stopped.\n");
                break;
        }
    }
    
    void async(const struct device *lpuart)
    {
        int err = 0;
        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, 10);
        __ASSERT(err == 0, "Failed to enable RX");
    
        struct uart_config cfg = {0};
        err = uart_config_get(lpuart, &cfg);
        __ASSERT(err == 0, "Failed to get config");
    
        printk("Completed async() setup.\n");
    //    unsigned char ch;
    //    while(1) {
    //        //int result = uart_poll_in(lpuart, &ch);
    //    }
    }
    
    void run_loopback(void)
    {
        const struct device *lpuart;
    
        k_msleep(1000);
    
        lpuart = device_get_binding("UART_1");
        __ASSERT(lpuart, "Failed to get the device");
    
        async(lpuart);
    }

    Is everything in this C file correct?

    The problem, Oivind is that my callback is NOT seeing any data received.  Please help!

    /Loren

Related