uart_callback_set() returns ENOSYS on nRF52840dk

I'm working on implementing asynchronous UART on a nRF52840dk but uart_callback_set() is returning -88 (ENOSYS), which according to the tutorial here means it's not supported by the device.  According to the Product Specification the UART is asynchronous (via EasyDMA), so I must be doing something wrong.

My overlay:

&pinctrl {
	uart1_default: uart1_default {
	   group1 {
		  psels = <NRF_PSEL(UART_TX, 1, 2)>,
				  <NRF_PSEL(UART_RX, 1, 1)>;
	   };
	};
	/* required if CONFIG_PM_DEVICE=y */
	uart1_sleep: uart1_sleep {
	   group1 {
		  psels = <NRF_PSEL(UART_TX, 1, 2)>,
				  <NRF_PSEL(UART_RX, 1, 2)>;
		  low-power-enable;
	   };
	};
 };
 
 &uart1 {
   compatible = "nordic,nrf-uarte";
   current-speed = <38400>;
   status = "okay";
   pinctrl-0 = <&uart1_default>;
   pinctrl-1 = <&uart1_sleep>;
   pinctrl-names = "default", "sleep";
 };

My config:

# From prj.conf
CONFIG_NCS_SAMPLES_DEFAULTS=y

CONFIG_CONSOLE=y
CONFIG_CONSOLE_SUBSYS=y
CONFIG_CONSOLE_HANDLER=y
CONFIG_CONSOLE_GETCHAR=y

CONFIG_BT_CTLR_SDC_LLPM=y

CONFIG_BT_DEVICE_NAME="Nordic_LLPM"
CONFIG_BT=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_SMP=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_MAX_CONN=2

CONFIG_BT_SCAN=y
CONFIG_BT_SCAN_FILTER_ENABLE=y
CONFIG_BT_SCAN_UUID_CNT=1

CONFIG_BT_LATENCY=y
CONFIG_BT_LATENCY_CLIENT=y

CONFIG_BT_LL_SOFTDEVICE=y
CONFIG_BT_HCI_VS_EVT_USER=y
CONFIG_HEAP_MEM_POOL_SIZE=2048
CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=n

CONFIG_GPIO=y
CONFIG_UART_ASYNC_API=y

# From nrf52840dk_nrf52840.conf
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_REMOTE_WAKEUP=n
CONFIG_USB_DEVICE_PRODUCT="LLPM sample console"
CONFIG_USB_CDC_ACM_LOG_LEVEL_OFF=y

CONFIG_UART_CONSOLE=y #Tried commenting out
CONFIG_UART_INTERRUPT_DRIVEN=y #Tried commenting out
CONFIG_UART_LINE_CTRL=y #Tried commenting out

# Since the default LOG_MODE_MINIMAL is synchronous, it will mess with the USB
# driver/subsys. Use the deferred mode instead.
CONFIG_LOG_MODE_DEFERRED=y

Relevant code:

	printk("Starting Uart1\r\n");
    struct device *uart
	uart = DEVICE_DT_GET(DT_NODELABEL(uart1));
	if (!device_is_ready(uart)) {
		printk("Uart1 not ready!\r\n");
		return;
	}
	const struct uart_config uart_cfg = {
		.baudrate = 38400,
		.parity = UART_CFG_PARITY_NONE,
		.stop_bits = UART_CFG_STOP_BITS_1,
		.data_bits = UART_CFG_DATA_BITS_7,
		.flow_ctrl = UART_CFG_FLOW_CTRL_NONE
	};
	err = uart_configure(uart, &uart_cfg);
	if (err == -ENOSYS) {
		printk("Uart1 configure failure: %d\r\n", err);
		return;
	}
	err = uart_callback_set(uart, uart_cb, NULL);
	if (err) {
		printk("Uart1 callback set failure: %d\r\n", err);
		return;
	}
	err = uart_rx_enable(uart, rx_buf, RX_BUFF_SIZE, 50); // 50ms timeout
	if (err) {
		printk("Uart1 rx buffer enable failure: %d\r\n", err);
		return;
	}

I used the llpm application as a starting point while following the nordic academy lesson above, I'm wondering if there's maybe a conflict with the config values that were there initially?  Or I've noticed that the .dts file for the nrf52840dk is quite busy, possibly something conflicts there?  Fwiw I initially implemented polling and had it working well before I tried the asynchronous approach.  For that reason I have some confidence in my device tree.

Other than above issue, a few questions also have come to mind:

  • Should I be using drivers/uarte.h instead of drivers/uart.h because of the EasyDMA support of the chipset?  Would that be a problem if I didn't?  I only favored uart.h because most of the examples follow it
  • Does it matter if I enable CONFIG_UART_INTERRUPT_DRIVEN with the asynchronous approach?  I've tried it both ways

Thanks

Parents
  • Hello,

    You can find an overview of the 3 supported ways to access the UART peripheral here:
    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/hardware/peripherals/uart.html 

    In your case you should set CONFIG_UART_ASYNC_API=y (CONFIG_UART_INTERRUPT_DRIVEN=n) and use the api that is then supported when using async:
    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/hardware/peripherals/uart.html#uart-async-api 

    If you search through the example projects in ncs you can find several examples that use CONFIG_UART_ASYNC_API=y in prj.conf (these should also work for the nRF52840dk_nrf52840 boards you are using), such as:
    v2.1.0\zephyr\tests\drivers\uart\uart_async_api\
    v2.1.0\nrf\samples\bluetooth\peripheral_uart\

    You should only need to use #include <zephyr/drivers/uart.h> in your projects, the underlying hardware driver that will be used depending on your configuration option is not something you need to consider (this is handled by the build system depending on the config option you use). In general the dts file describe the hardware interface, while the config option choose how the software should use the hardware interface.

    Edit: Honestly I don't see a specific reason why uart_callback_set() return -88 here, so I suggest to take a look at the above examples and hopefully they will show what you may be missing. It would be good if you can share what was the problem. 

    Edit2: Looking at the implementation of uart_callback_set() it may look like the only reason why it will return -88 is when this fails:

    if (api->callback_set == NULL) {
        return -ENOSYS;
    }

    Are you sure you have made a callback function such as

    void uart_cb(const struct device *uart_dev, struct uart_event *evt, void *user_data)
    {
        /* empty for now */
    }

    Best regards,
    Kenneth

Reply
  • Hello,

    You can find an overview of the 3 supported ways to access the UART peripheral here:
    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/hardware/peripherals/uart.html 

    In your case you should set CONFIG_UART_ASYNC_API=y (CONFIG_UART_INTERRUPT_DRIVEN=n) and use the api that is then supported when using async:
    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/hardware/peripherals/uart.html#uart-async-api 

    If you search through the example projects in ncs you can find several examples that use CONFIG_UART_ASYNC_API=y in prj.conf (these should also work for the nRF52840dk_nrf52840 boards you are using), such as:
    v2.1.0\zephyr\tests\drivers\uart\uart_async_api\
    v2.1.0\nrf\samples\bluetooth\peripheral_uart\

    You should only need to use #include <zephyr/drivers/uart.h> in your projects, the underlying hardware driver that will be used depending on your configuration option is not something you need to consider (this is handled by the build system depending on the config option you use). In general the dts file describe the hardware interface, while the config option choose how the software should use the hardware interface.

    Edit: Honestly I don't see a specific reason why uart_callback_set() return -88 here, so I suggest to take a look at the above examples and hopefully they will show what you may be missing. It would be good if you can share what was the problem. 

    Edit2: Looking at the implementation of uart_callback_set() it may look like the only reason why it will return -88 is when this fails:

    if (api->callback_set == NULL) {
        return -ENOSYS;
    }

    Are you sure you have made a callback function such as

    void uart_cb(const struct device *uart_dev, struct uart_event *evt, void *user_data)
    {
        /* empty for now */
    }

    Best regards,
    Kenneth

Children
No Data
Related