summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/rp2/CMakeLists.txt29
-rw-r--r--ports/rp2/Makefile4
-rw-r--r--ports/rp2/README.md7
-rw-r--r--ports/rp2/cyw43_configport.h98
-rw-r--r--ports/rp2/machine_pin.c354
-rw-r--r--ports/rp2/main.c29
-rw-r--r--ports/rp2/modrp2.c26
-rw-r--r--ports/rp2/mpconfigport.h22
-rw-r--r--ports/rp2/mphalport.c23
-rw-r--r--ports/rp2/mphalport.h13
-rw-r--r--ports/rp2/mpnetworkport.c35
-rw-r--r--ports/rp2/pendsv.c13
-rw-r--r--ports/rp2/pendsv.h3
-rw-r--r--ports/rp2/rp2_pio.c5
14 files changed, 597 insertions, 64 deletions
diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index 50afa55a9..9185c7d64 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -16,6 +16,10 @@ endif()
# Use the local tinyusb instead of the one in pico-sdk
set(PICO_TINYUSB_PATH ${MICROPY_DIR}/lib/tinyusb)
+# Use the local cyw43_driver instead of the one in pico-sdk
+set(PICO_CYW43_DRIVER_PATH ${MICROPY_DIR}/lib/cyw43-driver)
+# Use the local lwip instead of the one in pico-sdk
+set(PICO_LWIP_PATH ${MICROPY_DIR}/lib/lwip)
# Set the location of this port's directory.
set(MICROPY_PORT_DIR ${CMAKE_SOURCE_DIR})
@@ -73,6 +77,7 @@ set(MICROPY_SOURCE_LIB
${MICROPY_DIR}/lib/mbedtls_errors/mp_mbedtls_errors.c
${MICROPY_DIR}/lib/oofatfs/ff.c
${MICROPY_DIR}/lib/oofatfs/ffunicode.c
+ ${MICROPY_DIR}/shared/netutils/dhcpserver.c
${MICROPY_DIR}/shared/netutils/netutils.c
${MICROPY_DIR}/shared/netutils/trace.c
${MICROPY_DIR}/shared/readline/readline.c
@@ -216,6 +221,30 @@ if(MICROPY_BLUETOOTH_NIMBLE)
list(APPEND MICROPY_INC_CORE ${NIMBLE_INCLUDE})
endif()
+if (MICROPY_PY_NETWORK_CYW43)
+ string(CONCAT GIT_SUBMODULES "${GIT_SUBMODULES} " lib/cyw43-driver)
+
+ target_compile_definitions(${MICROPY_TARGET} PRIVATE
+ MICROPY_PY_NETWORK_CYW43=1
+ MICROPY_PY_NETWORK_CYW43_USE_LIB_DRIVER=1
+ MICROPY_PY_SOCKET_DEFAULT_TIMEOUT_MS=30000 # default socket timeout
+ )
+ if (CMAKE_BUILD_TYPE MATCHES Debug)
+ target_compile_definitions(${MICROPY_TARGET} PRIVATE
+ CYW43_USE_STATS=1
+ )
+ endif()
+
+ list(APPEND MICROPY_SOURCE_EXTMOD
+ ${MICROPY_DIR}/extmod/network_cyw43.c
+ )
+
+ target_link_libraries(${MICROPY_TARGET}
+ cyw43_driver_picow
+ cmsis_core
+ )
+endif()
+
if (MICROPY_PY_NETWORK_NINAW10)
target_compile_definitions(${MICROPY_TARGET} PRIVATE
MICROPY_PY_NETWORK_NINAW10=1
diff --git a/ports/rp2/Makefile b/ports/rp2/Makefile
index c2138a340..87c1d650e 100644
--- a/ports/rp2/Makefile
+++ b/ports/rp2/Makefile
@@ -29,9 +29,11 @@ all:
clean:
$(RM) -rf $(BUILD)
-GIT_SUBMODULES += lib/mbedtls lib/pico-sdk lib/tinyusb
+GIT_SUBMODULES += lib/mbedtls lib/tinyusb
submodules:
+ # lib/pico-sdk is required for the cmake build to function (as used for boards other than PICO below)
+ $(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="lib/pico-sdk" submodules
ifeq ($(BOARD),PICO)
# Run the standard submodules target with minimum required submodules above
$(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$(GIT_SUBMODULES)" submodules
diff --git a/ports/rp2/README.md b/ports/rp2/README.md
index 5836ac0cd..078919ce8 100644
--- a/ports/rp2/README.md
+++ b/ports/rp2/README.md
@@ -37,6 +37,13 @@ You can also build the standard CMake way. The final firmware is found in
the top-level of the CMake build directory (`build` by default) and is
called `firmware.uf2`.
+If you are using a different board other than a Rasoberry Pi Pico, then you should
+pass the board name to the build; e.g. for Raspberry Pi Pico W:
+
+ $ make BOARD=PICO_W submodules
+ $ make BOARD=PICO_W clean
+ $ make BOARD=PICO_W
+
## Deploying firmware to the device
Firmware can be deployed to the device by putting it into bootloader mode
diff --git a/ports/rp2/cyw43_configport.h b/ports/rp2/cyw43_configport.h
new file mode 100644
index 000000000..6173964cb
--- /dev/null
+++ b/ports/rp2/cyw43_configport.h
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_RP2_CYW43_CONFIGPORT_H
+#define MICROPY_INCLUDED_RP2_CYW43_CONFIGPORT_H
+
+// The board-level config will be included here, so it can set some CYW43 values.
+#include "py/mpconfig.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "pendsv.h"
+
+#define CYW43_IOCTL_TIMEOUT_US (1000000)
+#define CYW43_SLEEP_MAX (10)
+#define CYW43_NETUTILS (1)
+#define CYW43_USE_OTP_MAC (1)
+
+#define CYW43_EPERM MP_EPERM // Operation not permitted
+#define CYW43_EIO MP_EIO // I/O error
+#define CYW43_EINVAL MP_EINVAL // Invalid argument
+#define CYW43_ETIMEDOUT MP_ETIMEDOUT // Connection timed out
+
+#define CYW43_THREAD_ENTER MICROPY_PY_LWIP_ENTER
+#define CYW43_THREAD_EXIT MICROPY_PY_LWIP_EXIT
+#define CYW43_THREAD_LOCK_CHECK
+
+#define CYW43_SDPCM_SEND_COMMON_WAIT __WFI();
+#define CYW43_DO_IOCTL_WAIT __WFI();
+
+#define CYW43_ARRAY_SIZE(a) MP_ARRAY_SIZE(a)
+
+#define CYW43_HAL_PIN_MODE_INPUT MP_HAL_PIN_MODE_INPUT
+#define CYW43_HAL_PIN_MODE_OUTPUT MP_HAL_PIN_MODE_OUTPUT
+#define CYW43_HAL_PIN_PULL_NONE MP_HAL_PIN_PULL_NONE
+#define CYW43_HAL_PIN_PULL_UP MP_HAL_PIN_PULL_UP
+#define CYW43_HAL_PIN_PULL_DOWN MP_HAL_PIN_PULL_DOWN
+
+#define CYW43_HAL_MAC_WLAN0 MP_HAL_MAC_WLAN0
+
+// set in SDK board header
+#define CYW43_NUM_GPIOS CYW43_WL_GPIO_COUNT
+
+#define CYW43_POST_POLL_HOOK cyw43_post_poll_hook();
+
+#define cyw43_hal_ticks_us mp_hal_ticks_us
+#define cyw43_hal_ticks_ms mp_hal_ticks_ms
+
+#define cyw43_hal_pin_obj_t mp_hal_pin_obj_t
+#define cyw43_hal_pin_config mp_hal_pin_config
+#define cyw43_hal_pin_read mp_hal_pin_read
+#define cyw43_hal_pin_low mp_hal_pin_low
+#define cyw43_hal_pin_high mp_hal_pin_high
+
+#define cyw43_hal_get_mac mp_hal_get_mac
+#define cyw43_hal_get_mac_ascii mp_hal_get_mac_ascii
+#define cyw43_hal_generate_laa_mac mp_hal_generate_laa_mac
+
+#define cyw43_schedule_internal_poll_dispatch(func) pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, func)
+
+void cyw43_post_poll_hook(void);
+
+static inline void cyw43_delay_us(uint32_t us) {
+ uint32_t start = mp_hal_ticks_us();
+ while (mp_hal_ticks_us() - start < us) {
+ }
+}
+
+static inline void cyw43_delay_ms(uint32_t ms) {
+ uint32_t us = ms * 1000;
+ int32_t start = mp_hal_ticks_us();
+ while (mp_hal_ticks_us() - start < us) {
+ __WFI();
+ }
+}
+
+#endif // MICROPY_INCLUDED_RP2_CYW43_CONFIGPORT_H
diff --git a/ports/rp2/machine_pin.c b/ports/rp2/machine_pin.c
index ca8de6ce2..a0c5dead9 100644
--- a/ports/rp2/machine_pin.c
+++ b/ports/rp2/machine_pin.c
@@ -58,9 +58,18 @@
// Open drain behaviour is simulated.
#define GPIO_IS_OPEN_DRAIN(id) (machine_pin_open_drain_mask & (1 << (id)))
+#ifndef MICROPY_HW_PIN_RESERVED
+#define MICROPY_HW_PIN_RESERVED(i) (0)
+#endif
+
typedef struct _machine_pin_obj_t {
mp_obj_base_t base;
- uint32_t id;
+ uint8_t id;
+ #if MICROPY_HW_PIN_CYW43_COUNT
+ bool is_cyw43;
+ bool is_output;
+ bool last_output_value;
+ #endif
} machine_pin_obj_t;
typedef struct _machine_pin_irq_obj_t {
@@ -104,9 +113,60 @@ STATIC const machine_pin_obj_t machine_pin_obj[NUM_BANK0_GPIOS] = {
{{&machine_pin_type}, 29},
};
+#if MICROPY_HW_PIN_CYW43_COUNT
+#include "lib/cyw43-driver/src/cyw43.h"
+#define CYW43_PIN_NAME_PREFIX "WL_GPIO"
+STATIC machine_pin_obj_t cyw43_pin_obj[MICROPY_HW_PIN_CYW43_COUNT];
+#endif
+
+#define LED_PIN_NAME "LED"
+
+#ifndef MICROPY_HW_PIN_ENABLE_LED_PIN
+#if defined(MICROPY_HW_PIN_CYW43_LED_PIN_NUM) || defined(PICO_DEFAULT_LED_PIN)
+#define MICROPY_HW_PIN_ENABLE_LED_PIN 1
+#endif
+#endif
+
+#ifdef MICROPY_HW_PIN_ENABLE_LED_PIN
+#ifdef MICROPY_HW_PIN_CYW43_LED_PIN_NUM
+STATIC machine_pin_obj_t *led_pin_obj = &cyw43_pin_obj[MICROPY_HW_PIN_CYW43_LED_PIN_NUM];
+#elif defined(MICROPY_HW_PIN_LED_PIN_NUM)
+STATIC machine_pin_obj_t *led_pin_obj = &machine_pin_obj[MICROPY_HW_PIN_LED_PIN_NUM];
+#elif defined(PICO_DEFAULT_LED_PIN)
+STATIC const machine_pin_obj_t *led_pin_obj = &machine_pin_obj[PICO_DEFAULT_LED_PIN];
+#else
+#error MICROPY_HW_PIN_ENABLE_LED_PIN defined but there is no LED pin
+#endif
+#endif
+
// Mask with "1" indicating that the corresponding pin is in simulated open-drain mode.
uint32_t machine_pin_open_drain_mask;
+#if MICROPY_HW_PIN_CYW43_COUNT
+STATIC inline bool is_cyw43_pin(__unused const machine_pin_obj_t *self) {
+ return self->is_cyw43;
+}
+#else
+#define is_cyw43_pin(x) false
+#endif
+
+#if MICROPY_HW_PIN_CYW43_COUNT
+STATIC inline void update_cyw43_value(__unused machine_pin_obj_t *self, bool value) {
+ if (value != self->last_output_value || !self->is_output) {
+ cyw43_gpio_set(&cyw43_state, self->id, value);
+ }
+ self->last_output_value = value;
+}
+#endif
+
+#if MICROPY_HW_PIN_CYW43_COUNT
+STATIC inline bool get_cyw43_value(__unused machine_pin_obj_t *self) {
+ bool value = false;
+ cyw43_gpio_get(&cyw43_state, self->id, &value);
+ return value;
+}
+#endif
+
STATIC void gpio_irq(void) {
for (int i = 0; i < 4; ++i) {
uint32_t intr = iobank0_hw->intr[i];
@@ -129,15 +189,24 @@ STATIC void gpio_irq(void) {
void machine_pin_init(void) {
memset(MP_STATE_PORT(machine_pin_irq_obj), 0, sizeof(MP_STATE_PORT(machine_pin_irq_obj)));
- irq_set_exclusive_handler(IO_IRQ_BANK0, gpio_irq);
+ irq_add_shared_handler(IO_IRQ_BANK0, gpio_irq, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
irq_set_enabled(IO_IRQ_BANK0, true);
+ #if MICROPY_HW_PIN_CYW43_COUNT
+ for (uint i = 0; i < count_of(cyw43_pin_obj); i++) {
+ cyw43_pin_obj[i].id = i;
+ cyw43_pin_obj[i].base.type = &machine_pin_type;
+ cyw43_pin_obj[i].is_cyw43 = true;
+ }
+ #endif
}
void machine_pin_deinit(void) {
for (int i = 0; i < NUM_BANK0_GPIOS; ++i) {
+ if (MICROPY_HW_PIN_RESERVED(i)) {
+ continue;
+ }
gpio_set_irq_enabled(i, GPIO_IRQ_ALL, false);
}
- irq_set_enabled(IO_IRQ_BANK0, false);
irq_remove_handler(IO_IRQ_BANK0, gpio_irq);
}
@@ -145,45 +214,112 @@ STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_prin
machine_pin_obj_t *self = self_in;
uint funcsel = GPIO_GET_FUNCSEL(self->id);
qstr mode_qst;
- if (funcsel == GPIO_FUNC_SIO) {
- if (GPIO_IS_OPEN_DRAIN(self->id)) {
- mode_qst = MP_QSTR_OPEN_DRAIN;
- } else if (GPIO_IS_OUT(self->id)) {
- mode_qst = MP_QSTR_OUT;
+ if (!is_cyw43_pin(self)) {
+ if (funcsel == GPIO_FUNC_SIO) {
+ if (GPIO_IS_OPEN_DRAIN(self->id)) {
+ mode_qst = MP_QSTR_OPEN_DRAIN;
+ } else if (GPIO_IS_OUT(self->id)) {
+ mode_qst = MP_QSTR_OUT;
+ } else {
+ mode_qst = MP_QSTR_IN;
+ }
} else {
- mode_qst = MP_QSTR_IN;
+ mode_qst = MP_QSTR_ALT;
+ }
+ mp_printf(print, "Pin(%u, mode=%q", self->id, mode_qst);
+ bool pull_up = false;
+ if (GPIO_IS_PULL_UP(self->id)) {
+ mp_printf(print, ", pull=%q", MP_QSTR_PULL_UP);
+ pull_up = true;
+ }
+ if (GPIO_IS_PULL_DOWN(self->id)) {
+ if (pull_up) {
+ mp_printf(print, "|%q", MP_QSTR_PULL_DOWN);
+ } else {
+ mp_printf(print, ", pull=%q", MP_QSTR_PULL_DOWN);
+ }
+ }
+ if (funcsel != GPIO_FUNC_SIO) {
+ mp_printf(print, ", alt=%u", funcsel);
}
} else {
- mode_qst = MP_QSTR_ALT;
+ #if MICROPY_HW_PIN_CYW43_COUNT
+ mode_qst = self->is_output ? MP_QSTR_OUT : MP_QSTR_IN;
+ mp_printf(print, "Pin(%s%u, mode=%q", CYW43_PIN_NAME_PREFIX, self->id, mode_qst);
+ #endif
+ }
+ mp_printf(print, ")");
+}
+
+enum {
+ ARG_mode, ARG_pull, ARG_value, ARG_alt
+};
+static const mp_arg_t allowed_args[] = {
+ {MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
+ {MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
+ {MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
+ {MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = GPIO_FUNC_SIO}},
+};
+
+#if MICROPY_HW_PIN_CYW43_COUNT
+// pin.init(mode, pull=None, *, value=None, alt=FUNC_SIO)
+STATIC mp_obj_t machine_pin_cyw43_obj_init_helper(machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (args[ARG_pull].u_obj != mp_const_none) {
+ int pull = mp_obj_get_int(args[ARG_pull].u_obj);
+ if (pull) {
+ mp_raise_ValueError("Pulls are not supported for this pin");
+ }
+ }
+
+ if (args[ARG_alt].u_int != GPIO_FUNC_SIO) {
+ mp_raise_ValueError("Alternate functions are not supported for this pin");
}
- mp_printf(print, "Pin(%u, mode=%q", self->id, mode_qst);
- bool pull_up = false;
- if (GPIO_IS_PULL_UP(self->id)) {
- mp_printf(print, ", pull=%q", MP_QSTR_PULL_UP);
- pull_up = true;
+
+ int value = -1;
+ if (args[ARG_value].u_obj != mp_const_none) {
+ value = mp_obj_is_true(args[ARG_value].u_obj);
}
- if (GPIO_IS_PULL_DOWN(self->id)) {
- if (pull_up) {
- mp_printf(print, "|%q", MP_QSTR_PULL_DOWN);
+
+ if (args[ARG_mode].u_obj != mp_const_none) {
+ mp_int_t mode = mp_obj_get_int(args[ARG_mode].u_obj);
+ if (mode == GPIO_MODE_IN) {
+ if (self->is_output) {
+ // todo need to disable output
+ }
+ self->is_output = false;
+ } else if (mode == GPIO_MODE_OUT) {
+ if (!self->is_output) {
+ // todo need to enable output
+ // for now we just set the value
+ if (value == -1) {
+ value = self->last_output_value;
+ }
+ self->last_output_value = !self->last_output_value; // defeat shortcircuit
+ update_cyw43_value(self, value);
+ self->is_output = true;
+ }
} else {
- mp_printf(print, ", pull=%q", MP_QSTR_PULL_DOWN);
+ mp_raise_ValueError("only Pin.OUT and Pin.IN are supported for this pin");
}
}
- if (funcsel != GPIO_FUNC_SIO) {
- mp_printf(print, ", alt=%u", funcsel);
+
+ if (value != -1) {
+ if (self->is_output) {
+ update_cyw43_value(self, value);
+ } else {
+ // figure if you pass a value to IN it should still remember it (this is what regular GPIO does)
+ self->last_output_value = value;
+ }
}
- mp_printf(print, ")");
+
+ return mp_const_none;
}
+#endif
-// pin.init(mode, pull=None, *, value=None, alt=FUNC_SIO)
STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_mode, ARG_pull, ARG_value, ARG_alt };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
- { MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
- { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
- { MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = GPIO_FUNC_SIO}},
- };
// parse args
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@@ -216,7 +352,6 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
pull = mp_obj_get_int(args[ARG_pull].u_obj);
}
gpio_set_pulls(self->id, pull & GPIO_PULL_UP, pull & GPIO_PULL_DOWN);
-
return mp_const_none;
}
@@ -224,21 +359,57 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
- // get the wanted pin object
- int wanted_pin = mp_obj_get_int(args[0]);
- if (!(0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj))) {
- mp_raise_ValueError("invalid pin");
- }
- const machine_pin_obj_t *self = &machine_pin_obj[wanted_pin];
+ const machine_pin_obj_t *self = NULL;
+ if (mp_obj_is_str(args[0])) {
+ const char *name = mp_obj_str_get_str(args[0]);
+ #if MICROPY_HW_PIN_ENABLE_LED_PIN
+ if (!strcmp(name, LED_PIN_NAME)) {
+ self = led_pin_obj;
+ }
+ #endif
+ #if MICROPY_HW_PIN_CYW43_COUNT
+ static_assert(MICROPY_HW_PIN_CYW43_COUNT < 10, ""); // makes parsing name easy!
+ if (!self && !strncmp(name, CYW43_PIN_NAME_PREFIX, strlen(CYW43_PIN_NAME_PREFIX)) && strlen(name) == strlen(CYW43_PIN_NAME_PREFIX) + 1) {
+ int num = name[strlen(CYW43_PIN_NAME_PREFIX)] - '0';
+ if (num < MICROPY_HW_PIN_CYW43_COUNT) {
+ self = &cyw43_pin_obj[num];
+ }
+ }
+ #endif
+ if (!self) {
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Unknown named pin \"%s\""), name);
+ }
+ }
+ if (!self) {
+ // get the wanted pin object
+ int wanted_pin = mp_obj_get_int(args[0]);
+ if (!(0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj))) {
+ mp_raise_ValueError("invalid pin");
+ }
+ self = &machine_pin_obj[wanted_pin];
+ }
+ // note we have different init args based on the type of pin. so Pin("LED", Pin.OUT) may not always make sense
+ if (!is_cyw43_pin(self)) {
+ if (n_args > 1 || n_kw > 0) {
+ // pin mode given, so configure this GPIO
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args);
+ }
+ return MP_OBJ_FROM_PTR(self);
+ }
+ #if MICROPY_HW_PIN_CYW43_COUNT
if (n_args > 1 || n_kw > 0) {
// pin mode given, so configure this GPIO
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
- machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args);
+ // The regular Pins are const, but the CYW43 pins are mutable.
+ machine_pin_obj_t *mutable_self = (machine_pin_obj_t *)self;
+ machine_pin_cyw43_obj_init_helper(mutable_self, n_args - 1, args + 1, &kw_args);
}
-
return MP_OBJ_FROM_PTR(self);
+ #endif
}
// fast method for getting/setting pin value
@@ -247,23 +418,39 @@ STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c
machine_pin_obj_t *self = self_in;
if (n_args == 0) {
// get pin
- return MP_OBJ_NEW_SMALL_INT(gpio_get(self->id));
+ if (!is_cyw43_pin(self)) {
+ return MP_OBJ_NEW_SMALL_INT(gpio_get(self->id));
+ }
+ #if MICROPY_HW_PIN_CYW43_COUNT
+ return MP_OBJ_NEW_SMALL_INT(get_cyw43_value(self));
+ #endif
} else {
// set pin
bool value = mp_obj_is_true(args[0]);
- if (GPIO_IS_OPEN_DRAIN(self->id)) {
- MP_STATIC_ASSERT(GPIO_IN == 0 && GPIO_OUT == 1);
- gpio_set_dir(self->id, 1 - value);
- } else {
- gpio_put(self->id, value);
+ if (!is_cyw43_pin(self)) {
+ if (GPIO_IS_OPEN_DRAIN(self->id)) {
+ MP_STATIC_ASSERT(GPIO_IN == 0 && GPIO_OUT == 1);
+ gpio_set_dir(self->id, 1 - value);
+ } else {
+ gpio_put(self->id, value);
+ }
+ return mp_const_none;
}
- return mp_const_none;
+ #if MICROPY_HW_PIN_CYW43_COUNT
+ update_cyw43_value(self, value);
+ #endif
}
+ return mp_const_none;
}
// pin.init(mode, pull)
STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
- return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
+ if (!is_cyw43_pin(args[0])) {
+ return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
+ }
+ #if MICROPY_HW_PIN_CYW43_COUNT
+ return machine_pin_cyw43_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
+ #endif
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init);
@@ -276,40 +463,59 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_
// pin.low()
STATIC mp_obj_t machine_pin_low(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (GPIO_IS_OPEN_DRAIN(self->id)) {
- gpio_set_dir(self->id, GPIO_OUT);
- } else {
- gpio_clr_mask(1u << self->id);
+ if (!is_cyw43_pin(self)) {
+ if (GPIO_IS_OPEN_DRAIN(self->id)) {
+ gpio_set_dir(self->id, GPIO_OUT);
+ } else {
+ gpio_clr_mask(1u << self->id);
+ }
+ return mp_const_none;
}
+ #if MICROPY_HW_PIN_CYW43_COUNT
+ update_cyw43_value(self, 0);
return mp_const_none;
+ #endif
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_low_obj, machine_pin_low);
// pin.high()
STATIC mp_obj_t machine_pin_high(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (GPIO_IS_OPEN_DRAIN(self->id)) {
- gpio_set_dir(self->id, GPIO_IN);
- } else {
- gpio_set_mask(1u << self->id);
+ if (!is_cyw43_pin(self)) {
+ if (GPIO_IS_OPEN_DRAIN(self->id)) {
+ gpio_set_dir(self->id, GPIO_IN);
+ } else {
+ gpio_set_mask(1u << self->id);
+ }
+ return mp_const_none;
}
+ #if MICROPY_HW_PIN_CYW43_COUNT
+ update_cyw43_value(self, 1);
return mp_const_none;
+ #endif
}
+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_high_obj, machine_pin_high);
// pin.toggle()
STATIC mp_obj_t machine_pin_toggle(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (GPIO_IS_OPEN_DRAIN(self->id)) {
- if (GPIO_IS_OUT(self->id)) {
- gpio_set_dir(self->id, GPIO_IN);
+ if (!is_cyw43_pin(self)) {
+ if (GPIO_IS_OPEN_DRAIN(self->id)) {
+ if (GPIO_IS_OUT(self->id)) {
+ gpio_set_dir(self->id, GPIO_IN);
+ } else {
+ gpio_set_dir(self->id, GPIO_OUT);
+ }
} else {
- gpio_set_dir(self->id, GPIO_OUT);
+ gpio_xor_mask(1u << self->id);
}
- } else {
- gpio_xor_mask(1u << self->id);
+ return mp_const_none;
}
+ #if MICROPY_HW_PIN_CYW43_COUNT
+ update_cyw43_value(self, self->last_output_value ^ 1);
return mp_const_none;
+ #endif
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_toggle_obj, machine_pin_toggle);
@@ -357,6 +563,10 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
};
machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ if (is_cyw43_pin(self)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("expecting a regular GPIO Pin"));
+ }
+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -400,16 +610,31 @@ STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, i
(void)errcode;
machine_pin_obj_t *self = self_in;
+ if (!is_cyw43_pin(self)) {
+ switch (request) {
+ case MP_PIN_READ: {
+ return gpio_get(self->id);
+ }
+ case MP_PIN_WRITE: {
+ gpio_put(self->id, arg);
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+ #if MICROPY_HW_PIN_CYW43_COUNT
switch (request) {
case MP_PIN_READ: {
- return gpio_get(self->id);
+ return get_cyw43_value(self);
}
case MP_PIN_WRITE: {
- gpio_put(self->id, arg);
+ update_cyw43_value(self, arg);
return 0;
}
}
return -1;
+ #endif
}
STATIC const mp_pin_p_t pin_pin_p = {
@@ -457,5 +682,8 @@ mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t obj) {
mp_raise_ValueError(MP_ERROR_TEXT("expecting a Pin"));
}
machine_pin_obj_t *pin = MP_OBJ_TO_PTR(obj);
+ if (is_cyw43_pin(pin)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("expecting a regular GPIO Pin"));
+ }
return pin->id;
}
diff --git a/ports/rp2/main.c b/ports/rp2/main.c
index da21e0b39..664bb1810 100644
--- a/ports/rp2/main.c
+++ b/ports/rp2/main.c
@@ -46,12 +46,16 @@
#include "pico/stdlib.h"
#include "pico/binary_info.h"
+#include "pico/unique_id.h"
#include "hardware/rtc.h"
#include "hardware/structs/rosc.h"
#if MICROPY_PY_LWIP
#include "lwip/init.h"
#include "lwip/apps/mdns.h"
#endif
+#if MICROPY_PY_NETWORK_CYW43
+#include "lib/cyw43-driver/src/cyw43.h"
+#endif
#ifndef MICROPY_GC_HEAP_SIZE
#if MICROPY_PY_LWIP
@@ -90,6 +94,10 @@ int main(int argc, char **argv) {
mp_thread_init();
#endif
+ #ifndef NDEBUG
+ stdio_init_all();
+ #endif
+
// Start and initialise the RTC
datetime_t t = {
.year = 2021,
@@ -118,6 +126,27 @@ int main(int argc, char **argv) {
#endif
#endif
+ #if MICROPY_PY_NETWORK_CYW43
+ {
+ cyw43_init(&cyw43_state);
+ cyw43_irq_init();
+ cyw43_post_poll_hook(); // enable the irq
+ uint8_t buf[8];
+ memcpy(&buf[0], "PICO", 4);
+
+ // MAC isn't loaded from OTP yet, so use unique id to generate the default AP ssid.
+ const char hexchr[16] = "0123456789ABCDEF";
+ pico_unique_board_id_t pid;
+ pico_get_unique_board_id(&pid);
+ buf[4] = hexchr[pid.id[7] >> 4];
+ buf[5] = hexchr[pid.id[6] & 0xf];
+ buf[6] = hexchr[pid.id[5] >> 4];
+ buf[7] = hexchr[pid.id[4] & 0xf];
+ cyw43_wifi_ap_set_ssid(&cyw43_state, 8, buf);
+ cyw43_wifi_ap_set_password(&cyw43_state, 8, (const uint8_t *)"picoW123");
+ }
+ #endif
+
for (;;) {
// Initialise MicroPython runtime.
diff --git a/ports/rp2/modrp2.c b/ports/rp2/modrp2.c
index 5dc066d65..19c7ad608 100644
--- a/ports/rp2/modrp2.c
+++ b/ports/rp2/modrp2.c
@@ -28,6 +28,28 @@
#include "drivers/dht/dht.h"
#include "modrp2.h"
+#if MICROPY_PY_NETWORK_CYW43
+#include "lib/cyw43-driver/src/cyw43_country.h"
+
+extern uint32_t cyw43_country_code;
+
+STATIC mp_obj_t rp2_country(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ char code[2] = {cyw43_country_code, cyw43_country_code >> 8};
+ return mp_obj_new_str(code, 2);
+ } else {
+ size_t len;
+ const char *str = mp_obj_str_get_data(args[0], &len);
+ if (len != 2) {
+ mp_raise_ValueError(NULL);
+ }
+ cyw43_country_code = CYW43_COUNTRY(str[0], str[1], 0);
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rp2_country_obj, 0, 1, rp2_country);
+#endif
+
STATIC const mp_rom_map_elem_t rp2_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rp2) },
{ MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&rp2_flash_type) },
@@ -35,6 +57,10 @@ STATIC const mp_rom_map_elem_t rp2_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_StateMachine), MP_ROM_PTR(&rp2_state_machine_type) },
{ MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
+
+ #if MICROPY_PY_NETWORK_CYW43
+ { MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&rp2_country_obj) },
+ #endif
};
STATIC MP_DEFINE_CONST_DICT(rp2_module_globals, rp2_module_globals_table);
diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h
index 62388c6bc..9143b5f6c 100644
--- a/ports/rp2/mpconfigport.h
+++ b/ports/rp2/mpconfigport.h
@@ -154,6 +154,20 @@ struct _mp_bluetooth_nimble_malloc_t;
#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE
#endif
+#if MICROPY_PY_NETWORK_CYW43
+extern const struct _mp_obj_type_t mp_network_cyw43_type;
+#define MICROPY_HW_NIC_CYW43 \
+ { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) }, \
+ { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(CYW43_LINK_DOWN) }, \
+ { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(CYW43_LINK_JOIN) }, \
+ { MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(CYW43_LINK_BADAUTH) }, \
+ { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(CYW43_LINK_NONET) }, \
+ { MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(CYW43_LINK_FAIL) }, \
+ { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(CYW43_LINK_UP) },
+#else
+#define MICROPY_HW_NIC_CYW43
+#endif
+
#if MICROPY_PY_NETWORK_NINAW10
// This Network interface requires the extended socket state.
#ifndef MICROPY_PY_USOCKET_EXTENDED_STATE
@@ -184,6 +198,7 @@ extern const struct _mod_network_nic_type_t mod_network_nic_type_wiznet5k;
#endif
#define MICROPY_PORT_NETWORK_INTERFACES \
+ MICROPY_HW_NIC_CYW43 \
MICROPY_HW_NIC_NINAW10 \
MICROPY_HW_NIC_WIZNET5K \
MICROPY_BOARD_NETWORK_INTERFACES \
@@ -258,3 +273,10 @@ typedef intptr_t mp_off_t;
extern uint32_t rosc_random_u32(void);
extern void lwip_lock_acquire(void);
extern void lwip_lock_release(void);
+
+extern uint32_t cyw43_country_code;
+extern void cyw43_irq_init(void);
+extern void cyw43_post_poll_hook(void);
+
+#define CYW43_POST_POLL_HOOK cyw43_post_poll_hook();
+#define MICROPY_CYW43_COUNTRY cyw43_country_code
diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c
index 4ed648de0..aec4a9672 100644
--- a/ports/rp2/mphalport.c
+++ b/ports/rp2/mphalport.c
@@ -35,6 +35,10 @@
#include "hardware/rtc.h"
#include "pico/unique_id.h"
+#if MICROPY_PY_NETWORK_CYW43
+#include "lib/cyw43-driver/src/cyw43.h"
+#endif
+
#if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_ENABLE_USBDEV
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
@@ -168,6 +172,9 @@ uint64_t mp_hal_time_ns(void) {
// Generate a random locally administered MAC address (LAA)
void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]) {
+ #ifndef NDEBUG
+ printf("Warning: No MAC in OTP, generating MAC from board id\n");
+ #endif
pico_unique_board_id_t pid;
pico_get_unique_board_id(&pid);
buf[0] = 0x02; // LAA range
@@ -180,5 +187,21 @@ void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]) {
// A board can override this if needed
MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) {
+ #if MICROPY_PY_NETWORK_CYW43
+ // The mac should come from cyw43 otp when CYW43_USE_OTP_MAC is defined
+ // This is loaded into the state after the driver is initialised
+ // cyw43_hal_generate_laa_mac is only called by the driver to generate a mac if otp is not set
+ memcpy(buf, cyw43_state.mac, 6);
+ #else
mp_hal_generate_laa_mac(idx, buf);
+ #endif
+}
+
+void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest) {
+ static const char hexchr[16] = "0123456789ABCDEF";
+ uint8_t mac[6];
+ mp_hal_get_mac(idx, mac);
+ for (; chr_len; ++chr_off, --chr_len) {
+ *dest++ = hexchr[mac[chr_off >> 1] >> (4 * (1 - (chr_off & 1))) & 0xf];
+ }
}
diff --git a/ports/rp2/mphalport.h b/ports/rp2/mphalport.h
index 88eef1308..88683d936 100644
--- a/ports/rp2/mphalport.h
+++ b/ports/rp2/mphalport.h
@@ -30,6 +30,7 @@
#include "pico/time.h"
#include "hardware/clocks.h"
#include "hardware/structs/systick.h"
+#include "RP2040.h" // cmsis, for __WFI
#define SYSTICK_MAX (0xffffff)
@@ -74,6 +75,11 @@ static inline mp_uint_t mp_hal_get_cpu_freq(void) {
#define MP_HAL_PIN_FMT "%u"
#define mp_hal_pin_obj_t uint
+#define MP_HAL_PIN_MODE_INPUT (GPIO_IN)
+#define MP_HAL_PIN_MODE_OUTPUT (GPIO_OUT)
+#define MP_HAL_PIN_PULL_NONE (0)
+#define MP_HAL_PIN_PULL_UP (1)
+#define MP_HAL_PIN_PULL_DOWN (2)
extern uint32_t machine_pin_open_drain_mask;
@@ -102,6 +108,12 @@ static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) {
machine_pin_open_drain_mask |= 1 << pin;
}
+static inline void mp_hal_pin_config(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint32_t alt) {
+ assert((mode == MP_HAL_PIN_MODE_INPUT || mode == MP_HAL_PIN_MODE_OUTPUT) && alt == 0);
+ gpio_set_dir(pin, mode);
+ gpio_set_pulls(pin, pull == MP_HAL_PIN_PULL_UP, pull == MP_HAL_PIN_PULL_DOWN);
+}
+
static inline int mp_hal_pin_read(mp_hal_pin_obj_t pin) {
return gpio_get(pin);
}
@@ -143,6 +155,7 @@ enum {
};
void mp_hal_get_mac(int idx, uint8_t buf[6]);
+void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest);
void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]);
#endif // MICROPY_INCLUDED_RP2_MPHALPORT_H
diff --git a/ports/rp2/mpnetworkport.c b/ports/rp2/mpnetworkport.c
index 2b01b6219..0cd6eb14c 100644
--- a/ports/rp2/mpnetworkport.c
+++ b/ports/rp2/mpnetworkport.c
@@ -38,6 +38,41 @@
static alarm_id_t lwip_alarm_id = -1;
+#if MICROPY_PY_NETWORK_CYW43
+#include "lib/cyw43-driver/src/cyw43.h"
+#include "lib/cyw43-driver/src/cyw43_country.h"
+#include "lib/cyw43-driver/src/cyw43_stats.h"
+#include "hardware/irq.h"
+
+#define CYW43_IRQ_LEVEL GPIO_IRQ_LEVEL_HIGH
+#define CYW43_SHARED_IRQ_HANDLER_PRIORITY PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY
+
+uint32_t cyw43_country_code = CYW43_COUNTRY_WORLDWIDE;
+
+static void gpio_irq_handler(void) {
+ uint32_t events = gpio_get_irq_event_mask(CYW43_PIN_WL_HOST_WAKE);
+ if (events & CYW43_IRQ_LEVEL) {
+ // As we use a high level interrupt, it will go off forever until it's serviced.
+ // So disable the interrupt until this is done. It's re-enabled again by
+ // CYW43_POST_POLL_HOOK which is called at the end of cyw43_poll_func.
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, CYW43_IRQ_LEVEL, false);
+ pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll);
+ CYW43_STAT_INC(IRQ_COUNT);
+ }
+}
+
+void cyw43_irq_init(void) {
+ gpio_add_raw_irq_handler_with_order_priority(IO_IRQ_BANK0, gpio_irq_handler, CYW43_SHARED_IRQ_HANDLER_PRIORITY);
+ irq_set_enabled(IO_IRQ_BANK0, true);
+ NVIC_SetPriority(PendSV_IRQn, PICO_LOWEST_IRQ_PRIORITY);
+}
+
+void cyw43_post_poll_hook(void) {
+ gpio_set_irq_enabled(CYW43_PIN_WL_HOST_WAKE, CYW43_IRQ_LEVEL, true);
+}
+
+#endif
+
#if MICROPY_PY_NETWORK_WIZNET5K
void wiznet5k_poll(void);
void wiznet5k_deinit(void);
diff --git a/ports/rp2/pendsv.c b/ports/rp2/pendsv.c
index 006303d46..91b133c06 100644
--- a/ports/rp2/pendsv.c
+++ b/ports/rp2/pendsv.c
@@ -28,6 +28,10 @@
#include "pendsv.h"
#include "RP2040.h"
+#if MICROPY_PY_NETWORK_CYW43
+#include "lib/cyw43-driver/src/cyw43_stats.h"
+#endif
+
static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
static int pendsv_lock;
@@ -54,12 +58,21 @@ void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
pendsv_dispatch_table[slot] = f;
if (pendsv_lock == 0) {
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
+ } else {
+ #if MICROPY_PY_NETWORK_CYW43
+ CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
+ #endif
}
}
// PendSV interrupt handler to perform background processing.
void PendSV_Handler(void) {
assert(pendsv_lock == 0);
+
+ #if MICROPY_PY_NETWORK_CYW43
+ CYW43_STAT_INC(PENDSV_RUN_COUNT);
+ #endif
+
for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) {
if (pendsv_dispatch_table[i] != NULL) {
pendsv_dispatch_t f = pendsv_dispatch_table[i];
diff --git a/ports/rp2/pendsv.h b/ports/rp2/pendsv.h
index 7bb43208a..1da3d22e5 100644
--- a/ports/rp2/pendsv.h
+++ b/ports/rp2/pendsv.h
@@ -32,6 +32,9 @@ enum {
#if MICROPY_PY_LWIP
PENDSV_DISPATCH_LWIP,
#endif
+ #if MICROPY_PY_NETWORK_CYW43
+ PENDSV_DISPATCH_CYW43,
+ #endif
#if MICROPY_PY_NETWORK_WIZNET5K
PENDSV_DISPATCH_WIZNET,
#endif
diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c
index fe09ebe24..9955cc544 100644
--- a/ports/rp2/rp2_pio.c
+++ b/ports/rp2/rp2_pio.c
@@ -103,8 +103,13 @@ STATIC void pio1_irq0(void) {
void rp2_pio_init(void) {
// Reset all PIO instruction memory.
+ #if MICROPY_PY_NETWORK_CYW43
+ // TODO: cannot reset PIO memory when CYW43 driver is enabled and active
+ // because it uses a PIO for the bus interface.
+ #else
pio_clear_instruction_memory(pio0);
pio_clear_instruction_memory(pio1);
+ #endif
// Set up interrupts.
memset(MP_STATE_PORT(rp2_pio_irq_obj), 0, sizeof(MP_STATE_PORT(rp2_pio_irq_obj)));