Skip to content
Permalink
Browse files

boards: arm: nrf52840_pca10090: add a GPIO reset line

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 17, 2019
1 parent 0604e21 commit 3dc71c8d34d288d9db283a298e4c9f774faf8023
Showing with 227 additions and 20 deletions.
  1. +59 −0 boards/arm/nrf52840_pca10090/Kconfig
  2. +159 −20 boards/arm/nrf52840_pca10090/board.c
  3. +9 −0 boards/arm/nrf52840_pca10090/integrity.c
@@ -192,6 +192,65 @@ config BOARD_PCA10090_INTERFACE2_MCU

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-str = Board Control
@@ -21,6 +21,7 @@ LOG_MODULE_REGISTER(board_control, CONFIG_BOARD_PCA10090_LOG_LEVEL);
*/

/* GPIO pins on Port 0 */

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

/* GPIO pins on Port 1 */

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

/* The following tables specify the -default- values for each pin.
* Thus, when configuring the pins if there is a one in this table,
* pull the pin to zero instead.
__packed struct pin_config {
u8_t pin;
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) },
{ INTERFACE1_U6, IS_ENABLED(CONFIG_BOARD_PCA10090_INTERFACE1_TRACE) },
{ UART1_VCOM_U7, IS_ENABLED(CONFIG_BOARD_PCA10090_UART1_ARDUINO) },
@@ -67,7 +75,7 @@ static const u8_t pins_on_p0[][2] = {
{ 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) },
{ UART0_VCOM_U14, IS_ENABLED(CONFIG_BOARD_PCA10090_UART0_VCOM) },
{ UART1_VCOM_U7, IS_ENABLED(CONFIG_BOARD_PCA10090_UART1_ARDUINO) },
@@ -163,40 +171,171 @@ static void config_print(void)
IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_ARDUINO));
}

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

for (size_t i = 0; i < size; i++) {
err = gpio_pin_configure(port, pins[i][0], GPIO_DIR_OUT);
__ASSERT(err == 0, "Unable to configure pin %u", pins[i][0]);

/* The pin tables contain the default values for each pin.
* Thus, if there is a one in the table, pull the pin to zero.
/* Write to the pins before configuring them as output,
* to make sure we are driving them to the correct level
* right after they are configured.
*/
for (size_t i = 0; i < pins; i++) {
/* 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]);
__ASSERT(err == 0, "Unable to set pin %u to %u", pins[i][0],
!pins[i][1]);
err = gpio_pin_write(port, cfg[i].pin, !cfg[i].val);
if (err) {
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)
{
int rc;
struct device *p0;
struct device *p1;

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);
__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(p1, pins_on_p1, ARRAY_SIZE(pins_on_p1));
/* Configure pins on each port */
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();

/* 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.");

return 0;
@@ -49,3 +49,12 @@ BUILD_ASSERT_MSG(IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH0_PHY) ||
BUILD_ASSERT_MSG(IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_PHY) ||
IS_ENABLED(CONFIG_BOARD_PCA10090_SWITCH1_ARDUINO),
"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.
You can’t perform that action at this time.