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