Adafruit nRF52840 Feather Express GPIO and DTS

Hi, I have an Adafruit nRF52840 Feather Express and am developing for it using Zephyr 3.1.1 and the nRF Connect SDK with VS Code.

I want to read and write from two of the GPIO pins via UART but am struggling with setting this up. My understanding of DTS files is a little fuzzy tbh. I've looked at the board DTS file (zephyr\boards\adafruit\feather_nrf52840\adafruit_feather_nrf52840.dts) but it has very little in it, specifically the following:

/*
 * Copyright (c) 2020 Tobias Svehagen
 * Copyright (c) 2024 Jacob Winther
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/dts-v1/;
#include "adafruit_feather_nrf52840_common.dtsi"
#include <nordic/nrf52840_partition.dtsi>

/ {
	model = "Adafruit Feather nRF52840 Express";
	compatible = "adafruit,feather-nrf52840";

	chosen {
		zephyr,console = &uart0;
		zephyr,shell-uart = &uart0;
		zephyr,uart-mcumgr = &uart0;
		zephyr,bt-mon-uart = &uart0;
		zephyr,bt-c2h-uart = &uart0;
	};

	leds {
		led0: led_0 {
			gpios = <&gpio1 15 0>;
		};
	};
};

The pin I want to write to is GPIO p0.25 as shown on this page: https://learn.adafruit.com/introducing-the-adafruit-nrf52840-feather/pinouts 

What do I need to do to make the pin accessible from my C code? Put something in a DTS overlay file?

I'd very much appreciate some guidance with this. I've worked with other boards successfully in the past but for some reason am finding it hard to get started here. The only examples I can find involve the Blinky sample which flashes led0 which is defined in the DTS file. Is the DTS file for the board basically incomplete?

Thanks in anticipation

  • The Nordic DevAcademy is doing a good job of educating me on the subject of the Zephyr Device Tree!

    I've found the DTS definition for a node called connector which has a label of feather_header. In there, I see a property called gpio-map which includes values for all the header pins, including the one I want to write to:

    <10 0 &gpio0 25 0>, /* TXD */

    /*
     * Copyright (c) 2020 Richard Osterloh <[email protected]>
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    / {
    	feather_header: connector {
    		compatible = "adafruit-feather-header";
    		#gpio-cells = <2>;
    		gpio-map-mask = <0xffffffff 0xffffffc0>;
    		gpio-map-pass-thru = <0 0x3f>;
    		gpio-map = <0 0 &gpio0 4 0>,	/* A0 */
    			   <1 0 &gpio0 5 0>,	/* A1 */
    			   <2 0 &gpio0 30 0>,	/* A2 */
    			   <3 0 &gpio0 28 0>,	/* A3 */
    			   <4 0 &gpio0 2 0>,	/* A4 */
    			   <5 0 &gpio0 3 0>,	/* A5 */
    			   <6 0 &gpio0 14 0>,	/* SCK */
    			   <7 0 &gpio0 13 0>,	/* MOSI */
    			   <8 0 &gpio0 15 0>,	/* MISO */
    			   <9 0 &gpio0 24 0>,	/* RXD */
    			   <10 0 &gpio0 25 0>,	/* TXD */
    			   <11 0 &gpio0 10 0>,	/* D2 (NFC2) */
    			   <12 0 &gpio0 12 0>,	/* SDA */
    			   <13 0 &gpio0 11 0>,	/* SCL */
    			   <14 0 &gpio1 8 0>,	/* D5 */
    			   <15 0 &gpio0 7 0>,	/* D6 */
    			   <16 0 &gpio0 26 0>,	/* D9 */
    			   <17 0 &gpio0 27 0>,	/* D10 */
    			   <18 0 &gpio0 6 0>,	/* D11 */
    			   <19 0 &gpio0 8 0>,	/* D12 */
    			   <20 0 &gpio1 9 0>;	/* D13 */
    	};
    };
    
    feather_serial: &uart0 {};
    feather_i2c: &i2c0 {};
    feather_spi: &spi1 {};

    So, I guess I need to figure out how to use the Zephyr DTS macros to get a device pointer for feather_header and from there the specific pin I want to use? I'll keep investigating but if anyone wants to make this easier for me, please don't hesitate :-)

  • Hi Martin,

    Welcome to Nordic, it seems like you are on a good trajectory already!

    I can answer some of your questions, but the best way to learn is continuing the DevAcademy and browsing the samples available in our SDK. There are also a ton of resources available in the documentation (Nordic TechDocs and Zephyr Project Docs).

    Put something in a DTS overlay file?

    Yes, you need to define the GPIO pin in the device tree. Overlays let you avoid editing the main device tree files for the SoC and board. In an overlay, create a node for your GPIO pin. A generic GPIO pin node can look like this:

    / {
        my_pin: my_pin_node {
            compatible = "nordic,gpio-pins";
            gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
            status = "okay";
        };
    };

    What do I need to do to make the pin accessible from my C code?

    To access the pin from your C code you need a device pointer. Here is a simple code snippet that creates a device pointer with the use of a thin wrapper:

    static const struct gpio_dt_spec my_pin = GPIO_DT_SPEC_GET(DT_NODELABEL(my_pin), gpios);

    To make use of it you need to initialize and configure it. Here is a bare minimum example that just toggles a pin:

    int main(void)
    {
        device_is_ready(my_pin.port)
    
        gpio_pin_configure_dt(&my_pin, GPIO_OUTPUT_INACTIVE)
    
        while (1) {
            gpio_pin_toggle_dt(&my_pin);
            k_sleep(K_MSEC(500));
        }
    
        return 0;
    }

    Is the DTS file for the board basically incomplete?

    No, it is not incomplete. Devictree is hierarchical and most nodes lives inside these included files:

    #include "adafruit_feather_nrf52840_common.dtsi"
    #include <nordic/nrf52840_partition.dtsi>

    To communicate over UART using two GPIO pins, you should check out Lesson 5 – Serial communication (UART) and other relevant samples.

    Best regards,
    Benjamin

  • Benjamin, thank you so much for this. Happily, last night I'd managed to arrive at some similar conclusions (although I ended up with the macro GPIO_DT_SPEC_GET_OR so I need to make sure I'm clear on the difference between this macro and GPIO_DT_SPEC_GET. I haven't tested yet but it's very reassuring to see your code fragments looking so similar to what I currently have.

    So, next step is testing this in a simple application and then, per your suggestion, more work in the excellent DevAcademy!

    Thanks once again, Much appreciated :-)

    Martin

Related