diff --git a/docs/samd/quickref.rst b/docs/samd/quickref.rst index 25b5a8fc8ab2b..32d7138124ca0 100644 --- a/docs/samd/quickref.rst +++ b/docs/samd/quickref.rst @@ -18,6 +18,7 @@ working with this board it may be useful to get an overview of the microcontroll general.rst tutorial/intro.rst pinout.rst + wlan_pinout.rst Installing MicroPython @@ -511,6 +512,58 @@ with the Neopixel driver from the MicroPython driver library:: machine.bitstream() is set up for a SAMD21 clock frequency of 48MHz and a SAMD51 clock frequency of 120 MHz. At other clock frequencies, the timing will not fit. +WLAN and BLE +------------ + +Some boards can be combined with an ESP32 based WLAN module to support +WLAN and BLE connectivity. WLAN is then another class +of the the :mod:`network` module.:: + + import network + + wlan = network.WLAN(network.STA_IF) # create station interface + wlan.active(True) # activate the interface + wlan.scan() # scan for access points + wlan.isconnected() # check if the station is connected to an AP + wlan.connect('ssid', 'key') # connect to an AP + wlan.config('mac') # get the interface's MAC address + wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses + + ap = network.WLAN(network.AP_IF) # create access-point interface + ap.active(True) # activate the interface + ap.config(ssid='ESP-AP') # set the SSID of the access point + +A useful function for connecting to your local WiFi network is:: + + def do_connect(): + import network + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + if not wlan.isconnected(): + print('connecting to network...') + wlan.connect('ssid', 'key') + while not wlan.isconnected(): + pass + print('network config:', wlan.ifconfig()) + +Once the network is established the :mod:`socket ` module can be used +to create and use TCP/UDP sockets as usual, and the ``requests`` module for +convenient HTTP requests. + +Supported boards are: + +- Adafruit Metro M4 Airlift: WLAN adapter built-in +- Adafruit ItsyBitsy M4 with e.g. the Adafruit ItsyBity Airlift boards +- Adafruit Feather M4 with e.g. the Adafruit Feather Airlift boards +- Sparkfun SAMD51 Things Plus with e.g. the Adafruit Feather Airlift boards +- Adafruit Grand Central M4 with e.g. the Adafruit Airlift Uno board + +More boards may support it. Basic WiFi support could even be provided +for SAMD21 board with external flash. As external +WLAN module, any ESP32 based breakout can be used. It has to be loaded +with the proper firmware and wired up accordingly. For the wiring +scheme, see the :ref:`WLAN connection scheme `. + Transferring files ------------------ diff --git a/docs/samd/wlan_pinout.rst b/docs/samd/wlan_pinout.rst new file mode 100644 index 0000000000000..799ca7923134b --- /dev/null +++ b/docs/samd/wlan_pinout.rst @@ -0,0 +1,189 @@ +.. _samd_wlan_pinout: + +Managing external WLAN/BLE adapters +=================================== + +Connection scheme for the SAMD WLAN adapters +-------------------------------------------- + +Mapping between the NINA/esp_hosted signals and board pins by name and number. + +======== ========== ======== ========= ========= ============== ========= ========== +NINAW10 esp_hosted Airlift ItsyBitsy Feather METRO M4 Sparkfun Grand Ctrl +Name Name Name M4 M4 Airlift SAMD51 M4 Express +======== ========== ======== ========= ========= ============== ========= ========== +MOSI/RTS MOSI MOSI MOSI (0) MOSI (55) MOSI (12) MOSI (44) D11 (55) +MISO MISO MISO MISO (55) MISO (54) MISO (14) MISO (43) D12 (32) +SCK SCK SCK SCK (1) SCK (17) SCK (13) SCK (45) D13 (33) +CS CS CS D13 (22) D13 (23) ESP_CS (15) D13 (17) D10 (54) +ACK/CTS HANDSHAKE Busy D11 (21) D11 (21) ESP_BUSY (36) D11 (16) D7 (117) +RESET RESET Reset D12 (23) D12 (22) ESP_RESET (37) D12 (19) D5 (85) +GPIO0 DATAREADY GP0 D10 (20) D10 (20) ESP_GPIO0 (33) D10 (18) D6 (116) +SPI # 1 1 1 4 5 +TX TX TX D0 (16) D0 (49) D0 (7) D0 (13) D1 (56) +RX TX RX D1 ( 17) D1 (48) D1 (4) D1 (12) D0 (57) +RTS MOSI/RTS RTS MOSI (0) MOSI (55) MOSI (12) MOSI (44) MOSI (55) +CTS CTS CTS D11 (21) D11 (21) ESP_BUSY (36) D11 (16) D7 (117) +UART # 3 5 0 2 ? +======== ========== ======== ========= ========= ============== ========= ========== + +Mapping between firmware signal names and ESP32 pins for the NINA firmware +and esp_hosted firmware + +======== ========== ======== ======= ======= +NINAW10 esp_hosted NINA Airlift Airlift +Name Name W102 pin Name pin +======== ========== ======== ======= ======= +MOSI MOSI 12 MOSI 14 +MISO MISO 23 MISO 23 +SCK SCK 18 SCK 18 +GPIO1/CS CS 5 CS 5 +ACK HANDSHAKE 33 Busy 33 +RESET RESET EN Reset EN +GPIO0 DATAREADY 0 GP0 0 +TX TX 1 TX 1 +RX TX 3 RX 3 +RTS MOSI/RTS 12 - 14 +CTS CTS 33 - 33 +======== ========== ======== ======= ======= + +Mapping between the NINA/esp_hosted signals and adapter pins by name. + +======== ========== ======= ========= ======== ========= ========== +NINAW10 esp_hosted Airlift ItsyBitsy Feather METRO M4 Airlift +Name Name Name Add-on Add-on Airlift Uno Shield +======== ========== ======= ========= ======== ========= ========== +MOSI MOSI MOSI MOSI MOSI MOSI MOSI +MISO MISO MISO MISO MISO MISO MISO +SCK SCK SCK SCK SCK SCK SCK +GPIO1/CS CS CS ECS ESPCS ESP_CS CS +ACK HANDSHAKE Busy EBSY ESPBUSY ESP_BUSY BUSY +RESET RESET Reset RST ESPRESET ESP_RESET RST +GPIO0 DATAREADY GP0 GPIO0 ESPGPIO0 ESP_GP0 G0 +TX TX TX ETX ESPTX ESP_TX TX +RX RX RX ERX ESPRX ESP_RX RX +======== ========== ======= ========= ======== ========= ========== + +Signals required for WiFi: + +- NinaW10: MISO/MOSI/SCK (SPI), CS, Busy (ACK), Reset +- esp_hosted: MISO/MOSI/SCK (SPI), CS, Handshake, Dataready, Reset + +Signals required for Bluetooth: + +- NinaW10: RX/TX (UART), RTS (MOSI), CS, RESET +- esp_hosted: RX/TX (UART), RTS (MOSI), CS, RESET + +CTS seems not to be used for the NINA firmware, but specified. + +Signals required for NINA/esp_hosted firmware upload: + +- RX/TX (UART), GPIO0, Reset. + +If the hardware supports it, pull RESET low (!). That keeps the +ESP32 with the NINA/esp_hosted firmware silent and at low power +when not being used. + + +.. _samd_wlan_firmware_upload: + +Instructions for WLAN/BLE firmware upload ESP32 module +------------------------------------------------------ + +The NINA firmware in the NINA module has to be updated for use with MicroPython. That can be done +using MicroPython and two small Python scripts. + +The firmware binaries are available at +https://github.com/micropython/micropython-lib/tree/master/micropython/espflash +There are the firmware files available for different esp32 modules. + +1. Adafruit Airlift modules with NINA firmware: NINA_FW_v1.5.0_Airlift.bin. +2. Adafruit Airlift modules with esp_hosted firmware: esp_hosted_airlift.bin +3. Arduino Nano RP2040 connect: NINA_FW_v1.5.0_W102.bin + +Depending on the firmware for the SAMD boards you need the file +NINA_FW_v1.5.0_Airlift.bin or esp_hosted_airlift.bin. + +For firmware upload, the following connections to the WiFi module are required: + +- Pin Reset (as above) +- Pin GPIO0 +- UART RX +- UART TX + +The GPIO pins and UART device id varies between boards. See the tables above. +At the Adafruit Metro M4 board for instance, the UART is UART(5), and the Pin names +for reset and GPIO0 are ESP_RESET and ESP_GPIO0. +The firmware can be uploaded, using the espflash.py module, a short script +using espflash.py and mpremote. espflash.py is available at +https://github.com/micropython/micropython-lib/tree/master/micropython/espflash. +This place also holds the example script.:: + + import espflash + from machine import Pin + from machine import UART + import sys + sys.path.append("/") + + reset = Pin(37, Pin.OUT) + gpio0 = Pin(33, Pin.OUT) + uart = UART(0, 115200, tx=4, rx=7, timeout=350) + + md5sum = b"b0b9ab23da820a469e597c41364acb3a" + path = "/remote/NINA_FW_v1.5.0_Airlift.bin" + # md5sum = b"28ab84372ff4f07551b984671f7f9ff9" + # path = "/remote/esp_hosted_airlift.bin" + + esp = espflash.ESPFlash(reset, gpio0, uart) + # Enter bootloader download mode, at 115200 + esp.bootloader() + # Can now change to higher/lower baudrate + esp.set_baudrate(921600) + # Must call this first before any flash functions. + esp.flash_attach() + # Read flash size + size = esp.flash_read_size() + # Configure flash parameters. + esp.flash_config(size) + # Write firmware image from internal storage. + esp.flash_write_file(path) + # Compares file and flash MD5 checksum. + esp.flash_verify_file(path, md5sum) + # Resets the ESP32 chip. + esp.reboot() + +The script shows the set-up for the Metro M4 board. +The md5sum is the one of the WiFi firmware. It may change and +can be recalculated using e.g. the Linux *md5sum* command. It is used to +verify the firmware upload. To upload the firmware, place the firmware +and the above script (let's call it ninaflash.py) into the same directory +on your PC, and run the command:: + + mpremote connect mount . run ninaflash.py + +After a while, the upload will start. A typical start sequence looks like:: + + Local directory . is mounted at /remote + Failed to read response to command 8. + Failed to read response to command 8. + Changing baudrate => 921600 + Flash attached + Flash size 2.0 MBytes + Flash write size: 1310720 total_blocks: 320 block size: 4096 + Writing sequence number 0/320... + Writing sequence number 1/320... + Writing sequence number 2/320... + Writing sequence number 3/320... + Writing sequence number 4/320... + .... + .... + Writing sequence number 317/320... + Writing sequence number 318/320... + Writing sequence number 319/320... + Flash write finished + Flash verify: File MD5 b'b0b9ab23da820a469e597c41364acb3a' + Flash verify: Flash MD5 b'b0b9ab23da820a469e597c41364acb3a' + Firmware verified. + +The initial messages *Failed to read response to command 8.* +can be ignored. diff --git a/drivers/ninaw10/nina_bt_hci.c b/drivers/ninaw10/nina_bt_hci.c index f0d1b9bc8986b..b93a605f9047a 100644 --- a/drivers/ninaw10/nina_bt_hci.c +++ b/drivers/ninaw10/nina_bt_hci.c @@ -50,6 +50,11 @@ #define OCF_SET_EVENT_MASK (0x0001) #define OCF_RESET (0x0003) +// Use the name CS instead of GPIO1 +#ifndef MICROPY_HW_NINA_CS +#define MICROPY_HW_NINA_CS MICROPY_HW_NINA_GPIO1 +#endif + #define error_printf(...) // mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__) #define debug_printf(...) // mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__) @@ -59,6 +64,12 @@ extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256]; static int nina_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_buf) { uint8_t *buf = mp_bluetooth_hci_cmd_buf; + // Clear the UART input buffer before sending the reset command. + // The ESP32 reset message may stick in it. + while (mp_bluetooth_hci_uart_any()) { + mp_bluetooth_hci_uart_readchar(); + } + buf[0] = HCI_COMMAND_PACKET; buf[1] = ocf; buf[2] = ogf << 2 | ocf >> 8; @@ -125,8 +136,17 @@ int mp_bluetooth_hci_controller_init(void) { mp_hal_pin_output(MICROPY_HW_NINA_RESET); mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0); - mp_hal_pin_output(MICROPY_HW_NINA_GPIO1); - mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 0); + // care for dedicated setting of RTS/CTS + #ifdef MICROPY_HW_NINA_RTS + mp_hal_pin_output(MICROPY_HW_NINA_RTS); + mp_hal_pin_write(MICROPY_HW_NINA_RTS, 0); + #endif + #ifdef MICROPY_HW_NINA_CTS + mp_hal_pin_input(MICROPY_HW_NINA_CTS); + #endif + + mp_hal_pin_output(MICROPY_HW_NINA_CS); + mp_hal_pin_write(MICROPY_HW_NINA_CS, 0); mp_hal_delay_ms(150); mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1); diff --git a/drivers/ninaw10/nina_wifi_bsp.c b/drivers/ninaw10/nina_wifi_bsp.c index dc71c8260c61f..04a20b2efb281 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 75a4d9b1de355..259af4b51d990 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 @@ -33,6 +37,7 @@ FROZEN_MANIFEST ?= boards/manifest.py # Include py core make definitions include $(TOP)/py/py.mk include $(TOP)/extmod/extmod.mk +include ${TOP}/extmod/nimble/nimble.mk GIT_SUBMODULES += lib/asf4 lib/tinyusb diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h index 880df8d200390..66d0e1853519a 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h @@ -5,3 +5,14 @@ #define MICROPY_HW_SPIFLASH (1) #define MICROPY_HW_SPIFLASH_ID (2) + +#define MICROPY_HW_WIFI_SPI_ID (4) +#define MICROPY_HW_WIFI_SPI_BAUDRATE (8000000) + +#define MICROPY_HW_WIFI_SPI_MOSI (42) +#define MICROPY_HW_WIFI_SPI_MISO (12) +#define MICROPY_HW_WIFI_SPI_SCK (43) + +#define MICROPY_HW_NINA_CS (17) +#define MICROPY_HW_NINA_ACK (16) +#define MICROPY_HW_NINA_RESET (19) diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/board.json index 06cd9a4fe4d9b..02eec091ccf11 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/board.json +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/board.json @@ -14,6 +14,10 @@ "feather_m4_express.jpg" ], "mcu": "samd51", + "variants": { + "WLAN": "WiFi support using a ESP32 module with NINA firmware", + "WLAN_BLE": "WiFi and BLE support using a ESP32 module with NINA firmware" + }, "product": "Feather M4 Express", "thumbnail": "", "url": "https://www.adafruit.com/product/3857", diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.h index a9f7d518e2364..c80fb70e3b989 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.h +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M4_EXPRESS/mpconfigboard.h @@ -5,3 +5,26 @@ #define MICROPY_HW_MCU_OSC32KULP (1) #define MICROPY_HW_QSPIFLASH GD25Q16C + +#define MICROPY_HW_WIFI_SPI_ID (1) +#define MICROPY_HW_WIFI_SPI_BAUDRATE (8000000) + +#define MICROPY_HW_WIFI_SPI_MOSI (55) +#define MICROPY_HW_WIFI_SPI_MISO (54) +#define MICROPY_HW_WIFI_SPI_SCK (17) + +#define MICROPY_HW_NINA_ACK (21) +#define MICROPY_HW_NINA_CS (23) +#define MICROPY_HW_NINA_RESET (22) + +// defines for BLE +#define MICROPY_PY_BLUETOOTH_NINAW10 (1) + +#define MICROPY_HW_BLE_UART_ID (5) +#define MICROPY_HW_BLE_UART_BAUDRATE (115200) + +#define MICROPY_HW_BLE_UART_TX (48) +#define MICROPY_HW_BLE_UART_RX (49) + +#define MICROPY_HW_NINA_RTS (55) +#define MICROPY_HW_NINA_CTS (21) diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.h index 16018fdc56356..c7b08b7e0ea5e 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.h +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M0_EXPRESS/mpconfigboard.h @@ -5,3 +5,14 @@ #define MICROPY_HW_SPIFLASH (1) #define MICROPY_HW_SPIFLASH_ID (5) + +#define MICROPY_HW_WIFI_SPI_ID (4) +#define MICROPY_HW_WIFI_SPI_BAUDRATE (8000000) + +#define MICROPY_HW_WIFI_SPI_MOSI (42) +#define MICROPY_HW_WIFI_SPI_MISO (12) +#define MICROPY_HW_WIFI_SPI_SCK (43) + +#define MICROPY_HW_NINA_CS (17) +#define MICROPY_HW_NINA_ACK (16) +#define MICROPY_HW_NINA_RESET (19) diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json index a998529ccde2e..4d0be6bbe4e13 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json @@ -12,6 +12,10 @@ "itsybitsy_m4_express.jpg" ], "mcu": "samd51", + "variants": { + "WLAN": "WiFi support using a ESP32 module with NINA firmware", + "WLAN_BLE": "WiFi and BLE 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/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h index 2f246c60b188c..1bda9991a9261 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h @@ -4,3 +4,28 @@ #define MICROPY_HW_DFLL_USB_SYNC (1) #define MICROPY_HW_QSPIFLASH GD25Q16C + +#define MICROPY_HW_DFLL_USB_SYNC (1) + +#define MICROPY_HW_WIFI_SPI_ID (1) +#define MICROPY_HW_WIFI_SPI_BAUDRATE (8000000) + +#define MICROPY_HW_WIFI_SPI_MOSI (0) +#define MICROPY_HW_WIFI_SPI_MISO (55) +#define MICROPY_HW_WIFI_SPI_SCK (1) + +#define MICROPY_HW_NINA_CS (22) +#define MICROPY_HW_NINA_ACK (21) +#define MICROPY_HW_NINA_RESET (23) + +// defines for BLE +#define MICROPY_PY_BLUETOOTH_NINAW10 (1) + +#define MICROPY_HW_BLE_UART_ID (3) +#define MICROPY_HW_BLE_UART_BAUDRATE (115200) + +#define MICROPY_HW_BLE_UART_TX (17) +#define MICROPY_HW_BLE_UART_RX (16) + +#define MICROPY_HW_NINA_RTS (0) +#define MICROPY_HW_NINA_CTS (21) diff --git a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/board.json index 4a3158d71334c..bde0cd8fa9777 100644 --- a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/board.json +++ b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/board.json @@ -15,6 +15,9 @@ "metro_m4_express_airlift.jpg" ], "mcu": "samd51", + "variants": { + "WLAN_BLE": "WiFi and BLE support using a ESP32 module with NINA firmware" + }, "product": "Metro M4 Express Airlift", "thumbnail": "", "url": "https://www.adafruit.com/product/4000", diff --git a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk index 43ca5a59cc636..d1826351a76e7 100644 --- a/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_METRO_M4_EXPRESS/mpconfigboard.mk @@ -3,8 +3,6 @@ CMSIS_MCU = SAMD51J19A LD_FILES = boards/samd51x19a.ld sections.ld TEXT0 = 0x4000 -# MicroPython settings -MICROPY_PY_NETWORK ?= 1 -MICROPY_PY_NETWORK_NINAW10 ?= 1 +MICROPY_HW_CODESIZE = 496K -MICROPY_HW_CODESIZE ?= 496K +BOARD_VARIANT ?= WLAN diff --git a/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/board.json b/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/board.json index ee9ca9d3689b0..13ad1afc05c33 100644 --- a/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/board.json +++ b/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/board.json @@ -13,6 +13,10 @@ "sparkfun_samd51_thing_plus.jpg" ], "mcu": "samd51", + "variants": { + "WLAN": "WiFi support using a ESP32 module with NINA firmware", + "WLAN_BLE": "WiFi and BLE support using a ESP32 module with NINA firmware" + }, "product": "Sparkfun SAMD51 Thing Plus", "thumbnail": "", "url": "https://www.sparkfun.com/products/14713", diff --git a/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.h b/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.h index 706fc3c64c37b..7a6266319222f 100644 --- a/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.h +++ b/ports/samd/boards/SPARKFUN_SAMD51_THING_PLUS/mpconfigboard.h @@ -13,3 +13,26 @@ // the board's external flash. #define MICROPY_HW_SPIFLASH (1) #define MICROPY_HW_SPIFLASH_ID (0) + +#define MICROPY_HW_WIFI_SPI_ID (4) +#define MICROPY_HW_WIFI_SPI_BAUDRATE (8000000) + +#define MICROPY_HW_WIFI_SPI_MOSI (44) +#define MICROPY_HW_WIFI_SPI_MISO (43) +#define MICROPY_HW_WIFI_SPI_SCK (45) + +#define MICROPY_HW_NINA_ACK (16) +#define MICROPY_HW_NINA_CS (17) +#define MICROPY_HW_NINA_RESET (19) + +// defines for BLE +#define MICROPY_PY_BLUETOOTH_NINAW10 (1) + +#define MICROPY_HW_BLE_UART_ID (2) +#define MICROPY_HW_BLE_UART_BAUDRATE (115200) + +#define MICROPY_HW_BLE_UART_TX (12) +#define MICROPY_HW_BLE_UART_RX (13) + +#define MICROPY_HW_NINA_RTS (44) +#define MICROPY_HW_NINA_CTS (16) diff --git a/ports/samd/boards/deploy.md b/ports/samd/boards/deploy.md index fac5c994ab702..f6f90c1d0cfd9 100644 --- a/ports/samd/boards/deploy.md +++ b/ports/samd/boards/deploy.md @@ -1,10 +1,167 @@ +# Deploy firmware to the SAMD boards and a NINA/ESP32 WiFi module. + +## Deploy the MicroPython firmware + For deploying the MicroPython firmware to the SAMD module, follow -the procedure: +the usual procedure: + +1. Push reset twice or call machine.bootloader(), if there was already + MicroPyhton installed at the board. A drive icon should appear + representing a virtual drive. +2. Copy the .uf2 file with the required firmware to that drive. As + soon as the drive disappears, the firmware is loaded and started. + +If a MicroPython firmware is already installed at the board, it is also +possible to enable the bootloader by shortly switching the USB Serial +to 1200 baud and back, like it is done in the short script below. That +allows for scripted update. + +```Py +import serial +import time +import sys +com=serial.Serial(sys.argv[1], 1200, dsrdtr=True) +com.dtr=False +com.rts=False +time.sleep(0.2) +com.close() +time.sleep(4) +# then copy the firmware file to the drive +``` + +## Deploy the Wifi firmware. + +The WiFi module uses the NINA firmware, which works on any ESP32 module, +like the u.Blox NINA W102, the Adafruit Airlink modules or a generic +ESP32 device with at least 2 MB flash. Before the first use the appropriate +firmware has to be loaded to the device. A pre-existing firmware might +not work. The procedure differs between device types. + +### Firmware source and types. + +There exist two firmware versions, which only differ in the connection +for the MOSI connection between host MCU and WiFi module. The connections +for Wifi use are: +``` + Driver NINA Airlift Airlift + Name W102 pin Name pin + ---------------------------------- + MOSI 12 MOSI 14 + MISO 23 MISO 23 + SCK 18 SCK 18 + GPIO1 5 CS 5 + ACK 33 Busy 33 + RESET EN Reset EN +``` +The firmware binaries are available at https://github.com/micropython/micropython-lib/tree/master/micropython/espflash or https://github.com/robert-hh/Shared-Stuff. +For a generic ESP32 device you can use either version, given that the +MOSI signal is wired properly. If possible, add a **pull-down** resistor to +the RESET pin, value 1.5 to 10k, such that RESET is kept low as long as +WiFi is not used. That keeps the ESP32 in inactive state and it's GPIO pins +at high impedance. + +### Firmware upload to a Generic ESP32 device. + +That is the easiest task, if the USB port of the device is available. Just +follow the standard ESP procedure for uploading firmware using esptool.py with +the command: + +``` +esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0 NINA_FW_v1.5.0_W102.bin +``` + +Note that the load address is 0. The port name will be different depending on +the PC set-up and it's operating system. If the USB port is not available, follow +the procedure for built-in modules. + +### Firmware upload for built-in or breakout modules + +For firmware upload, the following connections to the WiFi module are required: + +- Pin Reset (as above) +- Pin GPIO0 +- UART RX +- UART TX + +The GPIO pins and UART device id varies between boards. If the WiFi module is hardwired +to a MCU or Add-on board, the Pin and UART properties can be found in the documentation, +otherwise any suitable pins can be used. On some add-on boards like the Adafruit ItsyBitsy, +Feather or Arduino Shield modules solder bridges may have to be closed to RX, TX and GPIO0. +RX and TX are needed for bluetooth as well. +Once the wiring is done, the firmware can be uploaded, using the espflash.py module, a short script +using espflash.py and mpremote. espflash.py is usually embedded into the MicroPython firmware +of the SAMD device as frozen bytecode. Otherwise, it is available at https://github.com/micropython/micropython-lib/tree/master/micropython/espflash. This place also holds the example script. + +``` +import espflash +from machine import Pin +from machine import UART +import sys +sys.path.append("/") + +if True: + reset = Pin("ESP_RESET", Pin.OUT) + gpio0 = Pin("ESP_GPIO0", Pin.OUT) + uart = UART(0, 115200, tx=Pin("ESP_TX"), rx=Pin("ESP_RX"), timeout=350) -- Push the reset button twice or call machine.bootloader(). A drive - icon should appear representing a virtual drive. + md5sum = b"b0b9ab23da820a469e597c41364acb3a" + path = "/remote/NINA_FW_v1.5.0_Airlift.bin" -- Copy the .uf2 file with the required firmware to that drive. + esp = espflash.ESPFlash(reset, gpio0, uart) + # Enter bootloader download mode, at 115200 + esp.bootloader() + # Can now change to higher/lower baud rate + esp.set_baudrate(921600) + # Must call this first before any flash functions. + esp.flash_attach() + # Read flash size + size = esp.flash_read_size() + # Configure flash parameters. + esp.flash_config(size) + # Write firmware image from internal storage. + esp.flash_write_file(path) + # Compares file and flash MD5 checksum. + esp.flash_verify_file(path, md5sum) + # Resets the ESP32 chip. + esp.reboot() +``` -As soon as the drive disappears, the firmware is loaded and started. +The script shows the set-up for the Metro M4 Express Airlift board. +The md5sum is the one of the WiFi firmware. It may change and +can be recalculated using e.g. the Linux `md5sum` command. It is used to +verify the firmware upload. To upload the firmware, place the firmware +and the above script (let's call it ninaflash.py) into the same directory +on your PC, and run the command: +``` +mprememote connect mount . run ninaflash.py +``` +After a while the upload will start. A typical start sequence looks like: +``` +Local directory . is mounted at /remote +Failed to read response to command 8. +Failed to read response to command 8. +Changing baudrate => 921600 +Flash attached +Flash size 2.0 MBytes +Flash write size: 1310720 total_blocks: 320 block size: 4096 +Writing sequence number 0/320... +Writing sequence number 1/320... +Writing sequence number 2/320... +Writing sequence number 3/320... +Writing sequence number 4/320... +.... +.... +Writing sequence number 317/320... +Writing sequence number 318/320... +Writing sequence number 319/320... +Flash write finished +Flash verify: File MD5 b'b0b9ab23da820a469e597c41364acb3a' +Flash verify: Flash MD5 b'b0b9ab23da820a469e597c41364acb3a' +Firmware verified. +``` +The initial messages `Failed to read response to command 8.` +can be ignored. +Once the firmware upload is finished, the connection to RX, TX and GPIO0 +can be removed, unless the modules is used to Bluetooth communication, +which needs RX and TX. diff --git a/ports/samd/main.c b/ports/samd/main.c index 2bbaf63e6e4c5..e9ba2971e212f 100644 --- a/ports/samd/main.c +++ b/ports/samd/main.c @@ -29,12 +29,15 @@ #include "py/gc.h" #include "py/mperrno.h" #include "py/stackctrl.h" +#include "extmod/modnetwork.h" #include "shared/readline/readline.h" #include "shared/runtime/gchelper.h" #include "shared/runtime/pyexec.h" #include "shared/runtime/softtimer.h" #include "shared/tinyusb/mp_usbd.h" #include "clock_config.h" +#include "extmod/modbluetooth.h" +#include "mpbthciport.h" extern uint8_t _sstack, _estack, _sheap, _eheap; extern void adc_deinit_all(void); @@ -50,8 +53,15 @@ void samd_main(void) { gc_init(&_sheap, &_eheap); mp_init(); + #if MICROPY_PY_BLUETOOTH + mp_bluetooth_hci_init(); + #endif + // Initialise sub-systems. readline_init0(); + #if MICROPY_PY_NETWORK + mod_network_init(); + #endif // Execute _boot.py to set up the filesystem. pyexec_frozen_module("_boot.py", false); @@ -87,6 +97,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_port.h b/ports/samd/mbedtls/mbedtls_config_port.h new file mode 100644 index 0000000000000..18cedbae10fc9 --- /dev/null +++ b/ports/samd/mbedtls/mbedtls_config_port.h @@ -0,0 +1,41 @@ +/* + * 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 + +// Time hook. +#include +extern time_t samd_rtctime_seconds(time_t *timer); +#define MBEDTLS_PLATFORM_TIME_MACRO samd_rtctime_seconds +#define MBEDTLS_PLATFORM_MS_TIME_ALT mbedtls_ms_time + +// 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 0000000000000..da6059ca6b651 --- /dev/null +++ b/ports/samd/mbedtls/mbedtls_port.c @@ -0,0 +1,84 @@ +/* + * 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_port.h" +#include +uint32_t trng_random_u32(void); +#if defined(MBEDTLS_HAVE_TIME) || defined(MBEDTLS_HAVE_TIME_DATE) +#include +#include "py/runtime.h" +#include "shared/timeutils/timeutils.h" +#include "mbedtls/platform_time.h" +extern void rtc_gettime(timeutils_struct_time_t *tm); +#endif + +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 + +#if defined(MBEDTLS_HAVE_TIME) +time_t samd_rtctime_seconds(time_t *timer) { + timeutils_struct_time_t tm; + rtc_gettime(&tm); + return timeutils_seconds_since_epoch(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); +} + +mbedtls_ms_time_t mbedtls_ms_time(void) { + time_t *tv = NULL; + mbedtls_ms_time_t current_ms; + current_ms = samd_rtctime_seconds(tv) * 1000; + return current_ms; +} +#endif + +#if defined(MBEDTLS_HAVE_TIME_DATE) +struct tm *gmtime(const time_t *timep) { + static struct tm tm; + timeutils_struct_time_t tm_buf = {0}; + timeutils_seconds_since_epoch_to_struct_time(*timep, &tm_buf); + + tm.tm_sec = tm_buf.tm_sec; + tm.tm_min = tm_buf.tm_min; + tm.tm_hour = tm_buf.tm_hour; + tm.tm_mday = tm_buf.tm_mday; + tm.tm_mon = tm_buf.tm_mon - 1; + tm.tm_year = tm_buf.tm_year - 1900; + tm.tm_wday = tm_buf.tm_wday; + tm.tm_yday = tm_buf.tm_yday; + tm.tm_isdst = -1; + + return &tm; +} +#endif diff --git a/ports/samd/mcu/samd51/manifest_net.py b/ports/samd/mcu/samd51/manifest_net.py new file mode 100644 index 0000000000000..b0554adc1960e --- /dev/null +++ b/ports/samd/mcu/samd51/manifest_net.py @@ -0,0 +1,16 @@ +include("$(PORT_DIR)/boards/manifest.py") +include("$(MPY_DIR)/extmod/asyncio") +# Drivers +require("onewire") +require("ds18x20") +require("dht") +# Networking +require("bundle-networking") +# BLE +include( + "$(MPY_LIB_DIR)/micropython/bluetooth/aioble/manifest.py", + client=True, + central=True, + l2cap=True, + security=True, +) diff --git a/ports/samd/mcu/samd51/mpconfigmcu.h b/ports/samd/mcu/samd51/mpconfigmcu.h index 9a7b8528f3573..5e8221d1ff08f 100644 --- a/ports/samd/mcu/samd51/mpconfigmcu.h +++ b/ports/samd/mcu/samd51/mpconfigmcu.h @@ -17,11 +17,15 @@ unsigned long trng_random_u32(void); #define MICROPY_PY_MACHINE_UART_IRQ (1) +// 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 9bef5eca166ab..7dedcb1fdcbf2 100644 --- a/ports/samd/mcu/samd51/mpconfigmcu.mk +++ b/ports/samd/mcu/samd51/mpconfigmcu.mk @@ -8,11 +8,49 @@ MICROPY_HW_CODESIZE ?= 368K MICROPY_VFS_LFS2 ?= 1 MICROPY_VFS_FAT ?= 1 -FROZEN_MANIFEST ?= mcu/$(MCU_SERIES_LOWER)/manifest.py SRC_S += shared/runtime/gchelper_thumb2.s - SRC_C += \ - fatfs_port.c \ + fatfs_port.c UF2CONV_FLAGS += -f 0x55114460 + +ifneq ($(BOARD_VARIANT),) + MICROPY_PY_NETWORK ?= 1 + CFLAGS += -DMICROPY_PY_NETWORK=1 + MICROPY_PY_NETWORK_NINAW10 ?= 1 + CFLAGS += -DMICROPY_PY_NETWORK_NINAW10=1 + + INC += -I$(TOP)/drivers/ninaw10 + SRC_C += \ + mbedtls/mbedtls_port.c\ + nina_wifi_bsp.c + SHARED_SRC_C += \ + shared/netutils/dhcpserver.c \ + shared/netutils/netutils.c \ + shared/netutils/trace.c + 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 + + ifeq ($(MICROPY_HW_CODESIZE),$(filter $(MICROPY_HW_CODESIZE), 496K 1008K)) + MICROPY_PY_SSL ?= 1 + MICROPY_SSL_MBEDTLS ?= 1 + + ifeq ($(BOARD_VARIANT),WLAN_BLE) + MICROPY_PY_BLUETOOTH ?= 1 + MICROPY_BLUETOOTH_NIMBLE ?= 1 + SRC_C += \ + mpbthciport.c \ + mpnimbleport.c + + INC += \ + -I$(TOP)/extmod/nimble + endif + endif + FROZEN_MANIFEST ?= mcu/$(MCU_SERIES_LOWER)/manifest_net.py +else + FROZEN_MANIFEST ?= mcu/$(MCU_SERIES_LOWER)/manifest.py +endif diff --git a/ports/samd/modmachine.h b/ports/samd/modmachine.h index e1279a2886d0c..1a2a7627f305b 100644 --- a/ports/samd/modmachine.h +++ b/ports/samd/modmachine.h @@ -34,5 +34,6 @@ extern const mp_obj_type_t machine_dac_type; #endif void rtc_gettime(timeutils_struct_time_t *tm); +void machine_uart_set_baudrate(mp_obj_t self, uint32_t baudrate); #endif // MICROPY_INCLUDED_SAMD_MODMACHINE_H diff --git a/ports/samd/mpbthciport.c b/ports/samd/mpbthciport.c new file mode 100644 index 0000000000000..4df6404f44fc4 --- /dev/null +++ b/ports/samd/mpbthciport.c @@ -0,0 +1,204 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Ibrahim Abdelkader + * + * 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. + */ + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "extmod/modbluetooth.h" +#include "extmod/mpbthci.h" +#include "shared/runtime/softtimer.h" +#include "modmachine.h" +#include "extmod/modmachine.h" +#include "mpbthciport.h" + +#if MICROPY_PY_BLUETOOTH + +#define debug_printf(...) // mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) +#define error_printf(...) mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) + +uint8_t mp_bluetooth_hci_cmd_buf[4 + 256]; + +MP_REGISTER_ROOT_POINTER(mp_obj_t mp_bthci_uart); + +// Soft timer for scheduling a HCI poll. +static soft_timer_entry_t mp_bluetooth_hci_soft_timer; + +// This is called by soft_timer and executes at IRQ_PRI_PENDSV. +static void mp_bluetooth_hci_soft_timer_callback(soft_timer_entry_t *self) { + mp_bluetooth_hci_poll_now(); +} + +void mp_bluetooth_hci_init(void) { + soft_timer_static_init( + &mp_bluetooth_hci_soft_timer, + SOFT_TIMER_MODE_ONE_SHOT, + 0, + mp_bluetooth_hci_soft_timer_callback + ); +} + +static void mp_bluetooth_hci_start_polling(void) { + mp_bluetooth_hci_poll_now(); +} + +void mp_bluetooth_hci_poll_in_ms(uint32_t ms) { + soft_timer_reinsert(&mp_bluetooth_hci_soft_timer, ms); +} + +static mp_sched_node_t mp_bluetooth_hci_sched_node; + +// For synchronous mode, we run all BLE stack code inside a scheduled task. +// This task is scheduled periodically via a timer, or immediately after UART RX IRQ. +static void run_events_scheduled_task(mp_sched_node_t *node) { + (void)node; + // This will process all buffered HCI UART data, and run any callouts or events. + mp_bluetooth_hci_poll(); +} + +// Called periodically (systick) or directly (e.g. UART RX IRQ) in order to +// request that processing happens ASAP in the scheduler. +void mp_bluetooth_hci_poll_now(void) { + mp_sched_schedule_node(&mp_bluetooth_hci_sched_node, run_events_scheduled_task); +} + +int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) { + debug_printf("mp_bluetooth_hci_uart_init\n"); + + mp_obj_t args[] = { + MP_OBJ_NEW_SMALL_INT(port), + MP_OBJ_NEW_SMALL_INT(baudrate), + MP_OBJ_NEW_QSTR(MP_QSTR_tx), MP_OBJ_NEW_SMALL_INT(MICROPY_HW_BLE_UART_TX), + MP_OBJ_NEW_QSTR(MP_QSTR_rx), MP_OBJ_NEW_SMALL_INT(MICROPY_HW_BLE_UART_RX), + MP_OBJ_NEW_QSTR(MP_QSTR_timeout), MP_OBJ_NEW_SMALL_INT(1000), + MP_OBJ_NEW_QSTR(MP_QSTR_timeout_char), MP_OBJ_NEW_SMALL_INT(1000), + MP_OBJ_NEW_QSTR(MP_QSTR_rxbuf), MP_OBJ_NEW_SMALL_INT(768), + MP_OBJ_NEW_QSTR(MP_QSTR_txbuf), MP_OBJ_NEW_SMALL_INT(768), + }; + + // This is not a statically-allocated UART (see machine_uart.c), + // so it has to be tracked as a root pointer. + MP_STATE_PORT(mp_bthci_uart) = MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, make_new)((mp_obj_t)&machine_uart_type, 2, 6, args); + // Start the HCI polling to process any initial events/packets. + mp_bluetooth_hci_start_polling(); + return 0; +} + +int mp_bluetooth_hci_uart_deinit(void) { + debug_printf("mp_bluetooth_hci_uart_deinit\n"); + mp_obj_t uart = MP_OBJ_TO_PTR(MP_STATE_PORT(mp_bthci_uart)); + mp_obj_t uart_deinit_args[] = { + NULL, // Method pointer + uart, // uart object + }; + mp_load_method_maybe((mp_obj_t)uart, MP_QSTR_deinit, uart_deinit_args); + if (uart_deinit_args[0] != MP_OBJ_NULL && uart_deinit_args[1] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, uart_deinit_args); + } + soft_timer_remove(&mp_bluetooth_hci_soft_timer); + return 0; +} + +int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) { + debug_printf("mp_bluetooth_hci_uart_set_baudrate(%lu)\n", baudrate); + mp_obj_t uart = MP_OBJ_TO_PTR(MP_STATE_PORT(mp_bthci_uart)); + machine_uart_set_baudrate(uart, baudrate); + return 0; +} + +int mp_bluetooth_hci_uart_any(void) { + int errcode = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, protocol); + + mp_uint_t ret = proto->ioctl(MP_STATE_PORT(mp_bthci_uart), MP_STREAM_POLL, MP_STREAM_POLL_RD, &errcode); + if (errcode != 0) { + error_printf("Uart ioctl failed to poll UART %d\n", errcode); + return -1; + } + return ret & MP_STREAM_POLL_RD; +} + +int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) { + debug_printf("mp_bluetooth_hci_uart_write\n"); + + int errcode = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, protocol); + + mp_bluetooth_hci_controller_wakeup(); + + if (proto->write(MP_STATE_PORT(mp_bthci_uart), (void *)buf, len, &errcode) < 0) { + error_printf("mp_bluetooth_hci_uart_write: failed to write to UART %d\n", errcode); + } + return 0; +} + +// This function expects the controller to be in the wake state via a previous call +// to mp_bluetooth_hci_controller_woken. +int mp_bluetooth_hci_uart_readchar(void) { + debug_printf("mp_bluetooth_hci_uart_readchar\n"); + if (mp_bluetooth_hci_uart_any()) { + int errcode = 0; + uint8_t buf = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, protocol); + if (proto->read(MP_STATE_PORT(mp_bthci_uart), (void *)&buf, 1, &errcode) < 0) { + error_printf("mp_bluetooth_hci_uart_readchar: failed to read UART %d\n", errcode); + return -1; + } + return buf; + } else { + debug_printf("mp_bluetooth_hci_uart_readchar: not ready\n"); + return -1; + } +} + +// Default (weak) implementation of the HCI controller interface. +// A driver (e.g. cywbt43.c) can override these for controller-specific +// functionality (i.e. power management). +MP_WEAK int mp_bluetooth_hci_controller_init(void) { + debug_printf("mp_bluetooth_hci_controller_init (default)\n"); + return 0; +} + +MP_WEAK int mp_bluetooth_hci_controller_deinit(void) { + debug_printf("mp_bluetooth_hci_controller_deinit (default)\n"); + return 0; +} + +MP_WEAK int mp_bluetooth_hci_controller_sleep_maybe(void) { + debug_printf("mp_bluetooth_hci_controller_sleep_maybe (default)\n"); + return 0; +} + +MP_WEAK bool mp_bluetooth_hci_controller_woken(void) { + debug_printf("mp_bluetooth_hci_controller_woken (default)\n"); + return true; +} + +MP_WEAK int mp_bluetooth_hci_controller_wakeup(void) { + debug_printf("mp_bluetooth_hci_controller_wakeup (default)\n"); + return 0; +} + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/samd/mpbthciport.h b/ports/samd/mpbthciport.h new file mode 100644 index 0000000000000..a732f347d56e0 --- /dev/null +++ b/ports/samd/mpbthciport.h @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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_MPBTHCIPORT_H +#define MICROPY_INCLUDED_RP2_MPBTHCIPORT_H + +#include "mphalport.h" + +void mp_bluetooth_hci_config_interface(mp_obj_t uart, mp_obj_t cs, mp_obj_t busy, mp_obj_t rts, mp_obj_t cts); + +// Initialise the HCI subsystem (should be called once, early on). +void mp_bluetooth_hci_init(void); + +// Poll the HCI now, or after a certain timeout. +void mp_bluetooth_hci_poll_now(void); +void mp_bluetooth_hci_poll_in_ms(uint32_t ms); + +// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c). +// Request new data from the uart and pass to the stack, and run pending events/callouts. +// This is a low-level function and should not be called directly, use +// mp_bluetooth_hci_poll_now/mp_bluetooth_hci_poll_in_ms instead. +void mp_bluetooth_hci_poll(void); + +#endif // MICROPY_INCLUDED_RP2_MPBTHCIPORT_H diff --git a/ports/samd/mpconfigport.h b/ports/samd/mpconfigport.h index 0b47500bf7e7c..3a5c05447be7a 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,52 @@ #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) }, + +#define MICROPY_PY_HASHLIB_SHA1 (MICROPY_PY_SSL) + +#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/mpnimbleport.c b/ports/samd/mpnimbleport.c new file mode 100644 index 0000000000000..74e9ecb02602a --- /dev/null +++ b/ports/samd/mpnimbleport.c @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * Copyright (c) 2020 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. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/stream.h" + +#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE + +#define DEBUG_printf(...) // printf("mpnimbleport.c: " __VA_ARGS__) + +#include "host/ble_hs.h" +#include "nimble/nimble_npl.h" + +#include "extmod/modbluetooth.h" +#include "extmod/mpbthci.h" +#include "extmod/nimble/modbluetooth_nimble.h" +#include "extmod/nimble/hal/hal_uart.h" +#include "mpbthciport.h" + +// Get any pending data from the UART and send it to NimBLE's HCI buffers. +// Any further processing by NimBLE will be run via its event queue. +void mp_bluetooth_hci_poll(void) { + if (mp_bluetooth_nimble_ble_state >= MP_BLUETOOTH_NIMBLE_BLE_STATE_WAITING_FOR_SYNC) { + // DEBUG_printf("mp_bluetooth_hci_poll_uart %d\n", mp_bluetooth_nimble_ble_state); + + // Run any timers. + mp_bluetooth_nimble_os_callout_process(); + + // Process incoming UART data, and run events as they are generated. + mp_bluetooth_nimble_hci_uart_process(true); + + // Run any remaining events (e.g. if there was no UART data). + mp_bluetooth_nimble_os_eventq_run_all(); + } + + if (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { + // Call this function again in 128ms to check for new events. + // TODO: improve this by only calling back when needed. + mp_bluetooth_hci_poll_in_ms(128); + } +} + +// --- Port-specific helpers for the generic NimBLE bindings. ----------------- + +void mp_bluetooth_nimble_hci_uart_wfi(void) { + #if defined(__WFI) + __WFI(); + #endif + // This is called while NimBLE is waiting in ble_npl_sem_pend, i.e. waiting for an HCI ACK. + // Do not need to run events here (it must not invoke Python code), only processing incoming HCI data. + mp_bluetooth_nimble_hci_uart_process(false); +} + +#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE diff --git a/ports/samd/mpnimbleport.h b/ports/samd/mpnimbleport.h new file mode 100644 index 0000000000000..64debea33a828 --- /dev/null +++ b/ports/samd/mpnimbleport.h @@ -0,0 +1,29 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jim Mussared + * + * 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_MPNIMBLEPORT_H +#define MICROPY_INCLUDED_RP2_MPNIMBLEPORT_H + +#endif // MICROPY_INCLUDED_RP2_MPNIMBLEPORT_H diff --git a/ports/samd/nina_wifi_bsp.c b/ports/samd/nina_wifi_bsp.c new file mode 100644 index 0000000000000..abe6e585bc737 --- /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 diff --git a/ports/samd/pendsv.h b/ports/samd/pendsv.h index 6671fa4e28a84..b5c4e10d40c10 100644 --- a/ports/samd/pendsv.h +++ b/ports/samd/pendsv.h @@ -28,6 +28,9 @@ enum { PENDSV_DISPATCH_SOFT_TIMER, // For later & for having at least one entry + #if MICROPY_PY_BLUETOOTH && !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS + PENDSV_DISPATCH_BLUETOOTH_HCI, + #endif MICROPY_BOARD_PENDSV_ENTRIES PENDSV_DISPATCH_MAX }; diff --git a/pyproject.toml b/pyproject.toml index e44afe37e0ebb..6470c4626a490 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ max-complexity = 40 # manifest.py files are evaluated with some global names pre-defined "**/manifest.py" = ["F821"] "ports/**/boards/**/manifest_*.py" = ["F821"] +"ports/**/mcu/**/manifest_*.py" = ["F821"] [tool.ruff.format] # Exclude third-party code, and exclude the following tests: