Browse Source

rp2: Integrate CYW43xx WiFi driver.

This includes:
- Configuration file for the cyw43-driver.
- Integration of cyw43-driver into the build, using lwIP.
- Enhancements to machine.Pin to support extension IO pins provided by the
  CYW43xx.
- More mp-hal pin helper functions.
- mp_hal_get_mac_ascii MAC address helper function.
- Addition of rp2.country() function to set the country code.

A board can enable this driver by setting MICROPY_PY_NETWORK_CYW43 in their
cmake snippet.

Work done in collaboration with Graham Sanderson and Peter Harper.

Signed-off-by: Damien George <damien@micropython.org>
pull/8839/head
Damien George 2 years ago
parent
commit
50e46552c0
  1. 29
      ports/rp2/CMakeLists.txt
  2. 4
      ports/rp2/Makefile
  3. 7
      ports/rp2/README.md
  4. 98
      ports/rp2/cyw43_configport.h
  5. 354
      ports/rp2/machine_pin.c
  6. 29
      ports/rp2/main.c
  7. 26
      ports/rp2/modrp2.c
  8. 22
      ports/rp2/mpconfigport.h
  9. 23
      ports/rp2/mphalport.c
  10. 13
      ports/rp2/mphalport.h
  11. 35
      ports/rp2/mpnetworkport.c
  12. 13
      ports/rp2/pendsv.c
  13. 3
      ports/rp2/pendsv.h
  14. 5
      ports/rp2/rp2_pio.c

29
ports/rp2/CMakeLists.txt

@ -16,6 +16,10 @@ endif()
# Use the local tinyusb instead of the one in pico-sdk # Use the local tinyusb instead of the one in pico-sdk
set(PICO_TINYUSB_PATH ${MICROPY_DIR}/lib/tinyusb) 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 the location of this port's directory.
set(MICROPY_PORT_DIR ${CMAKE_SOURCE_DIR}) 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/mbedtls_errors/mp_mbedtls_errors.c
${MICROPY_DIR}/lib/oofatfs/ff.c ${MICROPY_DIR}/lib/oofatfs/ff.c
${MICROPY_DIR}/lib/oofatfs/ffunicode.c ${MICROPY_DIR}/lib/oofatfs/ffunicode.c
${MICROPY_DIR}/shared/netutils/dhcpserver.c
${MICROPY_DIR}/shared/netutils/netutils.c ${MICROPY_DIR}/shared/netutils/netutils.c
${MICROPY_DIR}/shared/netutils/trace.c ${MICROPY_DIR}/shared/netutils/trace.c
${MICROPY_DIR}/shared/readline/readline.c ${MICROPY_DIR}/shared/readline/readline.c
@ -216,6 +221,30 @@ if(MICROPY_BLUETOOTH_NIMBLE)
list(APPEND MICROPY_INC_CORE ${NIMBLE_INCLUDE}) list(APPEND MICROPY_INC_CORE ${NIMBLE_INCLUDE})
endif() 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) if (MICROPY_PY_NETWORK_NINAW10)
target_compile_definitions(${MICROPY_TARGET} PRIVATE target_compile_definitions(${MICROPY_TARGET} PRIVATE
MICROPY_PY_NETWORK_NINAW10=1 MICROPY_PY_NETWORK_NINAW10=1

4
ports/rp2/Makefile

@ -29,9 +29,11 @@ all:
clean: clean:
$(RM) -rf $(BUILD) $(RM) -rf $(BUILD)
GIT_SUBMODULES += lib/mbedtls lib/pico-sdk lib/tinyusb GIT_SUBMODULES += lib/mbedtls lib/tinyusb
submodules: 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) ifeq ($(BOARD),PICO)
# Run the standard submodules target with minimum required submodules above # Run the standard submodules target with minimum required submodules above
$(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$(GIT_SUBMODULES)" submodules $(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$(GIT_SUBMODULES)" submodules

7
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 the top-level of the CMake build directory (`build` by default) and is
called `firmware.uf2`. 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 ## Deploying firmware to the device
Firmware can be deployed to the device by putting it into bootloader mode Firmware can be deployed to the device by putting it into bootloader mode

98
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

354
ports/rp2/machine_pin.c

@ -58,9 +58,18 @@
// Open drain behaviour is simulated. // Open drain behaviour is simulated.
#define GPIO_IS_OPEN_DRAIN(id) (machine_pin_open_drain_mask & (1 << (id))) #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 { typedef struct _machine_pin_obj_t {
mp_obj_base_t base; 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; } machine_pin_obj_t;
typedef struct _machine_pin_irq_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}, {{&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. // Mask with "1" indicating that the corresponding pin is in simulated open-drain mode.
uint32_t machine_pin_open_drain_mask; 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) { STATIC void gpio_irq(void) {
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
uint32_t intr = iobank0_hw->intr[i]; uint32_t intr = iobank0_hw->intr[i];
@ -129,15 +189,24 @@ STATIC void gpio_irq(void) {
void machine_pin_init(void) { void machine_pin_init(void) {
memset(MP_STATE_PORT(machine_pin_irq_obj), 0, sizeof(MP_STATE_PORT(machine_pin_irq_obj))); 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); 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) { void machine_pin_deinit(void) {
for (int i = 0; i < NUM_BANK0_GPIOS; ++i) { 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); gpio_set_irq_enabled(i, GPIO_IRQ_ALL, false);
} }
irq_set_enabled(IO_IRQ_BANK0, false);
irq_remove_handler(IO_IRQ_BANK0, gpio_irq); 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; machine_pin_obj_t *self = self_in;
uint funcsel = GPIO_GET_FUNCSEL(self->id); uint funcsel = GPIO_GET_FUNCSEL(self->id);
qstr mode_qst; qstr mode_qst;
if (funcsel == GPIO_FUNC_SIO) { if (!is_cyw43_pin(self)) {
if (GPIO_IS_OPEN_DRAIN(self->id)) { if (funcsel == GPIO_FUNC_SIO) {
mode_qst = MP_QSTR_OPEN_DRAIN; if (GPIO_IS_OPEN_DRAIN(self->id)) {
} else if (GPIO_IS_OUT(self->id)) { mode_qst = MP_QSTR_OPEN_DRAIN;
mode_qst = MP_QSTR_OUT; } else if (GPIO_IS_OUT(self->id)) {
mode_qst = MP_QSTR_OUT;
} else {
mode_qst = MP_QSTR_IN;
}
} else { } 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 { } 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; int value = -1;
if (GPIO_IS_PULL_UP(self->id)) { if (args[ARG_value].u_obj != mp_const_none) {
mp_printf(print, ", pull=%q", MP_QSTR_PULL_UP); value = mp_obj_is_true(args[ARG_value].u_obj);
pull_up = true;
} }
if (GPIO_IS_PULL_DOWN(self->id)) {
if (pull_up) { if (args[ARG_mode].u_obj != mp_const_none) {
mp_printf(print, "|%q", MP_QSTR_PULL_DOWN); 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 { } 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) { 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 // parse args
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_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); pull = mp_obj_get_int(args[ARG_pull].u_obj);
} }
gpio_set_pulls(self->id, pull & GPIO_PULL_UP, pull & GPIO_PULL_DOWN); gpio_set_pulls(self->id, pull & GPIO_PULL_UP, pull & GPIO_PULL_DOWN);
return mp_const_none; 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_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); 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) { if (n_args > 1 || n_kw > 0) {
// pin mode given, so configure this GPIO // pin mode given, so configure this GPIO
mp_map_t kw_args; mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_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); return MP_OBJ_FROM_PTR(self);
#endif
} }
// fast method for getting/setting pin value // 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; machine_pin_obj_t *self = self_in;
if (n_args == 0) { if (n_args == 0) {
// get pin // 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 { } else {
// set pin // set pin
bool value = mp_obj_is_true(args[0]); bool value = mp_obj_is_true(args[0]);
if (GPIO_IS_OPEN_DRAIN(self->id)) { if (!is_cyw43_pin(self)) {
MP_STATIC_ASSERT(GPIO_IN == 0 && GPIO_OUT == 1); if (GPIO_IS_OPEN_DRAIN(self->id)) {
gpio_set_dir(self->id, 1 - value); MP_STATIC_ASSERT(GPIO_IN == 0 && GPIO_OUT == 1);
} else { gpio_set_dir(self->id, 1 - value);
gpio_put(self->id, 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) // 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) { 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); 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() // pin.low()
STATIC mp_obj_t machine_pin_low(mp_obj_t self_in) { STATIC mp_obj_t machine_pin_low(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (GPIO_IS_OPEN_DRAIN(self->id)) { if (!is_cyw43_pin(self)) {
gpio_set_dir(self->id, GPIO_OUT); if (GPIO_IS_OPEN_DRAIN(self->id)) {
} else { gpio_set_dir(self->id, GPIO_OUT);
gpio_clr_mask(1u << self->id); } 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; return mp_const_none;
#endif
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_low_obj, machine_pin_low); STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_low_obj, machine_pin_low);
// pin.high() // pin.high()
STATIC mp_obj_t machine_pin_high(mp_obj_t self_in) { STATIC mp_obj_t machine_pin_high(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (GPIO_IS_OPEN_DRAIN(self->id)) { if (!is_cyw43_pin(self)) {
gpio_set_dir(self->id, GPIO_IN); if (GPIO_IS_OPEN_DRAIN(self->id)) {
} else { gpio_set_dir(self->id, GPIO_IN);
gpio_set_mask(1u << self->id); } 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; return mp_const_none;
#endif
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_high_obj, machine_pin_high); STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_high_obj, machine_pin_high);
// pin.toggle() // pin.toggle()
STATIC mp_obj_t machine_pin_toggle(mp_obj_t self_in) { STATIC mp_obj_t machine_pin_toggle(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (GPIO_IS_OPEN_DRAIN(self->id)) { if (!is_cyw43_pin(self)) {
if (GPIO_IS_OUT(self->id)) { if (GPIO_IS_OPEN_DRAIN(self->id)) {
gpio_set_dir(self->id, GPIO_IN); if (GPIO_IS_OUT(self->id)) {
gpio_set_dir(self->id, GPIO_IN);
} else {
gpio_set_dir(self->id, GPIO_OUT);
}
} else { } else {
gpio_set_dir(self->id, GPIO_OUT); gpio_xor_mask(1u << self->id);
} }
} else { return mp_const_none;
gpio_xor_mask(1u << self->id);
} }
#if MICROPY_HW_PIN_CYW43_COUNT
update_cyw43_value(self, self->last_output_value ^ 1);
return mp_const_none; return mp_const_none;
#endif
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_toggle_obj, machine_pin_toggle); 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} }, { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
}; };
machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); 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_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); 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; (void)errcode;
machine_pin_obj_t *self = self_in; 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) { switch (request) {
case MP_PIN_READ: { case MP_PIN_READ: {
return gpio_get(self->id); return get_cyw43_value(self);
} }
case MP_PIN_WRITE: { case MP_PIN_WRITE: {
gpio_put(self->id, arg); update_cyw43_value(self, arg);
return 0; return 0;
} }
} }
return -1; return -1;
#endif
} }
STATIC const mp_pin_p_t pin_pin_p = { 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")); mp_raise_ValueError(MP_ERROR_TEXT("expecting a Pin"));
} }
machine_pin_obj_t *pin = MP_OBJ_TO_PTR(obj); 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; return pin->id;
} }

29
ports/rp2/main.c

@ -46,12 +46,16 @@
#include "pico/stdlib.h" #include "pico/stdlib.h"
#include "pico/binary_info.h" #include "pico/binary_info.h"
#include "pico/unique_id.h"
#include "hardware/rtc.h" #include "hardware/rtc.h"
#include "hardware/structs/rosc.h" #include "hardware/structs/rosc.h"
#if MICROPY_PY_LWIP #if MICROPY_PY_LWIP
#include "lwip/init.h" #include "lwip/init.h"
#include "lwip/apps/mdns.h" #include "lwip/apps/mdns.h"
#endif #endif
#if MICROPY_PY_NETWORK_CYW43
#include "lib/cyw43-driver/src/cyw43.h"
#endif
#ifndef MICROPY_GC_HEAP_SIZE #ifndef MICROPY_GC_HEAP_SIZE
#if MICROPY_PY_LWIP #if MICROPY_PY_LWIP
@ -90,6 +94,10 @@ int main(int argc, char **argv) {
mp_thread_init(); mp_thread_init();
#endif #endif
#ifndef NDEBUG
stdio_init_all();
#endif
// Start and initialise the RTC // Start and initialise the RTC
datetime_t t = { datetime_t t = {
.year = 2021, .year = 2021,
@ -118,6 +126,27 @@ int main(int argc, char **argv) {
#endif #endif
#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 (;;) { for (;;) {
// Initialise MicroPython runtime. // Initialise MicroPython runtime.

26
ports/rp2/modrp2.c

@ -28,6 +28,28 @@
#include "drivers/dht/dht.h" #include "drivers/dht/dht.h"
#include "modrp2.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[] = { 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___name__), MP_ROM_QSTR(MP_QSTR_rp2) },
{ MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&rp2_flash_type) }, { 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_StateMachine), MP_ROM_PTR(&rp2_state_machine_type) },
{ MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, { 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); STATIC MP_DEFINE_CONST_DICT(rp2_module_globals, rp2_module_globals_table);

22
ports/rp2/mpconfigport.h

@ -154,6 +154,20 @@ struct _mp_bluetooth_nimble_malloc_t;
#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE #define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE
#endif #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 #if MICROPY_PY_NETWORK_NINAW10
// This Network interface requires the extended socket state. // This Network interface requires the extended socket state.
#ifndef MICROPY_PY_USOCKET_EXTENDED_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 #endif
#define MICROPY_PORT_NETWORK_INTERFACES \ #define MICROPY_PORT_NETWORK_INTERFACES \
MICROPY_HW_NIC_CYW43 \
MICROPY_HW_NIC_NINAW10 \ MICROPY_HW_NIC_NINAW10 \
MICROPY_HW_NIC_WIZNET5K \ MICROPY_HW_NIC_WIZNET5K \
MICROPY_BOARD_NETWORK_INTERFACES \ MICROPY_BOARD_NETWORK_INTERFACES \
@ -258,3 +273,10 @@ typedef intptr_t mp_off_t;
extern uint32_t rosc_random_u32(void); extern uint32_t rosc_random_u32(void);
extern void lwip_lock_acquire(void); extern void lwip_lock_acquire(void);
extern void lwip_lock_release(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

23
ports/rp2/mphalport.c

@ -35,6 +35,10 @@
#include "hardware/rtc.h" #include "hardware/rtc.h"
#include "pico/unique_id.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 #if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_ENABLE_USBDEV
#ifndef MICROPY_HW_STDIN_BUFFER_LEN #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) // Generate a random locally administered MAC address (LAA)
void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]) { 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_unique_board_id_t pid;
pico_get_unique_board_id(&pid); pico_get_unique_board_id(&pid);
buf[0] = 0x02; // LAA range 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 // A board can override this if needed
MP_WEAK void mp_hal_get_mac(int idx, uint8_t buf[6]) { 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); 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];
}
} }

13
ports/rp2/mphalport.h

@ -30,6 +30,7 @@
#include "pico/time.h" #include "pico/time.h"
#include "hardware/clocks.h" #include "hardware/clocks.h"
#include "hardware/structs/systick.h" #include "hardware/structs/systick.h"
#include "RP2040.h" // cmsis, for __WFI
#define SYSTICK_MAX (0xffffff) #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_FMT "%u"
#define mp_hal_pin_obj_t uint #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; 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; 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) { static inline int mp_hal_pin_read(mp_hal_pin_obj_t pin) {
return gpio_get(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(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]); void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]);
#endif // MICROPY_INCLUDED_RP2_MPHALPORT_H #endif // MICROPY_INCLUDED_RP2_MPHALPORT_H

35
ports/rp2/mpnetworkport.c

@ -38,6 +38,41 @@
static alarm_id_t lwip_alarm_id = -1; 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 #if MICROPY_PY_NETWORK_WIZNET5K
void wiznet5k_poll(void); void wiznet5k_poll(void);
void wiznet5k_deinit(void); void wiznet5k_deinit(void);

13
ports/rp2/pendsv.c

@ -28,6 +28,10 @@
#include "pendsv.h" #include "pendsv.h"
#include "RP2040.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 pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
static int pendsv_lock; static int pendsv_lock;
@ -54,12 +58,21 @@ void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
pendsv_dispatch_table[slot] = f; pendsv_dispatch_table[slot] = f;
if (pendsv_lock == 0) { if (pendsv_lock == 0) {
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; 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. // PendSV interrupt handler to perform background processing.
void PendSV_Handler(void) { void PendSV_Handler(void) {
assert(pendsv_lock == 0); 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) { for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) {
if (pendsv_dispatch_table[i] != NULL) { if (pendsv_dispatch_table[i] != NULL) {
pendsv_dispatch_t f = pendsv_dispatch_table[i]; pendsv_dispatch_t f = pendsv_dispatch_table[i];

3
ports/rp2/pendsv.h

@ -32,6 +32,9 @@ enum {
#if MICROPY_PY_LWIP #if MICROPY_PY_LWIP
PENDSV_DISPATCH_LWIP, PENDSV_DISPATCH_LWIP,
#endif #endif
#if MICROPY_PY_NETWORK_CYW43
PENDSV_DISPATCH_CYW43,
#endif
#if MICROPY_PY_NETWORK_WIZNET5K #if MICROPY_PY_NETWORK_WIZNET5K
PENDSV_DISPATCH_WIZNET, PENDSV_DISPATCH_WIZNET,
#endif #endif

5
ports/rp2/rp2_pio.c

@ -103,8 +103,13 @@ STATIC void pio1_irq0(void) {
void rp2_pio_init(void) { void rp2_pio_init(void) {
// Reset all PIO instruction memory. // 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(pio0);
pio_clear_instruction_memory(pio1); pio_clear_instruction_memory(pio1);
#endif
// Set up interrupts. // Set up interrupts.
memset(MP_STATE_PORT(rp2_pio_irq_obj), 0, sizeof(MP_STATE_PORT(rp2_pio_irq_obj))); memset(MP_STATE_PORT(rp2_pio_irq_obj), 0, sizeof(MP_STATE_PORT(rp2_pio_irq_obj)));

Loading…
Cancel
Save