diff --git a/drivers/ninaw10/nina_wifi_bsp.c b/drivers/ninaw10/nina_wifi_bsp.c index dc71c8260c..04a20b2efb 100644 --- a/drivers/ninaw10/nina_wifi_bsp.c +++ b/drivers/ninaw10/nina_wifi_bsp.c @@ -46,15 +46,22 @@ #define debug_printf(...) #endif -int nina_bsp_init(void) { - mp_hal_pin_output(MICROPY_HW_NINA_GPIO1); +// Use the name CS instead of GPIO1 +#ifndef MICROPY_HW_NINA_CS +#define MICROPY_HW_NINA_CS MICROPY_HW_NINA_GPIO1 +#endif + +MP_WEAK int nina_bsp_init(void) { + mp_hal_pin_output(MICROPY_HW_NINA_CS); mp_hal_pin_input(MICROPY_HW_NINA_ACK); mp_hal_pin_output(MICROPY_HW_NINA_RESET); + #ifdef MICROPY_HW_NINA_GPIO0 mp_hal_pin_output(MICROPY_HW_NINA_GPIO0); + mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1); + #endif // Reset module in WiFi mode - mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1); - mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1); + mp_hal_pin_write(MICROPY_HW_NINA_CS, 1); mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0); mp_hal_delay_ms(100); @@ -62,51 +69,59 @@ int nina_bsp_init(void) { mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1); mp_hal_delay_ms(750); - mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 0); + #ifdef MICROPY_HW_NINA_GPIO0 mp_hal_pin_input(MICROPY_HW_NINA_GPIO0); + #endif // Initialize SPI. mp_obj_t args[] = { MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_ID), MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_BAUDRATE), }; - - MP_STATE_PORT(mp_wifi_spi) = MP_OBJ_TYPE_GET_SLOT(&machine_spi_type, make_new)((mp_obj_t)&machine_spi_type, 2, 0, args); + MP_STATE_PORT(mp_wifi_spi) = MP_OBJ_TYPE_GET_SLOT(&machine_spi_type, make_new)( + (mp_obj_t)&machine_spi_type, 2, 0, args); return 0; } -int nina_bsp_deinit(void) { - mp_hal_pin_output(MICROPY_HW_NINA_GPIO1); - mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1); +MP_WEAK int nina_bsp_deinit(void) { + mp_hal_pin_output(MICROPY_HW_NINA_CS); + mp_hal_pin_write(MICROPY_HW_NINA_CS, 1); mp_hal_pin_output(MICROPY_HW_NINA_RESET); mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0); mp_hal_delay_ms(100); + #ifdef MICROPY_HW_NINA_GPIO0 mp_hal_pin_output(MICROPY_HW_NINA_GPIO0); mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1); + #endif + return 0; } -int nina_bsp_atomic_enter(void) { +MP_WEAK int nina_bsp_atomic_enter(void) { #if MICROPY_ENABLE_SCHEDULER mp_sched_lock(); #endif return 0; } -int nina_bsp_atomic_exit(void) { +MP_WEAK int nina_bsp_atomic_exit(void) { #if MICROPY_ENABLE_SCHEDULER mp_sched_unlock(); #endif return 0; } -int nina_bsp_read_irq(void) { +MP_WEAK int nina_bsp_read_irq(void) { + #ifdef MICROPY_HW_NINA_GPIO0 return mp_hal_pin_read(MICROPY_HW_NINA_GPIO0); + #else + return 1; + #endif } -int nina_bsp_spi_slave_select(uint32_t timeout) { +MP_WEAK int nina_bsp_spi_slave_select(uint32_t timeout) { // Wait for ACK to go low. for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 1; mp_hal_delay_ms(1)) { if (timeout && ((mp_hal_ticks_ms() - start) >= timeout)) { @@ -115,12 +130,12 @@ int nina_bsp_spi_slave_select(uint32_t timeout) { } // Chip select. - mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 0); + mp_hal_pin_write(MICROPY_HW_NINA_CS, 0); // Wait for ACK to go high. for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 0; mp_hal_delay_ms(1)) { if ((mp_hal_ticks_ms() - start) >= 100) { - mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1); + mp_hal_pin_write(MICROPY_HW_NINA_CS, 1); return -1; } } @@ -128,12 +143,12 @@ int nina_bsp_spi_slave_select(uint32_t timeout) { return 0; } -int nina_bsp_spi_slave_deselect(void) { - mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1); +MP_WEAK int nina_bsp_spi_slave_deselect(void) { + mp_hal_pin_write(MICROPY_HW_NINA_CS, 1); return 0; } -int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size) { +MP_WEAK int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size) { mp_obj_t mp_wifi_spi = MP_STATE_PORT(mp_wifi_spi); ((mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_spi_type, protocol))->transfer(mp_wifi_spi, size, tx_buf, rx_buf); #if NINA_DEBUG diff --git a/ports/samd/Makefile b/ports/samd/Makefile index b678cd9828..e45813c9b3 100644 --- a/ports/samd/Makefile +++ b/ports/samd/Makefile @@ -13,7 +13,11 @@ ifeq ($(wildcard $(BOARD_DIR)/.),) $(error Invalid BOARD specified: $(BOARD_DIR)) endif +ifneq ($(BOARD_VARIANT),) +BUILD ?= build-$(BOARD)-$(BOARD_VARIANT) +else BUILD ?= build-$(BOARD) +endif CROSS_COMPILE ?= arm-none-eabi- UF2CONV ?= $(TOP)/tools/uf2conv.py diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json index a998529ccd..315068eeab 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json @@ -12,6 +12,9 @@ "itsybitsy_m4_express.jpg" ], "mcu": "samd51", + "variants": { + "wlan": "WiFi support using a ESP32 module with NINA firmware" + }, "product": "ItsyBitsy M4 Express", "thumbnail": "", "url": "https://www.adafruit.com/product/3800", diff --git a/ports/samd/main.c b/ports/samd/main.c index 2bbaf63e6e..8a393f88a8 100644 --- a/ports/samd/main.c +++ b/ports/samd/main.c @@ -29,6 +29,8 @@ #include "py/gc.h" #include "py/mperrno.h" #include "py/stackctrl.h" +// #include "extmod/modbluetooth.h" +#include "extmod/modnetwork.h" #include "shared/readline/readline.h" #include "shared/runtime/gchelper.h" #include "shared/runtime/pyexec.h" @@ -52,6 +54,12 @@ void samd_main(void) { // Initialise sub-systems. readline_init0(); + #if MICROPY_PY_BLUETOOTH + // mp_bluetooth_hci_init(); + #endif + #if MICROPY_PY_NETWORK + mod_network_init(); + #endif // Execute _boot.py to set up the filesystem. pyexec_frozen_module("_boot.py", false); @@ -87,6 +95,12 @@ void samd_main(void) { soft_reset_exit: mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n"); + #if MICROPY_PY_NETWORK + mod_network_deinit(); + #endif + #if MICROPY_PY_BLUETOOTH + // mp_bluetooth_deinit(); + #endif #if MICROPY_PY_MACHINE_ADC adc_deinit_all(); #endif diff --git a/ports/samd/mbedtls/mbedtls_config.h b/ports/samd/mbedtls/mbedtls_config.h new file mode 100644 index 0000000000..4140bb5145 --- /dev/null +++ b/ports/samd/mbedtls/mbedtls_config.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 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_MBEDTLS_CONFIG_H +#define MICROPY_INCLUDED_MBEDTLS_CONFIG_H + +// Set MicroPython-specific options. +#define MICROPY_MBEDTLS_CONFIG_BARE_METAL (1) + +// Include common mbedtls configuration. +#include "extmod/mbedtls/mbedtls_config_common.h" + +#endif /* MICROPY_INCLUDED_MBEDTLS_CONFIG_H */ diff --git a/ports/samd/mbedtls/mbedtls_port.c b/ports/samd/mbedtls/mbedtls_port.c new file mode 100644 index 0000000000..d2509488bf --- /dev/null +++ b/ports/samd/mbedtls/mbedtls_port.c @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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. + */ + +#ifdef MICROPY_SSL_MBEDTLS + +#include "mbedtls_config.h" +#include +uint32_t trng_random_u32(); + +int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) { + + *olen = len; + for (size_t i = 0; i < len; i++) { + output[i] = (unsigned char)trng_random_u32(); + } + return 0; +} + +#endif diff --git a/ports/samd/mcu/samd51/manifest_net.py b/ports/samd/mcu/samd51/manifest_net.py new file mode 100644 index 0000000000..6353bdb47e --- /dev/null +++ b/ports/samd/mcu/samd51/manifest_net.py @@ -0,0 +1,8 @@ +include("$(PORT_DIR)/boards/manifest.py") +include("$(MPY_DIR)/extmod/asyncio") +# Drivers +require("onewire") +require("ds18x20") +require("dht") +# Networking +require("bundle-networking") diff --git a/ports/samd/mcu/samd51/mpconfigmcu.h b/ports/samd/mcu/samd51/mpconfigmcu.h index d567f28eb4..43e03ccde5 100644 --- a/ports/samd/mcu/samd51/mpconfigmcu.h +++ b/ports/samd/mcu/samd51/mpconfigmcu.h @@ -16,11 +16,15 @@ #define MICROPY_PY_RANDOM_SEED_INIT_FUNC (trng_random_u32()) unsigned long trng_random_u32(void); +// Enable MD5 hash. +#define MICROPY_PY_UHASHLIB_MD5 (MICROPY_SSL_MBEDTLS) +#define MICROPY_TRACKED_ALLOC (MICROPY_SSL_MBEDTLS) + // fatfs configuration used in ffconf.h -#define MICROPY_FATFS_ENABLE_LFN (1) -#define MICROPY_FATFS_RPATH (2) -#define MICROPY_FATFS_MAX_SS (4096) -#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_MAX_SS (4096) +#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define VFS_BLOCK_SIZE_BYTES (1536) // diff --git a/ports/samd/mcu/samd51/mpconfigmcu.mk b/ports/samd/mcu/samd51/mpconfigmcu.mk index 0201bacffe..d47ab6c6db 100644 --- a/ports/samd/mcu/samd51/mpconfigmcu.mk +++ b/ports/samd/mcu/samd51/mpconfigmcu.mk @@ -8,9 +8,53 @@ MICROPY_HW_CODESIZE ?= 368K MICROPY_VFS_LFS2 ?= 1 MICROPY_VFS_FAT ?= 1 + +ifeq ($(BOARD_VARIANT),WLAN) +MICROPY_PY_NETWORK ?= 1 +MICROPY_PY_NETWORK_NINAW10 ?= 1 +ifeq ($(MICROPY_HW_CODESIZE),496K) +MICROPY_PY_SSL ?= 1 +MICROPY_SSL_MBEDTLS ?= 1 +endif +ifeq ($(MICROPY_HW_CODESIZE),1008K) +MICROPY_PY_SSL ?= 1 +MICROPY_SSL_MBEDTLS ?= 1 +endif +endif + +ifeq ($(MICROPY_PY_NETWORK),1) +FROZEN_MANIFEST ?= mcu/$(MCU_SERIES_LOWER)/manifest_net.py +else FROZEN_MANIFEST ?= mcu/$(MCU_SERIES_LOWER)/manifest.py +endif SRC_S += shared/runtime/gchelper_thumb2.s SRC_C += \ fatfs_port.c \ + mbedtls/mbedtls_port.c + + +ifeq ($(MICROPY_PY_NETWORK),1) +CFLAGS += -DMICROPY_PY_NETWORK=1 + +SHARED_SRC_C += \ + shared/netutils/dhcpserver.c \ + shared/netutils/netutils.c \ + shared/netutils/trace.c +endif + +ifeq ($(MICROPY_PY_NETWORK_NINAW10),1) +CFLAGS += -DMICROPY_PY_NETWORK_NINAW10=1 +INC += -I$(TOP)/drivers/ninaw10 + +DRIVERS_SRC_C += \ + drivers/ninaw10/nina_bt_hci.c \ + drivers/ninaw10/nina_wifi_drv.c \ + drivers/ninaw10/nina_wifi_bsp.c \ + drivers/ninaw10/machine_pin_nina.c + +SRC_C += \ + nina_wifi_bsp.c + +endif diff --git a/ports/samd/mpconfigport.h b/ports/samd/mpconfigport.h index 0b47500bf7..85401269eb 100644 --- a/ports/samd/mpconfigport.h +++ b/ports/samd/mpconfigport.h @@ -48,7 +48,6 @@ #endif #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) #define MICROPY_PY_BUILTINS_HELP_TEXT samd_help_text -#define MICROPY_USE_INTERNAL_ERRNO (1) #define MICROPY_SCHEDULER_STATIC_NODES (1) #define MICROPY_HW_ENABLE_USBDEV (1) @@ -139,6 +138,50 @@ #define MICROPY_HW_USB_PID (0x9802) #endif +// By default networking should include sockets, ssl, websockets, webrepl, dupterm. +#if MICROPY_PY_NETWORK + +#ifndef MICROPY_PY_NETWORK_HOSTNAME_DEFAULT +#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-samd" +#endif + +#ifndef MICROPY_PY_SOCKET +#define MICROPY_PY_SOCKET (1) +#endif +#ifndef MICROPY_PY_SSL +#define MICROPY_PY_SSL (1) +#endif +#ifndef MICROPY_PY_WEBSOCKET +#define MICROPY_PY_WEBSOCKET (1) +#endif +#ifndef MICROPY_PY_WEBREPL +#define MICROPY_PY_WEBREPL (1) +#endif + +#if MICROPY_PY_NETWORK_NINAW10 +// This Network interface requires the extended socket state. +#ifndef MICROPY_PY_SOCKET_EXTENDED_STATE +#define MICROPY_PY_SOCKET_EXTENDED_STATE (1) +#endif +extern const struct _mp_obj_type_t mod_network_nic_type_nina; +#define MICROPY_HW_NIC_NINAW10 { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_nic_type_nina) }, + +#else + +#define MICROPY_HW_NIC_NINAW10 + +#endif // MICROPY_PY_NETWORK_NINAW10 + +#ifndef MICROPY_BOARD_NETWORK_INTERFACES +#define MICROPY_BOARD_NETWORK_INTERFACES +#endif + +#define MICROPY_PORT_NETWORK_INTERFACES \ + MICROPY_HW_NIC_NINAW10 \ + MICROPY_BOARD_NETWORK_INTERFACES + +#endif // MICROPY_PY_NETWORK + // Additional entries for use with pendsv_schedule_dispatch. #ifndef MICROPY_BOARD_PENDSV_ENTRIES #define MICROPY_BOARD_PENDSV_ENTRIES diff --git a/ports/samd/nina_wifi_bsp.c b/ports/samd/nina_wifi_bsp.c new file mode 100644 index 0000000000..abe6e585bc --- /dev/null +++ b/ports/samd/nina_wifi_bsp.c @@ -0,0 +1,113 @@ +/* + * This file is part of the OpenMV project, https://openmv.io. + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * 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. + * + * NINA-W10 driver BSP implementation. + */ + +#include "py/mphal.h" + +#if MICROPY_PY_NETWORK_NINAW10 + +#include +#include + +#include "py/runtime.h" +#include "extmod/modmachine.h" +#include "extmod/virtpin.h" +#include "mpconfigboard.h" + +#include "nina_bsp.h" +#include "nina_wifi_drv.h" + +#if NINA_DEBUG +#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#else +#define debug_printf(...) +#endif + +// Use the name CS instead of GPIO1 +#ifndef MICROPY_HW_NINA_CS +#define MICROPY_HW_NINA_CS MICROPY_HW_NINA_GPIO1 +#endif + +int nina_bsp_init(void) { + mp_hal_pin_output(MICROPY_HW_NINA_CS); + mp_hal_pin_input(MICROPY_HW_NINA_ACK); + mp_hal_pin_output(MICROPY_HW_NINA_RESET); + #ifdef MICROPY_HW_NINA_GPIO0 + mp_hal_pin_output(MICROPY_HW_NINA_GPIO0); + mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1); + #endif + + // Reset module in WiFi mode + mp_hal_pin_write(MICROPY_HW_NINA_CS, 1); + + mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0); + mp_hal_delay_ms(100); + + mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1); + mp_hal_delay_ms(750); + + #ifdef MICROPY_HW_NINA_GPIO0 + mp_hal_pin_input(MICROPY_HW_NINA_GPIO0); + #endif + + // Initialize SPI. + mp_obj_t args[] = { + MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_ID), + MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_BAUDRATE), + MP_ROM_QSTR(MP_QSTR_sck), MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_SCK), + MP_ROM_QSTR(MP_QSTR_miso), MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_MISO), + MP_ROM_QSTR(MP_QSTR_mosi), MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_MOSI), + }; + MP_STATE_PORT(mp_wifi_spi) = MP_OBJ_TYPE_GET_SLOT(&machine_spi_type, make_new)( + (mp_obj_t)&machine_spi_type, 2, 3, args); + return 0; +} + +int nina_bsp_spi_slave_select(uint32_t timeout) { + // Wait for ACK to go low. + for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 1; mp_hal_delay_us(100)) { + if (timeout && ((mp_hal_ticks_ms() - start) >= timeout)) { + return -1; + } + } + + // Chip select. + mp_hal_pin_write(MICROPY_HW_NINA_CS, 0); + + // Wait for ACK to go high. + for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 0; mp_hal_delay_us(100)) { + if ((mp_hal_ticks_ms() - start) >= 100) { + mp_hal_pin_write(MICROPY_HW_NINA_CS, 1); + return -1; + } + } + + return 0; +} + +#endif // MICROPY_PY_NETWORK_NINAW10