diff --git a/boards.txt b/boards.txt index fbfbd13f..4cefc03d 100644 --- a/boards.txt +++ b/boards.txt @@ -564,3 +564,67 @@ opta.debug.cortex-debug.custom.request=attach opta.debug.svd_file={runtime.platform.path}/svd/STM32H747_CM7.svd ############################################################################################################## + +rpi_pico.name=Raspberry Pi Pico +rpi_pico.build.core=arduino +rpi_pico.build.crossprefix=arm-zephyr-eabi- +rpi_pico.build.compiler_path={runtime.tools.arm-zephyr-eabi-0.16.8.path}/bin/ + +rpi_pico.menu.debug.false=Standard +rpi_pico.menu.debug.true=Debug + +rpi_pico.menu.debug.false.postbuild_debug= +rpi_pico.menu.debug.true.postbuild_debug=-debug + +rpi_pico.build.zephyr_target=rpi_pico +rpi_pico.build.zephyr_args= +rpi_pico.build.zephyr_hals=hal_rpi_pico +rpi_pico.build.variant=rpi_pico_rp2040 +rpi_pico.build.mcu=cortex-m0plus +rpi_pico.build.fpu= +rpi_pico.build.architecture=cortex-m0plus +rpi_pico.compiler.zephyr.arch.define= + +rpi_pico.build.float-abi=-mfloat-abi=soft +rpi_pico.build.extra_flags= +rpi_pico.build.postbuild.cmd="{tools.imgtool.path}/{tools.imgtool.cmd}" exit +rpi_pico.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" +rpi_pico.build.architecture=cortex-m0plus +rpi_pico.build.board=RASPBERRY_PI_PICO +rpi_pico.compiler.zephyr= +rpi_pico.vid.0=0x2e8a +rpi_pico.pid.0=0x00C0 +rpi_pico.upload_port.0.vid=0x2e8a +rpi_pico.upload_port.0.pid=0x00C0 + +rpi_pico.upload.tool=picotool +rpi_pico.upload.tool.default=picotool +rpi_pico.upload.protocol= +rpi_pico.upload.transport= +rpi_pico.upload.vid=0x2e8a +rpi_pico.upload.pid=0x00C0 +rpi_pico.upload.interface=0 +rpi_pico.upload.use_1200bps_touch=true +rpi_pico.upload.wait_for_upload_port=false +rpi_pico.upload.native_usb=true +rpi_pico.upload.maximum_size=2097152 +rpi_pico.upload.maximum_data_size=270336 + +rpi_pico.upload.address=0x100E0000 + +rpi_pico.bootloader.tool=picotool +rpi_pico.bootloader.tool.default=picotool +rpi_pico.bootloader.vid=0x2e8a +rpi_pico.bootloader.pid=0x00C0 +rpi_pico.bootloader.interface=0 +rpi_pico.bootloader.file=zephyr-{build.variant} + + +rpi_pico.debug.tool=gdb +rpi_pico.debug.server.openocd.scripts.0=interface/{programmer.protocol}.cfg +rpi_pico.debug.server.openocd.scripts.1={programmer.transport_script} +rpi_pico.debug.server.openocd.scripts.2=target/rp2040-core0.cfg +rpi_pico.debug.cortex-debug.custom.request=attach +rpi_pico.debug.svd_file={runtime.platform.path}/svd/rp2040.svd + +############################################################################################################## diff --git a/extra/bin2uf2/.gitignore b/extra/bin2uf2/.gitignore new file mode 100644 index 00000000..07e9ecf8 --- /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 00000000..5aca6047 --- /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 00000000..6db6ad1e --- /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 diff --git a/extra/build.sh b/extra/build.sh index 6d7d63f1..a70104bb 100755 --- a/extra/build.sh +++ b/extra/build.sh @@ -82,7 +82,7 @@ line_comment_only='^\s*\/\*' # match lines starting with comment 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 diff --git a/platform.txt b/platform.txt index 889d0e94..acb3f77a 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= +compiler.zephyr.extra_ldflags=-lgcc # this can be overriden in boards.txt build.extra_flags= @@ -222,7 +222,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 diff --git a/variants/rpi_pico_rp2040/rpi_pico_rp2040.conf b/variants/rpi_pico_rp2040/rpi_pico_rp2040.conf new file mode 100644 index 00000000..c8da0b54 --- /dev/null +++ b/variants/rpi_pico_rp2040/rpi_pico_rp2040.conf @@ -0,0 +1,10 @@ +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_PRODUCT="Raspberry Pi Pico" +CONFIG_USB_DEVICE_MANUFACTURER="Raspberry Pi" +CONFIG_USB_DEVICE_VID=0x2E8A +CONFIG_USB_DEVICE_PID=0x00C0 + +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_LINE_CTRL=y \ No newline at end of file diff --git a/variants/rpi_pico_rp2040/rpi_pico_rp2040.overlay b/variants/rpi_pico_rp2040/rpi_pico_rp2040.overlay new file mode 100644 index 00000000..9aec28be --- /dev/null +++ b/variants/rpi_pico_rp2040/rpi_pico_rp2040.overlay @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2024 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + zephyr,user { + digital-pin-gpios = <&pico_header 0 0>, + <&pico_header 1 0>, + <&pico_header 2 0>, + <&pico_header 3 0>, + <&pico_header 4 0>, + <&pico_header 5 0>, + <&pico_header 6 0>, + <&pico_header 7 0>, + <&pico_header 8 0>, + <&pico_header 9 0>, + <&pico_header 10 0>, + <&pico_header 11 0>, + <&pico_header 12 0>, + <&pico_header 13 0>, + <&pico_header 14 0>, + <&pico_header 15 0>, + <&pico_header 16 0>, + <&pico_header 17 0>, + <&pico_header 18 0>, + <&pico_header 19 0>, + <&pico_header 20 0>, + <&pico_header 21 0>, + <&pico_header 22 0>, + <&gpio0 23 0>, + <&gpio0 24 0>, + <&gpio0 25 0>, + <&pico_header 26 0>, + <&pico_header 27 0>, + <&pico_header 28 0>; + + builtin-led-gpios = <&gpio0 25 0>; + + pwm-pin-gpios = <&pico_header 2 0>, + <&pico_header 3 0>, + <&pico_header 7 0>, + <&pico_header 8 0>, + <&pico_header 10 0>, + <&pico_header 11 0>, + <&pico_header 12 0>, + <&pico_header 13 0>, + <&pico_header 14 0>, + <&pico_header 15 0>, + <&pico_header 20 0>, + <&pico_header 21 0>, + <&pico_header 22 0>, + <&gpio0 25 0>; + + adc-pin-gpios = <&pico_header 26 0>, + <&pico_header 27 0>, + <&pico_header 28 0>; + + pwms = <&pwm 2 255 PWM_POLARITY_NORMAL>, + <&pwm 3 255 PWM_POLARITY_NORMAL>, + <&pwm 7 255 PWM_POLARITY_NORMAL>, + <&pwm 8 255 PWM_POLARITY_NORMAL>, + <&pwm 10 255 PWM_POLARITY_NORMAL>, + <&pwm 11 255 PWM_POLARITY_NORMAL>, + <&pwm 12 255 PWM_POLARITY_NORMAL>, + <&pwm 13 255 PWM_POLARITY_NORMAL>, + <&pwm 14 255 PWM_POLARITY_NORMAL>, + <&pwm 15 255 PWM_POLARITY_NORMAL>, + <&pwm 4 255 PWM_POLARITY_NORMAL>, + <&pwm 5 255 PWM_POLARITY_NORMAL>, + <&pwm 6 255 PWM_POLARITY_NORMAL>, + <&pwm 9 255 PWM_POLARITY_NORMAL>; + + io-channels = <&adc 0>, + <&adc 1>, + <&adc 2>; + + serials = <&board_cdc_acm_uart>, <&pico_serial>; + cdc-acm = <&board_cdc_acm_uart>; + i2cs = <&pico_i2c0>; + spis = <&pico_spi>; + }; +}; + +&pinctrl { + pwm_ch1a_default: pwm_ch1a_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch1b_default: pwm_ch1b_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch2a_default: pwm_ch2a_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch2b_default: pwm_ch2b_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch3a_default: pwm_ch3a_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch3b_default: pwm_ch3b_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch4a_default: pwm_ch4a_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch5a_default: pwm_ch5a_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch5b_default: pwm_ch5b_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch6a_default: pwm_ch6a_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch6b_default: pwm_ch6b_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch7a_default: pwm_ch7a_default { + group1 { + pinmux = ; + }; + }; + + pwm_ch7b_default: pwm_ch7b_default { + group1 { + pinmux = ; + }; + }; +}; + +&pwm { + status = "okay"; + divider-frac-4 = <15>; + divider-int-4 = <255>; +}; + +&adc { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; + +&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/rpi_pico_rp2040/variant.h b/variants/rpi_pico_rp2040/variant.h new file mode 100644 index 00000000..597ceefa --- /dev/null +++ b/variants/rpi_pico_rp2040/variant.h @@ -0,0 +1,5 @@ +/* + * Copyright (c) 2024 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */