I am having problems setting up UART communication between nrf9160 and nrf52840 on Thingy91.
My set up consist of a Thingy52 and a Thingy91. I am using ncs version 2.0.1.
The Thingy52 is currently running the peripheral_uart sample and seems to work as intended.
The Thingy91 is currently running the mqtt_simple sample on nrf9160 and the central_uart sample on nrf52840.
The peripheral_uart sample is built with the correct boardfile: thingy52_nrf52832.
The central_uart sample was not compatible with the correct boardfile for the nrf52-chip on Thingy91 (thingy91_nrf52840). However I got it to build with the nrf52840 DK boardfile (nrf52840dk_nrf52840). When flashing the sample built with this boardfile, it seems to work fine. The two Thingy's manage to establish a bluetooth connection and are able to send messages back and forth.
The mqtt_simple sample is built with thingy91_nrf9160_ns, which is the correct boardfile for my case. It connects successfully to our MQTT broker and is able to send and receive messages.
The missing link in my data flow is the internal communication between the nrf52840 and the nrf9160 on the Thingy91. I am trying to set up the uart0-peripheral on both chips based on the schematics. I am using the following pins as RX and TX:
On nrf9160:
RX ---> P0.23 = MCU_IF5
TX ---> P0.22 = MCU_IF4
on nrf52840:
TX ---> P0.25 = MCU_IF5
RX ---> P1.00 = MCU_IF4
This is implemented with the following overlay files:
mqtt_simple/boards/thingy91_nrf9160_ns.overlay&uart0 {
compatible = "nordic,nrf-uarte";
current-speed = <115200>;
status = "okay";
pinctrl-0 = <&uart0_default>;
pinctrl-1 = <&uart0_sleep>;
pinctrl-names = "default", "sleep";
};
&pinctrl {
uart0_default: uart0_default {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 22)>,
<NRF_PSEL(UART_RX, 0, 23)>;
};
};
uart0_sleep: uart0_sleep {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 22)>,
<NRF_PSEL(UART_RX, 0, 23)>;
};
};
};
central_uart/boards/nrf52840dk_nrf52840.overlay&uart0 {
compatible = "nordic,nrf-uarte";
status = "okay";
current-speed = <115200>;
pinctrl-0 = <&uart0_default>;
pinctrl-1 = <&uart0_sleep>;
pinctrl-names = "default", "sleep";
};
&pinctrl {
uart0_default: uart0_default {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 25)>,
<NRF_PSEL(UART_RX, 1, 0)>;
};
};
uart0_sleep: uart0_sleep {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 25)>,
<NRF_PSEL(UART_RX, 1, 0)>;
};
};
};
I have not made any major changes to the central_uart sample, as it already implements the UART async api. The device is linked to uart0.
In the mqtt_simple sample I have tried to implement async uart similar to how it is implemented in the central_uart_sample. The init rutine succeeds and so does the uart_tx, but none of the messages are received by the other part.
Here is my UART module, added to the mqtt_simple sample:
#include "uart.h" #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/logging/log.h> #include <zephyr/drivers/uart.h> #define LOG_MODULE_NAME uart LOG_MODULE_REGISTER(LOG_MODULE_NAME); /* UART payload buffer element size. */ #define UART_BUF_SIZE 20 #define UART_WAIT_FOR_BUF_DELAY K_MSEC(50) #define UART_RX_TIMEOUT 50 static const struct device *uart; // = DEVICE_DT_GET(DT_NODELABEL(uart0)); static struct k_work_delayable uart_work; static void uart_work_handler(struct k_work *item); static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data); struct uart_data_t { void *fifo_reserved; uint8_t data[UART_BUF_SIZE]; uint16_t len; }; static K_FIFO_DEFINE(fifo_uart_tx_data); static K_FIFO_DEFINE(fifo_uart_rx_data); static struct k_fifo * p_fifo_uart_tx_data; static struct k_fifo * p_fifo_uart_rx_data; int uart_init(struct k_fifo * p_tx_fifo, struct k_fifo * p_rx_fifo) { int err; p_fifo_uart_tx_data = p_tx_fifo; p_fifo_uart_rx_data = p_rx_fifo; struct uart_data_t *rx; uart = device_get_binding("UART_0"); if (!device_is_ready(uart)) { LOG_ERR("UART device not ready"); return -ENODEV; } LOG_INF("UART device ready"); rx = k_malloc(sizeof(*rx)); if (rx) { rx->len = 0; } else { return -ENOMEM; } k_work_init_delayable(&uart_work, uart_work_handler); err = uart_callback_set(uart, uart_cb, NULL); if (err) { return err; } return uart_rx_enable(uart, rx->data, sizeof(rx->data), UART_RX_TIMEOUT); } static void uart_work_handler(struct k_work *item) { struct uart_data_t *buf; buf = k_malloc(sizeof(*buf)); if (buf) { buf->len = 0; } else { LOG_WRN("Not able to allocate UART receive buffer"); k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY); return; } uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT); } void uart_tx_data_received(const uint8_t *data, uint16_t len) { int err; LOG_INF("In uart_tx_data_received()"); for (uint16_t pos = 0; pos != len;) { struct uart_data_t *tx = k_malloc(sizeof(*tx)); if (!tx) { LOG_WRN("Not able to allocate UART send data buffer"); } /* Keep the last byte of TX buffer for potential LF char. */ size_t tx_data_size = sizeof(tx->data) - 1; if ((len - pos) > tx_data_size) { tx->len = tx_data_size; } else { tx->len = (len - pos); } memcpy(tx->data, &data[pos], tx->len); pos += tx->len; /* Append the LF character when the CR character triggered * transmission from the peer. */ if ((pos == len) && (data[len - 1] == '\r')) { tx->data[tx->len] = '\n'; tx->len++; } LOG_INF("Transmitting UART data!"); err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS); if (err) { LOG_WRN("uart_tx() failed"); k_fifo_put(&fifo_uart_tx_data, tx); } } } static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data) { ARG_UNUSED(dev); static size_t aborted_len; struct uart_data_t *buf; static uint8_t *aborted_buf; static bool disable_req; switch (evt->type) { case UART_TX_DONE: LOG_DBG("UART_TX_DONE"); if ((evt->data.tx.len == 0) || (!evt->data.tx.buf)) { return; } if (aborted_buf) { buf = CONTAINER_OF(aborted_buf, struct uart_data_t, data); aborted_buf = NULL; aborted_len = 0; } else { buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t, data); } k_free(buf); buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT); if (!buf) { return; } if (uart_tx(uart, buf->data, buf->len, SYS_FOREVER_MS)) { LOG_WRN("Failed to send data over UART"); } break; case UART_RX_RDY: LOG_DBG("UART_RX_RDY"); buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data); buf->len += evt->data.rx.len; if (disable_req) { return; } if ((evt->data.rx.buf[buf->len - 1] == '\n') || (evt->data.rx.buf[buf->len - 1] == '\r')) { disable_req = true; uart_rx_disable(uart); } break; case UART_RX_DISABLED: LOG_DBG("UART_RX_DISABLED"); disable_req = false; buf = k_malloc(sizeof(*buf)); if (buf) { buf->len = 0; } else { LOG_WRN("Not able to allocate UART receive buffer"); k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY); return; } uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT); break; case UART_RX_BUF_REQUEST: LOG_DBG("UART_RX_BUF_REQUEST"); buf = k_malloc(sizeof(*buf)); if (buf) { buf->len = 0; uart_rx_buf_rsp(uart, buf->data, sizeof(buf->data)); } else { LOG_WRN("Not able to allocate UART receive buffer"); } break; case UART_RX_BUF_RELEASED: LOG_DBG("UART_RX_BUF_RELEASED"); buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t, data); if (buf->len > 0) { k_fifo_put(&fifo_uart_rx_data, buf); } else { k_free(buf); } break; case UART_TX_ABORTED: LOG_DBG("UART_TX_ABORTED"); if (!aborted_buf) { aborted_buf = (uint8_t *)evt->data.tx.buf; } aborted_len += evt->data.tx.len; buf = CONTAINER_OF(aborted_buf, struct uart_data_t, data); uart_tx(uart, &buf->data[aborted_len], buf->len - aborted_len, SYS_FOREVER_MS); break; default: break; } }
I am also attaching both of my pr.conf in case there is something missing there.
prj.conf on nrf9160 (with mqtt_simple):
#
# Copyright (c) 2020 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
# Networking
CONFIG_NETWORKING=y
CONFIG_NET_NATIVE=n
CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
# LTE link control
CONFIG_LTE_LINK_CONTROL=y
CONFIG_LTE_AUTO_INIT_AND_CONNECT=n
# Modem library
CONFIG_NRF_MODEM_LIB=y
# MQTT
CONFIG_MQTT_LIB=y
CONFIG_MQTT_LIB_TLS=n
CONFIG_MODEM_KEY_MGMT=y
CONFIG_MQTT_CLEAN_SESSION=y
# Application
CONFIG_MQTT_PUB_TOPIC="CriticAlert/DevText"
CONFIG_MQTT_SUB_TOPIC="CriticAlert/WebText"
CONFIG_MQTT_CLIENT_ID="T91-U1"
CONFIG_MQTT_BROKER_HOSTNAME="62.92.148.234"
CONFIG_MQTT_BROKER_PORT=1883
CONFIG_BUTTON_EVENT_PUBLISH_MSG="Hello from nrf9160"
CONFIG_MQTT_RECONNECT_DELAY_S=30
CONFIG_LTE_CONNECT_RETRY_DELAY_S=10
# Button support
CONFIG_DK_LIBRARY=y
# Enable logging
CONFIG_LOG=y
CONFIG_MQTT_SIMPLE_LOG_LEVEL_DBG=y
# Memory
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_HEAP_MEM_POOL_SIZE=2048
# NewLib C
CONFIG_NEWLIB_LIBC=y
# Config logger
CONFIG_LOG=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_LOG_BACKEND_UART=n
# CONFIG_NET_LOG=y
# CONFIG_MQTT_LOG_LEVEL_DBG=y
# Enable the UART driver
CONFIG_UART_ASYNC_API=y
CONFIG_NRFX_UARTE0=y
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_UART_LOG_LEVEL_DBG=y
prj.conf on nrf52840 (with central_uart):#
# Copyright (c) 2018 Nordic Semiconductor
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
# Enable the UART driver
CONFIG_UART_ASYNC_API=y
CONFIG_NRFX_UARTE0=y
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
# Enable the BLE stack with GATT Client configuration
CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_SMP=y
CONFIG_BT_GATT_CLIENT=y
# Enable the BLE modules from NCS
CONFIG_BT_NUS_CLIENT=y
CONFIG_BT_SCAN=y
CONFIG_BT_SCAN_FILTER_ENABLE=y
CONFIG_BT_SCAN_UUID_CNT=1
CONFIG_BT_GATT_DM=y
CONFIG_HEAP_MEM_POOL_SIZE=2048
# This example requires more workqueue stack
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
# Enable bonding
CONFIG_BT_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SETTINGS=y
# Config logger
CONFIG_LOG=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_LOG_BACKEND_UART=n
CONFIG_ASSERT=y
CONFIG_UART_LOG_LEVEL_DBG=y
I really hope you can help me out here! Let me know if there is any more information you would like me to provide.
Best regards,
Tonja