From 10b514ed38aee5860ba1ac7192ebd54d9f66e40c Mon Sep 17 00:00:00 2001 From: Kevin Thomas Date: Sun, 5 Apr 2026 16:25:29 -0400 Subject: [PATCH] Add 0x05_servo_cbm: bare-metal RP2350 servo driver - PWM slice 3, channel A on GPIO6 at 50 Hz - Fractional divider 14.5 (14.5 MHz XOSC / 50 Hz / 20000) - Sweep 0-180-0 degrees in 10-degree steps - Pulse range 1000-2000 us, angle-to-pulse mapping - UART reports each angle step - 1557B FLASH, 11 source files, zero warnings --- .../.vscode/c_cpp_properties.json | 45 ++ .../0x05_servo_cbm/.vscode/extensions.json | 9 + drivers/0x05_servo_cbm/.vscode/launch.json | 47 ++ drivers/0x05_servo_cbm/.vscode/settings.json | 40 ++ drivers/0x05_servo_cbm/.vscode/tasks.json | 128 +++++ drivers/0x05_servo_cbm/Inc/rp2350.h | 215 +++++++++ .../0x05_servo_cbm/Inc/rp2350_coprocessor.h | 33 ++ drivers/0x05_servo_cbm/Inc/rp2350_delay.h | 34 ++ drivers/0x05_servo_cbm/Inc/rp2350_gpio.h | 63 +++ drivers/0x05_servo_cbm/Inc/rp2350_led.h | 63 +++ drivers/0x05_servo_cbm/Inc/rp2350_reset.h | 33 ++ .../0x05_servo_cbm/Inc/rp2350_reset_handler.h | 33 ++ drivers/0x05_servo_cbm/Inc/rp2350_servo.h | 54 +++ drivers/0x05_servo_cbm/Inc/rp2350_stack.h | 34 ++ drivers/0x05_servo_cbm/Inc/rp2350_uart.h | 73 +++ drivers/0x05_servo_cbm/Inc/rp2350_xosc.h | 40 ++ drivers/0x05_servo_cbm/Makefile | 79 ++++ drivers/0x05_servo_cbm/Src/image_def.c | 35 ++ drivers/0x05_servo_cbm/Src/main.c | 101 ++++ .../0x05_servo_cbm/Src/rp2350_coprocessor.c | 34 ++ drivers/0x05_servo_cbm/Src/rp2350_delay.c | 39 ++ drivers/0x05_servo_cbm/Src/rp2350_gpio.c | 90 ++++ drivers/0x05_servo_cbm/Src/rp2350_led.c | 49 ++ drivers/0x05_servo_cbm/Src/rp2350_reset.c | 33 ++ .../0x05_servo_cbm/Src/rp2350_reset_handler.c | 48 ++ drivers/0x05_servo_cbm/Src/rp2350_servo.c | 168 +++++++ drivers/0x05_servo_cbm/Src/rp2350_stack.c | 38 ++ drivers/0x05_servo_cbm/Src/rp2350_uart.c | 126 +++++ drivers/0x05_servo_cbm/Src/rp2350_xosc.c | 40 ++ drivers/0x05_servo_cbm/Src/vector_table.c | 38 ++ drivers/0x05_servo_cbm/linker.ld | 114 +++++ drivers/0x05_servo_cbm/uf2conv.py | 438 ++++++++++++++++++ drivers/0x05_servo_cbm/uf2families.json | 22 + 33 files changed, 2436 insertions(+) create mode 100644 drivers/0x05_servo_cbm/.vscode/c_cpp_properties.json create mode 100644 drivers/0x05_servo_cbm/.vscode/extensions.json create mode 100644 drivers/0x05_servo_cbm/.vscode/launch.json create mode 100644 drivers/0x05_servo_cbm/.vscode/settings.json create mode 100644 drivers/0x05_servo_cbm/.vscode/tasks.json create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350.h create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350_coprocessor.h create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350_delay.h create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350_gpio.h create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350_led.h create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350_reset.h create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350_reset_handler.h create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350_servo.h create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350_stack.h create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350_uart.h create mode 100644 drivers/0x05_servo_cbm/Inc/rp2350_xosc.h create mode 100644 drivers/0x05_servo_cbm/Makefile create mode 100644 drivers/0x05_servo_cbm/Src/image_def.c create mode 100644 drivers/0x05_servo_cbm/Src/main.c create mode 100644 drivers/0x05_servo_cbm/Src/rp2350_coprocessor.c create mode 100644 drivers/0x05_servo_cbm/Src/rp2350_delay.c create mode 100644 drivers/0x05_servo_cbm/Src/rp2350_gpio.c create mode 100644 drivers/0x05_servo_cbm/Src/rp2350_led.c create mode 100644 drivers/0x05_servo_cbm/Src/rp2350_reset.c create mode 100644 drivers/0x05_servo_cbm/Src/rp2350_reset_handler.c create mode 100644 drivers/0x05_servo_cbm/Src/rp2350_servo.c create mode 100644 drivers/0x05_servo_cbm/Src/rp2350_stack.c create mode 100644 drivers/0x05_servo_cbm/Src/rp2350_uart.c create mode 100644 drivers/0x05_servo_cbm/Src/rp2350_xosc.c create mode 100644 drivers/0x05_servo_cbm/Src/vector_table.c create mode 100644 drivers/0x05_servo_cbm/linker.ld create mode 100644 drivers/0x05_servo_cbm/uf2conv.py create mode 100644 drivers/0x05_servo_cbm/uf2families.json diff --git a/drivers/0x05_servo_cbm/.vscode/c_cpp_properties.json b/drivers/0x05_servo_cbm/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..60ea1fe --- /dev/null +++ b/drivers/0x05_servo_cbm/.vscode/c_cpp_properties.json @@ -0,0 +1,45 @@ +{ + "configurations": [ + { + "name": "ARM GCC", + "includePath": [ + "${workspaceFolder}/Inc/**" + ], + "defines": [ + "__GNUC__", + "__ARM_ARCH_8M_MAIN__", + "__ARMCC_VERSION" + ], + "compilerPath": "${userHome}/.pico-sdk/toolchain/14_2_Rel1/bin/arm-none-eabi-gcc", + "compileCommands": "${workspaceFolder}/compile_commands.json", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "gcc-arm", + "compilerArgs": [ + "-mcpu=cortex-m33", + "-mthumb" + ] + }, + { + "name": "ARM GCC (Windows)", + "includePath": [ + "${workspaceFolder}/Inc/**" + ], + "defines": [ + "__GNUC__", + "__ARM_ARCH_8M_MAIN__", + "__ARMCC_VERSION" + ], + "compilerPath": "${env:USERPROFILE}/.pico-sdk/toolchain/14_2_Rel1/bin/arm-none-eabi-gcc.exe", + "compileCommands": "${workspaceFolder}/compile_commands.json", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "gcc-arm", + "compilerArgs": [ + "-mcpu=cortex-m33", + "-mthumb" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/drivers/0x05_servo_cbm/.vscode/extensions.json b/drivers/0x05_servo_cbm/.vscode/extensions.json new file mode 100644 index 0000000..a940d7c --- /dev/null +++ b/drivers/0x05_servo_cbm/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "marus25.cortex-debug", + "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack", + "ms-vscode.vscode-serial-monitor", + "raspberry-pi.raspberry-pi-pico" + ] +} \ No newline at end of file diff --git a/drivers/0x05_servo_cbm/.vscode/launch.json b/drivers/0x05_servo_cbm/.vscode/launch.json new file mode 100644 index 0000000..f599abf --- /dev/null +++ b/drivers/0x05_servo_cbm/.vscode/launch.json @@ -0,0 +1,47 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug RP2350 (OpenOCD)", + "cwd": "${workspaceFolder}", + "executable": "${workspaceFolder}/build/servo.elf", + "request": "launch", + "type": "cortex-debug", + "servertype": "openocd", + "serverpath": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd", + "searchDir": [ + "${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts" + ], + "gdbPath": "${userHome}/.pico-sdk/toolchain/14_2_Rel1/bin/arm-none-eabi-gdb", + "device": "RP2350", + "configFiles": [ + "interface/cmsis-dap.cfg", + "target/rp2350.cfg" + ], + "svdFile": "${userHome}/.pico-sdk/sdk/2.2.0/src/rp2350/hardware_regs/RP2350.svd", + "overrideLaunchCommands": [ + "set arch armv8-m.main", + "set output-radix 16", + "monitor reset init", + "load", + "monitor reset halt" + ], + "openOCDPreConfigLaunchCommands": [ + "set USE_CORE { cm0 cm1 }" + ], + "openOCDLaunchCommands": [ + "adapter speed 5000" + ], + "preLaunchTask": "Compile Project", + "showDevDebugOutput": "raw", + "windows": { + "serverpath": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe", + "searchDir": [ + "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/scripts" + ], + "gdbPath": "${env:USERPROFILE}/.pico-sdk/toolchain/14_2_Rel1/bin/arm-none-eabi-gdb.exe", + "svdFile": "${env:USERPROFILE}/.pico-sdk/sdk/2.2.0/src/rp2350/hardware_regs/RP2350.svd" + } + } + ] +} \ No newline at end of file diff --git a/drivers/0x05_servo_cbm/.vscode/settings.json b/drivers/0x05_servo_cbm/.vscode/settings.json new file mode 100644 index 0000000..05d7bce --- /dev/null +++ b/drivers/0x05_servo_cbm/.vscode/settings.json @@ -0,0 +1,40 @@ +{ + "cmake.showSystemKits": false, + "cmake.options.statusBarVisibility": "hidden", + "cmake.options.advanced": { + "build": { + "statusBarVisibility": "hidden" + }, + "launch": { + "statusBarVisibility": "hidden" + }, + "debug": { + "statusBarVisibility": "hidden" + } + }, + "cmake.configureOnEdit": false, + "cmake.automaticReconfigure": false, + "cmake.configureOnOpen": false, + "cmake.generator": "Ninja", + "cmake.cmakePath": "${userHome}/.pico-sdk/cmake/v3.31.5/bin/cmake", + "C_Cpp.debugShortcut": false, + "terminal.integrated.env.windows": { + "PICO_SDK_PATH": "${env:USERPROFILE}/.pico-sdk/sdk/2.2.0", + "PICO_TOOLCHAIN_PATH": "${env:USERPROFILE}/.pico-sdk/toolchain/14_2_Rel1", + "Path": "${env:USERPROFILE}/.pico-sdk/toolchain/14_2_Rel1/bin;${env:USERPROFILE}/.pico-sdk/picotool/2.2.0-a4/picotool;${env:USERPROFILE}/.pico-sdk/cmake/v3.31.5/bin;${env:USERPROFILE}/.pico-sdk/ninja/v1.12.1;${env:PATH}" + }, + "terminal.integrated.env.osx": { + "PICO_SDK_PATH": "${env:HOME}/.pico-sdk/sdk/2.2.0", + "PICO_TOOLCHAIN_PATH": "${env:HOME}/.pico-sdk/toolchain/14_2_Rel1", + "PATH": "${env:HOME}/.pico-sdk/toolchain/14_2_Rel1/bin:${env:HOME}/.pico-sdk/picotool/2.2.0-a4/picotool:${env:HOME}/.pico-sdk/cmake/v3.31.5/bin:${env:HOME}/.pico-sdk/ninja/v1.12.1:${env:PATH}" + }, + "terminal.integrated.env.linux": { + "PICO_SDK_PATH": "${env:HOME}/.pico-sdk/sdk/2.2.0", + "PICO_TOOLCHAIN_PATH": "${env:HOME}/.pico-sdk/toolchain/14_2_Rel1", + "PATH": "${env:HOME}/.pico-sdk/toolchain/14_2_Rel1/bin:${env:HOME}/.pico-sdk/picotool/2.2.0-a4/picotool:${env:HOME}/.pico-sdk/cmake/v3.31.5/bin:${env:HOME}/.pico-sdk/ninja/v1.12.1:${env:PATH}" + }, + "raspberry-pi-pico.cmakeAutoConfigure": true, + "raspberry-pi-pico.useCmakeTools": false, + "raspberry-pi-pico.cmakePath": "${HOME}/.pico-sdk/cmake/v3.31.5/bin/cmake", + "raspberry-pi-pico.ninjaPath": "${HOME}/.pico-sdk/ninja/v1.12.1/ninja" +} \ No newline at end of file diff --git a/drivers/0x05_servo_cbm/.vscode/tasks.json b/drivers/0x05_servo_cbm/.vscode/tasks.json new file mode 100644 index 0000000..b40fc37 --- /dev/null +++ b/drivers/0x05_servo_cbm/.vscode/tasks.json @@ -0,0 +1,128 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Compile Project", + "type": "shell", + "command": "make", + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "dedicated" + }, + "problemMatcher": "$gcc", + "windows": { + "command": ".\\build.bat" + } + }, + { + "label": "Clean Project", + "type": "shell", + "command": "make clean", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "dedicated" + }, + "problemMatcher": [], + "windows": { + "command": ".\\clean.bat" + } + }, + { + "label": "Run Project", + "type": "shell", + "command": "${userHome}/.pico-sdk/picotool/2.2.0-a4/picotool/picotool", + "args": [ + "load", + "build/servo.uf2", + "-fx" + ], + "presentation": { + "reveal": "always", + "panel": "dedicated" + }, + "problemMatcher": [], + "dependsOn": [ + "Compile Project" + ], + "windows": { + "command": "${env:USERPROFILE}/.pico-sdk/picotool/2.2.0-a4/picotool/picotool.exe" + } + }, + { + "label": "Flash", + "type": "shell", + "command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd", + "args": [ + "-s", + "${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts", + "-f", + "interface/cmsis-dap.cfg", + "-f", + "target/rp2350.cfg", + "-c", + "adapter speed 5000; program build/servo.elf verify reset exit" + ], + "problemMatcher": [], + "dependsOn": [ + "Compile Project" + ], + "windows": { + "command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe" + } + }, + { + "label": "Rescue Reset", + "type": "process", + "command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd", + "args": [ + "-s", + "${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts", + "-f", + "interface/cmsis-dap.cfg", + "-f", + "target/${command:raspberry-pi-pico.getChip}-rescue.cfg", + "-c", + "adapter speed 5000; reset halt; exit" + ], + "problemMatcher": [], + "windows": { + "command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe" + } + }, + { + "label": "RISC-V Reset (RP2350)", + "type": "process", + "command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd", + "args": [ + "-s", + "${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts", + "-c", + "set USE_CORE { rv0 rv1 cm0 cm1 }", + "-f", + "interface/cmsis-dap.cfg", + "-f", + "target/rp2350.cfg", + "-c", + "adapter speed 5000; init;", + "-c", + "write_memory 0x40120158 8 { 0x3 }; echo [format \"Info : ARCHSEL 0x%02x\" [read_memory 0x40120158 8 1]];", + "-c", + "reset halt; targets rp2350.rv0; echo [format \"Info : ARCHSEL_STATUS 0x%02x\" [read_memory 0x4012015C 8 1]]; exit" + ], + "problemMatcher": [], + "windows": { + "command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe" + } + } + ] +} +], +"problemMatcher": [] +} +] +} \ No newline at end of file diff --git a/drivers/0x05_servo_cbm/Inc/rp2350.h b/drivers/0x05_servo_cbm/Inc/rp2350.h new file mode 100644 index 0000000..fe9620c --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350.h @@ -0,0 +1,215 @@ +/** + ****************************************************************************** + * @file rp2350.h + * @author Kevin Thomas + * @brief RP2350 Device Peripheral Access Layer Header File. + * + * Memory-mapped register structures and peripheral base addresses + * for the RP2350 microcontroller (Cortex-M33 dual-core). All + * register offsets verified against the RP2350 datasheet + * (RP-008373-DS-2). + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_H +#define __RP2350_H + +#include +#include + +/*!< Defines 'read / write' permissions */ +#define __IO volatile + +/*!< Stack addresses */ +#define STACK_TOP 0x20082000UL +#define STACK_LIMIT 0x2007A000UL + +/*!< Memory map */ +#define XIP_BASE 0x10000000UL +#define SRAM_BASE 0x20000000UL +#define SIO_BASE 0xD0000000UL +#define PPB_BASE 0xE0000000UL + +/*!< APB peripherals */ +#define CLOCKS_BASE 0x40010000UL +#define RESETS_BASE 0x40020000UL +#define IO_BANK0_BASE 0x40028000UL +#define PADS_BANK0_BASE 0x40038000UL +#define XOSC_BASE 0x40048000UL +#define UART0_BASE 0x40070000UL +#define PWM_BASE 0x400A8000UL + +/** + * @brief XOSC (External Crystal Oscillator) + */ +typedef struct +{ + __IO uint32_t CTRL; // Control register Address offset: 0x00 + __IO uint32_t STATUS; // Status register Address offset: 0x04 + __IO uint32_t DORMANT; // Dormant mode Address offset: 0x08 + __IO uint32_t STARTUP; // Startup delay Address offset: 0x0C + __IO uint32_t COUNT; // Frequency count Address offset: 0x10 +} XOSC_TypeDef; + +/** + * @brief CLOCKS + */ +typedef struct +{ + __IO uint32_t RESERVED0[18]; // Other clock registers Address offset: 0x00-0x44 + __IO uint32_t CLK_PERI_CTRL; // Peripheral clock control Address offset: 0x48 +} CLOCKS_TypeDef; + +/** + * @brief RESETS + */ +typedef struct +{ + __IO uint32_t RESET; // Reset control Address offset: 0x00 + __IO uint32_t WDSEL; // Watchdog select Address offset: 0x04 + __IO uint32_t RESET_DONE; // Reset done status Address offset: 0x08 +} RESETS_TypeDef; + +/** + * @brief IO_BANK0 GPIO Control (one per GPIO) + */ +typedef struct +{ + __IO uint32_t STATUS; // GPIO status Address offset: 0x00 + __IO uint32_t CTRL; // GPIO control Address offset: 0x04 +} IO_BANK0_GPIO_TypeDef; + +/** + * @brief IO_BANK0 + */ +typedef struct +{ + IO_BANK0_GPIO_TypeDef GPIO[30]; // GPIO 0-29 status/ctrl pairs Address offset: 0x000-0x0E8 +} IO_BANK0_TypeDef; + +/** + * @brief PADS_BANK0 + */ +typedef struct +{ + __IO uint32_t VOLTAGE_SELECT; // Voltage select Address offset: 0x00 + __IO uint32_t GPIO[30]; // GPIO 0-29 pad control Address offset: 0x04-0x78 +} PADS_BANK0_TypeDef; + +/** + * @brief Peripheral Definitions + */ +#define XOSC ((XOSC_TypeDef *) XOSC_BASE) +#define CLOCKS ((CLOCKS_TypeDef *) CLOCKS_BASE) +#define RESETS ((RESETS_TypeDef *) RESETS_BASE) +#define IO_BANK0 ((IO_BANK0_TypeDef *) IO_BANK0_BASE) +#define PADS_BANK0 ((PADS_BANK0_TypeDef *) PADS_BANK0_BASE) +#define SIO ((volatile uint32_t *) SIO_BASE) +#define CPACR ((volatile uint32_t *) (PPB_BASE + 0x0ED88UL)) + +/** + * @brief XOSC bit definitions + */ +#define XOSC_STATUS_STABLE_SHIFT 31U + +/** + * @brief CPACR bit definitions + */ +#define CPACR_CP0_SHIFT 0U +#define CPACR_CP1_SHIFT 1U + +/** + * @brief CLOCKS bit definitions + */ +#define CLK_PERI_CTRL_ENABLE_SHIFT 11U +#define CLK_PERI_CTRL_AUXSRC_SHIFT 5U +#define CLK_PERI_CTRL_AUXSRC_XOSC 4U + +/** + * @brief RESETS bit definitions + */ +#define RESETS_RESET_IO_BANK0_SHIFT 6U +#define RESETS_RESET_PWM_SHIFT 16U +#define RESETS_RESET_UART0_SHIFT 26U + +/** + * @brief IO_BANK0 bit definitions + */ +#define IO_BANK0_CTRL_FUNCSEL_MASK 0x1FU +#define IO_BANK0_CTRL_FUNCSEL_UART 0x02U +#define IO_BANK0_CTRL_FUNCSEL_PWM 0x04U +#define IO_BANK0_CTRL_FUNCSEL_SIO 0x05U + +/** + * @brief PADS_BANK0 bit definitions + */ +#define PADS_BANK0_OD_SHIFT 7U +#define PADS_BANK0_IE_SHIFT 6U +#define PADS_BANK0_ISO_SHIFT 8U + +/** + * @brief UART register offsets (word indices from UART0_BASE) + */ +#define UART_DR_OFFSET (0x000U / 4U) +#define UART_FR_OFFSET (0x018U / 4U) +#define UART_IBRD_OFFSET (0x024U / 4U) +#define UART_FBRD_OFFSET (0x028U / 4U) +#define UART_LCR_H_OFFSET (0x02CU / 4U) +#define UART_CR_OFFSET (0x030U / 4U) + +/** + * @brief UART flag register bit definitions + */ +#define UART_FR_TXFF_MASK 32U +#define UART_FR_RXFE_MASK 16U + +/** + * @brief UART line control and enable values + */ +#define UART_LCR_H_8N1_FIFO 0x70U +#define UART_CR_ENABLE ((3U << 8) | 1U) + +/** + * @brief GPIO pin definitions + */ +#define LED_PIN 25U +#define SERVO_PIN 6U + +/** + * @brief SIO GPIO register offsets (word indices from SIO_BASE) + */ +#define SIO_GPIO_IN_OFFSET (0x004U / 4U) +#define SIO_GPIO_OUT_SET_OFFSET (0x018U / 4U) +#define SIO_GPIO_OUT_CLR_OFFSET (0x020U / 4U) +#define SIO_GPIO_OUT_XOR_OFFSET (0x028U / 4U) +#define SIO_GPIO_OE_SET_OFFSET (0x038U / 4U) + +/** + * @brief PWM register offsets (per slice, stride 0x14) + */ +#define PWM_CH_CSR_OFFSET 0x00U +#define PWM_CH_DIV_OFFSET 0x04U +#define PWM_CH_CC_OFFSET 0x0CU +#define PWM_CH_TOP_OFFSET 0x10U +#define PWM_CH_STRIDE 0x14U + +/** + * @brief PWM bit definitions + */ +#define PWM_CSR_EN_SHIFT 0U +#define PWM_DIV_INT_SHIFT 4U +#define PWM_CC_B_SHIFT 16U +#define PWM_WRAP_DEFAULT 9999U + +#endif /* __RP2350_H */ diff --git a/drivers/0x05_servo_cbm/Inc/rp2350_coprocessor.h b/drivers/0x05_servo_cbm/Inc/rp2350_coprocessor.h new file mode 100644 index 0000000..6e26fa0 --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350_coprocessor.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * @file rp2350_coprocessor.h + * @author Kevin Thomas + * @brief Coprocessor access control driver header for RP2350. + * + * Enables coprocessor access via the CPACR register. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_COPROCESSOR_H +#define __RP2350_COPROCESSOR_H + +#include "rp2350.h" + +/** + * @brief Enable coprocessor access via CPACR with DSB/ISB barriers. + * @retval None + */ +void coprocessor_enable(void); + +#endif /* __RP2350_COPROCESSOR_H */ diff --git a/drivers/0x05_servo_cbm/Inc/rp2350_delay.h b/drivers/0x05_servo_cbm/Inc/rp2350_delay.h new file mode 100644 index 0000000..fccb205 --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350_delay.h @@ -0,0 +1,34 @@ +/** + ****************************************************************************** + * @file rp2350_delay.h + * @author Kevin Thomas + * @brief Delay driver header for RP2350. + * + * Millisecond busy-wait delay calibrated for a 14.5 MHz clock. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_DELAY_H +#define __RP2350_DELAY_H + +#include "rp2350.h" + +/** + * @brief Delay for the specified number of milliseconds. + * @param ms number of milliseconds to delay + * @retval None + */ +void delay_ms(uint32_t ms); + +#endif /* __RP2350_DELAY_H */ diff --git a/drivers/0x05_servo_cbm/Inc/rp2350_gpio.h b/drivers/0x05_servo_cbm/Inc/rp2350_gpio.h new file mode 100644 index 0000000..4d20089 --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350_gpio.h @@ -0,0 +1,63 @@ +/** + ****************************************************************************** + * @file rp2350_gpio.h + * @author Kevin Thomas + * @brief GPIO driver header for RP2350. + * + * SIO-based GPIO configuration, set, clear, toggle, and read + * functions for the RP2350 GPIO pins 0-29. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_GPIO_H +#define __RP2350_GPIO_H + +#include "rp2350.h" + +/** + * @brief Configure a GPIO pin as SIO output. + * @param gpio_num GPIO pin number (0-29) + * @retval None + */ +void gpio_config(uint32_t gpio_num); + +/** + * @brief Drive a GPIO output high. + * @param gpio_num GPIO pin number (0-29) + * @retval None + */ +void gpio_set(uint32_t gpio_num); + +/** + * @brief Drive a GPIO output low. + * @param gpio_num GPIO pin number (0-29) + * @retval None + */ +void gpio_clear(uint32_t gpio_num); + +/** + * @brief Toggle a GPIO output. + * @param gpio_num GPIO pin number (0-29) + * @retval None + */ +void gpio_toggle(uint32_t gpio_num); + +/** + * @brief Read the current input level of a GPIO pin. + * @param gpio_num GPIO pin number (0-29) + * @retval bool true if pin is high, false if low + */ +bool gpio_get(uint32_t gpio_num); + +#endif /* __RP2350_GPIO_H */ diff --git a/drivers/0x05_servo_cbm/Inc/rp2350_led.h b/drivers/0x05_servo_cbm/Inc/rp2350_led.h new file mode 100644 index 0000000..ba5f24c --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350_led.h @@ -0,0 +1,63 @@ +/** + ****************************************************************************** + * @file rp2350_led.h + * @author Kevin Thomas + * @brief LED driver header for RP2350. + * + * High-level GPIO output / LED driver wrapping the + * low-level GPIO functions. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_LED_H +#define __RP2350_LED_H + +#include "rp2350.h" + +/** + * @brief Initialize a GPIO pin as a push-pull digital output. + * @param pin GPIO pin number to configure + * @retval None + */ +void led_init(uint32_t pin); + +/** + * @brief Drive the output pin high (LED on). + * @param pin GPIO pin number + * @retval None + */ +void led_on(uint32_t pin); + +/** + * @brief Drive the output pin low (LED off). + * @param pin GPIO pin number + * @retval None + */ +void led_off(uint32_t pin); + +/** + * @brief Toggle the current state of the output pin. + * @param pin GPIO pin number + * @retval None + */ +void led_toggle(uint32_t pin); + +/** + * @brief Query the current drive state of the output pin. + * @param pin GPIO pin number + * @retval bool true if the pin is driven high, false if low + */ +bool led_get_state(uint32_t pin); + +#endif /* __RP2350_LED_H */ diff --git a/drivers/0x05_servo_cbm/Inc/rp2350_reset.h b/drivers/0x05_servo_cbm/Inc/rp2350_reset.h new file mode 100644 index 0000000..4a10831 --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350_reset.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * @file rp2350_reset.h + * @author Kevin Thomas + * @brief Reset controller driver header for RP2350. + * + * Provides subsystem reset release for IO_BANK0. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_RESET_H +#define __RP2350_RESET_H + +#include "rp2350.h" + +/** + * @brief Release IO_BANK0 from reset and wait until ready. + * @retval None + */ +void reset_init_subsystem(void); + +#endif /* __RP2350_RESET_H */ diff --git a/drivers/0x05_servo_cbm/Inc/rp2350_reset_handler.h b/drivers/0x05_servo_cbm/Inc/rp2350_reset_handler.h new file mode 100644 index 0000000..2565e29 --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350_reset_handler.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * @file rp2350_reset_handler.h + * @author Kevin Thomas + * @brief Reset handler header for RP2350. + * + * Entry point after reset. Performs stack initialization, XOSC + * setup, subsystem reset release, UART initialization, + * coprocessor enable, and branches to main(). + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_RESET_HANDLER_H +#define __RP2350_RESET_HANDLER_H + +/** + * @brief Reset handler entry point (naked, noreturn). + * @retval None + */ +void Reset_Handler(void) __attribute__((noreturn)); + +#endif /* __RP2350_RESET_HANDLER_H */ diff --git a/drivers/0x05_servo_cbm/Inc/rp2350_servo.h b/drivers/0x05_servo_cbm/Inc/rp2350_servo.h new file mode 100644 index 0000000..e005fea --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350_servo.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * @file rp2350_servo.h + * @author Kevin Thomas + * @brief SG90 servo driver header for RP2350. + * + * PWM-based servo driver on GPIO 6 at 50 Hz. Supports pulse + * width control in microseconds and angle control in degrees. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_SERVO_H +#define __RP2350_SERVO_H + +#include "rp2350.h" + +/** + * @brief Release PWM from reset and wait until ready. + * @retval None + */ +void servo_release_reset(void); + +/** + * @brief Initialize servo PWM on GPIO 6 at 50 Hz. + * @retval None + */ +void servo_init(void); + +/** + * @brief Set the servo pulse width in microseconds (clamped 1000-2000). + * @param pulse_us pulse width in microseconds + * @retval None + */ +void servo_set_pulse_us(uint16_t pulse_us); + +/** + * @brief Set the servo angle in degrees (clamped 0-180). + * @param degrees angle from 0 to 180 + * @retval None + */ +void servo_set_angle(uint8_t degrees); + +#endif /* __RP2350_SERVO_H */ diff --git a/drivers/0x05_servo_cbm/Inc/rp2350_stack.h b/drivers/0x05_servo_cbm/Inc/rp2350_stack.h new file mode 100644 index 0000000..952d26e --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350_stack.h @@ -0,0 +1,34 @@ +/** + ****************************************************************************** + * @file rp2350_stack.h + * @author Kevin Thomas + * @brief Stack pointer initialization header for RP2350. + * + * Sets MSP, PSP, MSPLIM, and PSPLIM from the STACK_TOP and + * STACK_LIMIT values defined in rp2350.h. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_STACK_H +#define __RP2350_STACK_H + +#include "rp2350.h" + +/** + * @brief Initialize MSP, PSP, MSPLIM, and PSPLIM stack pointers. + * @retval None + */ +void stack_init(void); + +#endif /* __RP2350_STACK_H */ diff --git a/drivers/0x05_servo_cbm/Inc/rp2350_uart.h b/drivers/0x05_servo_cbm/Inc/rp2350_uart.h new file mode 100644 index 0000000..b99425b --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350_uart.h @@ -0,0 +1,73 @@ +/** + ****************************************************************************** + * @file rp2350_uart.h + * @author Kevin Thomas + * @brief UART0 driver header for RP2350. + * + * Bare-metal UART0 driver supporting TX/RX on GPIO 0/1 at + * 115200 baud (14.5 MHz XOSC clock). + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_UART_H +#define __RP2350_UART_H + +#include "rp2350.h" + +/** + * @brief Release UART0 from reset and wait until ready. + * @retval None + */ +void uart_release_reset(void); + +/** + * @brief Initialize UART0 pins, baud rate, line control, and enable. + * @retval None + */ +void uart_init(void); + +/** + * @brief Check whether a received byte is waiting in the UART FIFO. + * @retval bool true if at least one byte is available + */ +bool uart_is_readable(void); + +/** + * @brief Read one character from UART0 (blocking). + * @retval char the received character + */ +char uart_getchar(void); + +/** + * @brief Transmit one character over UART0 (blocking). + * @param c character to transmit + * @retval None + */ +void uart_putchar(char c); + +/** + * @brief Transmit a null-terminated string over UART0. + * @param str pointer to the string to send + * @retval None + */ +void uart_puts(const char *str); + +/** + * @brief Convert a lowercase ASCII character to uppercase. + * @param c input character + * @retval char uppercase equivalent or original character + */ +char uart_to_upper(char c); + +#endif /* __RP2350_UART_H */ diff --git a/drivers/0x05_servo_cbm/Inc/rp2350_xosc.h b/drivers/0x05_servo_cbm/Inc/rp2350_xosc.h new file mode 100644 index 0000000..d2d6523 --- /dev/null +++ b/drivers/0x05_servo_cbm/Inc/rp2350_xosc.h @@ -0,0 +1,40 @@ +/** + ****************************************************************************** + * @file rp2350_xosc.h + * @author Kevin Thomas + * @brief XOSC driver header for RP2350. + * + * External crystal oscillator initialization and peripheral + * clock enable using the XOSC registers. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#ifndef __RP2350_XOSC_H +#define __RP2350_XOSC_H + +#include "rp2350.h" + +/** + * @brief Initialize the external crystal oscillator and wait until stable. + * @retval None + */ +void xosc_init(void); + +/** + * @brief Enable the XOSC peripheral clock via CLK_PERI_CTRL. + * @retval None + */ +void xosc_enable_peri_clk(void); + +#endif /* __RP2350_XOSC_H */ diff --git a/drivers/0x05_servo_cbm/Makefile b/drivers/0x05_servo_cbm/Makefile new file mode 100644 index 0000000..24f5a22 --- /dev/null +++ b/drivers/0x05_servo_cbm/Makefile @@ -0,0 +1,79 @@ +# ------------------------------------------------------------------------------ +# @file Makefile +# @author Kevin Thomas +# @brief Build script for RP2350 bare-metal C servo driver. +# +# Compiles, links, and generates UF2 firmware for the RP2350. +# ------------------------------------------------------------------------------ + +# Toolchain +CC = arm-none-eabi-gcc +OBJCOPY = arm-none-eabi-objcopy +SIZE = arm-none-eabi-size + +# Target +TARGET = servo + +# Directories +SRC_DIR = Src +INC_DIR = Inc +BUILD_DIR = build + +# CPU flags +CPU_FLAGS = -mcpu=cortex-m33 -mthumb + +# Compiler flags +CFLAGS = $(CPU_FLAGS) -Og -g3 -Wall -Wextra \ + -ffunction-sections -fdata-sections \ + -I$(INC_DIR) + +# Linker flags +LDFLAGS = $(CPU_FLAGS) -T linker.ld -nostdlib -Wl,--gc-sections + +# Source files +SRCS = $(SRC_DIR)/vector_table.c \ + $(SRC_DIR)/rp2350_reset_handler.c \ + $(SRC_DIR)/rp2350_stack.c \ + $(SRC_DIR)/rp2350_xosc.c \ + $(SRC_DIR)/rp2350_reset.c \ + $(SRC_DIR)/rp2350_coprocessor.c \ + $(SRC_DIR)/rp2350_uart.c \ + $(SRC_DIR)/rp2350_servo.c \ + $(SRC_DIR)/rp2350_delay.c \ + $(SRC_DIR)/main.c \ + $(SRC_DIR)/image_def.c + +# Object files +OBJS = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SRCS)) + +# Rules +.PHONY: all clean flash + +all: $(BUILD_DIR)/$(TARGET).uf2 + @echo "===================================" + @echo "SUCCESS! Created $(TARGET).bin and $(TARGET).uf2" + @echo "===================================" + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/$(TARGET).elf: $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ + $(SIZE) $@ + +$(BUILD_DIR)/$(TARGET).bin: $(BUILD_DIR)/$(TARGET).elf + $(OBJCOPY) -O binary $< $@ + +$(BUILD_DIR)/$(TARGET).uf2: $(BUILD_DIR)/$(TARGET).bin + python3 uf2conv.py -b 0x10000000 -f 0xe48bff59 -o $@ $< + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +clean: + rm -rf $(BUILD_DIR) + +flash: $(BUILD_DIR)/$(TARGET).elf + openocd -f interface/cmsis-dap.cfg -f target/rp2350.cfg \ + -c "adapter speed 5000" \ + -c "program $< verify reset exit" diff --git a/drivers/0x05_servo_cbm/Src/image_def.c b/drivers/0x05_servo_cbm/Src/image_def.c new file mode 100644 index 0000000..9a34198 --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/image_def.c @@ -0,0 +1,35 @@ +/** + ****************************************************************************** + * @file image_def.c + * @author Kevin Thomas + * @brief RP2350 IMAGE_DEF block for boot ROM image recognition. + * + * Must appear within the first 4 KB of flash for the boot ROM + * to accept the image. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include + +/** + * @brief IMAGE_DEF block structure placed in flash + */ +__attribute__((section(".embedded_block"), used)) +const uint8_t picobin_block[] = { + 0xD3, 0xDE, 0xFF, 0xFF, + 0x42, 0x01, 0x21, 0x10, + 0xFF, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x79, 0x35, 0x12, 0xAB +}; diff --git a/drivers/0x05_servo_cbm/Src/main.c b/drivers/0x05_servo_cbm/Src/main.c new file mode 100644 index 0000000..9c4532e --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/main.c @@ -0,0 +1,101 @@ +/** + ****************************************************************************** + * @file main.c + * @author Kevin Thomas + * @brief SG90 servo motor sweep demonstration. + * + * Demonstrates servo control using the servo driver. The servo + * sweeps from 0 to 180 degrees and back in 10-degree steps, + * reporting each angle over UART. + * + * Wiring: + * GPIO0 -> UART TX (USB-to-UART adapter RX) + * GPIO1 -> UART RX (USB-to-UART adapter TX) + * GPIO6 -> Servo signal (orange/yellow) + * 5V -> Servo power (red) + * GND -> Servo ground (brown/black) + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_servo.h" +#include "rp2350_uart.h" +#include "rp2350_delay.h" + +#define STEP_DEGREES 10 +#define STEP_DELAY_MS 150 + +/** + * @brief Print an angle value as a decimal string over UART. + * @param angle angle in degrees (0-180) + * @retval None + */ +static void _print_angle(uint8_t angle) +{ + char buf[4]; + uint8_t idx = 0; + if (angle >= 100) { + buf[idx++] = (char)('0' + angle / 100); + buf[idx++] = (char)('0' + (angle / 10) % 10); + buf[idx++] = (char)('0' + angle % 10); + } else if (angle >= 10) { + buf[idx++] = (char)('0' + angle / 10); + buf[idx++] = (char)('0' + angle % 10); + } else { + buf[idx++] = (char)('0' + angle); + } + buf[idx] = '\0'; + uart_puts("Angle: "); + uart_puts(buf); + uart_puts(" deg\r\n"); +} + +/** + * @brief Sweep servo angle upward from 0 to 180 degrees. + * @retval None + */ +static void _sweep_up(void) +{ + for (uint8_t angle = 0; angle <= 180; angle += STEP_DEGREES) { + servo_set_angle(angle); + _print_angle(angle); + delay_ms(STEP_DELAY_MS); + } +} + +/** + * @brief Sweep servo angle downward from 180 to 0 degrees. + * @retval None + */ +static void _sweep_down(void) +{ + for (int16_t angle = 180; angle >= 0; angle -= STEP_DEGREES) { + servo_set_angle((uint8_t)angle); + _print_angle((uint8_t)angle); + delay_ms(STEP_DELAY_MS); + } +} + +/** + * @brief Application entry point for the servo sweep demo. + * @retval int does not return + */ +int main(void) +{ + uart_puts("Servo driver initialized on GPIO6\r\n"); + uart_puts("Sweeping 0 -> 180 -> 0 degrees\r\n"); + while (1) { + _sweep_up(); + _sweep_down(); + } +} diff --git a/drivers/0x05_servo_cbm/Src/rp2350_coprocessor.c b/drivers/0x05_servo_cbm/Src/rp2350_coprocessor.c new file mode 100644 index 0000000..b637b36 --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/rp2350_coprocessor.c @@ -0,0 +1,34 @@ +/** + ****************************************************************************** + * @file rp2350_coprocessor.c + * @author Kevin Thomas + * @brief Coprocessor access control driver implementation for RP2350. + * + * Grants access to coprocessors 0 and 1 by setting the + * corresponding bits in CPACR with DSB/ISB barriers. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_coprocessor.h" + +void coprocessor_enable(void) +{ + uint32_t value; + value = *CPACR; + value |= (1U << CPACR_CP1_SHIFT); + value |= (1U << CPACR_CP0_SHIFT); + *CPACR = value; + __asm__ volatile ("dsb"); + __asm__ volatile ("isb"); +} diff --git a/drivers/0x05_servo_cbm/Src/rp2350_delay.c b/drivers/0x05_servo_cbm/Src/rp2350_delay.c new file mode 100644 index 0000000..579c211 --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/rp2350_delay.c @@ -0,0 +1,39 @@ +/** + ****************************************************************************** + * @file rp2350_delay.c + * @author Kevin Thomas + * @brief Delay driver implementation for RP2350. + * + * Busy-wait millisecond delay calibrated for a 14.5 MHz clock + * (3600 loop iterations per millisecond). + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_delay.h" + +void delay_ms(uint32_t ms) +{ + if (ms == 0) + return; + __asm__ volatile ( + "mov r4, #3600\n\t" + "mul r5, %0, r4\n\t" + "1:\n\t" + "subs r5, #1\n\t" + "bne 1b\n\t" + : + : "r" (ms) + : "r4", "r5", "cc" + ); +} diff --git a/drivers/0x05_servo_cbm/Src/rp2350_gpio.c b/drivers/0x05_servo_cbm/Src/rp2350_gpio.c new file mode 100644 index 0000000..b93c954 --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/rp2350_gpio.c @@ -0,0 +1,90 @@ +/** + ****************************************************************************** + * @file rp2350_gpio.c + * @author Kevin Thomas + * @brief GPIO driver implementation for RP2350. + * + * SIO-based GPIO configuration using IO_BANK0 and PADS_BANK0 + * register structs defined in rp2350.h. All register offsets + * verified against the RP2350 datasheet (RP-008373-DS-2). + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_gpio.h" + +/** + * @brief Configure pad control for a GPIO pin. + * @param gpio_num GPIO pin number (0-29) + * @retval None + */ +static void _gpio_config_pad(uint32_t gpio_num) +{ + uint32_t value; + value = PADS_BANK0->GPIO[gpio_num]; + value &= ~(1U << PADS_BANK0_OD_SHIFT); + value |= (1U << PADS_BANK0_IE_SHIFT); + value &= ~(1U << PADS_BANK0_ISO_SHIFT); + PADS_BANK0->GPIO[gpio_num] = value; +} + +/** + * @brief Set IO_BANK0 FUNCSEL to SIO for a GPIO pin. + * @param gpio_num GPIO pin number (0-29) + * @retval None + */ +static void _gpio_config_funcsel(uint32_t gpio_num) +{ + uint32_t value; + value = IO_BANK0->GPIO[gpio_num].CTRL; + value &= ~IO_BANK0_CTRL_FUNCSEL_MASK; + value |= IO_BANK0_CTRL_FUNCSEL_SIO; + IO_BANK0->GPIO[gpio_num].CTRL = value; +} + +/** + * @brief Enable the output driver for a GPIO pin via SIO. + * @param gpio_num GPIO pin number (0-29) + * @retval None + */ +static void _gpio_enable_output(uint32_t gpio_num) +{ + SIO[SIO_GPIO_OE_SET_OFFSET] = (1U << gpio_num); +} + +void gpio_config(uint32_t gpio_num) +{ + _gpio_config_pad(gpio_num); + _gpio_config_funcsel(gpio_num); + _gpio_enable_output(gpio_num); +} + +void gpio_set(uint32_t gpio_num) +{ + SIO[SIO_GPIO_OUT_SET_OFFSET] = (1U << gpio_num); +} + +void gpio_clear(uint32_t gpio_num) +{ + SIO[SIO_GPIO_OUT_CLR_OFFSET] = (1U << gpio_num); +} + +void gpio_toggle(uint32_t gpio_num) +{ + SIO[SIO_GPIO_OUT_XOR_OFFSET] = (1U << gpio_num); +} + +bool gpio_get(uint32_t gpio_num) +{ + return (SIO[SIO_GPIO_IN_OFFSET] & (1U << gpio_num)) != 0; +} diff --git a/drivers/0x05_servo_cbm/Src/rp2350_led.c b/drivers/0x05_servo_cbm/Src/rp2350_led.c new file mode 100644 index 0000000..ebf2a76 --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/rp2350_led.c @@ -0,0 +1,49 @@ +/** + ****************************************************************************** + * @file rp2350_led.c + * @author Kevin Thomas + * @brief LED driver implementation for RP2350. + * + * High-level wrapper around the GPIO driver for LED control. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_led.h" +#include "rp2350_gpio.h" + +void led_init(uint32_t pin) +{ + gpio_config(pin); + gpio_clear(pin); +} + +void led_on(uint32_t pin) +{ + gpio_set(pin); +} + +void led_off(uint32_t pin) +{ + gpio_clear(pin); +} + +void led_toggle(uint32_t pin) +{ + gpio_toggle(pin); +} + +bool led_get_state(uint32_t pin) +{ + return gpio_get(pin); +} diff --git a/drivers/0x05_servo_cbm/Src/rp2350_reset.c b/drivers/0x05_servo_cbm/Src/rp2350_reset.c new file mode 100644 index 0000000..b0e18e8 --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/rp2350_reset.c @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * @file rp2350_reset.c + * @author Kevin Thomas + * @brief Reset controller driver implementation for RP2350. + * + * Releases IO_BANK0 from reset and waits until the subsystem + * is ready. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_reset.h" + +void reset_init_subsystem(void) +{ + uint32_t value; + value = RESETS->RESET; + value &= ~(1U << RESETS_RESET_IO_BANK0_SHIFT); + RESETS->RESET = value; + while ((RESETS->RESET_DONE & (1U << RESETS_RESET_IO_BANK0_SHIFT)) == 0) { + } +} diff --git a/drivers/0x05_servo_cbm/Src/rp2350_reset_handler.c b/drivers/0x05_servo_cbm/Src/rp2350_reset_handler.c new file mode 100644 index 0000000..1bb634e --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/rp2350_reset_handler.c @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * @file rp2350_reset_handler.c + * @author Kevin Thomas + * @brief Reset handler implementation for RP2350. + * + * Entry point after power-on or system reset. Initializes the + * stack, XOSC, subsystem resets, UART, servo, coprocessor, + * then branches to main(). + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_reset_handler.h" +#include "rp2350_stack.h" +#include "rp2350_xosc.h" +#include "rp2350_reset.h" +#include "rp2350_uart.h" +#include "rp2350_servo.h" +#include "rp2350_coprocessor.h" + +extern int main(void); + +void __attribute__((naked, noreturn)) Reset_Handler(void) +{ + __asm__ volatile ( + "bl stack_init\n\t" + "bl xosc_init\n\t" + "bl xosc_enable_peri_clk\n\t" + "bl reset_init_subsystem\n\t" + "bl uart_release_reset\n\t" + "bl uart_init\n\t" + "bl servo_release_reset\n\t" + "bl servo_init\n\t" + "bl coprocessor_enable\n\t" + "b main\n\t" + ); +} diff --git a/drivers/0x05_servo_cbm/Src/rp2350_servo.c b/drivers/0x05_servo_cbm/Src/rp2350_servo.c new file mode 100644 index 0000000..7ac6d76 --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/rp2350_servo.c @@ -0,0 +1,168 @@ +/** + ****************************************************************************** + * @file rp2350_servo.c + * @author Kevin Thomas + * @brief SG90 servo driver implementation for RP2350. + * + * Configures PWM slice 3, channel A on GPIO 6 at 50 Hz for + * standard hobby servo control. Uses a wrap of 19999 and a + * fractional clock divider of 14.5 (14.5 MHz XOSC / 50 Hz / + * 20000 = 14.5). + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_servo.h" + +#define PWM ((volatile uint32_t *) PWM_BASE) + +/** + * @brief PWM slice number for GPIO 6. + */ +#define SERVO_SLICE 3U + +/** + * @brief Wrap value for 50 Hz at 14.5 MHz with divider 14.5. + */ +#define SERVO_WRAP 19999U + +/** + * @brief Clock divider register value for 14.5 (INT=14, FRAC=8). + */ +#define SERVO_DIV_VAL ((14U << PWM_DIV_INT_SHIFT) | 8U) + +/** + * @brief Minimum pulse width in microseconds (0 degrees). + */ +#define SERVO_MIN_US 1000U + +/** + * @brief Maximum pulse width in microseconds (180 degrees). + */ +#define SERVO_MAX_US 2000U + +/** + * @brief Compute the byte offset for a register within the slice. + * @param reg per-slice register offset (e.g. PWM_CH_CSR_OFFSET) + * @retval uint32_t word index from PWM_BASE + */ +#define SERVO_REG(reg) (((SERVO_SLICE * PWM_CH_STRIDE) + (reg)) / 4U) + +/** + * @brief Clear the PWM reset bit in the reset controller. + * @retval None + */ +static void _servo_clear_reset_bit(void) +{ + uint32_t value; + value = RESETS->RESET; + value &= ~(1U << RESETS_RESET_PWM_SHIFT); + RESETS->RESET = value; +} + +/** + * @brief Wait until the PWM block is out of reset. + * @retval None + */ +static void _servo_wait_reset_done(void) +{ + while ((RESETS->RESET_DONE & (1U << RESETS_RESET_PWM_SHIFT)) == 0) { + } +} + +/** + * @brief Configure GPIO 6 pad and funcsel for PWM output. + * @retval None + */ +static void _servo_configure_pin(void) +{ + uint32_t value; + value = PADS_BANK0->GPIO[SERVO_PIN]; + value &= ~(1U << PADS_BANK0_OD_SHIFT); + value |= (1U << PADS_BANK0_IE_SHIFT); + value &= ~(1U << PADS_BANK0_ISO_SHIFT); + PADS_BANK0->GPIO[SERVO_PIN] = value; + IO_BANK0->GPIO[SERVO_PIN].CTRL = IO_BANK0_CTRL_FUNCSEL_PWM; +} + +/** + * @brief Set the fractional clock divider for 50 Hz servo frequency. + * @retval None + */ +static void _servo_set_divider(void) +{ + PWM[SERVO_REG(PWM_CH_DIV_OFFSET)] = SERVO_DIV_VAL; +} + +/** + * @brief Set the wrap value and zero the compare register. + * @retval None + */ +static void _servo_set_wrap(void) +{ + PWM[SERVO_REG(PWM_CH_TOP_OFFSET)] = SERVO_WRAP; + PWM[SERVO_REG(PWM_CH_CC_OFFSET)] = 0; +} + +/** + * @brief Enable the PWM slice counter. + * @retval None + */ +static void _servo_enable(void) +{ + PWM[SERVO_REG(PWM_CH_CSR_OFFSET)] = (1U << PWM_CSR_EN_SHIFT); +} + +/** + * @brief Convert a pulse width in microseconds to a PWM counter level. + * @param pulse_us pulse width in microseconds + * @retval uint32_t PWM level for the CC register + */ +static uint32_t _pulse_us_to_level(uint16_t pulse_us) +{ + return ((uint32_t)pulse_us * (SERVO_WRAP + 1)) / 20000U; +} + +void servo_release_reset(void) +{ + _servo_clear_reset_bit(); + _servo_wait_reset_done(); +} + +void servo_init(void) +{ + _servo_configure_pin(); + _servo_set_divider(); + _servo_set_wrap(); + _servo_enable(); +} + +void servo_set_pulse_us(uint16_t pulse_us) +{ + uint32_t level; + if (pulse_us < SERVO_MIN_US) + pulse_us = SERVO_MIN_US; + if (pulse_us > SERVO_MAX_US) + pulse_us = SERVO_MAX_US; + level = _pulse_us_to_level(pulse_us); + PWM[SERVO_REG(PWM_CH_CC_OFFSET)] = level; +} + +void servo_set_angle(uint8_t degrees) +{ + uint16_t pulse; + if (degrees > 180) + degrees = 180; + pulse = (uint16_t)(SERVO_MIN_US + ((uint32_t)degrees * (SERVO_MAX_US - SERVO_MIN_US)) / 180U); + servo_set_pulse_us(pulse); +} diff --git a/drivers/0x05_servo_cbm/Src/rp2350_stack.c b/drivers/0x05_servo_cbm/Src/rp2350_stack.c new file mode 100644 index 0000000..9c328dc --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/rp2350_stack.c @@ -0,0 +1,38 @@ +/** + ****************************************************************************** + * @file rp2350_stack.c + * @author Kevin Thomas + * @brief Stack pointer initialization for RP2350. + * + * Sets MSP, PSP, MSPLIM, and PSPLIM using inline assembly. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_stack.h" + +void stack_init(void) +{ + __asm__ volatile ( + "ldr r0, =%0\n\t" + "msr PSP, r0\n\t" + "ldr r0, =%1\n\t" + "msr MSPLIM, r0\n\t" + "msr PSPLIM, r0\n\t" + "ldr r0, =%0\n\t" + "msr MSP, r0\n\t" + : + : "i" (STACK_TOP), "i" (STACK_LIMIT) + : "r0" + ); +} diff --git a/drivers/0x05_servo_cbm/Src/rp2350_uart.c b/drivers/0x05_servo_cbm/Src/rp2350_uart.c new file mode 100644 index 0000000..281ad52 --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/rp2350_uart.c @@ -0,0 +1,126 @@ +/** + ****************************************************************************** + * @file rp2350_uart.c + * @author Kevin Thomas + * @brief UART0 driver implementation for RP2350. + * + * Configures UART0 on GPIO 0 (TX) and GPIO 1 (RX) at 115200 + * baud using the 14.5 MHz XOSC clock. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_uart.h" + +#define UART_BASE ((volatile uint32_t *) UART0_BASE) + +/** + * @brief Clear the UART0 reset bit in the reset controller. + * @retval None + */ +static void _uart_clear_reset_bit(void) +{ + uint32_t value; + value = RESETS->RESET; + value &= ~(1U << RESETS_RESET_UART0_SHIFT); + RESETS->RESET = value; +} + +/** + * @brief Wait until the UART0 block is out of reset. + * @retval None + */ +static void _uart_wait_reset_done(void) +{ + while ((RESETS->RESET_DONE & (1U << RESETS_RESET_UART0_SHIFT)) == 0) { + } +} + +/** + * @brief Configure GPIO pins 0 (TX) and 1 (RX) for UART function. + * @retval None + */ +static void _uart_configure_pins(void) +{ + IO_BANK0->GPIO[0].CTRL = IO_BANK0_CTRL_FUNCSEL_UART; + IO_BANK0->GPIO[1].CTRL = IO_BANK0_CTRL_FUNCSEL_UART; + PADS_BANK0->GPIO[0] = 0x04; + PADS_BANK0->GPIO[1] = 0x40; +} + +/** + * @brief Set UART0 baud rate divisors for 115200 at 14.5 MHz. + * @retval None + */ +static void _uart_set_baud(void) +{ + UART_BASE[UART_CR_OFFSET] = 0; + UART_BASE[UART_IBRD_OFFSET] = 6; + UART_BASE[UART_FBRD_OFFSET] = 33; +} + +/** + * @brief Configure line control and enable UART0. + * @retval None + */ +static void _uart_enable(void) +{ + UART_BASE[UART_LCR_H_OFFSET] = UART_LCR_H_8N1_FIFO; + UART_BASE[UART_CR_OFFSET] = UART_CR_ENABLE; +} + +void uart_release_reset(void) +{ + _uart_clear_reset_bit(); + _uart_wait_reset_done(); +} + +void uart_init(void) +{ + _uart_configure_pins(); + _uart_set_baud(); + _uart_enable(); +} + +bool uart_is_readable(void) +{ + return (UART_BASE[UART_FR_OFFSET] & UART_FR_RXFE_MASK) == 0; +} + +char uart_getchar(void) +{ + while (UART_BASE[UART_FR_OFFSET] & UART_FR_RXFE_MASK) { + } + return (char)(UART_BASE[UART_DR_OFFSET] & 0xFF); +} + +void uart_putchar(char c) +{ + while (UART_BASE[UART_FR_OFFSET] & UART_FR_TXFF_MASK) { + } + UART_BASE[UART_DR_OFFSET] = (uint32_t)c; +} + +void uart_puts(const char *str) +{ + while (*str) { + uart_putchar(*str++); + } +} + +char uart_to_upper(char c) +{ + if (c >= 'a' && c <= 'z') + return (char)(c - 32); + return c; +} diff --git a/drivers/0x05_servo_cbm/Src/rp2350_xosc.c b/drivers/0x05_servo_cbm/Src/rp2350_xosc.c new file mode 100644 index 0000000..2051745 --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/rp2350_xosc.c @@ -0,0 +1,40 @@ +/** + ****************************************************************************** + * @file rp2350_xosc.c + * @author Kevin Thomas + * @brief XOSC driver implementation for RP2350. + * + * Configures the external crystal oscillator and enables the + * peripheral clock sourced from XOSC. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include "rp2350_xosc.h" + +void xosc_init(void) +{ + XOSC->STARTUP = 0x00C4U; + XOSC->CTRL = 0x00FABAA0U; + while ((XOSC->STATUS & (1U << XOSC_STATUS_STABLE_SHIFT)) == 0) { + } +} + +void xosc_enable_peri_clk(void) +{ + uint32_t value; + value = CLOCKS->CLK_PERI_CTRL; + value |= (1U << CLK_PERI_CTRL_ENABLE_SHIFT); + value |= (CLK_PERI_CTRL_AUXSRC_XOSC << CLK_PERI_CTRL_AUXSRC_SHIFT); + CLOCKS->CLK_PERI_CTRL = value; +} diff --git a/drivers/0x05_servo_cbm/Src/vector_table.c b/drivers/0x05_servo_cbm/Src/vector_table.c new file mode 100644 index 0000000..5d234c5 --- /dev/null +++ b/drivers/0x05_servo_cbm/Src/vector_table.c @@ -0,0 +1,38 @@ +/** + ****************************************************************************** + * @file vector_table.c + * @author Kevin Thomas + * @brief Vector table with initial stack pointer and reset handler. + * + * Placed in the .vectors section at the start of flash. + * The Thumb bit (bit 0 = 1) is automatically set by the + * linker for function pointers in Thumb mode. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#include + +extern uint32_t _stack_top; +extern void Reset_Handler(void); + +typedef void (*vector_func_t)(void); + +/** + * @brief Vector table placed in .vectors section + */ +__attribute__((section(".vectors"), used)) +const void *_vectors[2] = { + &_stack_top, + Reset_Handler +}; diff --git a/drivers/0x05_servo_cbm/linker.ld b/drivers/0x05_servo_cbm/linker.ld new file mode 100644 index 0000000..09ea7a6 --- /dev/null +++ b/drivers/0x05_servo_cbm/linker.ld @@ -0,0 +1,114 @@ +/** + ****************************************************************************** + * @file linker.ld + * @author Kevin Thomas + * @brief Minimal linker script for bare-metal RP2350 development. + * + * Defines FLASH (XIP 32 MB) and RAM (520 kB SRAM) regions. + * The vector table is placed at the start of flash (0x10000000). + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 Kevin Thomas. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/** + * Entry point. + */ +ENTRY(Reset_Handler) + +/** + * Define memory regions. + */ +__XIP_BASE = 0x10000000; +__XIP_SIZE = 32M; + +__SRAM_BASE = 0x20000000; +__SRAM_SIZE = 520K; +__STACK_SIZE = 32K; + +/** + * Memory layout. + */ +MEMORY +{ + RAM (rwx) : ORIGIN = __SRAM_BASE, LENGTH = __SRAM_SIZE + FLASH (rx) : ORIGIN = __XIP_BASE, LENGTH = __XIP_SIZE +} + +/** + * Program headers. + */ +PHDRS +{ + text PT_LOAD FLAGS(5); +} + +/** + * Section placement. + */ +SECTIONS +{ + . = ORIGIN(FLASH); + + /** + * Vector table MUST be first at 0x10000000. + */ + .vectors : + { + KEEP(*(.vectors)) + } > FLASH :text + + /** + * Verify vector table placement. + */ + ASSERT((ADDR(.vectors) == ORIGIN(FLASH)), + "Vector table must be at start of flash (0x10000000)") + + /** + * Text and read-only data. + */ + .text : + { + . = ALIGN(4); + *(.text*) + *(.rodata*) + KEEP(*(.init)) + KEEP(*(.fini)) + KEEP(*(.ARM.attributes)) + } > FLASH :text + + /** + * IMAGE_DEF block at end of code. + */ + .embedded_block : + { + KEEP(*(.embedded_block)) + } > FLASH :text + + /** + * Non-secure stack symbols. + */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - __STACK_SIZE; + __stack = __StackTop; + _stack_top = __StackTop; + + /** + * Stack section (no load). + */ + .stack (NOLOAD) : { . = ALIGN(8); } > RAM + + /** + * Provide vector table symbol to startup code. + */ + PROVIDE(__Vectors = ADDR(.vectors)); +} diff --git a/drivers/0x05_servo_cbm/uf2conv.py b/drivers/0x05_servo_cbm/uf2conv.py new file mode 100644 index 0000000..529dd96 --- /dev/null +++ b/drivers/0x05_servo_cbm/uf2conv.py @@ -0,0 +1,438 @@ +#!/usr/bin/env python3 +import sys +import struct +import subprocess +import re +import os +import os.path +import argparse +import json +from time import sleep + + +UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" +UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected +UF2_MAGIC_END = 0x0AB16F30 # Ditto + +INFO_FILE = "/INFO_UF2.TXT" + +appstartaddr = 0x2000 +familyid = 0x0 + + +def is_uf2(buf): + w = struct.unpack(" 476: + assert False, "Invalid UF2 data size at " + ptr + newaddr = hd[3] + if (hd[2] & 0x2000) and (currfamilyid == None): + currfamilyid = hd[7] + if curraddr == None or ((hd[2] & 0x2000) and hd[7] != currfamilyid): + currfamilyid = hd[7] + curraddr = newaddr + if familyid == 0x0 or familyid == hd[7]: + appstartaddr = newaddr + padding = newaddr - curraddr + if padding < 0: + assert False, "Block out of order at " + ptr + if padding > 10 * 1024 * 1024: + assert False, "More than 10M of padding needed at " + ptr + if padding % 4 != 0: + assert False, "Non-word padding size at " + ptr + while padding > 0: + padding -= 4 + outp.append(b"\x00\x00\x00\x00") + if familyid == 0x0 or ((hd[2] & 0x2000) and familyid == hd[7]): + outp.append(block[32 : 32 + datalen]) + curraddr = newaddr + datalen + if hd[2] & 0x2000: + if hd[7] in families_found.keys(): + if families_found[hd[7]] > newaddr: + families_found[hd[7]] = newaddr + else: + families_found[hd[7]] = newaddr + if prev_flag == None: + prev_flag = hd[2] + if prev_flag != hd[2]: + all_flags_same = False + if blockno == (numblocks - 1): + print("--- UF2 File Header Info ---") + families = load_families() + for family_hex in families_found.keys(): + family_short_name = "" + for name, value in families.items(): + if value == family_hex: + family_short_name = name + print( + "Family ID is {:s}, hex value is 0x{:08x}".format( + family_short_name, family_hex + ) + ) + print("Target Address is 0x{:08x}".format(families_found[family_hex])) + if all_flags_same: + print("All block flag values consistent, 0x{:04x}".format(hd[2])) + else: + print("Flags were not all the same") + print("----------------------------") + if len(families_found) > 1 and familyid == 0x0: + outp = [] + appstartaddr = 0x0 + return b"".join(outp) + + +def convert_to_carray(file_content): + outp = "const unsigned long bindata_len = %d;\n" % len(file_content) + outp += "const unsigned char bindata[] __attribute__((aligned(16))) = {" + for i in range(len(file_content)): + if i % 16 == 0: + outp += "\n" + outp += "0x%02x, " % file_content[i] + outp += "\n};\n" + return bytes(outp, "utf-8") + + +def convert_to_uf2(file_content): + global familyid + datapadding = b"" + while len(datapadding) < 512 - 256 - 32 - 4: + datapadding += b"\x00\x00\x00\x00" + numblocks = (len(file_content) + 255) // 256 + outp = [] + for blockno in range(numblocks): + ptr = 256 * blockno + chunk = file_content[ptr : ptr + 256] + flags = 0x0 + if familyid: + flags |= 0x2000 + hd = struct.pack( + b"