Adafruit Feather nRF52840 UART config incorrect

I have an Adafruit Feather nRF52840 which I'm trying to use to transmit data over a UART serial connection to a Raspberry Pi. The Raspberry Pi is running a Python test script (details below) which configures its serial port per the MIDI specification which says:

"The hardware MIDI interface operates at 31.25 (+/- 1%) Kbaud, asynchronous, with a start bit, 8 data bits (D0 to D7), and a stop bit. This makes a total of 10 bits for a period of 320 microseconds per serial byte. The start bit is a logical 0 (current on) and the stop bit is a logical 1 (current off)".

My Zephyr code configures the nRF52840 in the same way. I then send 8 bytes with known values. The Raspberry Pi script prints what it receives to the console.

The Pi is printing 5 times more bytes than are being transmitted and the byte values bear no resemblance to those that were transmitted. I believe this is indicative of a mismatch between the UART configs on the transmitting nRF52840 and the Pi.

Here's the Raspberry Pi receiver script:

import serial

ser = serial.Serial('/dev/ttyAMA0', baudrate=31250)

while True:

  data = ord(ser.read(1))
  print("Decimal: "+str(data)+"\t\tBinary: "+format(data,'008b')+"\t\tHex: 0x"+format(data,'02x'))

Note that I validated the Python script by connecting a commercial MIDI keyboard directly to the Pi and pressing a key (note=F3). The results were as expected and are presented here:

MIDI Keyboard sending NOTE ON then NOTE OFF to the Receiver (key played, F3)
Decimal: 144            Binary: 10010000                Hex: 0x90
Decimal: 65             Binary: 01000001                Hex: 0x41
Decimal: 52             Binary: 00110100                Hex: 0x34
Decimal: 128            Binary: 10000000                Hex: 0x80
Decimal: 65             Binary: 01000001                Hex: 0x41
Decimal: 59             Binary: 00111011                Hex: 0x3b

NOTE ON  is 1001nnnn 0kkkkkkk 0vvvvvvv where n is the channel, k is the note number and v is the velocity value.
NOTE OFF is 1000nnnn 0kkkkkkk 0vvvvvvv where n is the channel, k is the note number and v is the velocity value.

So the data received:
10010000    01000001    00110100 - NOTE ON  (channel 1), note=F3, velocity=52
10000000    01000001    00111011 - NOTE OFF (channel 1), note=F3, velocity=59

Results are as expected. Python script validated.

Here's my Zephyr code:

// C code
#include <zephyr/kernel.h>
#include <zephyr/drivers/uart.h>
#include <math.h>

/* Get UART1 device */
static const struct device *uart = DEVICE_DT_GET(DT_NODELABEL(uart1));

// 1200, 2400, 4800, 9600, 19200, 31250, 57600, 115200
#define BAUDRATE 31250

int main(void)
{
    printk("uart_tx_text V1.3 - baudrate=%d\n",BAUDRATE);

    if (!device_is_ready(uart)) {
            printk("ERROR: uart1 is not ready\n");
            return -1;
    }

    printk("UART1 is ready\n");
	/* UART configuration */
	const struct uart_config uart_cfg = {
		.baudrate = BAUDRATE,
		.parity = UART_CFG_PARITY_NONE,
		.stop_bits = UART_CFG_STOP_BITS_1,
		.data_bits = UART_CFG_DATA_BITS_8,
		.flow_ctrl = UART_CFG_FLOW_CTRL_NONE
	};

    int ret = uart_configure(uart, &uart_cfg);
    if (ret < 0) {
            printk("ERROR configuring UART: %d",ret);
            return ret;
    }

    printk("UART1 has been configured - start receiver now\n");

    k_msleep(10000);

    int p=0;
    for (p=1; p<9;p++) {
        uint8_t val=(pow(2,p)-1);
        uart_poll_out(uart, val);
        printk("TX Decimal: %d Hex: %02x\n",val, val);          
    }

    return 0;
}


// DTS overlay

/*
 * Copyright (c) 2025
 * SPDX-License-Identifier: Apache-2.0
 */

&uart1 {
	compatible = "nordic,nrf-uarte";
	status = "okay";
	current-speed = <31250>;
	pinctrl-0 = <&uart1_default>;
	pinctrl-1 = <&uart1_sleep>;
	pinctrl-names = "default", "sleep";
};

&pinctrl {
	uart1_default: uart1_default {
		group1 {
			psels = <NRF_PSEL(UART_TX, 1, 10)>;
		};
		group2 {
			psels = <NRF_PSEL(UART_RX, 1, 9)>; 
			bias-pull-up;
		};
	};

	uart1_sleep: uart1_sleep {
		group1 {
			psels = <NRF_PSEL(UART_TX, 1, 10)>,
				<NRF_PSEL(UART_RX, 1, 9)>;
			low-power-enable;
		};
	};
};

// prj.conf

CONFIG_GPIO=y
CONFIG_SERIAL=y

CONFIG_UART_USE_RUNTIME_CONFIGURE=y

CONFIG_LOG=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_SEGGER_RTT_PRINTF_BUFFER_SIZE=512

And here are my test results:

// output from the Adafruit Feather nRF52840
00> *** Booting nRF Connect SDK v3.1.1-e2a97fe2578a ***
00> *** Using Zephyr OS v4.1.99-ff8f0c579eeb ***
00> uart_tx_text V1.3 - baudrate=31250
00> UART1 is ready
00> UART1 has been configured - start receiver now
00> TX Decimal: 1 Hex: 01
00> TX Decimal: 3 Hex: 03
00> TX Decimal: 7 Hex: 07
00> TX Decimal: 15 Hex: 0f
00> TX Decimal: 31 Hex: 1f
00> TX Decimal: 63 Hex: 3f
00> TX Decimal: 127 Hex: 7f
00> TX Decimal: 255 Hex: ff

// Output from the Raspberry Pi receiver script
Receiver:
Decimal: 129            Binary: 10000001                Hex: 0x81
Decimal: 78             Binary: 01001110                Hex: 0x4e
Decimal: 198            Binary: 11000110                Hex: 0xc6
Decimal: 39             Binary: 00100111                Hex: 0x27
Decimal: 237            Binary: 11101101                Hex: 0xed
Decimal: 136            Binary: 10001000                Hex: 0x88
Decimal: 139            Binary: 10001011                Hex: 0x8b
Decimal: 200            Binary: 11001000                Hex: 0xc8
Decimal: 220            Binary: 11011100                Hex: 0xdc
Decimal: 107            Binary: 01101011                Hex: 0x6b
Decimal: 239            Binary: 11101111                Hex: 0xef
Decimal: 11             Binary: 00001011                Hex: 0x0b
Decimal: 224            Binary: 11100000                Hex: 0xe0
Decimal: 220            Binary: 11011100                Hex: 0xdc
Decimal: 107            Binary: 01101011                Hex: 0x6b
Decimal: 239            Binary: 11101111                Hex: 0xef
Decimal: 11             Binary: 00001011                Hex: 0x0b
Decimal: 224            Binary: 11100000                Hex: 0xe0
Decimal: 196            Binary: 11000100                Hex: 0xc4
Decimal: 107            Binary: 01101011                Hex: 0x6b
Decimal: 207            Binary: 11001111                Hex: 0xcf
Decimal: 11             Binary: 00001011                Hex: 0x0b
Decimal: 113            Binary: 01110001                Hex: 0x71
Decimal: 198            Binary: 11000110                Hex: 0xc6
Decimal: 107            Binary: 01101011                Hex: 0x6b
Decimal: 207            Binary: 11001111                Hex: 0xcf
Decimal: 11             Binary: 00001011                Hex: 0x0b
Decimal: 224            Binary: 11100000                Hex: 0xe0
Decimal: 198            Binary: 11000110                Hex: 0xc6
Decimal: 59             Binary: 00111011                Hex: 0x3b
Decimal: 207            Binary: 11001111                Hex: 0xcf
Decimal: 3              Binary: 00000011                Hex: 0x03
Decimal: 232            Binary: 11101000                Hex: 0xe8
Decimal: 198            Binary: 11000110                Hex: 0xc6
Decimal: 59             Binary: 00111011                Hex: 0x3b
Decimal: 207            Binary: 11001111                Hex: 0xcf
Decimal: 139            Binary: 10001011                Hex: 0x8b
Decimal: 232            Binary: 11101000                Hex: 0xe8
Decimal: 228            Binary: 11100100                Hex: 0xe4
Decimal: 255            Binary: 11111111                Hex: 0xff

My UART config params look correct in my Zephyr C code and I am not getting an error when I call uart_configure. And yet the evidence would suggest that the configuration is not being set as requested. The transmitting nRF52840 and receiving Pi are presumably not using the same parameters which is why the Pi reports nonsense results.

Note that this Pi has been used for MIDI applications many times before and is therefore a reliable, known quantity. My validation test also verifies that the problem is not at the receiver end of the communication.

Could someone please help with this? Is this a Zephyr bug? Or is it my code?

Thanks in anticipation

Parents
  • Looking at the file zephyr/boards/adafruit/feather_nrf52840/adafruit_feather_nrf52840.dts on the Adafruit Feather nRF52840, the only pinned UART is uart0 on NRF_PSEL(UART_TX, 0, 25) and NRF_PSEL(UART_RX, 0, 24). I think the uart1 is not routed to the header, so in your overlay you ended up configuring a UART that isn’t actually connected to your wires. That most likely is giving you the garbage at 5x the expected length just because the PI is sampling noise, nothing else.

    use uart0 instead of uart1 and see if you see the same issue. Route the logs to the RTT instead of uart0 so that uart0 is available to your use

    CONFIG_UART_CONSOLE=n
    CONFIG_SERIAL=y
    CONFIG_LOG=y
    CONFIG_LOG_BACKEND_RTT=y 
    

    If uart1 is brought out to a header, is something not very clear to me. 

  • Hi Susheel, thanks for looking into this. I think you're right in that uart0 should be used. I switched to uart1 after seeing one of your colleagues use it in a previous support request. See  RE: UART config rejected with error -134 

    But I now realise they were probably using a different board.

    I also see the DeviceTree view in VS Code showing this quite clearly:

    I've changed my code and included the config properties you recommended but unfortunately I'm now seeing nothing received at all. I've checked connections and see no issue at the hardware level at this stage and it was working before.

    /*
     * Copyright (c) 2025
     * SPDX-License-Identifier: Apache-2.0
     */
    
    &uart0 {
    	compatible = "nordic,nrf-uarte";
    	status = "okay";
    	current-speed = <31250>;
    	pinctrl-0 = <&uart0_default>;
    	pinctrl-1 = <&uart0_sleep>;
    	pinctrl-names = "default", "sleep";
    };
    
    &pinctrl {
    	uart0_default: uart0_default {
    		group1 {
    			psels = <NRF_PSEL(UART_TX, 1, 10)>;
    		};
    		group2 {
    			psels = <NRF_PSEL(UART_RX, 1, 9)>; 
    			bias-pull-up;
    		};
    	};
    
    	uart0_sleep: uart0_sleep {
    		group1 {
    			psels = <NRF_PSEL(UART_TX, 1, 10)>,
    				<NRF_PSEL(UART_RX, 1, 9)>;
    			low-power-enable;
    		};
    	};
    };

    FYI before I switched to using Zephyr I was using CircuitPython and communication was working perfectly with this simple code:

    import time
    import board
    import busio
    import digitalio
    
    uart = busio.UART(board.TX, board.RX, baudrate=31250)
    
    noteON = [144, 48, 100]
    noteOFF = [128, 48, 100]
    
    while True:
        uart.write(bytes(noteON))
        print("note on")
        time.sleep(2)
    
        uart.write(bytes(noteOFF))
        print("note off")
        time.sleep(2)

    So, the hardware is definitely capable of supporting this.

    Any other ideas?

    Thanks in anticipation

  • Yes, I believe this to be the case. As I explained at the start, the serial config I'm trying to use is defined by the MIDI specification. I have commercial MIDI products like keyboards which use this specification and when I plug one of them into the Raspberry Pi and (say) press and release a key, I see exactly the six bytes I expect to see (three for NOTE ON and three for NOTE OFF).

    // Python
    
    import serial
    
    ser = serial.Serial('/dev/ttyAMA0', baudrate=31250)
    
    while True:
    
      data = ord(ser.read(1))
      print("Decimal: "+str(data)+"\t\tBinary: "+format(data,'008b')+"\t\tHex: 0x"+format(data,'02x'))
    
    
    // MIDI data from commercial keyboard - results as expected
    
    Decimal: 232            Binary: 11101000                Hex: 0xe8
    Decimal: 222            Binary: 11011110                Hex: 0xde
    Decimal: 211            Binary: 11010011                Hex: 0xd3
    Decimal: 224            Binary: 11100000                Hex: 0xe0
    Decimal: 222            Binary: 11011110                Hex: 0xde
    Decimal: 221            Binary: 11011101                Hex: 0xdd
    
    

    This verifies that the Raspberry Pi and Python code are using the serial interface the correct way and it is this config that I am trying to use on the Adafruit Feather.

    FYI the constructor spec for the Serial Python class indicates default parameter values that meet the requirements apart from baud rate, hence it being specified explicitly:

    __init__(port=None, baudrate=9600, bytesize=EIGHTBITS, parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=None, xonxoff=False, rtscts=False, write_timeout=None, dsrdtr=False, inter_byte_timeout=None, exclusive=None)

    I have to conclude that if there is a config mismatch, it must be the Adafruit board that is wrong.

    Do you have one of these boards to try this with?  Or any other suggestions? I don't have a serial sniffer or any way I can think of to capture and determine the config (e.g. baud rate) being used by the Adafruit board.

  • It's definitely transmitting which I suppose is something. I have a simple oscilloscope and see activity as transmission is taking place as indicated by console messages. It seems it *must* be the serial config that is the problem.

  • We are not the Rasberry Pi experts, you need to ask this in Rasberry Pi forum as their environment is very different than our solutions. If they are using Linux console, then it is probable that the Linux is still trying own the uart console and trying to write to that pins. But again, I am no expert in that product.

  • I'm not asking for help with the Raspberry Pi side of this. I've also had the nRF52840 board connected to a PC and got similar garbage results. I've proved that the Pi is operating with the required serial comms config using commercial products (i.e. out of the box behaviour).

    The problem is categorically with the nRF52840 end of things.

  • Understood. Can you please give me the firmware for it, that creates the garbage results, I want to test it on my end using nrf52840 DK. I can assist you better then. 

Reply Children
Related