Skip to content

RPI RP 2040 support #144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: arduino
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions boards.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

##############################################################################################################
1 change: 1 addition & 0 deletions extra/bin2uf2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bin2uf2
3 changes: 3 additions & 0 deletions extra/bin2uf2/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/pennam/bin2uf2

go 1.21
181 changes: 181 additions & 0 deletions extra/bin2uf2/main.go
Original file line number Diff line number Diff line change
@@ -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] <source file> <destination file>\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)
}
2 changes: 1 addition & 1 deletion extra/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 10 additions & 2 deletions platform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions variants/rpi_pico_rp2040/rpi_pico_rp2040.conf
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading