2022-04-14

Hello,

In an nRF9160, Zephyr based design I am having trouble to configure the 9160’s GPIOs P0.18 through P0.21. I am successfully utilizing other pins on 9160’s port 0. I can drive a couple of LEDs, and I’m able to drive some other external-to-SiP circuit features such as chip select lines.

The pins I can drive correctly are connected to other components outside the nRF9160 SiP. The four GPIOs in question are brought out to a pin header, but are not tied to any rail or other component.

In board files written in device tree source, and in C code I set up GPIOs in the follow manner, device tree (DTS) shown here first:

Code excerpt - DTS:

------------------------------------------------------------------------

          leds {
                compatible = "gpio-leds";
                red_led: led_1 {
                        gpios = <&gpio0 4 0>;
                        label = "RGB red channel";
                };
           .
           .
           .
        };

        signal_and_breakout_pins {
                compatible = "gpio-leds";
                gpio_breakout_1: breakout_line_1 {
                        gpios = <&gpio0 18 0>;
                        label = "GPIO breakout line 1";
                };
           .
           .
           .
        };

------------------------------------------------------------------------

This first excerpt is part of my board’s “common” dts board file. There are two C-like scopes, one named ‘leds’ and the next named ‘signal_and_breakout_pins’. Both have a DTS “compatible” stanza, which I copied from working examples in Jared Wolff’s ‘nfed’ repository and also note from Nordic Semi ncs 1.6.1 sample Zephyr apps.

In code that’s called early from my app’s void main(void), I follow a Zephyr macro pattern and create a device pointer this way in excerpt 2:

Code excerpt 2 - Zephyr device macros and device pointers:

------------------------------------------------------------------------

#define LED0_NODE DT_ALIAS(led0)

#if DT_NODE_HAS_STATUS(LED0_NODE, okay)
#warning --- --- --- macro evaluating 'led0' dts alias returns true --- --- ---
#define LED0_LABEL   DT_GPIO_LABEL(LED0_NODE, gpios)
#define LED0_PIN     DT_GPIO_PIN(LED0_NODE, gpios)
#define LED0_FLAGS   DT_GPIO_FLAGS(LED0_NODE, gpios)
#else
#warning --- --- --- macro evaluating 'led0' dts alias returns false --- --- ---
#define LED0_LABEL   ""
#define LED0_PIN     0
#define LED0_FLAGS   0
#endif


static const struct device *dev_led_red;



static uint32_t app_config__configure_line__led0(void)
{
    uint32_t rstatus = ROUTINE_OK;

    dev_led_red = device_get_binding(LED0_LABEL);

    if ( dev_led_red == NULL )
    { rstatus = ZR__WARNING__FAIL_ON_DEVICE_GET_BINDING; }

    if ( rstatus == ROUTINE_OK )
    {   
        rstatus = gpio_pin_configure(dev_led_red, LED0_PIN, GPIO_OUTPUT_ACTIVE | LED0_FLAGS);
        if ( rstatus < 0 ) 
        {   
            rstatus = ZR__WARNING__FAIL_ON_GPIO_PIN_CONFIGURE;
        }   
    }   

    if ( rstatus == ROUTINE_OK )
    { gpio_pin_set(dev_led_red, LED0_PIN, CUSTOM_APP__PIN_STATE_DEFAULT_START_VALUE__LED0); }

    return rstatus;
}

------------------------------------------------------------------------

Here is how I similarly set up for the break out GPIO . . .

Code excerpt 3 - GPIO set up for pin in question:

------------------------------------------------------------------------

#if DT_NODE_HAS_STATUS(GPIO_BREAKOUT_1, okay)
#warning --- --- --- macro evaluating 'aliasgpiobreakout1' dts alias returns true --- --- ---
#define GPIO_BREAKOUT_1_LABEL   DT_GPIO_LABEL(GPIO_BREAKOUT_1, gpios)
#define GPIO_BREAKOUT_1_PIN     DT_GPIO_PIN(GPIO_BREAKOUT_1, gpios)
#define GPIO_BREAKOUT_1_FLAGS   DT_GPIO_FLAGS(GPIO_BREAKOUT_1, gpios)
#else
#warning --- --- --- macro evaluating 'aliasgpiobreakout1' dts alias returns false --- --- ---
#define GPIO_BREAKOUT_1_LABEL   ""
#define GPIO_BREAKOUT_1_PIN     0
#define GPIO_BREAKOUT_1_FLAGS   0
#endif


static const struct device *dev_gpio_breakout_1;


static uint32_t module_app_config__configure_line__gpio_breakout_1(void)
{
    uint32_t rstatus = ROUTINE_OK;

    dev_gpio_breakout_1 = device_get_binding(GPIO_BREAKOUT_1_LABEL);

    if ( dev_gpio_breakout_1 == NULL )
    { rstatus = ZR__WARNING__FAIL_ON_DEVICE_GET_BINDING; }

    if ( rstatus == ROUTINE_OK )
    {
//        rstatus = gpio_pin_configure(dev_gpio_breakout_1, GPIO_BREAKOUT_1_PIN, GPIO_OUTPUT_ACTIVE | GPIO_BREAKOUT_1_FLAGS);
        rstatus = gpio_pin_configure(dev_gpio_breakout_1, GPIO_BREAKOUT_1_PIN, GPIO_OUTPUT | GPIO_BREAKOUT_1_FLAGS);
        if ( rstatus < 0 )
        { rstatus = ZR__WARNING__FAIL_ON_GPIO_PIN_CONFIGURE; }
    }

    if ( rstatus == ROUTINE_OK )
    { gpio_pin_set(dev_gpio_breakout_1, GPIO_BREAKOUT_1_PIN, CUSTOM_APP__START_VALUE__GPIO_BREAKOUT_1); }

    return rstatus;
}
------------------------------------------------------------------------

These GPIO pins are both on port 0 of the nRF9160. But while I can set the output of the LED just fine, I see no change in voltage level on P0.18, the pin I ma using as a test point / break out. Is there something different or special about 9160 GPIOs P0.18 through P0.21?

From the nRF9160 datasheet the only difference I see is that P0.18 can optionally be configured as an analog input. Given this, is there some possible effect that my configuration may be changed or overwritten in a situation where I have the ADC peripheral enabled for my target processor in the board file?

  • Ted

    tedhavelka66 Is there something different or special about 9160 GPIOs P0.18 through P0.21?

    I don’t believe so. I would make sure that the board definition you’re using isn’t setting them up as a SPI/I2C/etc interface. That’s my best guess though.

    Good evening Jared,

    Thank you for the fast reply. Your insight is spot on! It turns out elsewhere in the [custom_board]_common.dts file the pins in question are assigned to UART0. I’m not using UART0 external to the SiP let alone board, but I believe this UART is enabled to support Nordic’s AT command handler. Is it correct that nRF9160 modem requires a UART in order to be configurable at run time?

    Because device tree source is spread out across multiple files, I first checked [project_dir]/build/zephyr/zephyr.dts for multiple refs to the trouble pins. When I saw such there, I was able to track down what dtc reads at build time, the board files themselves.

    I have been able to assign other pins to UART0, and can still issue AT commands and see expected modem responses. ( I was able to simply comment out pin refs for control lines rts-pin and cts-pin. Modem commands work in spite of this change. )

    Thanks again for your help, Jared!

    • Ted

      tedhavelka66 Is it correct that nRF9160 modem requires a UART in order to be configurable at run time?

      Typically yes.

      Happy you got it resolved! 😃

      Terms and Conditions | Privacy Policy