I have an external GPS module connected to an nrf9151dk over UART. The module is correctly powered, and sending messages over its tx pin, which has been confirmed by attaching a logic analyzer in parallel with the dev board and seeing valid NMEA 0183 messages being sent. Despite this, and despite trying both the interrupt driven and DMA-based async api for uart, I've been unable to come up with firmware that can read any data. Below I've provided the overlay file definitions pertaining to this peripheral, and the code handling the UART device.
app.overlay
&uart1_default {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 27)>,
<NRF_PSEL(UART_RTS, 0, 16)>;
};
group2 {
psels = <NRF_PSEL(UART_RX, 0, 28)>,
<NRF_PSEL(UART_CTS, 0, 17)>;
};
};
&uart1 {
status = "okay";
compatible = "nordic,nrf-uarte";
current-speed = <9600>;
pinctrl-0 = <&uart1_default>;
pinctrl-1 = <&uart1_sleep>;
pinctrl-names = "default", "sleep";
};
prj.conf
CONFIG_SERIAL=y CONFIG_UART_ASYNC_API=y CONFIG_UART_INTERRUPT_DRIVEN=n CONFIG_TFM_SECURE_UART=n CONFIG_TFM_LOG_LEVEL_SILENCE=y
gps_uart.c:
#include "gps_uart.h"
#include <zephyr/drivers/uart.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(gnss_uart, LOG_LEVEL_DBG);
static const struct device *const uart_dev = DEVICE_DT_GET(UART_LABEL);
extern struct k_msgq nmea_queue;
#define NMEA_MAX_SIZE 83
static K_MEM_SLAB_DEFINE(uart_slab, NMEA_MAX_SIZE, 10, 4);
static void uart_callback(const struct device *dev, struct uart_event *evt,
void *user_data) {
LOG_INF("uart_callback called. ty %d", evt->type);
switch (evt->type) {
case UART_RX_RDY: {
uint8_t* buf = k_malloc(NMEA_MAX_SIZE);
memcpy(buf, evt->data.rx.buf + evt->data.rx.offset, evt->data.rx.len);
k_msgq_put(&nmea_queue, &buf, K_NO_WAIT);
break;
}
case UART_RX_BUF_REQUEST: {
uint8_t *buf;
int err = k_mem_slab_alloc(&uart_slab, (void **)&buf, K_NO_WAIT);
__ASSERT(err == 0, "Failed to allocate buffer");
LOG_INF("k_mem_slab_alloc %d", err);
err = uart_rx_buf_rsp(uart_dev, buf, NMEA_MAX_SIZE);
__ASSERT(err == 0, "Failed to provide a new buffer");
LOG_INF("buffer provided to uart driver %d", err);
break;
}
case UART_RX_BUF_RELEASED:
k_mem_slab_free(&uart_slab, (void *)evt->data.rx_buf.buf);
break;
default:
break;
}
}
int gps_uart_init() {
if (!device_is_ready(uart_dev)) {
return -1;
}
printk("Device is ready\n");
uint8_t *buf;
int rc = k_mem_slab_alloc(&uart_slab, (void **)&buf, K_NO_WAIT);
if (rc != 0) {
return rc;
}
printk("Initial buffer allocated\n");
rc = uart_callback_set(uart_dev, uart_callback, (void *)uart_dev);
if (rc != 0) {
return rc;
}
printk("uart callback set\n");
return uart_rx_enable(uart_dev, buf, NMEA_MAX_SIZE, 1e5);
}
gps_uart.h
#pragma once
#include <zephyr/kernel.h>
#define UART_LABEL DT_NODELABEL(uart0)
int gps_uart_init();
The actual UART driver code here is substantially based off the lpuart example found here.
The GPS module is sending ~10 (I haven't actually counted, but a significant number) NMEA messages every second, and yet at runtime the only UART events received by the callback are one or two buf requests, and one ready event at most.
I would appreciate any guidance as to what mistakes there may be here that are leading to the bizarre behaviour
Kaitlyn