I'm developing with an NRF52832, using NCS v2.6.1/Zephyr 3.5.99
My custom hardware has three NXP PCA9538 GPIO expanders on it, to allow me to control various address and enable pins on some other devices, plus a few status LEDs.
I seem to be having issues getting my setup to correctly talk to and configure the GPIO outputs on any of the PCA9538's.
This is how I have them set up in my .dts file for my custom board:
&i2c0 { status = "okay"; compatible = "nordic,nrf-twim"; pinctrl-0 = <&i2c0_ct_default>; pinctrl-1 = <&i2c0_ct_sleep>; pinctrl-names = "default", "sleep"; pca9538_70: pca9538@70 { compatible = "nxp,pca95xx"; reg = <0x70>; gpio-controller; #gpio-cells = <2>; ngpios = <8>; status = "okay"; addrenpins { compatible = "gpio-leds"; enai: gpio_out_enai { gpios = <&pca9538_70 0 GPIO_ACTIVE_LOW>; label = "Enable Input A Device"; }; enao: gpio_out_enao { gpios = <&pca9538_70 1 GPIO_ACTIVE_LOW>; label = "Enable Output A Device"; }; enbi: gpio_out_enbi { gpios = <&pca9538_70 2 GPIO_ACTIVE_LOW>; label = "Enable Input B Device"; }; enbo: gpio_out_enbo { gpios = <&pca9538_70 3 GPIO_ACTIVE_LOW>; label = "Enable Output B Device"; }; enci: gpio_out_enci { gpios = <&pca9538_70 4 GPIO_ACTIVE_LOW>; label = "Enable Input C Device"; }; enco: gpio_out_enco { gpios = <&pca9538_70 5 GPIO_ACTIVE_LOW>; label = "Enable Output C Device"; }; endi: gpio_out_endi { gpios = <&pca9538_70 6 GPIO_ACTIVE_LOW>; label = "Enable Input D Device"; }; endo: gpio_out_endo { gpios = <&pca9538_70 7 GPIO_ACTIVE_LOW>; label = "Enable Output D Device"; }; }; }; pca9538_72: pca9538@72 { compatible = "nxp,pca95xx"; reg = <0x72>; gpio-controller; #gpio-cells = <2>; ngpios = <8>; status = "okay"; ledpins { compatible = "gpio-leds"; testactive: gpio_out_testactive { gpios = <&pca9538_72 0 GPIO_ACTIVE_LOW>; label = "Test is active"; }; testpass: gpio_out_testpass { gpios = <&pca9538_72 1 GPIO_ACTIVE_LOW>; label = "Test has passed"; }; testfail: gpio_out_testfail { gpios = <&pca9538_72 2 GPIO_ACTIVE_LOW>; label = "Test has failed"; }; }; }; pca9538_73: pca9538@73 { compatible = "nxp,pca95xx"; reg = <0x73>; gpio-controller; #gpio-cells = <2>; ngpios = <8>; status = "okay"; }; };
Note that <&i2c0_ct_default> and <&i2c0_ct_sleep>; are set up in my .dtsi file as follows:
i2c0_ct_default: i2c0_default { group1 { psels = <NRF_PSEL(TWIM_SDA, 0, 26)>, <NRF_PSEL(TWIM_SCL, 0, 27)>; }; }; i2c0_ct_sleep: i2c0_sleep { group1 { psels = <NRF_PSEL(TWIM_SDA, 0, 26)>, <NRF_PSEL(TWIM_SCL, 0, 27)>; low-power-enable; }; };
I then have a buch of alias in my overlay file referencing all the gpio:
aliases { testactive = &testactive; testpass = &testpass; testfail = &testfail; enai = &enai; enbi = &enbi; enci = &enci; endi = &endi; enao = &enao; enbo = &enbo; enco = &enco; endo = &endo; };
Then, in my firmware, when I set up the gpio that I want to use on my expanders, I do this:
static const struct gpio_dt_spec enable_a_in = GPIO_DT_SPEC_GET(DT_ALIAS(enai), gpios); static const struct gpio_dt_spec enable_b_in = GPIO_DT_SPEC_GET(DT_ALIAS(enbi), gpios); static const struct gpio_dt_spec enable_c_in = GPIO_DT_SPEC_GET(DT_ALIAS(enci), gpios); static const struct gpio_dt_spec enable_d_in = GPIO_DT_SPEC_GET(DT_ALIAS(endi), gpios); static const struct gpio_dt_spec enable_a_out = GPIO_DT_SPEC_GET(DT_ALIAS(enao), gpios); static const struct gpio_dt_spec enable_b_out = GPIO_DT_SPEC_GET(DT_ALIAS(enbo), gpios); static const struct gpio_dt_spec enable_c_out = GPIO_DT_SPEC_GET(DT_ALIAS(enco), gpios); static const struct gpio_dt_spec enable_d_out = GPIO_DT_SPEC_GET(DT_ALIAS(endo), gpios); static const struct gpio_dt_spec test_active_led = GPIO_DT_SPEC_GET(DT_ALIAS(testactive), gpios); static const struct gpio_dt_spec test_pass_led = GPIO_DT_SPEC_GET(DT_ALIAS(testpass), gpios); static const struct gpio_dt_spec test_fail_led = GPIO_DT_SPEC_GET(DT_ALIAS(testfail), gpios);
And then I attempt to configure them as outputs, and set them to a starting value like this:
CHECK_ERR(gpio_pin_configure_dt(&enable_a_in, GPIO_OUTPUT)); CHECK_ERR(gpio_pin_configure_dt(&enable_b_in, GPIO_OUTPUT)); CHECK_ERR(gpio_pin_configure_dt(&enable_c_in, GPIO_OUTPUT)); CHECK_ERR(gpio_pin_configure_dt(&enable_d_in, GPIO_OUTPUT)); CHECK_ERR(gpio_pin_configure_dt(&enable_a_out, GPIO_OUTPUT)); CHECK_ERR(gpio_pin_configure_dt(&enable_b_out, GPIO_OUTPUT)); CHECK_ERR(gpio_pin_configure_dt(&enable_c_out, GPIO_OUTPUT)); CHECK_ERR(gpio_pin_configure_dt(&enable_d_out, GPIO_OUTPUT)); CHECK_ERR(gpio_pin_set_dt(&enable_a_in, GPIO_INACTIVE)); CHECK_ERR(gpio_pin_set_dt(&enable_b_in, GPIO_INACTIVE)); CHECK_ERR(gpio_pin_set_dt(&enable_c_in, GPIO_INACTIVE)); CHECK_ERR(gpio_pin_set_dt(&enable_d_in, GPIO_INACTIVE)); CHECK_ERR(gpio_pin_set_dt(&enable_a_out, GPIO_INACTIVE)); CHECK_ERR(gpio_pin_set_dt(&enable_b_out, GPIO_INACTIVE)); CHECK_ERR(gpio_pin_set_dt(&enable_c_out, GPIO_INACTIVE)); CHECK_ERR(gpio_pin_set_dt(&enable_d_out, GPIO_INACTIVE));
Note that CHECK_ERR() is a custom #define that just checks the return value and sends out some LOG info to the console if its < 0.
I seem to be having issues at the point that I call something like
CONFIG_GPIO=y CONFIG_I2C=y CONFIG_GPIO_PCA95XX=y