Navigation Menu

Skip to content

Commit

Permalink
boards: arm: nrf52840_pca10090: add a GPIO reset line
Browse files Browse the repository at this point in the history
Let one of the MCU interface pins be configured to act
as a reset line. This mitigates the lack of a connection
between the nRF9160 and nRF52840 PINRESET.
Minor refactoring and updated comments.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
  • Loading branch information
lemrey authored and carlescufi committed Apr 19, 2019
1 parent 0604e21 commit 3dc71c8
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 20 deletions.
59 changes: 59 additions & 0 deletions boards/arm/nrf52840_pca10090/Kconfig
Expand Up @@ -192,6 +192,65 @@ config BOARD_PCA10090_INTERFACE2_MCU


endchoice endchoice


config BOARD_PCA10090_NRF52840_RESET
bool "Enable GPIO reset line"
help
Let the nRF52840 be reset from the nRF9160 via a GPIO line.
The GPIO line may only be one of the first 6 MCU interface pins.
The line is active high.

if BOARD_PCA10090_NRF52840_RESET

choice
prompt "Pin used for reset"

comment "nRF52840 pins"

config BOARD_PCA10090_NRF52840_RESET_P0_17
bool "P0.17"
depends on BOARD_PCA10090_INTERFACE0_MCU
help
Pin P0.17 on nRF52840,
connected to P0.17 on the nRF9160.

config BOARD_PCA10090_NRF52840_RESET_P0_20
bool "P0.20"
depends on BOARD_PCA10090_INTERFACE0_MCU
help
Pin P0.20 on nRF52840,
connected to P0.18 on the nRF9160.

config BOARD_PCA10090_NRF52840_RESET_P0_15
bool "P0.15"
depends on BOARD_PCA10090_INTERFACE0_MCU
help
Pin P0.15 on nRF52840,
connected to P0.19 on the nRF9160.

config BOARD_PCA10090_NRF52840_RESET_P0_22
bool "P0.22"
depends on BOARD_PCA10090_INTERFACE1_MCU
help
Pin P0.22 on nRF52840,
connected to P0.21 on the nRF9160.

config BOARD_PCA10090_NRF52840_RESET_P1_04
bool "P1.04"
depends on BOARD_PCA10090_INTERFACE1_MCU
help
Pin P1.04 on nRF52840,
connected to P0.22 on the nRF9160.

config BOARD_PCA10090_NRF52840_RESET_P1_02
bool "P1.02"
depends on BOARD_PCA10090_INTERFACE1_MCU
help
Pin P1.02 on nRF52840,
connected to P0.23 on the nRF9160.

endchoice

endif # BOARD_PCA10090_NRF52840_RESET


module = BOARD_PCA10090 module = BOARD_PCA10090
module-str = Board Control module-str = Board Control
Expand Down
179 changes: 159 additions & 20 deletions boards/arm/nrf52840_pca10090/board.c
Expand Up @@ -21,6 +21,7 @@ LOG_MODULE_REGISTER(board_control, CONFIG_BOARD_PCA10090_LOG_LEVEL);
*/ */


/* GPIO pins on Port 0 */ /* GPIO pins on Port 0 */

#define INTERFACE0_U5 13 /* MCU interface pins 0 - 2 */ #define INTERFACE0_U5 13 /* MCU interface pins 0 - 2 */
#define INTERFACE1_U6 24 /* MCU interface pins 3 - 5 */ #define INTERFACE1_U6 24 /* MCU interface pins 3 - 5 */
#define UART1_VCOM_U7 12 /* Route nRF9160 UART1 to VCOM2 */ #define UART1_VCOM_U7 12 /* Route nRF9160 UART1 to VCOM2 */
Expand All @@ -29,6 +30,7 @@ LOG_MODULE_REGISTER(board_control, CONFIG_BOARD_PCA10090_LOG_LEVEL);
#define SWITCH2_U9 8 #define SWITCH2_U9 8


/* GPIO pins on Port 1 */ /* GPIO pins on Port 1 */

#define INTERFACE2_U21 10 /* COEX interface pins 6 - 8 */ #define INTERFACE2_U21 10 /* COEX interface pins 6 - 8 */
#define UART0_VCOM_U14 14 /* Route nRF9160 UART0 to VCOM0 */ #define UART0_VCOM_U14 14 /* Route nRF9160 UART0 to VCOM0 */
#define UART1_VCOM_U7 12 /* Route nRF9160 UART1 to VCOM2 */ #define UART1_VCOM_U7 12 /* Route nRF9160 UART1 to VCOM2 */
Expand All @@ -53,12 +55,18 @@ LOG_MODULE_REGISTER(board_control, CONFIG_BOARD_PCA10090_LOG_LEVEL);
* | COEX2 | -- MCU Interface Pin 8 -- | P1.15 | COEX2_PH | * | COEX2 | -- MCU Interface Pin 8 -- | P1.15 | COEX2_PH |
*/ */


/* The following tables specify the -default- values for each pin. __packed struct pin_config {
* Thus, when configuring the pins if there is a one in this table, u8_t pin;
* pull the pin to zero instead. u8_t val;
};

/* The following tables specify the configuration of each pin based on the
* Kconfig options that drive it.
* The switches have active-low logic, so when writing to the port we will
* need to invert the value to match the IS_ENABLED() logic.
*/ */


static const u8_t pins_on_p0[][2] = { static const struct pin_config pins_on_p0[] = {
{ INTERFACE0_U5, IS_ENABLED(CONFIG_BOARD_PCA10090_INTERFACE0_ARDUINO) }, { INTERFACE0_U5, IS_ENABLED(CONFIG_BOARD_PCA10090_INTERFACE0_ARDUINO) },
{ INTERFACE1_U6, IS_ENABLED(CONFIG_BOARD_PCA10090_INTERFACE1_TRACE) }, { INTERFACE1_U6, IS_ENABLED(CONFIG_BOARD_PCA10090_INTERFACE1_TRACE) },
{ UART1_VCOM_U7, IS_ENABLED(CONFIG_BOARD_PCA10090_UART1_ARDUINO) }, { UART1_VCOM_U7, IS_ENABLED(CONFIG_BOARD_PCA10090_UART1_ARDUINO) },
Expand All @@ -67,7 +75,7 @@ static const u8_t pins_on_p0[][2] = {
{ SWITCH2_U9, IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_PHY) }, { SWITCH2_U9, IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_PHY) },
}; };


static const u8_t pins_on_p1[][2] = { static const struct pin_config pins_on_p1[] = {
{ INTERFACE2_U21, IS_ENABLED(CONFIG_BOARD_PCA10090_INTERFACE2_COEX) }, { INTERFACE2_U21, IS_ENABLED(CONFIG_BOARD_PCA10090_INTERFACE2_COEX) },
{ UART0_VCOM_U14, IS_ENABLED(CONFIG_BOARD_PCA10090_UART0_VCOM) }, { UART0_VCOM_U14, IS_ENABLED(CONFIG_BOARD_PCA10090_UART0_VCOM) },
{ UART1_VCOM_U7, IS_ENABLED(CONFIG_BOARD_PCA10090_UART1_ARDUINO) }, { UART1_VCOM_U7, IS_ENABLED(CONFIG_BOARD_PCA10090_UART1_ARDUINO) },
Expand Down Expand Up @@ -163,40 +171,171 @@ static void config_print(void)
IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_ARDUINO)); IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_ARDUINO));
} }


static void configure_pins(struct device *port, const u8_t pins[][2], static int pins_configure(struct device *port, const struct pin_config cfg[],
size_t size) size_t pins)
{ {
int err; int err;


for (size_t i = 0; i < size; i++) { /* Write to the pins before configuring them as output,
err = gpio_pin_configure(port, pins[i][0], GPIO_DIR_OUT); * to make sure we are driving them to the correct level
__ASSERT(err == 0, "Unable to configure pin %u", pins[i][0]); * right after they are configured.

*/
/* The pin tables contain the default values for each pin. for (size_t i = 0; i < pins; i++) {
* Thus, if there is a one in the table, pull the pin to zero. /* The swiches on the board are active low, so we need
* to negate the IS_ENABLED() value from the tables.
*/ */
err = gpio_pin_write(port, pins[i][0], !pins[i][1]); err = gpio_pin_write(port, cfg[i].pin, !cfg[i].val);
__ASSERT(err == 0, "Unable to set pin %u to %u", pins[i][0], if (err) {
!pins[i][1]); return cfg[i].pin;
}

err = gpio_pin_configure(port, cfg[i].pin, GPIO_DIR_OUT);
if (err) {
return cfg[i].pin;
}

LOG_DBG("port %p, pin %u -> %u",
port, cfg[i].pin, !cfg[i].val);
}

return 0;
}

static void chip_reset(struct device *gpio,
struct gpio_callback *cb, u32_t pins)
{
const u32_t stamp = k_cycle_get_32();

printk("GPIO reset line asserted, device reset.\n");
printk("Bye @ cycle32 %u\n", stamp);

NVIC_SystemReset();
}

static void reset_pin_wait_low(struct device *port, u32_t pin)
{
int err;
u32_t val;

/* Wait until the pin is pulled low */
do {
err = gpio_pin_read(port, pin, &val);
} while (err == 0 && val != 0);
}

static int reset_pin_configure(struct device *p0, struct device *p1)
{
int err;
u32_t pin;
struct device *port = NULL;

static struct gpio_callback gpio_ctx;

/* MCU interface pins 0-2 */
if (IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P0_17)) {
port = p0;
pin = 17;
} }
if (IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P0_20)) {
port = p0;
pin = 20;
}
if (IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P0_15)) {
port = p0;
pin = 15;
}
/* MCU interface pins 3-6 */
if (IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P0_22)) {
port = p0;
pin = 22;
}
if (IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P1_04)) {
port = p1;
pin = 4;
}
if (IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P1_02)) {
port = p1;
pin = 2;
}

if (port == NULL) {
return -EINVAL;
}

err = gpio_pin_configure(port, pin,
GPIO_DIR_IN | GPIO_INT | GPIO_PUD_PULL_DOWN |
GPIO_INT_ACTIVE_HIGH | GPIO_INT_EDGE);
if (err) {
return err;
}

gpio_init_callback(&gpio_ctx, chip_reset, BIT(pin));

err = gpio_add_callback(port, &gpio_ctx);
if (err) {
return err;
}

err = gpio_pin_enable_callback(port, pin);
if (err) {
return err;
}

/* Wait until the pin is pulled low before continuing.
* This lets the other side ensure that they are ready.
*/
LOG_INF("GPIO reset line enabled on pin %s.%02u, holding..",
port == p0 ? "P0" : "P1", pin);

reset_pin_wait_low(port, pin);

return 0;
} }


static int init(struct device *dev) static int init(struct device *dev)
{ {
int rc;
struct device *p0; struct device *p0;
struct device *p1; struct device *p1;


p0 = device_get_binding(DT_GPIO_P0_DEV_NAME); p0 = device_get_binding(DT_GPIO_P0_DEV_NAME);
__ASSERT(p0, "Unable to find GPIO %s", DT_GPIO_P0_DEV_NAME); if (!p0) {
LOG_ERR("GPIO device " DT_GPIO_P0_DEV_NAME "not found!");
return -EIO;
}


p1 = device_get_binding(DT_GPIO_P1_DEV_NAME); p1 = device_get_binding(DT_GPIO_P1_DEV_NAME);
__ASSERT(p1, "Unable to find GPIO %s", DT_GPIO_P1_DEV_NAME); if (!p1) {
LOG_ERR("GPIO device " DT_GPIO_P1_DEV_NAME " not found!");
return -EIO;
}


configure_pins(p0, pins_on_p0, ARRAY_SIZE(pins_on_p0)); /* Configure pins on each port */
configure_pins(p1, pins_on_p1, ARRAY_SIZE(pins_on_p1)); rc = pins_configure(p0, pins_on_p0, ARRAY_SIZE(pins_on_p0));
if (rc) {
LOG_ERR("Error while configuring pin P0.%02d", rc);
return -EIO;
}
rc = pins_configure(p1, pins_on_p1, ARRAY_SIZE(pins_on_p1));
if (rc) {
LOG_ERR("Error while configuring pin P1.%02d", rc);
return -EIO;
}


config_print(); config_print();


/* Make sure to configure the switches before initializing
* the GPIO reset pin, so that we are connected to
* the nRF9160 before enabling our interrupt.
*/
if (IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET)) {
rc = reset_pin_configure(p0, p1);
if (rc) {
LOG_ERR("Unable to configure reset pin, err %d", rc);
return -EIO;
}
}

LOG_INF("Board configured."); LOG_INF("Board configured.");


return 0; return 0;
Expand Down
9 changes: 9 additions & 0 deletions boards/arm/nrf52840_pca10090/integrity.c
Expand Up @@ -49,3 +49,12 @@ BUILD_ASSERT_MSG(IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH0_PHY) ||
BUILD_ASSERT_MSG(IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_PHY) || BUILD_ASSERT_MSG(IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_PHY) ||
IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_ARDUINO), IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_ARDUINO),
"Invalid switch 2 routing"); "Invalid switch 2 routing");

BUILD_ASSERT_MSG(!IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET) ||
IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P0_17) ||
IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P0_20) ||
IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P0_15) ||
IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P0_22) ||
IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P1_04) ||
IS_ENABLED(CONFIG_BOARD_PCA10090_NRF52840_RESET_P1_02),
"No reset line selected, please check Kconfig macros");

0 comments on commit 3dc71c8

Please sign in to comment.