From 531536c8251a0184156dfc4dd0d675fa03a9d45c Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 17 Jun 2025 12:19:47 +0200 Subject: [PATCH 1/9] extra: add bin2uf2 tool --- extra/bin2uf2/.gitignore | 1 + extra/bin2uf2/go.mod | 3 + extra/bin2uf2/main.go | 181 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 extra/bin2uf2/.gitignore create mode 100644 extra/bin2uf2/go.mod create mode 100644 extra/bin2uf2/main.go diff --git a/extra/bin2uf2/.gitignore b/extra/bin2uf2/.gitignore new file mode 100644 index 000000000..07e9ecf8f --- /dev/null +++ b/extra/bin2uf2/.gitignore @@ -0,0 +1 @@ +bin2uf2 \ No newline at end of file diff --git a/extra/bin2uf2/go.mod b/extra/bin2uf2/go.mod new file mode 100644 index 000000000..5aca60477 --- /dev/null +++ b/extra/bin2uf2/go.mod @@ -0,0 +1,3 @@ +module github.com/pennam/bin2uf2 + +go 1.21 \ No newline at end of file diff --git a/extra/bin2uf2/main.go b/extra/bin2uf2/main.go new file mode 100644 index 000000000..6db6ad1eb --- /dev/null +++ b/extra/bin2uf2/main.go @@ -0,0 +1,181 @@ +package main + +import ( + "encoding/binary" + "flag" + "fmt" + "io" + "os" + "strconv" + "strings" + "unsafe" +) + +// UF2 block constants with fixed-size types. +const ( + magic1 uint32 = 0x0A324655 + magic2 uint32 = 0x9E5D5157 + magic3 uint32 = 0x0AB16F30 + flags uint32 = 0x00002000 // familyID present + payloadSize uint32 = 256 + blockSize uint32 = 512 + dataSectionSize uint32 = 476 +) + +// UF2Block defines the structure of a UF2 block, used as a data container. +// The Payload array is sized to hold the entire data section, so the unused +// portion of the array acts as our padding. +type UF2Block struct { + Magic1 uint32 + Magic2 uint32 + Flags uint32 + TargetAddr uint32 + PayloadSize uint32 + BlockNo uint32 + NumBlocks uint32 + FamilyID uint32 + Payload [dataSectionSize]byte + Magic3 uint32 +} + +// Calculate the offset of the NumBlocks field within the block struct. +const numBlocksOffset = unsafe.Offsetof(UF2Block{}.NumBlocks) + +func main() { + // Define optional string flags for address and family ID + addrStr := flag.String("addr", "0x100E0000", "The starting memory address in hexadecimal format.") + familyIDStr := flag.String("familyID", "0xe48bff56", "The family ID of the target device in hexadecimal format.") + + // Customize the default usage message to be more explicit. + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "Usage: %s [options] \n", os.Args[0]) + fmt.Fprintln(os.Stderr, "Converts a binary file to the UF2 format.") + fmt.Fprintln(os.Stderr, "\nOptions:") + flag.PrintDefaults() + } + + flag.Parse() + + // Check for the correct number of positional arguments. + if len(flag.Args()) != 2 { + flag.Usage() + os.Exit(1) + } + + // Parse the address string from the flag. + parsedAddr, err := strconv.ParseUint(strings.TrimPrefix(*addrStr, "0x"), 16, 32) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: Invalid address format: %v\n", err) + os.Exit(1) + } + address := uint32(parsedAddr) + + // Parse the familyID string from the flag. + parsedFamilyID, err := strconv.ParseUint(strings.TrimPrefix(*familyIDStr, "0x"), 16, 32) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: Invalid familyID format: %v\n", err) + os.Exit(1) + } + familyID := uint32(parsedFamilyID) + + srcPath := flag.Arg(0) + dstPath := flag.Arg(1) + + // Open source file + src, err := os.Open(srcPath) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: Could not open source file %s: %v\n", srcPath, err) + os.Exit(1) + } + defer src.Close() + + // Create destination file + dst, err := os.Create(dstPath) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: Could not create destination file %s: %v\n", dstPath, err) + os.Exit(1) + } + defer dst.Close() + + var blockNum uint32 + var totalBlocks uint32 + // This slice is a temporary buffer for reading one payload-worth of data. + readBuffer := make([]byte, payloadSize) + + // Main loop to read source and write UF2 blocks + for { + bytesRead, err := io.ReadFull(src, readBuffer) + if err == io.EOF { + break + } + if err != nil && err != io.ErrUnexpectedEOF { + fmt.Fprintf(os.Stderr, "Error: Failed reading from source file %s: %v\n", srcPath, err) + os.Exit(1) + } + + // Create the block struct and populate its fields. + block := UF2Block{ + Magic1: magic1, + Magic2: magic2, + Flags: flags, + TargetAddr: address, + PayloadSize: payloadSize, + BlockNo: blockNum, + NumBlocks: 0, // Placeholder, will be updated later. + FamilyID: familyID, + Magic3: magic3, + } + // Copy the data from our read buffer into the beginning of the + // larger Payload array. The rest of the array remains zero, acting as padding. + copy(block.Payload[:], readBuffer) + + // --- Write the block to disk piece-by-piece --- + // 1. Write the header fields + binary.Write(dst, binary.LittleEndian, block.Magic1) + binary.Write(dst, binary.LittleEndian, block.Magic2) + binary.Write(dst, binary.LittleEndian, block.Flags) + binary.Write(dst, binary.LittleEndian, block.TargetAddr) + binary.Write(dst, binary.LittleEndian, block.PayloadSize) + binary.Write(dst, binary.LittleEndian, block.BlockNo) + binary.Write(dst, binary.LittleEndian, block.NumBlocks) + binary.Write(dst, binary.LittleEndian, block.FamilyID) + + // 2. Write the entire 476-byte data section (payload + padding) in one go. + if _, err := dst.Write(block.Payload[:]); err != nil { + fmt.Fprintf(os.Stderr, "Error: Failed writing data section to %s: %v\n", dstPath, err) + os.Exit(1) + } + + // 3. Write the final magic number + if err := binary.Write(dst, binary.LittleEndian, block.Magic3); err != nil { + fmt.Fprintf(os.Stderr, "Error: Failed writing final magic to %s: %v\n", dstPath, err) + os.Exit(1) + } + + address += payloadSize + blockNum++ + + if err == io.EOF || bytesRead < int(payloadSize) { + break + } + } + + totalBlocks = blockNum + + // After writing all blocks, seek back and update the totalBlocks field in each header + for i := uint32(0); i < totalBlocks; i++ { + // Calculate the offset using our safe constant instead of a magic number. + offset := int64(i)*int64(blockSize) + int64(numBlocksOffset) + _, err := dst.Seek(offset, io.SeekStart) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: Failed seeking in destination file %s: %v\n", dstPath, err) + os.Exit(1) + } + if err := binary.Write(dst, binary.LittleEndian, totalBlocks); err != nil { + fmt.Fprintf(os.Stderr, "Error: Failed updating total blocks in %s: %v\n", dstPath, err) + os.Exit(1) + } + } + + fmt.Printf("Successfully converted %s to %s (%d blocks written).\n", srcPath, dstPath, totalBlocks) +} \ No newline at end of file From 4031539460542d41d2fa49bcddbe5940c8aa7d52 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 17 Jun 2025 12:20:54 +0200 Subject: [PATCH 2/9] extra: copy uf2 files to firmware folder --- extra/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/build.sh b/extra/build.sh index 2b2bac7d5..d837b126e 100755 --- a/extra/build.sh +++ b/extra/build.sh @@ -88,7 +88,7 @@ line_continuation='\\$' # match lines ending with '\' c_comment='\s*\/\*.*?\*\/' # match C-style comments and any preceding space perl -i -pe "s/${c_comment}//gs unless /${line_preproc_ok}/ || (/${line_comment_only}/ && !/${line_continuation}/)" $(find ${VARIANT_DIR}/llext-edk/include/ -type f) -for ext in elf bin hex; do +for ext in elf bin hex uf2; do rm -f firmwares/zephyr-$variant.$ext if [ -f ${BUILD_DIR}/zephyr/zephyr.$ext ]; then cp ${BUILD_DIR}/zephyr/zephyr.$ext firmwares/zephyr-$variant.$ext From 0fb4b4355d87bb50bcd30238812948b2683a2de4 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 17 Jun 2025 12:33:15 +0200 Subject: [PATCH 3/9] platform: allow using picotool to burn (boot)loader --- platform.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/platform.txt b/platform.txt index 0ba361610..2fbb748ec 100644 --- a/platform.txt +++ b/platform.txt @@ -245,7 +245,15 @@ tools.picotool.path={runtime.tools.rp2040tools.path} tools.picotool.cmd=rp2040load tools.picotool.upload.params.verbose=-v tools.picotool.upload.params.quiet= -tools.picotool.upload.pattern="{path}/{cmd}" {upload.verbose} -D "{build.path}/{build.project_name}.elf" +tools.picotool.upload.pattern="{path}/{cmd}" {upload.verbose} -D "{build.path}/{build.project_name}" + +tools.picotool.erase.params.verbose= +tools.picotool.erase.params.quiet= +tools.picotool.erase.pattern= + +tools.picotool.bootloader.params.verbose=-v +tools.picotool.bootloader.params.quiet= +tools.picotool.bootloader.pattern="{path}/{cmd}" {upload.verbose} -D "{runtime.platform.path}/firmwares/{bootloader.file}" # # IMGTOOL From c74b4f74816c75765021a4cfb1eb40f0f84a0eba Mon Sep 17 00:00:00 2001 From: Gilberto Conti Date: Mon, 26 Jan 2026 12:37:12 +0100 Subject: [PATCH 4/9] variants: add arduino_nano_rp2040 Signed-off-by: Gilberto Conti --- boards.txt | 66 ++- .../arduino_nano_rp2040_connect_rp2040.conf | 10 + ...arduino_nano_rp2040_connect_rp2040.overlay | 390 ++++++++++++++++++ .../nina_pins.cpp | 18 + .../nina_pins.h | 72 ++++ .../pins_arduino.h | 10 + .../variant.h | 139 +++++++ 7 files changed, 704 insertions(+), 1 deletion(-) create mode 100644 variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.conf create mode 100644 variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay create mode 100644 variants/arduino_nano_rp2040_connect_rp2040/nina_pins.cpp create mode 100644 variants/arduino_nano_rp2040_connect_rp2040/nina_pins.h create mode 100644 variants/arduino_nano_rp2040_connect_rp2040/pins_arduino.h create mode 100644 variants/arduino_nano_rp2040_connect_rp2040/variant.h diff --git a/boards.txt b/boards.txt index 6e9394f40..6c48f1fa4 100644 --- a/boards.txt +++ b/boards.txt @@ -689,4 +689,68 @@ unoq.bootloader.tool.default=remoteocd unoq.bootloader.file=zephyr-{build.variant}.elf unoq.bootloader.target=stm32u585zitxq -########################################################################################## +############################################################################################################## + +nano_connect.name=Arduino Nano RP2040 Connect +nano_connect.build.core=arduino +nano_connect.build.crossprefix=arm-zephyr-eabi- +nano_connect.build.compiler_path={runtime.tools.arm-zephyr-eabi-0.16.8.path}/bin/ + +nano_connect.menu.debug.false=Standard +nano_connect.menu.debug.true=Debug + +nano_connect.menu.debug.false.postbuild_debug= +nano_connect.menu.debug.true.postbuild_debug=-debug + +nano_connect.build.zephyr_target=arduino_nano_rp2040_connect +nano_connect.build.zephyr_args= +nano_connect.build.zephyr_hals=hal_rpi_pico +nano_connect.build.variant=arduino_nano_rp2040_connect_rp2040 +nano_connect.build.mcu=cortex-m0plus +nano_connect.build.fpu= +nano_connect.build.architecture=cortex-m0plus +nano_connect.compiler.zephyr.arch.define= + +nano_connect.build.float-abi=-mfloat-abi=soft +nano_connect.build.extra_flags= +nano_connect.build.postbuild.cmd="{tools.imgtool.path}/{tools.imgtool.cmd}" exit +nano_connect.recipe.hooks.objcopy.postobjcopy.3.pattern="{runtime.platform.path}/extra/bin2uf2/bin2uf2" "{build.path}/{build.project_name}.elf-zsk.bin" "{build.path}/{build.project_name}.uf2" +nano_connect.build.architecture=cortex-m0plus +nano_connect.build.board=ARDUINO_NANO_RP2040_CONNECT +nano_connect.compiler.zephyr= +nano_connect.vid.0=0x2341 +nano_connect.pid.0=0x005E +nano_connect.upload_port.0.vid=0x2341 +nano_connect.upload_port.0.pid=0x005E + +nano_connect.upload.tool=picotool +nano_connect.upload.tool.default=picotool +nano_connect.upload.protocol= +nano_connect.upload.transport= +nano_connect.upload.vid=0x2341 +nano_connect.upload.pid=0x005E +nano_connect.upload.interface=0 +nano_connect.upload.use_1200bps_touch=true +nano_connect.upload.wait_for_upload_port=false +nano_connect.upload.native_usb=true +nano_connect.upload.maximum_size=16777216 +nano_connect.upload.maximum_data_size=270336 + +nano_connect.upload.address=0x100E0000 + +nano_connect.bootloader.tool=picotool +nano_connect.bootloader.tool.default=picotool +nano_connect.bootloader.vid=0x2341 +nano_connect.bootloader.pid=0x005E +nano_connect.bootloader.interface=0 +nano_connect.bootloader.file=zephyr-{build.variant} + + +nano_connect.debug.tool=gdb +nano_connect.debug.server.openocd.scripts.0=interface/{programmer.protocol}.cfg +nano_connect.debug.server.openocd.scripts.1={programmer.transport_script} +nano_connect.debug.server.openocd.scripts.2=target/rp2040-core0.cfg +nano_connect.debug.cortex-debug.custom.request=attach +nano_connect.debug.svd_file={runtime.platform.path}/svd/rp2040.svd + +############################################################################################################## diff --git a/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.conf b/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.conf new file mode 100644 index 000000000..85e9f03aa --- /dev/null +++ b/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.conf @@ -0,0 +1,10 @@ +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_PRODUCT="Arduino Nano RP2040 Connect" +CONFIG_USB_DEVICE_MANUFACTURER="Arduino" +CONFIG_USB_DEVICE_VID=0x2341 +CONFIG_USB_DEVICE_PID=0x005E + +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_LINE_CTRL=y diff --git a/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay b/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay new file mode 100644 index 000000000..352f2cf32 --- /dev/null +++ b/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + zephyr,user { + /* + * Arduino Nano RP2040 Connect pin mapping + * Arduino Pin -> RP2040 GPIO + */ + digital-pin-gpios = <&gpio0 1 0>, /* D0 - RX */ + <&gpio0 0 0>, /* D1 - TX */ + <&gpio0 25 0>, /* D2 */ + <&gpio0 15 0>, /* D3 */ + <&gpio0 16 0>, /* D4 */ + <&gpio0 17 0>, /* D5 */ + <&gpio0 18 0>, /* D6 */ + <&gpio0 19 0>, /* D7 */ + <&gpio0 20 0>, /* D8 */ + <&gpio0 21 0>, /* D9 */ + <&gpio0 5 0>, /* D10 - SPI SS */ + <&gpio0 7 0>, /* D11 - SPI MOSI */ + <&gpio0 4 0>, /* D12 - SPI MISO */ + <&gpio0 6 0>, /* D13 - SPI SCK / LED */ + <&gpio0 26 0>, /* D14 / A0 */ + <&gpio0 27 0>, /* D15 / A1 */ + <&gpio0 28 0>, /* D16 / A2 */ + <&gpio0 29 0>, /* D17 / A3 */ + <&gpio0 12 0>, /* D18 / A4 / SDA */ + <&gpio0 13 0>, /* D19 / A5 / SCL */ + <&gpio0 2 0>, /* D20 - NINA GPIO0 */ + <&gpio0 24 0>, /* D21 - IMU IRQ */ + <&gpio0 22 0>, /* D22 - PDM DIN */ + <&gpio0 23 0>, /* D23 - PDM CLK */ + <&gpio0 3 0>, /* D24 - NINA RESET */ + <&gpio0 8 0>, /* D25 - NINA SPI MISO */ + <&gpio0 9 0>, /* D26 - NINA SPI CS */ + <&gpio0 10 0>, /* D27 - NINA SPI ACK */ + <&gpio0 11 0>, /* D28 - NINA SPI MOSI */ + <&gpio0 14 0>; /* D29 - NINA SPI SCK */ + + builtin-led-gpios = <&gpio0 6 0>; /* D13 = GPIO6 */ + + /* + * PWM-capable pins on Arduino Nano RP2040 Connect + * Listed by Arduino pin number with corresponding GPIO + */ + pwm-pin-gpios = <&gpio0 25 0>, /* D2 -> GPIO25 -> PWM4B */ + <&gpio0 15 0>, /* D3 -> GPIO15 -> PWM7B */ + <&gpio0 16 0>, /* D4 -> GPIO16 -> PWM0A */ + <&gpio0 17 0>, /* D5 -> GPIO17 -> PWM0B */ + <&gpio0 18 0>, /* D6 -> GPIO18 -> PWM1A */ + <&gpio0 19 0>, /* D7 -> GPIO19 -> PWM1B */ + <&gpio0 20 0>, /* D8 -> GPIO20 -> PWM2A */ + <&gpio0 21 0>, /* D9 -> GPIO21 -> PWM2B */ + <&gpio0 5 0>, /* D10 -> GPIO5 -> PWM2B */ + <&gpio0 7 0>, /* D11 -> GPIO7 -> PWM3B */ + <&gpio0 4 0>, /* D12 -> GPIO4 -> PWM2A */ + <&gpio0 6 0>; /* D13 -> GPIO6 -> PWM3A (LED) */ + + adc-pin-gpios = <&gpio0 26 0>, /* A0 -> GPIO26 -> ADC0 */ + <&gpio0 27 0>, /* A1 -> GPIO27 -> ADC1 */ + <&gpio0 28 0>, /* A2 -> GPIO28 -> ADC2 */ + <&gpio0 29 0>; /* A3 -> GPIO29 -> ADC3 */ + + pwms = <&pwm 25 255 PWM_POLARITY_NORMAL>, /* D2 GPIO25 */ + <&pwm 15 255 PWM_POLARITY_NORMAL>, /* D3 GPIO15 */ + <&pwm 16 255 PWM_POLARITY_NORMAL>, /* D4 GPIO16 */ + <&pwm 17 255 PWM_POLARITY_NORMAL>, /* D5 GPIO17 */ + <&pwm 18 255 PWM_POLARITY_NORMAL>, /* D6 GPIO18 */ + <&pwm 19 255 PWM_POLARITY_NORMAL>, /* D7 GPIO19 */ + <&pwm 20 255 PWM_POLARITY_NORMAL>, /* D8 GPIO20 */ + <&pwm 21 255 PWM_POLARITY_NORMAL>, /* D9 GPIO21 */ + <&pwm 5 255 PWM_POLARITY_NORMAL>, /* D10 GPIO5 */ + <&pwm 7 255 PWM_POLARITY_NORMAL>, /* D11 GPIO7 */ + <&pwm 4 255 PWM_POLARITY_NORMAL>, /* D12 GPIO4 */ + <&pwm 6 255 PWM_POLARITY_NORMAL>; /* D13 GPIO6 */ + + io-channels = <&adc 0>, /* A0 */ + <&adc 1>, /* A1 */ + <&adc 2>, /* A2 */ + <&adc 3>; /* A3 */ + + serials = <&board_cdc_acm_uart>, <&uart0>, <&uart1>; + cdc-acm = <&board_cdc_acm_uart>; + i2cs = <&i2c0>; + spis = <&spi0>, <&spi1>; + }; +}; + +&pinctrl { + /* + * PWM pin control + * PWM slice assignment: GPIO / 2 (integer division) + * PWM channel: A if GPIO even, B if GPIO odd + */ + + /* D4 -> GPIO16 -> PWM0A */ + pwm_ch0a_default: pwm_ch0a_default { + group1 { + pinmux = ; + }; + }; + + /* D5 -> GPIO17 -> PWM0B */ + pwm_ch0b_default: pwm_ch0b_default { + group1 { + pinmux = ; + }; + }; + + /* D6 -> GPIO18 -> PWM1A */ + pwm_ch1a_default: pwm_ch1a_default { + group1 { + pinmux = ; + }; + }; + + /* D7 -> GPIO19 -> PWM1B */ + pwm_ch1b_default: pwm_ch1b_default { + group1 { + pinmux = ; + }; + }; + + /* + * D8 -> GPIO20 -> PWM2A, + * D12 -> GPIO4 -> PWM2A + */ + pwm_ch2a_default: pwm_ch2a_default { + group1 { + pinmux = , ; + }; + }; + + /* D9 -> GPIO21 -> PWM2B, D10 -> GPIO5 -> PWM2B */ + pwm_ch2b_default: pwm_ch2b_default { + group1 { + pinmux = , ; + }; + }; + + /* D13/LED -> GPIO6 -> PWM3A */ + pwm_ch3a_default: pwm_ch3a_default { + group1 { + pinmux = ; + }; + }; + + /* D11 -> GPIO7 -> PWM3B */ + pwm_ch3b_default: pwm_ch3b_default { + group1 { + pinmux = ; + }; + }; + + /* D2 -> GPIO25 -> PWM4B */ + pwm_ch4b_default: pwm_ch4b_default { + group1 { + pinmux = ; + }; + }; + + /* D3 -> GPIO15 -> PWM7B */ + pwm_ch7b_default: pwm_ch7b_default { + group1 { + pinmux = ; + }; + }; + + /* + * SPI0 pin control + * MISO (D12) -> GPIO4 + * MOSI (D11) -> GPIO7 + * SCK (D13) -> GPIO6 + * SS (D10) -> GPIO5 (directly controlled) + */ + spi0_default: spi0_default { + group1 { + pinmux = ; /* MOSI -> GPIO7 */ + }; + group2 { + pinmux = ; /* MISO -> GPIO4 */ + input-enable; + }; + group3 { + pinmux = ; /* SCK -> GPIO6 */ + }; + }; + + /* + * SPI1 pin control (NINA WiFi module) + * MISO (D25) -> GPIO8 + * MOSI (D28) -> GPIO11 + * SCK (D29) -> GPIO14 + * CS (D26) -> GPIO9 (software controlled) + */ + spi1_default: spi1_default { + group1 { + pinmux = ; /* MOSI -> GPIO11 */ + }; + group2 { + pinmux = ; /* MISO -> GPIO8 */ + input-enable; + }; + group3 { + pinmux = ; /* SCK -> GPIO14 */ + }; + }; + + /* + * I2C0 pin control + * SDA (D18) -> GPIO12 + * SCL (D19) -> GPIO13 + */ + i2c0_default: i2c0_default { + group1 { + pinmux = , ; + input-enable; + input-schmitt-enable; + }; + }; + + /* + * UART0 pin control + * RX (D0) -> GPIO1 + * TX (D1) -> GPIO0 + */ + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + /* + * UART1 pin control (NINA WiFi module) + * TX (D25) -> GPIO8 + * RX (D26) -> GPIO9 + * CTS (D27) -> GPIO10 + * RTS (D28) -> GPIO11 + */ + uart1_default: uart1_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + group3 { + pinmux = ; + input-enable; + }; + group4 { + pinmux = ; + }; + }; +}; + +&pwm { + status = "okay"; + divider-frac-4 = <15>; + divider-int-4 = <255>; +}; + +&adc { + #address-cells = <1>; + #size-cells = <0>; + + /* A0 -> GPIO26 -> ADC0 */ + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + /* A1 -> GPIO27 -> ADC1 */ + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + /* A2 -> GPIO28 -> ADC2 */ + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + /* A3 -> GPIO29 -> ADC3 */ + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; + +/* + * SPI0 configuration + * MISO (D12) -> GPIO4 + * MOSI (D11) -> GPIO7 + * SCK (D13) -> GPIO6 + */ +&spi0 { + status = "okay"; + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; +}; + +/* + * SPI1 configuration (NINA WiFi module) + * MISO (D25) -> GPIO8 + * MOSI (D28) -> GPIO11 + * SCK (D29) -> GPIO14 + */ +&spi1 { + status = "okay"; + pinctrl-0 = <&spi1_default>; + pinctrl-names = "default"; +}; + +/* + * I2C0 configuration + * SDA (D18) -> GPIO12 + * SCL (D19) -> GPIO13 + */ +&i2c0 { + status = "okay"; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +/* + * UART0 configuration + * RX (D0) -> GPIO1 + * TX (D1) -> GPIO0 + */ +&uart0 { + status = "okay"; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; + current-speed = <115200>; +}; + +/* + * UART1 configuration (NINA WiFi module) + * TX (D25) -> GPIO8 + * RX (D26) -> GPIO9 + * CTS (D27) -> GPIO10 + * RTS (D28) -> GPIO11 + */ +&uart1 { + status = "okay"; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; + current-speed = <115200>; + hw-flow-control; +}; + +&zephyr_udc0 { + board_cdc_acm_uart: board_cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + status = "okay"; + }; +}; + +&flash0 { + partitions { + user_sketch: partition@e0000 { + reg = <0x0E0000 0x20000>; + }; + }; +}; diff --git a/variants/arduino_nano_rp2040_connect_rp2040/nina_pins.cpp b/variants/arduino_nano_rp2040_connect_rp2040/nina_pins.cpp new file mode 100644 index 000000000..feadb3973 --- /dev/null +++ b/variants/arduino_nano_rp2040_connect_rp2040/nina_pins.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nina_pins.h" + +// RGB LEDs on NINA module +NinaPin LEDR(27); +NinaPin LEDG(25); +NinaPin LEDB(26); + +// Analog pins on NINA module +NinaPin A4(34); +NinaPin A5(39); +NinaPin A6(36); +NinaPin A7(35); diff --git a/variants/arduino_nano_rp2040_connect_rp2040/nina_pins.h b/variants/arduino_nano_rp2040_connect_rp2040/nina_pins.h new file mode 100644 index 000000000..5ce95032e --- /dev/null +++ b/variants/arduino_nano_rp2040_connect_rp2040/nina_pins.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NINA_PINS_ +#define _NINA_PINS_ + +/****************************************************************************** + * INCLUDE + ******************************************************************************/ + +#include "Arduino.h" + +/****************************************************************************** + * PREPROCESSOR-MAGIC + ******************************************************************************/ + +#if __has_include("WiFiNINA.h") +# define NINA_ATTRIBUTE +#else +# define NINA_ATTRIBUTE __attribute__ ((error("Please include WiFiNINA.h to use this pin"))) +#endif + +/****************************************************************************** + * TYPEDEF + ******************************************************************************/ + +int getAnalogReadResolution(); + +class NinaPin { +public: + NinaPin(int _pin) : pin(_pin) {}; + int get() { + return pin; + }; + int analogReadResolution() { + return getAnalogReadResolution(); + }; + bool operator== (NinaPin const & other) const { + return pin == other.pin; + } + //operator int() = delete; + __attribute__ ((error("Change me to a #define"))) operator int(); +private: + int pin; +}; + +extern NinaPin LEDR; +extern NinaPin LEDG; +extern NinaPin LEDB; +extern NinaPin A4; +extern NinaPin A5; +extern NinaPin A6; +extern NinaPin A7; + +#define NINA_PINS_AS_CLASS + +/****************************************************************************** + * FUNCTION DECLARATION + ******************************************************************************/ + +void NINA_ATTRIBUTE pinMode (NinaPin pin, PinMode mode); +PinStatus NINA_ATTRIBUTE digitalRead (NinaPin pin); +void NINA_ATTRIBUTE digitalWrite(NinaPin pin, PinStatus value); +int NINA_ATTRIBUTE analogRead (NinaPin pin); +void NINA_ATTRIBUTE analogWrite (NinaPin pin, int value); + +#undef NINA_ATTRIBUTE + +#endif /* _NINA_PINS_ */ diff --git a/variants/arduino_nano_rp2040_connect_rp2040/pins_arduino.h b/variants/arduino_nano_rp2040_connect_rp2040/pins_arduino.h new file mode 100644 index 000000000..cdb4228df --- /dev/null +++ b/variants/arduino_nano_rp2040_connect_rp2040/pins_arduino.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +// For compatibility with Arduino mbed core +#include "variant.h" diff --git a/variants/arduino_nano_rp2040_connect_rp2040/variant.h b/variants/arduino_nano_rp2040_connect_rp2040/variant.h new file mode 100644 index 000000000..157dbd8f4 --- /dev/null +++ b/variants/arduino_nano_rp2040_connect_rp2040/variant.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifndef __PINS_ARDUINO__ +#define __PINS_ARDUINO__ + +#include + +// Pin count +// ---- +#define PINS_COUNT (30u) +#define NUM_DIGITAL_PINS (30u) +#define NUM_ANALOG_INPUTS (4u) +#define NUM_ANALOG_OUTPUTS (0u) + +// LEDs +// ---- +#define PIN_LED (13u) +#define LED_BUILTIN PIN_LED + +// Note: RGB LEDs (LEDR, LEDG, LEDB) are on the NINA module +// and require WiFiNINA library to control + +// Analog pins +// ----------- +#define PIN_A0 (14u) +#define PIN_A1 (15u) +#define PIN_A2 (16u) +#define PIN_A3 (17u) + +static const uint8_t A0 = PIN_A0; +static const uint8_t A1 = PIN_A1; +static const uint8_t A2 = PIN_A2; +static const uint8_t A3 = PIN_A3; + +#define ADC_RESOLUTION 12 + +// PDM Interfaces +// --------------- +#define PIN_PDM_CLK (23) +#define PIN_PDM_DIN (22) + +// IMU Interrupt +#define INT_IMU (21) + +// Serial +// ------ +#define PIN_SERIAL_RX (0ul) +#define PIN_SERIAL_TX (1ul) + +#define SERIAL_HOWMANY 3 + +// Serial1: Hardware UART (D0/D1) +#define SERIAL1_TX (1u) +#define SERIAL1_RX (0u) + +// Serial2: NINA HCI (D25/D26 with flow control) +#define SERIAL2_TX (25u) +#define SERIAL2_RX (26u) +#define SERIAL2_CTS (27u) +#define SERIAL2_RTS (28u) + +// Serial3: NINA communication (D25/D26) +#define SERIAL3_TX (25u) +#define SERIAL3_RX (26u) + +// USB CDC +#define SERIAL_CDC 1 +#define HAS_UNIQUE_ISERIAL_DESCRIPTOR +#define BOARD_VENDORID 0x2341 +#define BOARD_PRODUCTID 0x005E +#define BOARD_NAME "Arduino Nano RP2040 Connect" + +#define USB_MAX_POWER (500) + +// SPI +// --- +#define SPI_HOWMANY (2) + +#define PIN_SPI_MISO (12u) +#define PIN_SPI_MOSI (11u) +#define PIN_SPI_SCK (13u) +#define PIN_SPI_SS (10u) + +static const uint8_t SS = PIN_SPI_SS; +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +// SPI1 (NINA WiFi module SPI bus) +#define PIN_SPI1_MISO (25u) // GPIO8 +#define PIN_SPI1_SS (26u) // GPIO9 +#define PIN_SPI1_MOSI (28u) // GPIO11 +#define PIN_SPI1_SCK (29u) // GPIO14 + +// Wire (I2C) +// ---------- +#define WIRE_HOWMANY (1) + +#define PIN_WIRE_SDA (18u) +#define PIN_WIRE_SCL (19u) + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + +// NINA WiFi module pins +// --------------------- +#define NINA_RESETN (24u) +#define NINA_GPIO0 (20u) + +#define SPIWIFI_SS (26u) +#define SPIWIFI_ACK (27u) +#define SPIWIFI_RESET (NINA_RESETN) + +// Crypto (ATECC608A on I2C bus) +#define CRYPTO_WIRE Wire + +// NINA WiFi SPI interface +#define SPIWIFI SPI1 + +// Serial port definitions +#define SERIAL_PORT_USBVIRTUAL SerialUSB +#define SERIAL_PORT_MONITOR SerialUSB +#define SERIAL_PORT_HARDWARE Serial1 +#define SERIAL_PORT_HARDWARE_OPEN Serial2 + +// NINA Serial aliases +#define SerialNina Serial3 +#define SerialHCI Serial2 + +// Note: nina_pins.h should be included after Arduino.h +// It is automatically included by WiFiNINA.h when needed + +#endif /* __PINS_ARDUINO__ */ From afc5c076dd89b9f41a237156c0cfd83ebd85f89d Mon Sep 17 00:00:00 2001 From: Gilberto Conti Date: Mon, 26 Jan 2026 18:12:19 +0100 Subject: [PATCH 5/9] remove dts definitions already in board --- ...arduino_nano_rp2040_connect_rp2040.overlay | 148 ++---------------- 1 file changed, 9 insertions(+), 139 deletions(-) diff --git a/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay b/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay index 352f2cf32..fdfa65667 100644 --- a/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay +++ b/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay @@ -94,7 +94,7 @@ &pinctrl { /* - * PWM pin control + * Additional PWM pin control for Arduino analogWrite() * PWM slice assignment: GPIO / 2 (integer division) * PWM channel: A if GPIO even, B if GPIO odd */ @@ -128,9 +128,9 @@ }; /* - * D8 -> GPIO20 -> PWM2A, - * D12 -> GPIO4 -> PWM2A - */ + * D8 -> GPIO20 -> PWM2A, + * D12 -> GPIO4 -> PWM2A + */ pwm_ch2a_default: pwm_ch2a_default { group1 { pinmux = , ; @@ -144,13 +144,6 @@ }; }; - /* D13/LED -> GPIO6 -> PWM3A */ - pwm_ch3a_default: pwm_ch3a_default { - group1 { - pinmux = ; - }; - }; - /* D11 -> GPIO7 -> PWM3B */ pwm_ch3b_default: pwm_ch3b_default { group1 { @@ -172,80 +165,12 @@ }; }; - /* - * SPI0 pin control - * MISO (D12) -> GPIO4 - * MOSI (D11) -> GPIO7 - * SCK (D13) -> GPIO6 - * SS (D10) -> GPIO5 (directly controlled) - */ - spi0_default: spi0_default { - group1 { - pinmux = ; /* MOSI -> GPIO7 */ - }; - group2 { - pinmux = ; /* MISO -> GPIO4 */ - input-enable; - }; - group3 { - pinmux = ; /* SCK -> GPIO6 */ - }; - }; - - /* - * SPI1 pin control (NINA WiFi module) - * MISO (D25) -> GPIO8 - * MOSI (D28) -> GPIO11 - * SCK (D29) -> GPIO14 - * CS (D26) -> GPIO9 (software controlled) - */ - spi1_default: spi1_default { - group1 { - pinmux = ; /* MOSI -> GPIO11 */ - }; - group2 { - pinmux = ; /* MISO -> GPIO8 */ - input-enable; - }; - group3 { - pinmux = ; /* SCK -> GPIO14 */ - }; - }; - - /* - * I2C0 pin control - * SDA (D18) -> GPIO12 - * SCL (D19) -> GPIO13 - */ - i2c0_default: i2c0_default { - group1 { - pinmux = , ; - input-enable; - input-schmitt-enable; - }; - }; - - /* - * UART0 pin control - * RX (D0) -> GPIO1 - * TX (D1) -> GPIO0 - */ - uart0_default: uart0_default { - group1 { - pinmux = ; - }; - group2 { - pinmux = ; - input-enable; - }; - }; - /* * UART1 pin control (NINA WiFi module) - * TX (D25) -> GPIO8 - * RX (D26) -> GPIO9 - * CTS (D27) -> GPIO10 - * RTS (D28) -> GPIO11 + * TX -> GPIO8 + * RX -> GPIO9 + * CTS -> GPIO10 + * RTS -> GPIO11 */ uart1_default: uart1_default { group1 { @@ -266,7 +191,6 @@ }; &pwm { - status = "okay"; divider-frac-4 = <15>; divider-int-4 = <255>; }; @@ -312,60 +236,7 @@ }; }; -/* - * SPI0 configuration - * MISO (D12) -> GPIO4 - * MOSI (D11) -> GPIO7 - * SCK (D13) -> GPIO6 - */ -&spi0 { - status = "okay"; - pinctrl-0 = <&spi0_default>; - pinctrl-names = "default"; -}; - -/* - * SPI1 configuration (NINA WiFi module) - * MISO (D25) -> GPIO8 - * MOSI (D28) -> GPIO11 - * SCK (D29) -> GPIO14 - */ -&spi1 { - status = "okay"; - pinctrl-0 = <&spi1_default>; - pinctrl-names = "default"; -}; - -/* - * I2C0 configuration - * SDA (D18) -> GPIO12 - * SCL (D19) -> GPIO13 - */ -&i2c0 { - status = "okay"; - pinctrl-0 = <&i2c0_default>; - pinctrl-names = "default"; -}; - -/* - * UART0 configuration - * RX (D0) -> GPIO1 - * TX (D1) -> GPIO0 - */ -&uart0 { - status = "okay"; - pinctrl-0 = <&uart0_default>; - pinctrl-names = "default"; - current-speed = <115200>; -}; - -/* - * UART1 configuration (NINA WiFi module) - * TX (D25) -> GPIO8 - * RX (D26) -> GPIO9 - * CTS (D27) -> GPIO10 - * RTS (D28) -> GPIO11 - */ +/* UART1 for NINA WiFi module */ &uart1 { status = "okay"; pinctrl-0 = <&uart1_default>; @@ -377,7 +248,6 @@ &zephyr_udc0 { board_cdc_acm_uart: board_cdc_acm_uart { compatible = "zephyr,cdc-acm-uart"; - status = "okay"; }; }; From edce00d7a331f685bce20cec2f235acb16728fa4 Mon Sep 17 00:00:00 2001 From: Gilberto Conti Date: Thu, 29 Jan 2026 15:53:19 +0100 Subject: [PATCH 6/9] extra: bin2uf2: fix last chunk write --- extra/bin2uf2/main.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/extra/bin2uf2/main.go b/extra/bin2uf2/main.go index 6db6ad1eb..95194760f 100644 --- a/extra/bin2uf2/main.go +++ b/extra/bin2uf2/main.go @@ -113,6 +113,11 @@ func main() { os.Exit(1) } + // Zero out the unused portion of the buffer for partial reads + for i := bytesRead; i < int(payloadSize); i++ { + readBuffer[i] = 0 + } + // Create the block struct and populate its fields. block := UF2Block{ Magic1: magic1, From f8daf9c586bb817159fbbca68bc357503d75a32c Mon Sep 17 00:00:00 2001 From: Gilberto Conti Date: Thu, 29 Jan 2026 15:54:15 +0100 Subject: [PATCH 7/9] platform: nano connect fix llext undefined symbol __gnu_thumb1_case_uqi --- platform.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform.txt b/platform.txt index 2fbb748ec..6e0d98420 100644 --- a/platform.txt +++ b/platform.txt @@ -44,7 +44,7 @@ compiler.zephyr.common_cxxflags=-fdata-sections -ffunction-sections -fno-unwind- compiler.zephyr.common_ldflags=-fno-exceptions -fno-rtti -fno-threadsafe-statics -fno-unwind-tables -fno-use-cxa-atexit -lstdc++ -lsupc++ -lnosys -nostdlib compiler.zephyr.extra_cxxflags= -compiler.zephyr.extra_ldflags=-lstdc++ -lsupc++ +compiler.zephyr.extra_ldflags=-lstdc++ -lsupc++ -lgcc # these can be overriden in boards.txt build.extra_flags= From 69930c565e33aee666abd514c21c6bb9c9603dbb Mon Sep 17 00:00:00 2001 From: Gilberto Conti Date: Tue, 3 Feb 2026 15:13:39 +0100 Subject: [PATCH 8/9] variants: nano_connect arduino_nano_connect_rp2040 Signed-off-by: Gilberto Conti --- boards.txt | 2 +- loader/prj.conf | 4 ++-- .../arduino_nano_rp2040_connect_rp2040.conf | 21 +++++++++++++++++++ ...arduino_nano_rp2040_connect_rp2040.overlay | 7 ++++--- .../variant.h | 6 +----- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/boards.txt b/boards.txt index 6c48f1fa4..e2c0c2a7b 100644 --- a/boards.txt +++ b/boards.txt @@ -716,7 +716,7 @@ nano_connect.build.extra_flags= nano_connect.build.postbuild.cmd="{tools.imgtool.path}/{tools.imgtool.cmd}" exit nano_connect.recipe.hooks.objcopy.postobjcopy.3.pattern="{runtime.platform.path}/extra/bin2uf2/bin2uf2" "{build.path}/{build.project_name}.elf-zsk.bin" "{build.path}/{build.project_name}.uf2" nano_connect.build.architecture=cortex-m0plus -nano_connect.build.board=ARDUINO_NANO_RP2040_CONNECT +nano_connect.build.board=NANO_RP2040_CONNECT nano_connect.compiler.zephyr= nano_connect.vid.0=0x2341 nano_connect.pid.0=0x005E diff --git a/loader/prj.conf b/loader/prj.conf index dc40e9533..53edafd18 100644 --- a/loader/prj.conf +++ b/loader/prj.conf @@ -8,14 +8,14 @@ CONFIG_ARM_MPU=n CONFIG_LOG=y CONFIG_LOG_MODE_IMMEDIATE=y -CONFIG_HEAP_MEM_POOL_SIZE=32768 +CONFIG_HEAP_MEM_POOL_SIZE=100000 CONFIG_MAIN_STACK_SIZE=32768 CONFIG_ARDUINO_API=y CONFIG_LLEXT=y CONFIG_LLEXT_LOG_LEVEL_ERR=y -CONFIG_LLEXT_HEAP_SIZE=32 +CONFIG_LLEXT_HEAP_SIZE=100 CONFIG_LLEXT_STORAGE_WRITABLE=y CONFIG_LLEXT_EXPORT_DEVICES=y diff --git a/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.conf b/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.conf index 85e9f03aa..aeb9d75d1 100644 --- a/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.conf +++ b/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.conf @@ -8,3 +8,24 @@ CONFIG_SERIAL=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_UART_LINE_CTRL=y + +CONFIG_USB_CDC_ACM=y +CONFIG_USB_CDC_ACM_RINGBUF_SIZE=1024 +CONFIG_UART_LINE_CTRL=y +CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT=y + +CONFIG_LLEXT_STORAGE_WRITABLE=n + +CONFIG_HEAP_MEM_POOL_SIZE=16384 +CONFIG_MAIN_STACK_SIZE=32768 +CONFIG_LLEXT_HEAP_SIZE=64 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=-1 + +CONFIG_LOG_BACKEND_UART=y +CONFIG_LOG_BACKEND_UART_AUTOSTART=n +CONFIG_LOG_DEFAULT_LEVEL=2 + +CONFIG_ADC=y +CONFIG_DAC=n +CONFIG_PWM=n + diff --git a/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay b/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay index fdfa65667..899596c93 100644 --- a/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay +++ b/variants/arduino_nano_rp2040_connect_rp2040/arduino_nano_rp2040_connect_rp2040.overlay @@ -85,7 +85,7 @@ <&adc 2>, /* A2 */ <&adc 3>; /* A3 */ - serials = <&board_cdc_acm_uart>, <&uart0>, <&uart1>; + serials = <&board_cdc_acm_uart>, <&uart0>, <&uart1>, <&uart2>; cdc-acm = <&board_cdc_acm_uart>; i2cs = <&i2c0>; spis = <&spi0>, <&spi1>; @@ -166,7 +166,7 @@ }; /* - * UART1 pin control (NINA WiFi module) + * UART1 pin control (NINA module) * TX -> GPIO8 * RX -> GPIO9 * CTS -> GPIO10 @@ -188,6 +188,7 @@ pinmux = ; }; }; + }; &pwm { @@ -236,7 +237,7 @@ }; }; -/* UART1 for NINA WiFi module */ +/* UART1 for NINA module */ &uart1 { status = "okay"; pinctrl-0 = <&uart1_default>; diff --git a/variants/arduino_nano_rp2040_connect_rp2040/variant.h b/variants/arduino_nano_rp2040_connect_rp2040/variant.h index 157dbd8f4..1f20cd98e 100644 --- a/variants/arduino_nano_rp2040_connect_rp2040/variant.h +++ b/variants/arduino_nano_rp2040_connect_rp2040/variant.h @@ -28,16 +28,12 @@ // Analog pins // ----------- +// Note: A0-A3 are defined as enum values in Arduino.h via devicetree #define PIN_A0 (14u) #define PIN_A1 (15u) #define PIN_A2 (16u) #define PIN_A3 (17u) -static const uint8_t A0 = PIN_A0; -static const uint8_t A1 = PIN_A1; -static const uint8_t A2 = PIN_A2; -static const uint8_t A3 = PIN_A3; - #define ADC_RESOLUTION 12 // PDM Interfaces From 31621fb05a660814eeaeada2cfa3d74196dd9feb Mon Sep 17 00:00:00 2001 From: Gilberto Conti Date: Thu, 5 Feb 2026 16:52:27 +0100 Subject: [PATCH 9/9] loader: fixups(nano_connect): add double tap reset if the board is reset twice within 500ms enter USB bootloader (BOOTSEL) mode Signed-off-by: Gilberto Conti --- loader/fixups.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/loader/fixups.c b/loader/fixups.c index 80aa40369..e95c86b22 100644 --- a/loader/fixups.c +++ b/loader/fixups.c @@ -47,6 +47,52 @@ SYS_INIT(disable_bootloader_mpu, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAU SYS_INIT(disable_mpu_rasr_xn, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif +#if defined(CONFIG_BOARD_ARDUINO_NANO_RP2040_CONNECT) +#include +#include +#include + +/* + * Double-tap reset detection: if the board is reset twice within 500ms, + * enter USB bootloader (BOOTSEL) mode. This mirrors the original + * ArduinoCore-mbed NANO_RP2040_CONNECT behavior. + * + * A magic token is stored in uninitialized RAM (.noinit), which survives + * a warm reset but is lost on power cycle. On boot: + * - If the token is present: a second reset happened quickly, so we + * clear the token and enter USB boot mode (never returns). + * - If not: write the token, wait 500ms, then clear it and boot normally. + */ +static const uint32_t magic_token[] = { + 0xf01681de, 0xbd729b29, 0xd359be7a, +}; + +static uint32_t magic_location[3] __attribute__((section(".noinit.double_tap"))); + +#define NANO_RP2040_LED_PIN 6 + +int double_tap_check(void) { + if (magic_location[0] == magic_token[0] && + magic_location[1] == magic_token[1] && + magic_location[2] == magic_token[2]) { + magic_location[0] = 0; + reset_usb_boot(1 << NANO_RP2040_LED_PIN, 0); + /* never returns */ + } + + for (int i = 0; i < 3; i++) { + magic_location[i] = magic_token[i]; + } + + k_busy_wait(500000); + + magic_location[0] = 0; + return 0; +} + +SYS_INIT(double_tap_check, POST_KERNEL, 0); +#endif + #if defined(CONFIG_SOC_STM32H747XX_M7) int enable_bkp_access(void) { /* Enable access to the backup domain */