From c08a24c7766d87773d38829a564174f4143baffa Mon Sep 17 00:00:00 2001 From: Winford Date: Mon, 9 Oct 2023 19:05:40 -0700 Subject: [PATCH] Allow using Pico-W `WL_GPIO` pins with gpio nifs Modifies the Pico gpio dirver to accept atoms for the special wl_gpio pins present in the Pico-W. - Adds support for `wl0` and `wl1` as output pins in `gpio:digital_write/2`. - Adds support for `wl2` as an input pin in `gpio:digital_read/1`. Signed-off-by: Winford --- libs/eavmlib/src/gpio.erl | 2 +- src/platforms/rp2040/src/lib/gpiodriver.c | 50 ++++++++++++++++++++--- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/libs/eavmlib/src/gpio.erl b/libs/eavmlib/src/gpio.erl index f91ac90d1..0b5063d76 100644 --- a/libs/eavmlib/src/gpio.erl +++ b/libs/eavmlib/src/gpio.erl @@ -58,7 +58,7 @@ -type gpio() :: pid(). %% This is the pid returned by `gpio:start/0'. --type pin() :: non_neg_integer() | pin_tuple(). +-type pin() :: non_neg_integer() | pin_tuple() | atom(). %% The pin definition for ESP32 and PR2040 is a non-negative integer, on the STM32 platform it is a tuple. -type pin_tuple() :: {gpio_bank(), 0..15}. %% A pin parameter on STM32 is a tuple consisting of a GPIO bank and pin number. diff --git a/src/platforms/rp2040/src/lib/gpiodriver.c b/src/platforms/rp2040/src/lib/gpiodriver.c index 30b56f7a0..2462a12a1 100644 --- a/src/platforms/rp2040/src/lib/gpiodriver.c +++ b/src/platforms/rp2040/src/lib/gpiodriver.c @@ -66,6 +66,15 @@ static const AtomStringIntPair pin_level_table[] = { SELECT_INT_DEFAULT(AtomVMRP2040GPIOInvalid) }; +#ifdef LIB_PICO_CYW43_ARCH +static const AtomStringIntPair wl_pin_table[] = { + { ATOM_STR("\x3", "wl0"), 0 }, + { ATOM_STR("\x3", "wl1"), 1 }, + { ATOM_STR("\x3", "wl2"), 2 }, + SELECT_INT_DEFAULT(-1) +}; +#endif + static term nif_gpio_init(Context *ctx, int argc, term argv[]) { UNUSED(ctx); @@ -117,8 +126,7 @@ static term nif_gpio_digital_write(Context *ctx, int argc, term argv[]) { UNUSED(argc); - VALIDATE_VALUE(argv[0], term_is_integer); - int gpio_num = term_to_int(argv[0]); + term gpio_pin = argv[0]; term level_term = argv[1]; int level; @@ -133,7 +141,22 @@ static term nif_gpio_digital_write(Context *ctx, int argc, term argv[]) return ERROR_ATOM; } } - gpio_put(gpio_num, level); + + int gpio_num; + if (term_is_integer(gpio_pin)) { + gpio_num = gpio_pin; + gpio_put(gpio_num, level); +#ifdef LIB_PICO_CYW43_ARCH + } else if (term_is_atom(gpio_pin)) { + gpio_num = interop_atom_term_select_int(wl_pin_table, gpio_pin, ctx->global); + if (UNLIKELY((gpio_num == -1) || (gpio_num > 1))) { + return ERROR_ATOM; + } + cyw43_arch_gpio_put(gpio_num, level); +#endif + } else { + return ERROR_ATOM; + } return OK_ATOM; } @@ -142,9 +165,24 @@ static term nif_gpio_digital_read(Context *ctx, int argc, term argv[]) { UNUSED(argc); - VALIDATE_VALUE(argv[0], term_is_integer); - int gpio_num = term_to_int(argv[0]); - bool level = gpio_get(gpio_num); + term gpio_pin = argv[0]; + int gpio_num; + bool level; + + if (term_is_integer(gpio_pin)) { + gpio_num = gpio_pin; + level = gpio_get(gpio_num); +#ifdef LIB_PICO_CYW43_ARCH + } else if (term_is_atom(gpio_pin)) { + gpio_num = interop_atom_term_select_int(wl_pin_table, gpio_pin, ctx->global); + if (UNLIKELY((gpio_num != 2))) { + return ERROR_ATOM; + } + level = cyw43_arch_gpio_get(gpio_num); +#endif + } else { + return ERROR_ATOM; + } return level ? globalcontext_make_atom(ctx->global, ATOM_STR("\x4", "high")) : globalcontext_make_atom(ctx->global, ATOM_STR("\x3", "low")); }