This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

NRF DK Basic GPIO

I have the NRF52-DK, a 3-digit seven segment display, an RGB LED and a sensor. Using SES to try and get some basic code running.

I manage to open an nRF Connect SDK project (rgb_led) and update it to drive 3 IO via the PWM peripheral. Next up I'm trying to add to that a basic 7-segment display driver - map some GPIO for the a-g segments, decimal and 3 com IO, and write a basic decoder to drive it. 

I'm struggling to get my head around the device tree. Here is what I have so far:

in my nrf52dk_nrf52832.overlay file:

/ {
    gpio_header: connector2 {
        model = "Nordic nRF52 DK NRF52832";
        compatible = "nordic,nrf52-dk-nrf52832";
        
        #gpio-cells = <2>;
        gpio-map-mask = <0xffffffff 0xffffffc0>;
        gpio-map-pass-thru = <0 0x3f>;
        gpio-map =  <0 0 &gpio0 0 0>,
                    <1 0 &gpio0 1 0>,
                    <2 0 &gpio0 21 0>,
                    <3 0 &gpio0 5 0>,
                    <4 0 &gpio0 6 0>,
                    <5 0 &gpio0 7 0>,
                    <6 0 &gpio0 8 0>,
                    <7 0 &gpio0 9 0>,
                    <8 0 &gpio0 10 0>;
    };
    
    seven_seg_display: seven_seg {
        seg_a = <&gpio_header 0 0>;
        seg_b = <&gpio_header 1 0>;
        seg_c = <&gpio_header 2 0>;
        seg_d = <&gpio_header 3 0>;
        seg_e = <&gpio_header 4 0>;
        seg_f = <&gpio_header 5 0>;
        seg_g = <&gpio_header 6 0>;
        dp = <&gpio_header 7 0>;
        dig_1_en = <&gpio_header 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
        dig_2_en = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
        dig_3_en = <&gpio0 12 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
    };
};

The dts file for this DK already specifies an arduino-r3 header for most of the gpio. I attempt to assign the remaining gpio as another header, then finally group the IO i'm using as a seven segment device.

In main.c I attempt to statically assign the gpio specs from the device tree, which I'll use to then configure the gpio..

#define SEVEN_SEG_NODE DT_NODELABEL(seven_seg_display)

typedef struct three_digit_s {
    struct gpio_dt_spec a;
    struct gpio_dt_spec b;
    struct gpio_dt_spec c;
    struct gpio_dt_spec d;
    struct gpio_dt_spec e;
    struct gpio_dt_spec f;
    struct gpio_dt_spec g;

    struct gpio_dt_spec dp;
    struct gpio_dt_spec d1_en;
    struct gpio_dt_spec d2_en;
    struct gpio_dt_spec d3_en;
} three_digit_t;

static three_digit_t three_digit = {
  .a = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, seg_a ),
  .b = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, seg_b ),
  .c = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, seg_c ),
  .d = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, seg_d ),
  .e = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, seg_e ),
  .f = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, seg_f ),
  .g = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, seg_g ),
  .dp = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, dp ),
  .d1_en = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, dig_1_en ),
  .d2_en = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, dig_2_en ),
  .d3_en = GPIO_DT_SPEC_GET( SEVEN_SEG_NODE, dig_3_en )
};

// somewhere in main..
gpio_pin_configure_dt( &(td.a), 0 );
//.. etc

(note: dt.a in the code above should be three_digit.a - the form input field for my post is stuck in a disabled state with 'upload file(s)' on it so can't edit! I can go to preview and back and the cursor will appear in the disabled text box allowing me to add this!)

On clean build (CMake run after editing the overlay file), get a load of these for all of the GPIO_DT_SPEC calls..

2> Compiling ‘main.c’
2> In file included from C:/v1.7.0/zephyr/include/toolchain/gcc.h:66,
2>                  from C:/v1.7.0/zephyr/include/toolchain.h:43,
2>                  from C:/v1.7.0/zephyr/include/kernel_includes.h:19,
2>                  from C:/v1.7.0/zephyr/include/kernel.h:17,
2>                  from C:/v1.7.0/zephyr/include/zephyr.h:18,
2>                  from ../src/main.c:11:
2> C:/v1.7.0/zephyr/include/device.h:80:39:error: __device_dts_ord_DT_N_S_seven_seg_P_seg_a_IDX_0_PH_ORD' undeclared here (not in a function)
2> C:/v1.7.0/zephyr/include/toolchain/common.h:124:26:note: in definition of macro '_DO_CONCAT'
2> C:/v1.7.0/zephyr/include/device.h:80:31:note: in expansion of macro '_CONCAT'
2> C:/v1.7.0/zephyr/include/device.h:232:37:note: in expansion of macro 'DEVICE_NAME_GET'
2> C:/v1.7.0/zephyr/include/device.h:246:34:note: in expansion of macro 'DEVICE_DT_NAME_GET'
2> C:/v1.7.0/zephyr/include/drivers/gpio.h:363:11:note: in expansion of macro 'DEVICE_DT_GET'
2> C:/v1.7.0/zephyr/include/drivers/gpio.h:399:2:note: in expansion of macro 'GPIO_DT_SPEC_GET_BY_IDX'
2> ../src/main.c:92:8:note: in expansion of macro 'GPIO_DT_SPEC_GET'

Checking devicetree_unfixed.h there's a section there for seven_seg although I feel it's missing generic property macros:

/*
 * Devicetree node: /seven_seg
 *
 * Node identifier: DT_N_S_seven_seg
 */

/* Node's full path: */
#define DT_N_S_seven_seg_PATH "/seven_seg"

/* Node's name with unit-address: */
#define DT_N_S_seven_seg_FULL_NAME "seven_seg"

/* Node parent (/) identifier: */
#define DT_N_S_seven_seg_PARENT DT_N
#define DT_N_S_seven_seg_FOREACH_CHILD(fn) 
#define DT_N_S_seven_seg_FOREACH_CHILD_VARGS(fn, ...) 
#define DT_N_S_seven_seg_FOREACH_CHILD_STATUS_OKAY(fn) 
#define DT_N_S_seven_seg_FOREACH_CHILD_STATUS_OKAY_VARGS(fn, ...) 

/* Node's dependency ordinal: */
#define DT_N_S_seven_seg_ORD 6

/* Ordinals for what this node depends on directly: */
#define DT_N_S_seven_seg_REQUIRES_ORDS \
	0, /* / */

/* Ordinals for what depends directly on this node: */
#define DT_N_S_seven_seg_SUPPORTS_ORDS /* nothing */

/* Existence and alternate IDs: */
#define DT_N_S_seven_seg_EXISTS 1
#define DT_N_NODELABEL_seven_seg_display DT_N_S_seven_seg

/* Special property macros: */
#define DT_N_S_seven_seg_REG_NUM 0
#define DT_N_S_seven_seg_IRQ_NUM 0
#define DT_N_S_seven_seg_STATUS_okay 1

/* (No generic property macros) */

What am I doing wrong? I've spent three days with this, having gone through the Device tree spec, and the Zephyr documentation. I get having a system in place like the SES and Zephyr makes projects more hardware agnostic while making hardware configuration easier, but it doesn't half add a learning curve to getting started. Would love to just create a blank project for the nRF52 DK, import some nrf headers and add some API calls then build and run!

Cheers.

  • I've done away with my attempt to group some IO by specifying another connector, having looked around some of the dt binding files. So I'm just left with this:

      seven_seg_display: seven_seg {
        seg_a = <&gpio0 0 0>; 
        seg_b = <&gpio0 1 0>;
        seg_c = <&gpio0 21 0>;
        seg_d = <&gpio0 5 0>;
        seg_e = <&gpio0 6 0>;
        seg_f = <&gpio0 7 0>;
        seg_g = <&gpio0 8 0>;
        dp = <&gpio0 9 0>;
        dig_1_en = <&gpio0 10 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
        dig_2_en = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
        dig_3_en = <&gpio0 12 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
      };

    I understand my error is complaining that the properties of this node aren't GPIO instances, but is something like this possible? I spotted this post that I'll try tomorrow that describes just getting the GPIO_0 instance and using that on the configure calls, but I'd still like to know how to use GPIO_DT_SPEC_GET() with my example. 

    Any help appreciated. Cheers.

  • Found the comments in include/drivers/gpio.h

    /**
     * @brief Static initializer for a @p gpio_dt_spec
     *
     * This returns a static initializer for a @p gpio_dt_spec structure
     * given a devicetree node identifier and a property specifying a
     * GPIO.
     *
     * Example devicetree fragment:
     *
     *	n: node {
     *		foo-gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
     *	}
     *
     * Example usage:
     *
     *	const struct gpio_dt_spec spec = GPIO_DT_SPEC_GET(DT_NODELABEL(n),
     *							  foo_gpios);
     *	// Initializes 'spec' to:
     *	// {
     *	//         .port = DEVICE_DT_GET(DT_NODELABEL(gpio1)),
     *	//         .pin = 2,
     *	//         .dt_flags = GPIO_ACTIVE_LOW
     *	// }
     *...
     */

    I changed the prop names in the dts from underscore to dash, just in case. No joy.

  • Could you try using this approach: https://devzone.nordicsemi.com/f/nordic-q-a/72618/extra-gpios-in-board-overlay-for-nrf9160dk?

    Let me know if you get it to work or not

    Best regards,

    Simon

  • Funny enough I was already in the process of re-coding based on that very article! Got the GPIO working, although it would be nice to have done it via the dts overlay and the GPIO_DT_SPCE_GET macro, but I guess that's really now a question for the Zephyr community.

    It didn't help that I was using some GPIO that was already being used for the xtal and other functionality on the nRF DK board. For future reference:

    I freed up the GPIO assigned to the DK buttons and LED's by grounding the SHIELD detect header pin. 

    Grab a reference to the GPIO controller:

    #define GPIO_PORT DEVICE_DT_GET(DT_NODELABEL(gpio0))

    Grouped some IO bits together:

    typedef struct gpio_s {
        struct device const *port;
        gpio_pin_t const pin;
        gpio_flags_t flags;
    } gpio_t;
    
    

    Grouped the 3-digit seven seg LED IO into a structure..

    typedef struct three_digit_s {
        gpio_t a;
        gpio_t b;
        gpio_t c;
        gpio_t d;
        gpio_t e;
        gpio_t f;
        gpio_t g;
    
        gpio_t dp;
        gpio_t d1_en;
        gpio_t d2_en;
        gpio_t d3_en;
    } three_digit_t;

    with some static assignments specifying the pin numbers..

    static three_digit_t three_digit = {
      .a = {
        .port = GPIO_PORT,
        .pin = 11,
        .flags = GPIO_OUTPUT_INACTIVE
      },
      .b = {
        .port = GPIO_PORT,
        .pin = 12,
        .flags = GPIO_OUTPUT_INACTIVE
      },
      
      ... etc
      
    };

    configure..

    success = gpio_pin_configure(
        three_digit.a.port,
        three_digit.a.pin,
        three_digit.a.flags
      );

    then set..

    gpio_pin_set(
        three_digit.d1_en.port,
        three_digit.d1_en.pin,
        0   // or 1..
    );

    Thumbsup tone3

Related