I am in the process of migrating a project using the nrf5340 from nRF Connect SDK v1.6.0 to v2.2.0.
I have run into an issue where gpio pins I could use before are no longer usable and pins that I am allowed to use crash the app as well. My current guess is that there have been introduced a requirement to initialise the gpio0 and gpio1 devices before they can be used. Is this the case and if so how would they need to be initialised.
The error I am seeing is that an assert fails that checks if a given pin number is associated with the gpio device
ASSERTION FAIL [(cfg->port_pin_mask & (gpio_port_pins_t)(1UL << (pin))) != 0U] @ WEST_TOPDIR/zephyr/include/zephyr/drivers/gpio.h:732
Unsupported pin
Here is the content of the local variables before the assertion fails, it can be seen that gpio0->state->initialized == false
My issue can be reproduced using nRF Connect SDK v2.2.0 and running the peripheral_uart sample on a nRF5340-DK (I am not sure of the revision as we have several) with slight modifications:
- Adding src/p_gpio.c to target_sources in the CMakeLists:
target_sources(app PRIVATE src/main.c src/p_gpio.c )
- Including p_gpio.h in main.c and adding a call to p_gpio_init in the main function:
#include "p_gpio.h" //... void main(void) { int blink_status = 0; int err = 0; err = p_gpio_init(); if (err) { printk("Failed to init p_gpio.\n"); } configure_gpio(); err = uart_init(); if (err) { error(); } //... }
- Add the two following files to src:
#include "p_gpio.h" #include <zephyr/device.h> #include <zephyr/drivers/gpio.h> #include <zephyr/kernel.h> #include <zephyr/logging/log.h> LOG_MODULE_REGISTER(p_gpio); static const struct device* gpio_0; static const struct device* gpio_1; int p_gpio_set_pin_internal(const struct device* gpio, uint8_t pin, bool value); static int p_gpio_pin_callback_init_internal(const struct device* gpio, uint8_t pin, uint32_t pin_flags, gpio_callback_handler_t callback, struct gpio_callback* callback_data, uint32_t callback_flags); int p_gpio_init() { gpio_0 = device_get_binding("GPIO_0"); gpio_1 = device_get_binding("GPIO_1"); int res = p_gpio_init_pins(); if(!gpio_0 || !gpio_1 || res) { LOG_ERR("Error: Failed to init GPIO pins"); } return res; } int p_gpio_init_pins() { int res; //Test Setup Pins res = p_gpio_pin_init(gpio_0, 31, GPIO_OUTPUT | GPIO_PULL_UP); gpio_port_clear_bits(gpio_0, BIT(31)); res |= p_gpio_pin_init(gpio_0, 30, GPIO_OUTPUT | GPIO_PULL_UP); gpio_port_clear_bits(gpio_0, BIT(30)); res |= p_gpio_pin_init(gpio_0, 29, GPIO_OUTPUT | GPIO_PULL_UP); gpio_port_clear_bits(gpio_0, BIT(29)); return res; } int p_gpio_get_pin(uint8_t gpio, uint8_t pin) { if(!gpio) { return gpio_pin_get(gpio_0, pin); } else { return gpio_pin_get(gpio_1, pin); } } int p_gpio_set_pin(uint8_t gpio, uint8_t pin, bool value) { if(!gpio) { return p_gpio_set_pin_internal(gpio_0, pin, value); } else { return p_gpio_set_pin_internal(gpio_1, pin, value); } } int p_gpio_set_pin_internal(const struct device* gpio, uint8_t pin, bool value) { if(value) { return gpio_port_set_bits(gpio, BIT(pin)); } else { return gpio_port_clear_bits(gpio, BIT(pin)); } } int p_gpio_pin_init(const struct device* gpio, uint8_t pin, uint32_t flags) { int err = gpio_pin_configure(gpio, pin, flags); if(err) { LOG_ERR("Failed to init pin %d", pin); } else { LOG_INF("Pin %d inited", pin); } return err; } int p_gpio_pin_callback_init(uint8_t gpio, uint8_t pin, uint32_t pin_flags, gpio_callback_handler_t callback, struct gpio_callback* callback_data, uint32_t callback_flags) { if(!gpio) { return p_gpio_pin_callback_init_internal(gpio_0, pin, pin_flags, callback, callback_data, callback_flags); } else { return p_gpio_pin_callback_init_internal(gpio_1, pin, pin_flags, callback, callback_data, callback_flags); } } int p_gpio_pin_callback_init_internal(const struct device* gpio, uint8_t pin, uint32_t pin_flags, gpio_callback_handler_t callback, struct gpio_callback* callback_data, uint32_t callback_flags) { int ret; ret = p_gpio_pin_init(gpio, pin, pin_flags); if(ret != 0) { LOG_ERR("Error %d: failed to configure pin %d\n", ret, pin); return ret; } ret = gpio_pin_interrupt_configure(gpio, pin, callback_flags); if(ret != 0) { LOG_ERR("Error %d: failed to configure interrupt on pin %d\n", ret, pin); return ret; } gpio_init_callback(callback_data, callback, BIT(pin)); gpio_add_callback(gpio, callback_data); LOG_INF("Set up interrupt on pin %d\n", pin); return ret; }
- and lastly the build configuration used the board nrf5340dk_nrf5340_cpuapp and the prj.conf.
Here is a zip of the modified project: