Added cbm 1 2

This commit is contained in:
Kevin Thomas
2026-04-04 12:11:58 -04:00
parent aa8f2ca754
commit eb6150ffad
65 changed files with 4493 additions and 0 deletions

3
.gitignore vendored
View File

@@ -52,3 +52,6 @@ modules.order
Module.symvers
Mkfile.old
dkms.conf
# Build output
build/

11
drivers/0x01_uart_cbm/.gitattributes vendored Normal file
View File

@@ -0,0 +1,11 @@
# C files
*.c linguist-language=C
# Exclude from language statistics
*.ld linguist-vendored
*.bat linguist-vendored
*.py linguist-vendored
linker.ld linguist-vendored
build.bat linguist-vendored
clean.bat linguist-vendored
uf2conv.py linguist-vendored

10
drivers/0x01_uart_cbm/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
# Build artifacts
*.o
*.elf
*.bin
*.uf2
compile_commands.json
# OS files
.DS_Store
Thumbs.db

View File

@@ -0,0 +1,25 @@
{
"configurations": [
{
"name": "ARM GCC",
"includePath": [
"${workspaceFolder}/**"
],
"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
}

View File

@@ -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"
]
}

View File

@@ -0,0 +1,37 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug RP2350 (OpenOCD)",
"cwd": "${workspaceFolder}",
"executable": "${workspaceFolder}/uart.elf",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"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",
"device": "RP2350",
"configFiles": [
"interface/cmsis-dap.cfg",
"target/rp2350.cfg"
],
"svdFile": "${env:USERPROFILE}/.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"
}
]
}

View File

@@ -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"
}

107
drivers/0x01_uart_cbm/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,107 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Compile Project",
"type": "shell",
"command": ".\\build.bat",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"problemMatcher": "$gcc"
},
{
"label": "Clean Project",
"type": "shell",
"command": ".\\clean.bat",
"group": "build",
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"problemMatcher": []
},
{
"label": "Run Project",
"type": "shell",
"command": "${env:USERPROFILE}/.pico-sdk/picotool/2.2.0-a4/picotool/picotool.exe",
"args": [
"load",
"uart.uf2",
"-fx"
],
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"problemMatcher": [],
"dependsOn": ["Compile Project"]
},
{
"label": "Flash",
"type": "shell",
"command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
"args": [
"-s",
"${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/scripts",
"-f",
"interface/cmsis-dap.cfg",
"-f",
"target/rp2350.cfg",
"-c",
"adapter speed 5000; program uart.elf verify reset exit"
],
"problemMatcher": [],
"dependsOn": ["Compile Project"]
},
{
"label": "Rescue Reset",
"type": "process",
"command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
"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.exe",
"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"
}
}
]
}

97
drivers/0x01_uart_cbm/build.bat vendored Normal file
View File

@@ -0,0 +1,97 @@
@echo off
REM ==============================================================================
REM FILE: build.bat
REM
REM DESCRIPTION:
REM Build script for RP2350 bare-metal C UART driver.
REM
REM BRIEF:
REM Automates the process of compiling, linking, and generating UF2 firmware.
REM
REM AUTHOR: Kevin Thomas
REM CREATION DATE: 2025
REM UPDATE DATE: 2025
REM ==============================================================================
echo Building C bare-metal version...
REM ==============================================================================
REM Compile C Source Files
REM ==============================================================================
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c vector_table.c -o vector_table.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c reset_handler.c -o reset_handler.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c stack.c -o stack.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c xosc.c -o xosc.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c reset.c -o reset.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c coprocessor.c -o coprocessor.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c uart.c -o uart.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c delay.c -o delay.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c main.c -o main.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c image_def.c -o image_def.o
if errorlevel 1 goto error
REM ==============================================================================
REM Link Object Files
REM ==============================================================================
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -T linker.ld -nostdlib -Wl,--gc-sections vector_table.o reset_handler.o stack.o xosc.o reset.o coprocessor.o uart.o delay.o main.o image_def.o -o uart.elf
if errorlevel 1 goto error
REM ==============================================================================
REM Create Raw Binary from ELF
REM ==============================================================================
arm-none-eabi-objcopy -O binary uart.elf uart.bin
if errorlevel 1 goto error
REM ==============================================================================
REM Create UF2 Image for RP2350
REM -b 0x10000000 : base address
REM -f 0xe48bff59 : RP2350 family ID
REM ==============================================================================
python uf2conv.py -b 0x10000000 -f 0xe48bff59 -o uart.uf2 uart.bin
if errorlevel 1 goto error
REM ==============================================================================
REM Success Message and Flashing Instructions
REM ==============================================================================
echo.
echo =================================
echo SUCCESS! Created uart.uf2
echo =================================
echo.
echo To flash via UF2:
echo 1. Hold BOOTSEL button
echo 2. Plug in USB
echo 3. Copy uart.uf2 to RP2350 drive
echo.
echo To flash via OpenOCD (debug probe):
echo openocd -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000" -c "program uart.elf verify reset exit"
echo.
goto end
REM ==============================================================================
REM Error Handling
REM ==============================================================================
:error
echo.
echo BUILD FAILED!
echo.
:end

30
drivers/0x01_uart_cbm/clean.bat vendored Normal file
View File

@@ -0,0 +1,30 @@
@echo off
REM ==============================================================================
REM FILE: clean.bat
REM
REM DESCRIPTION:
REM Clean script for RP2350 bare-metal C UART driver.
REM
REM BRIEF:
REM Removes all build artifacts and generated files.
REM
REM AUTHOR: Kevin Thomas
REM CREATION DATE: 2025
REM UPDATE DATE: 2025
REM ==============================================================================
echo Cleaning build artifacts...
REM Remove object files
if exist *.o del /Q *.o
REM Remove ELF file
if exist uart.elf del /Q uart.elf
REM Remove binary file
if exist uart.bin del /Q uart.bin
REM Remove UF2 file
if exist uart.uf2 del /Q uart.uf2
echo Clean complete!

View File

@@ -0,0 +1,195 @@
/**
* @file constants.h
* @brief Memory-mapped register structures and peripheral base addresses
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CONSTANTS_H
#define CONSTANTS_H
#include <stdint.h>
/**
* Stack addresses.
*/
#define STACK_TOP 0x20082000U
#define STACK_LIMIT 0x2007A000U
/**
* XOSC (External Crystal Oscillator) Register Structure.
*/
typedef struct {
volatile uint32_t CTRL; /**< 0x00: Control register */
volatile uint32_t STATUS; /**< 0x04: Status register */
volatile uint32_t DORMANT; /**< 0x08: Dormant mode */
volatile uint32_t STARTUP; /**< 0x0C: Startup delay */
volatile uint32_t RESERVED[3]; /**< 0x10-0x18: Reserved */
volatile uint32_t COUNT; /**< 0x1C: Frequency count */
} xosc_hw_t;
/**
* XOSC base address and pointer.
*/
#define XOSC_BASE 0x40048000U
#define XOSC ((xosc_hw_t *)XOSC_BASE)
/**
* XOSC status bit definitions.
*/
#define XOSC_STATUS_STABLE_SHIFT 31U
/**
* CPACR (Coprocessor Access Control Register) in PPB.
*/
#define PPB_BASE 0xE0000000U
#define CPACR ((volatile uint32_t *)(PPB_BASE + 0x0ED88U))
/**
* Coprocessor access control bit definitions.
*/
#define CPACR_CP0_SHIFT 0U
#define CPACR_CP1_SHIFT 1U
/**
* CLOCKS Register Structure.
*/
typedef struct {
volatile uint32_t RESERVED0[18]; /**< 0x00-0x44: Other clock registers */
volatile uint32_t CLK_PERI_CTRL; /**< 0x48: Peripheral clock control */
} clocks_hw_t;
/**
* CLOCKS base address and pointer.
*/
#define CLOCKS_BASE 0x40010000U
#define CLOCKS ((clocks_hw_t *)CLOCKS_BASE)
/**
* Clock control bit definitions.
*/
#define CLOCKS_CLK_PERI_CTRL_ENABLE_SHIFT 11U
#define CLOCKS_CLK_PERI_CTRL_AUXSRC_SHIFT 5U
#define CLOCKS_CLK_PERI_CTRL_AUXSRC_XOSC 4U
/**
* RESETS Register Structure.
*/
typedef struct {
volatile uint32_t RESET; /**< 0x00: Reset control */
volatile uint32_t WDSEL; /**< 0x04: Watchdog select */
volatile uint32_t RESET_DONE; /**< 0x08: Reset done status */
} resets_hw_t;
/**
* RESETS base address and pointer.
*/
#define RESETS_BASE 0x40020000U
#define RESETS ((resets_hw_t *)RESETS_BASE)
#define RESETS_RESET_CLEAR ((volatile uint32_t *)(RESETS_BASE + 0x3000U))
/**
* Reset control bit definitions.
*/
#define RESETS_RESET_IO_BANK0_SHIFT 6U
#define RESETS_RESET_UART0_SHIFT 26U
/**
* IO_BANK0 GPIO Control Register (one per GPIO).
*/
typedef struct {
volatile uint32_t STATUS; /**< 0x00: GPIO status */
volatile uint32_t CTRL; /**< 0x04: GPIO control */
} io_bank0_gpio_ctrl_t;
/**
* IO_BANK0 Register Structure.
*/
typedef struct {
io_bank0_gpio_ctrl_t GPIO[30]; /**< 0x000-0x0E8: GPIO 0-29 */
} io_bank0_hw_t;
/**
* IO_BANK0 base address and pointer.
*/
#define IO_BANK0_BASE 0x40028000U
#define IO_BANK0 ((io_bank0_hw_t *)IO_BANK0_BASE)
/**
* GPIO control bit definitions.
*/
#define IO_BANK0_CTRL_FUNCSEL_MASK 0x1FU
#define IO_BANK0_CTRL_FUNCSEL_UART 0x02U
#define IO_BANK0_CTRL_FUNCSEL_SIO 0x05U
/**
* PADS_BANK0 Register Structure.
*/
typedef struct {
volatile uint32_t VOLTAGE_SELECT; /**< 0x00: Voltage select */
volatile uint32_t GPIO[30]; /**< 0x04-0x78: GPIO 0-29 pad control */
} pads_bank0_hw_t;
/**
* PADS_BANK0 base address and pointer.
*/
#define PADS_BANK0_BASE 0x40038000U
#define PADS_BANK0 ((pads_bank0_hw_t *)PADS_BANK0_BASE)
/**
* Pad control bit definitions.
*/
#define PADS_BANK0_OD_SHIFT 7U
#define PADS_BANK0_IE_SHIFT 6U
#define PADS_BANK0_ISO_SHIFT 8U
/**
* UART0 base address.
*/
#define UART0_BASE 0x40070000U
/**
* UART register offsets (as word indices from UART0_BASE).
*/
#define UART_DR_OFFSET (0x00U / 4U)
#define UART_FR_OFFSET (0x18U / 4U)
#define UART_IBRD_OFFSET (0x24U / 4U)
#define UART_FBRD_OFFSET (0x28U / 4U)
#define UART_LCR_H_OFFSET (0x2CU / 4U)
#define UART_CR_OFFSET (0x30U / 4U)
/**
* UART flag register bit definitions.
*/
#define UART_FR_TXFF_MASK 32U
#define UART_FR_RXFE_MASK 16U
/**
* UART line control and enable values.
*/
#define UART_LCR_H_8N1_FIFO 0x70U
#define UART_CR_ENABLE ((3U << 8) | 1U)
#endif // CONSTANTS_H

View File

@@ -0,0 +1,48 @@
/**
* @file coprocessor.c
* @brief Coprocessor access control enable functions
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "coprocessor.h"
#include "constants.h"
void Enable_Coprocessor(void) {
uint32_t value;
// read CPACR value
value = *CPACR;
// set CP1: Ctrl access priv coproc 1 bit
value |= (1U << CPACR_CP1_SHIFT);
// set CP0: Ctrl access priv coproc 0 bit
value |= (1U << CPACR_CP0_SHIFT);
// store value into CPACR
*CPACR = value;
// data sync barrier
__asm__ volatile ("dsb");
// instruction sync barrier
__asm__ volatile ("isb");
}

View File

@@ -0,0 +1,45 @@
/**
* @file coprocessor.h
* @brief Coprocessor access control enable functions
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef COPROCESSOR_H
#define COPROCESSOR_H
/**
* @brief Enable coprocessor access via CPACR
*
* Grants full access to coprocessors 0 and 1 by setting the
* corresponding bits in the Coprocessor Access Control Register,
* then issues DSB and ISB barriers.
*
* @param None
* @retval None
*/
void Enable_Coprocessor(void);
#endif // COPROCESSOR_H

View File

@@ -0,0 +1,46 @@
/**
* @file delay.c
* @brief Millisecond delay functions based on a 14.5 MHz clock
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "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"
);
}

View File

@@ -0,0 +1,45 @@
/**
* @file delay.h
* @brief Millisecond delay functions based on a 14.5 MHz clock
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef DELAY_H
#define DELAY_H
#include <stdint.h>
/**
* @brief Delay for the specified number of milliseconds
*
* Busy-waits using a calibrated loop count (3600 iterations per ms)
* based on a 14.5 MHz clock. Returns immediately if ms is zero.
*
* @param ms Number of milliseconds to delay
*/
void Delay_MS(uint32_t ms);
#endif // DELAY_H

View File

@@ -0,0 +1,48 @@
/**
* @file image_def.c
* @brief RP2350 IMAGE_DEF block for boot ROM image recognition
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdint.h>
/**
* IMAGE_DEF block structure placed in flash.
* Must appear within the first 4 KB for the boot ROM to accept the image.
*/
__attribute__((section(".embedded_block"), used))
const uint8_t picobin_block[] = {
// PICOBIN_BLOCK_MARKER_START (word: 0xffffded3)
0xD3, 0xDE, 0xFF, 0xFF,
// PICOBIN_BLOCK_ITEM_1BS_IMAGE_TYPE
0x42, 0x01, 0x21, 0x10,
// PICOBIN_BLOCK_ITEM_2BS_LAST
0xFF, 0x01, 0x00, 0x00,
// Relative pointer to next block (loop to self)
0x00, 0x00, 0x00, 0x00,
// PICOBIN_BLOCK_MARKER_END (word: 0xab123579)
0x79, 0x35, 0x12, 0xAB
};

106
drivers/0x01_uart_cbm/linker.ld vendored Normal file
View File

@@ -0,0 +1,106 @@
/**
* @file linker.ld
* @brief Minimal linker script for bare-metal RP2350 development
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
ENTRY(Reset_Handler)
/**
* Define memory regions.
*/
__XIP_BASE = 0x10000000;
__XIP_SIZE = 32M;
__SRAM_BASE = 0x20000000;
__SRAM_SIZE = 512K;
__STACK_SIZE = 32K;
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
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 (NOLOAD) : { . = ALIGN(8); } > RAM
PROVIDE(__Vectors = ADDR(.vectors));
}

View File

@@ -0,0 +1,78 @@
/**
* @file main.c
* @brief UART demonstration: echo received characters back in uppercase
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* -----------------------------------------------------------------------------
*
* Demonstrates bare-metal UART0 using the uart driver (uart.h / uart.c).
* Characters typed into a terminal via a USB-to-UART adapter are echoed
* back in uppercase, illustrating full-duplex raw UART operation at the
* register level without the Pico SDK.
*
* Wiring:
* GPIO0 (TX) -> USB-to-UART adapter RX
* GPIO1 (RX) -> USB-to-UART adapter TX
* GND -> USB-to-UART adapter GND
*/
#include "uart.h"
/**
* @brief Echo received characters back as uppercase
*
* @details Polls UART0 for incoming data. When a character is
* available, reads it, converts to uppercase, and echoes
* it back. Never returns.
*
* @param None
* @retval None
*/
static void _echo_uppercase(void) {
while (1) {
if (uart_driver_is_readable()) {
char c = uart_driver_getchar();
char upper = uart_driver_to_upper(c);
uart_driver_putchar(upper);
}
}
}
/**
* @brief Application entry point for the UART uppercase echo demo
*
* Prints two banner messages over UART0, then enters the echo loop.
* UART0 hardware initialization is performed by Reset_Handler before
* main() is called.
*
* @return int Does not return
*/
int main(void) {
uart_driver_puts("UART driver ready (115200 8N1)\r\n");
uart_driver_puts("Type characters to echo them back in UPPERCASE:\r\n");
_echo_uppercase();
return 0;
}

View File

@@ -0,0 +1,45 @@
/**
* @file reset.c
* @brief Reset controller functions for subsystem initialization
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "reset.h"
#include "constants.h"
void Init_Subsystem(void) {
uint32_t value;
// read RESETS->RESET value
value = RESETS->RESET;
// clear IO_BANK0 bit
value &= ~(1U << RESETS_RESET_IO_BANK0_SHIFT);
// store value into RESETS->RESET address
RESETS->RESET = value;
// wait until done
while ((RESETS->RESET_DONE & (1U << RESETS_RESET_IO_BANK0_SHIFT)) == 0) {
}
}

View File

@@ -0,0 +1,44 @@
/**
* @file reset.h
* @brief Reset controller functions for subsystem initialization
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef RESET_H
#define RESET_H
/**
* @brief Initialize the IO_BANK0 subsystem by clearing its reset bit
*
* Clears the IO_BANK0 reset bit in the Reset controller and waits
* until the RESET_DONE register confirms the block is out of reset.
*
* @param None
* @retval None
*/
void Init_Subsystem(void);
#endif // RESET_H

View File

@@ -0,0 +1,50 @@
/**
* @file reset_handler.c
* @brief Reset handler entry point after power-on or system reset
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "reset_handler.h"
#include "stack.h"
#include "xosc.h"
#include "reset.h"
#include "uart.h"
#include "coprocessor.h"
extern int main(void);
void __attribute__((naked, noreturn)) Reset_Handler(void) {
__asm__ volatile (
"bl Init_Stack\n\t"
"bl Init_XOSC\n\t"
"bl Enable_XOSC_Peri_Clock\n\t"
"bl Init_Subsystem\n\t"
"bl UART_Release_Reset\n\t"
"bl UART_Init\n\t"
"bl Enable_Coprocessor\n\t"
"b main\n\t"
);
}

View File

@@ -0,0 +1,45 @@
/**
* @file reset_handler.h
* @brief Reset handler entry point after power-on or system reset
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef RESET_HANDLER_H
#define RESET_HANDLER_H
/**
* @brief Reset handler for the RP2350
*
* Entry point after reset. Performs stack initialization, XOSC setup,
* subsystem reset release, UART initialization, coprocessor enable,
* and branches to main().
*
* @param None
* @retval None
*/
void Reset_Handler(void) __attribute__((noreturn));
#endif // RESET_HANDLER_H

View File

@@ -0,0 +1,46 @@
/**
* @file stack.c
* @brief Stack pointer initialization for MSP/PSP and their limits
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "stack.h"
#include "constants.h"
void Init_Stack(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"
);
}

View File

@@ -0,0 +1,44 @@
/**
* @file stack.h
* @brief Stack pointer initialization for MSP/PSP and their limits
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef STACK_H
#define STACK_H
/**
* @brief Initialize stack pointers
*
* Sets Main and Process Stack Pointers (MSP/PSP) and their limits
* using the STACK_TOP and STACK_LIMIT values from constants.h.
*
* @param None
* @retval None
*/
void Init_Stack(void);
#endif // STACK_H

View File

@@ -0,0 +1,165 @@
/**
* @file uart.c
* @brief Implementation of the bare-metal UART0 driver
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "uart.h"
#include "constants.h"
#define UART_BASE ((volatile uint32_t *)UART0_BASE)
/**
* @brief Clear the UART0 reset bit in the reset controller
*
* @details Reads RESETS->RESET, clears bit 26 (UART0), and writes
* the value back.
*
* @param None
* @retval None
*/
static void _uart_clear_reset_bit(void) {
uint32_t value;
// read RESETS->RESET value
value = RESETS->RESET;
// clear UART0 reset bit (bit 26)
value &= ~(1U << RESETS_RESET_UART0_SHIFT);
// write value back to RESETS->RESET
RESETS->RESET = value;
}
/**
* @brief Wait until the UART0 block is out of reset
*
* @details Polls RESETS->RESET_DONE until bit 26 (UART0) is set.
*
* @param None
* @retval None
*/
static void _uart_wait_reset_done(void) {
// loop until UART0 is out of reset
while ((RESETS->RESET_DONE & (1U << RESETS_RESET_UART0_SHIFT)) == 0) {
}
}
/**
* @brief Configure GPIO pins 0 (TX) and 1 (RX) for UART function
*
* @details Sets IO_BANK0 FUNCSEL to UART (0x02) for both pins and
* programs the corresponding pad controls.
*
* @param None
* @retval None
*/
static void _uart_configure_pins(void) {
// FUNCSEL = 2 -> select UART function
IO_BANK0->GPIO[0].CTRL = IO_BANK0_CTRL_FUNCSEL_UART;
IO_BANK0->GPIO[1].CTRL = IO_BANK0_CTRL_FUNCSEL_UART;
// pad config value for TX (pull/func recommended)
PADS_BANK0->GPIO[0] = 0x04;
// pad config value for RX (input enable)
PADS_BANK0->GPIO[1] = 0x40;
}
/**
* @brief Set UART0 baud rate divisors for 115200 baud at 14.5 MHz
*
* @details Programs UARTIBRD = 6 and UARTFBRD = 33 for the integer
* and fractional baud rate divisors respectively.
*
* @param None
* @retval None
*/
static void _uart_set_baud(void) {
// disable UART while configuring
UART_BASE[UART_CR_OFFSET] = 0;
// set integer baud divisor
UART_BASE[UART_IBRD_OFFSET] = 6;
// set fractional baud divisor
UART_BASE[UART_FBRD_OFFSET] = 33;
}
/**
* @brief Configure line control and enable UART0
*
* @details Sets 8-bit word length with FIFOs enabled, then enables
* UART0 with both TX and RX.
*
* @param None
* @retval None
*/
static void _uart_enable(void) {
// configure line control: FIFO enable + 8-bit
UART_BASE[UART_LCR_H_OFFSET] = UART_LCR_H_8N1_FIFO;
// enable UART with TX and RX enabled
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_driver_is_readable(void) {
// test bit 4, RX FIFO empty (RXFE)
return (UART_BASE[UART_FR_OFFSET] & UART_FR_RXFE_MASK) == 0;
}
char uart_driver_getchar(void) {
// wait for RX FIFO to be not empty
while (UART_BASE[UART_FR_OFFSET] & UART_FR_RXFE_MASK) {
}
// read data from UARTDR
return (char)(UART_BASE[UART_DR_OFFSET] & 0xFF);
}
void uart_driver_putchar(char c) {
// wait for TX FIFO to be not full
while (UART_BASE[UART_FR_OFFSET] & UART_FR_TXFF_MASK) {
}
// write data to UARTDR
UART_BASE[UART_DR_OFFSET] = (uint32_t)c;
}
void uart_driver_puts(const char *str) {
while (*str) {
uart_driver_putchar(*str++);
}
}
char uart_driver_to_upper(char c) {
if (c >= 'a' && c <= 'z') {
return (char)(c - 32);
}
return c;
}

View File

@@ -0,0 +1,111 @@
/**
* @file uart.h
* @brief Header for bare-metal UART0 driver (raw TX/RX, GPIO 0/1)
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef UART_H
#define UART_H
#include <stdint.h>
#include <stdbool.h>
/**
* @brief Release UART0 from reset and wait until it is ready
*
* Clears the UART0 reset bit in the Reset controller and polls
* RESET_DONE until the UART0 block is out of reset.
*
* @param None
* @retval None
*/
void UART_Release_Reset(void);
/**
* @brief Initialize UART0 (pins, baud divisors, line control, enable)
*
* Configures IO_BANK0 pins 0 (TX) and 1 (RX) to the UART function,
* programs pad controls, sets baud rate divisors (IBRD=6, FBRD=33
* for 115200 baud at 14.5 MHz), configures 8N1 with FIFOs, and
* enables UART0 with TX and RX.
*
* @param None
* @retval None
*/
void UART_Init(void);
/**
* @brief Check whether a received character is waiting in the UART FIFO
*
* Returns immediately without blocking. Use this to poll for incoming
* data before calling uart_driver_getchar().
*
* @return bool true if at least one byte is available, false otherwise
*/
bool uart_driver_is_readable(void);
/**
* @brief Read one character from UART0 (blocking)
*
* Blocks until a byte arrives in the receive FIFO, then returns it.
* Prefer pairing with uart_driver_is_readable() to avoid indefinite blocking.
*
* @return char The received character
*/
char uart_driver_getchar(void);
/**
* @brief Transmit one character over UART0 (blocking)
*
* Waits until the transmit FIFO has space, then writes the character
* to UARTDR.
*
* @param c Character to transmit
*/
void uart_driver_putchar(char c);
/**
* @brief Transmit a null-terminated string over UART0
*
* Calls uart_driver_putchar() for every character in the string up to
* and not including the null terminator.
*
* @param str Pointer to the null-terminated ASCII string to send
*/
void uart_driver_puts(const char *str);
/**
* @brief Convert a lowercase ASCII character to uppercase
*
* Returns the uppercase equivalent if the character is in 'a'-'z';
* all other characters are passed through unchanged.
*
* @param c Input character
* @return char Uppercase equivalent, or the original character
*/
char uart_driver_to_upper(char c);
#endif // UART_H

365
drivers/0x01_uart_cbm/uf2conv.py vendored Normal file
View File

@@ -0,0 +1,365 @@
#!/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("<II", buf[0:8])
return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1
def is_hex(buf):
try:
w = buf[0:30].decode("utf-8")
except UnicodeDecodeError:
return False
if w[0] == ':' and re.match(rb"^[:0-9a-fA-F\r\n]+$", buf):
return True
return False
def convert_from_uf2(buf):
global appstartaddr
global familyid
numblocks = len(buf) // 512
curraddr = None
currfamilyid = None
families_found = {}
prev_flag = None
all_flags_same = True
outp = []
for blockno in range(numblocks):
ptr = blockno * 512
block = buf[ptr:ptr + 512]
hd = struct.unpack(b"<IIIIIIII", block[0:32])
if hd[0] != UF2_MAGIC_START0 or hd[1] != UF2_MAGIC_START1:
print("Skipping block at " + ptr + "; bad magic")
continue
if hd[2] & 1:
# NO-flash flag set; skip block
continue
datalen = hd[4]
if datalen > 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"<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
flags, ptr + appstartaddr, 256, blockno, numblocks, familyid)
while len(chunk) < 256:
chunk += b"\x00"
block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END)
assert len(block) == 512
outp.append(block)
return b"".join(outp)
class Block:
def __init__(self, addr, default_data=0xFF):
self.addr = addr
self.bytes = bytearray([default_data] * 256)
def encode(self, blockno, numblocks):
global familyid
flags = 0x0
if familyid:
flags |= 0x2000
hd = struct.pack("<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
flags, self.addr, 256, blockno, numblocks, familyid)
hd += self.bytes[0:256]
while len(hd) < 512 - 4:
hd += b"\x00"
hd += struct.pack("<I", UF2_MAGIC_END)
return hd
def convert_from_hex_to_uf2(buf):
global appstartaddr
appstartaddr = None
upper = 0
currblock = None
blocks = []
for line in buf.split('\n'):
if line[0] != ":":
continue
i = 1
rec = []
while i < len(line) - 1:
rec.append(int(line[i:i+2], 16))
i += 2
tp = rec[3]
if tp == 4:
upper = ((rec[4] << 8) | rec[5]) << 16
elif tp == 2:
upper = ((rec[4] << 8) | rec[5]) << 4
elif tp == 1:
break
elif tp == 0:
addr = upper + ((rec[1] << 8) | rec[2])
if appstartaddr == None:
appstartaddr = addr
i = 4
while i < len(rec) - 1:
if not currblock or currblock.addr & ~0xff != addr & ~0xff:
currblock = Block(addr & ~0xff)
blocks.append(currblock)
currblock.bytes[addr & 0xff] = rec[i]
addr += 1
i += 1
numblocks = len(blocks)
resfile = b""
for i in range(0, numblocks):
resfile += blocks[i].encode(i, numblocks)
return resfile
def to_str(b):
return b.decode("utf-8")
def get_drives():
drives = []
if sys.platform == "win32":
r = subprocess.check_output([
"powershell",
"-Command",
'(Get-WmiObject Win32_LogicalDisk -Filter "VolumeName=\'RPI-RP2\'").DeviceID'
])
drive = to_str(r).strip()
if drive:
drives.append(drive)
else:
searchpaths = ["/mnt", "/media"]
if sys.platform == "darwin":
searchpaths = ["/Volumes"]
elif sys.platform == "linux":
searchpaths += ["/media/" + os.environ["USER"], "/run/media/" + os.environ["USER"]]
if "SUDO_USER" in os.environ.keys():
searchpaths += ["/media/" + os.environ["SUDO_USER"]]
searchpaths += ["/run/media/" + os.environ["SUDO_USER"]]
for rootpath in searchpaths:
if os.path.isdir(rootpath):
for d in os.listdir(rootpath):
if os.path.isdir(os.path.join(rootpath, d)):
drives.append(os.path.join(rootpath, d))
def has_info(d):
try:
return os.path.isfile(d + INFO_FILE)
except:
return False
return list(filter(has_info, drives))
def board_id(path):
with open(path + INFO_FILE, mode='r') as file:
file_content = file.read()
return re.search(r"Board-ID: ([^\r\n]*)", file_content).group(1)
def list_drives():
for d in get_drives():
print(d, board_id(d))
def write_file(name, buf):
with open(name, "wb") as f:
f.write(buf)
print("Wrote %d bytes to %s" % (len(buf), name))
def load_families():
# The expectation is that the `uf2families.json` file is in the same
# directory as this script. Make a path that works using `__file__`
# which contains the full path to this script.
filename = "uf2families.json"
pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename)
with open(pathname) as f:
raw_families = json.load(f)
families = {}
for family in raw_families:
families[family["short_name"]] = int(family["id"], 0)
return families
def main():
global appstartaddr, familyid
def error(msg):
print(msg, file=sys.stderr)
sys.exit(1)
parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.')
parser.add_argument('input', metavar='INPUT', type=str, nargs='?',
help='input file (HEX, BIN or UF2)')
parser.add_argument('-b', '--base', dest='base', type=str,
default="0x2000",
help='set base address of application for BIN format (default: 0x2000)')
parser.add_argument('-f', '--family', dest='family', type=str,
default="0x0",
help='specify familyID - number or name (default: 0x0)')
parser.add_argument('-o', '--output', metavar="FILE", dest='output', type=str,
help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible')
parser.add_argument('-d', '--device', dest="device_path",
help='select a device path to flash')
parser.add_argument('-l', '--list', action='store_true',
help='list connected devices')
parser.add_argument('-c', '--convert', action='store_true',
help='do not flash, just convert')
parser.add_argument('-D', '--deploy', action='store_true',
help='just flash, do not convert')
parser.add_argument('-w', '--wait', action='store_true',
help='wait for device to flash')
parser.add_argument('-C', '--carray', action='store_true',
help='convert binary file to a C array, not UF2')
parser.add_argument('-i', '--info', action='store_true',
help='display header information from UF2, do not convert')
args = parser.parse_args()
appstartaddr = int(args.base, 0)
families = load_families()
if args.family.upper() in families:
familyid = families[args.family.upper()]
else:
try:
familyid = int(args.family, 0)
except ValueError:
error("Family ID needs to be a number or one of: " + ", ".join(families.keys()))
if args.list:
list_drives()
else:
if not args.input:
error("Need input file")
with open(args.input, mode='rb') as f:
inpbuf = f.read()
from_uf2 = is_uf2(inpbuf)
ext = "uf2"
if args.deploy:
outbuf = inpbuf
elif from_uf2 and not args.info:
outbuf = convert_from_uf2(inpbuf)
ext = "bin"
elif from_uf2 and args.info:
outbuf = ""
convert_from_uf2(inpbuf)
elif is_hex(inpbuf):
outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8"))
elif args.carray:
outbuf = convert_to_carray(inpbuf)
ext = "h"
else:
outbuf = convert_to_uf2(inpbuf)
if not args.deploy and not args.info:
print("Converted to %s, output size: %d, start address: 0x%x" %
(ext, len(outbuf), appstartaddr))
if args.convert or ext != "uf2":
if args.output == None:
args.output = "flash." + ext
if args.output:
write_file(args.output, outbuf)
if ext == "uf2" and not args.convert and not args.info:
drives = get_drives()
if len(drives) == 0:
if args.wait:
print("Waiting for drive to deploy...")
while len(drives) == 0:
sleep(0.1)
drives = get_drives()
elif not args.output:
error("No drive to deploy.")
for d in drives:
print("Flashing %s (%s)" % (d, board_id(d)))
write_file(d + "/NEW.UF2", outbuf)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,22 @@
[
{
"short_name": "RP2040",
"id": "0xe48bff56",
"description": "Raspberry Pi RP2040"
},
{
"short_name": "RP2350-ARM-S",
"id": "0xe48bff59",
"description": "Raspberry Pi RP2350, ARM, Secure"
},
{
"short_name": "RP2350-ARM-NS",
"id": "0xe48bff5a",
"description": "Raspberry Pi RP2350, ARM, Non-Secure"
},
{
"short_name": "RP2350-RISCV",
"id": "0xe48bff5b",
"description": "Raspberry Pi RP2350, RISC-V"
}
]

View File

@@ -0,0 +1,46 @@
/**
* @file vector_table.c
* @brief Vector table with initial stack pointer and reset handler
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdint.h>
extern uint32_t _stack_top;
extern void Reset_Handler(void);
typedef void (*vector_func_t)(void);
/**
* Vector table placed in .vectors section.
* The Thumb bit (bit 0 = 1) is automatically set by the linker
* for function pointers in Thumb mode.
*/
__attribute__((section(".vectors"), used))
const void *_vectors[2] = {
&_stack_top,
Reset_Handler
};

View File

@@ -0,0 +1,54 @@
/**
* @file xosc.c
* @brief External crystal oscillator (XOSC) initialization and clock enable
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "xosc.h"
#include "constants.h"
void Init_XOSC(void) {
// set delay 50,000 cycles
XOSC->STARTUP = 0x00C4U;
// set 1_15MHz, freq range, actual 14.5MHz
XOSC->CTRL = 0x00FABAA0U;
// wait until stable bit is set
while ((XOSC->STATUS & (1U << XOSC_STATUS_STABLE_SHIFT)) == 0) {
}
}
void Enable_XOSC_Peri_Clock(void) {
uint32_t value;
// read CLK_PERI_CTRL value
value = CLOCKS->CLK_PERI_CTRL;
// set ENABLE bit
value |= (1U << CLOCKS_CLK_PERI_CTRL_ENABLE_SHIFT);
// set AUXSRC: XOSC_CLKSRC
value |= (CLOCKS_CLK_PERI_CTRL_AUXSRC_XOSC << CLOCKS_CLK_PERI_CTRL_AUXSRC_SHIFT);
// store value into CLK_PERI_CTRL
CLOCKS->CLK_PERI_CTRL = value;
}

View File

@@ -0,0 +1,55 @@
/**
* @file xosc.h
* @brief External crystal oscillator (XOSC) initialization and clock enable
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef XOSC_H
#define XOSC_H
/**
* @brief Initialize the external crystal oscillator and wait until stable
*
* Configures the XOSC startup delay and frequency range, then polls
* the status register until the STABLE bit is set.
*
* @param None
* @retval None
*/
void Init_XOSC(void);
/**
* @brief Enable the XOSC peripheral clock
*
* Sets the peripheral clock to use XOSC as its auxiliary source and
* enables it via CLK_PERI_CTRL.
*
* @param None
* @retval None
*/
void Enable_XOSC_Peri_Clock(void);
#endif // XOSC_H

11
drivers/0x02_blink_cbm/.gitattributes vendored Normal file
View File

@@ -0,0 +1,11 @@
# C files
*.c linguist-language=C
# Exclude from language statistics
*.ld linguist-vendored
*.bat linguist-vendored
*.py linguist-vendored
linker.ld linguist-vendored
build.bat linguist-vendored
clean.bat linguist-vendored
uf2conv.py linguist-vendored

10
drivers/0x02_blink_cbm/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
# Build artifacts
*.o
*.elf
*.bin
*.uf2
compile_commands.json
# OS files
.DS_Store
Thumbs.db

View File

@@ -0,0 +1,25 @@
{
"configurations": [
{
"name": "ARM GCC",
"includePath": [
"${workspaceFolder}/**"
],
"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
}

View File

@@ -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"
]
}

View File

@@ -0,0 +1,37 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug RP2350 (OpenOCD)",
"cwd": "${workspaceFolder}",
"executable": "${workspaceFolder}/blink.elf",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"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",
"device": "RP2350",
"configFiles": [
"interface/cmsis-dap.cfg",
"target/rp2350.cfg"
],
"svdFile": "${env:USERPROFILE}/.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"
}
]
}

View File

@@ -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"
}

View File

@@ -0,0 +1,107 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Compile Project",
"type": "shell",
"command": ".\\build.bat",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"problemMatcher": "$gcc"
},
{
"label": "Clean Project",
"type": "shell",
"command": ".\\clean.bat",
"group": "build",
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"problemMatcher": []
},
{
"label": "Run Project",
"type": "shell",
"command": "${env:USERPROFILE}/.pico-sdk/picotool/2.2.0-a4/picotool/picotool.exe",
"args": [
"load",
"blink.uf2",
"-fx"
],
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"problemMatcher": [],
"dependsOn": ["Compile Project"]
},
{
"label": "Flash",
"type": "shell",
"command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
"args": [
"-s",
"${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/scripts",
"-f",
"interface/cmsis-dap.cfg",
"-f",
"target/rp2350.cfg",
"-c",
"adapter speed 5000; program blink.elf verify reset exit"
],
"problemMatcher": [],
"dependsOn": ["Compile Project"]
},
{
"label": "Rescue Reset",
"type": "process",
"command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
"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.exe",
"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"
}
}
]
}

View File

@@ -0,0 +1,52 @@
/**
* @file blink.c
* @brief Implementation of the GPIO output / LED blink driver
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "blink.h"
#include "gpio.h"
void blink_init(uint32_t pin) {
GPIO_Config(pin);
GPIO_Clear(pin);
}
void blink_on(uint32_t pin) {
GPIO_Set(pin);
}
void blink_off(uint32_t pin) {
GPIO_Clear(pin);
}
void blink_toggle(uint32_t pin) {
GPIO_Toggle(pin);
}
bool blink_get_state(uint32_t pin) {
return GPIO_Get(pin);
}

View File

@@ -0,0 +1,78 @@
/**
* @file blink.h
* @brief Header for GPIO output / LED blink driver
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef BLINK_H
#define BLINK_H
#include <stdint.h>
#include <stdbool.h>
/**
* @brief Initialize a GPIO pin as a push-pull digital output
*
* Configures the pad control, sets IO_BANK0 FUNCSEL to SIO, and
* enables the output driver. The initial drive level is low (LED off).
*
* @param pin GPIO pin number to configure as a digital output
*/
void blink_init(uint32_t pin);
/**
* @brief Drive the output pin high (LED on)
*
* @param pin GPIO pin number previously initialized with blink_init()
*/
void blink_on(uint32_t pin);
/**
* @brief Drive the output pin low (LED off)
*
* @param pin GPIO pin number previously initialized with blink_init()
*/
void blink_off(uint32_t pin);
/**
* @brief Toggle the current state of the output pin
*
* Reads the current GPIO output level and inverts it. If the LED was on
* it is turned off, and vice versa.
*
* @param pin GPIO pin number previously initialized with blink_init()
*/
void blink_toggle(uint32_t pin);
/**
* @brief Query the current drive state of the output pin
*
* @param pin GPIO pin number previously initialized with blink_init()
* @return bool true if the pin is driven high, false if driven low
*/
bool blink_get_state(uint32_t pin);
#endif // BLINK_H

103
drivers/0x02_blink_cbm/build.bat vendored Normal file
View File

@@ -0,0 +1,103 @@
@echo off
REM ==============================================================================
REM FILE: build.bat
REM
REM DESCRIPTION:
REM Build script for RP2350 bare-metal C Blink driver.
REM
REM BRIEF:
REM Automates the process of compiling, linking, and generating UF2 firmware.
REM
REM AUTHOR: Kevin Thomas
REM CREATION DATE: 2025
REM UPDATE DATE: 2025
REM ==============================================================================
echo Building C bare-metal version...
REM ==============================================================================
REM Compile C Source Files
REM ==============================================================================
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c vector_table.c -o vector_table.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c reset_handler.c -o reset_handler.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c stack.c -o stack.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c xosc.c -o xosc.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c reset.c -o reset.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c coprocessor.c -o coprocessor.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c uart.c -o uart.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c gpio.c -o gpio.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c blink.c -o blink.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c delay.c -o delay.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c main.c -o main.o
if errorlevel 1 goto error
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -Og -g3 -Wall -Wextra -ffunction-sections -fdata-sections -c image_def.c -o image_def.o
if errorlevel 1 goto error
REM ==============================================================================
REM Link Object Files
REM ==============================================================================
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -T linker.ld -nostdlib -Wl,--gc-sections vector_table.o reset_handler.o stack.o xosc.o reset.o coprocessor.o uart.o gpio.o blink.o delay.o main.o image_def.o -o blink.elf
if errorlevel 1 goto error
REM ==============================================================================
REM Create Raw Binary from ELF
REM ==============================================================================
arm-none-eabi-objcopy -O binary blink.elf blink.bin
if errorlevel 1 goto error
REM ==============================================================================
REM Create UF2 Image for RP2350
REM -b 0x10000000 : base address
REM -f 0xe48bff59 : RP2350 family ID
REM ==============================================================================
python uf2conv.py -b 0x10000000 -f 0xe48bff59 -o blink.uf2 blink.bin
if errorlevel 1 goto error
REM ==============================================================================
REM Success Message and Flashing Instructions
REM ==============================================================================
echo.
echo =================================
echo SUCCESS! Created blink.uf2
echo =================================
echo.
echo To flash via UF2:
echo 1. Hold BOOTSEL button
echo 2. Plug in USB
echo 3. Copy blink.uf2 to RP2350 drive
echo.
echo To flash via OpenOCD (debug probe):
echo openocd -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000" -c "program blink.elf verify reset exit"
echo.
goto end
REM ==============================================================================
REM Error Handling
REM ==============================================================================
:error
echo.
echo BUILD FAILED!
echo.
:end

30
drivers/0x02_blink_cbm/clean.bat vendored Normal file
View File

@@ -0,0 +1,30 @@
@echo off
REM ==============================================================================
REM FILE: clean.bat
REM
REM DESCRIPTION:
REM Clean script for RP2350 bare-metal C Blink driver.
REM
REM BRIEF:
REM Removes all build artifacts and generated files.
REM
REM AUTHOR: Kevin Thomas
REM CREATION DATE: 2025
REM UPDATE DATE: 2025
REM ==============================================================================
echo Cleaning build artifacts...
REM Remove object files
if exist *.o del /Q *.o
REM Remove ELF file
if exist blink.elf del /Q blink.elf
REM Remove binary file
if exist blink.bin del /Q blink.bin
REM Remove UF2 file
if exist blink.uf2 del /Q blink.uf2
echo Clean complete!

View File

@@ -0,0 +1,214 @@
/**
* @file constants.h
* @brief Memory-mapped register structures and peripheral base addresses
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CONSTANTS_H
#define CONSTANTS_H
#include <stdint.h>
/**
* Stack addresses.
*/
#define STACK_TOP 0x20082000U
#define STACK_LIMIT 0x2007A000U
/**
* XOSC (External Crystal Oscillator) Register Structure.
*/
typedef struct {
volatile uint32_t CTRL; /**< 0x00: Control register */
volatile uint32_t STATUS; /**< 0x04: Status register */
volatile uint32_t DORMANT; /**< 0x08: Dormant mode */
volatile uint32_t STARTUP; /**< 0x0C: Startup delay */
volatile uint32_t RESERVED[3]; /**< 0x10-0x18: Reserved */
volatile uint32_t COUNT; /**< 0x1C: Frequency count */
} xosc_hw_t;
/**
* XOSC base address and pointer.
*/
#define XOSC_BASE 0x40048000U
#define XOSC ((xosc_hw_t *)XOSC_BASE)
/**
* XOSC status bit definitions.
*/
#define XOSC_STATUS_STABLE_SHIFT 31U
/**
* CPACR (Coprocessor Access Control Register) in PPB.
*/
#define PPB_BASE 0xE0000000U
#define CPACR ((volatile uint32_t *)(PPB_BASE + 0x0ED88U))
/**
* Coprocessor access control bit definitions.
*/
#define CPACR_CP0_SHIFT 0U
#define CPACR_CP1_SHIFT 1U
/**
* CLOCKS Register Structure.
*/
typedef struct {
volatile uint32_t RESERVED0[18]; /**< 0x00-0x44: Other clock registers */
volatile uint32_t CLK_PERI_CTRL; /**< 0x48: Peripheral clock control */
} clocks_hw_t;
/**
* CLOCKS base address and pointer.
*/
#define CLOCKS_BASE 0x40010000U
#define CLOCKS ((clocks_hw_t *)CLOCKS_BASE)
/**
* Clock control bit definitions.
*/
#define CLOCKS_CLK_PERI_CTRL_ENABLE_SHIFT 11U
#define CLOCKS_CLK_PERI_CTRL_AUXSRC_SHIFT 5U
#define CLOCKS_CLK_PERI_CTRL_AUXSRC_XOSC 4U
/**
* RESETS Register Structure.
*/
typedef struct {
volatile uint32_t RESET; /**< 0x00: Reset control */
volatile uint32_t WDSEL; /**< 0x04: Watchdog select */
volatile uint32_t RESET_DONE; /**< 0x08: Reset done status */
} resets_hw_t;
/**
* RESETS base address and pointer.
*/
#define RESETS_BASE 0x40020000U
#define RESETS ((resets_hw_t *)RESETS_BASE)
#define RESETS_RESET_CLEAR ((volatile uint32_t *)(RESETS_BASE + 0x3000U))
/**
* Reset control bit definitions.
*/
#define RESETS_RESET_IO_BANK0_SHIFT 6U
#define RESETS_RESET_UART0_SHIFT 26U
/**
* IO_BANK0 GPIO Control Register (one per GPIO).
*/
typedef struct {
volatile uint32_t STATUS; /**< 0x00: GPIO status */
volatile uint32_t CTRL; /**< 0x04: GPIO control */
} io_bank0_gpio_ctrl_t;
/**
* IO_BANK0 Register Structure.
*/
typedef struct {
io_bank0_gpio_ctrl_t GPIO[30]; /**< 0x000-0x0E8: GPIO 0-29 */
} io_bank0_hw_t;
/**
* IO_BANK0 base address and pointer.
*/
#define IO_BANK0_BASE 0x40028000U
#define IO_BANK0 ((io_bank0_hw_t *)IO_BANK0_BASE)
/**
* GPIO control bit definitions.
*/
#define IO_BANK0_CTRL_FUNCSEL_MASK 0x1FU
#define IO_BANK0_CTRL_FUNCSEL_UART 0x02U
#define IO_BANK0_CTRL_FUNCSEL_SIO 0x05U
/**
* PADS_BANK0 Register Structure.
*/
typedef struct {
volatile uint32_t VOLTAGE_SELECT; /**< 0x00: Voltage select */
volatile uint32_t GPIO[30]; /**< 0x04-0x78: GPIO 0-29 pad control */
} pads_bank0_hw_t;
/**
* PADS_BANK0 base address and pointer.
*/
#define PADS_BANK0_BASE 0x40038000U
#define PADS_BANK0 ((pads_bank0_hw_t *)PADS_BANK0_BASE)
/**
* Pad control bit definitions.
*/
#define PADS_BANK0_OD_SHIFT 7U
#define PADS_BANK0_IE_SHIFT 6U
#define PADS_BANK0_ISO_SHIFT 8U
/**
* UART0 base address.
*/
#define UART0_BASE 0x40070000U
/**
* UART register offsets (as word indices from UART0_BASE).
*/
#define UART_DR_OFFSET (0x00U / 4U)
#define UART_FR_OFFSET (0x18U / 4U)
#define UART_IBRD_OFFSET (0x24U / 4U)
#define UART_FBRD_OFFSET (0x28U / 4U)
#define UART_LCR_H_OFFSET (0x2CU / 4U)
#define UART_CR_OFFSET (0x30U / 4U)
/**
* UART flag register bit definitions.
*/
#define UART_FR_TXFF_MASK 32U
#define UART_FR_RXFE_MASK 16U
/**
* UART line control and enable values.
*/
#define UART_LCR_H_8N1_FIFO 0x70U
#define UART_CR_ENABLE ((3U << 8) | 1U)
/**
* GPIO pin definitions.
*/
#define LED_PIN 25U
/**
* SIO (Single-cycle IO) base address.
*/
#define SIO_BASE 0xD0000000U
/**
* SIO GPIO output register offsets (as word indices).
*/
#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)
#define SIO_GPIO_IN_OFFSET (0x008U / 4U)
#endif // CONSTANTS_H

View File

@@ -0,0 +1,48 @@
/**
* @file coprocessor.c
* @brief Coprocessor access control enable functions
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "coprocessor.h"
#include "constants.h"
void Enable_Coprocessor(void) {
uint32_t value;
// read CPACR value
value = *CPACR;
// set CP1: Ctrl access priv coproc 1 bit
value |= (1U << CPACR_CP1_SHIFT);
// set CP0: Ctrl access priv coproc 0 bit
value |= (1U << CPACR_CP0_SHIFT);
// store value into CPACR
*CPACR = value;
// data sync barrier
__asm__ volatile ("dsb");
// instruction sync barrier
__asm__ volatile ("isb");
}

View File

@@ -0,0 +1,45 @@
/**
* @file coprocessor.h
* @brief Coprocessor access control enable functions
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef COPROCESSOR_H
#define COPROCESSOR_H
/**
* @brief Enable coprocessor access via CPACR
*
* Grants full access to coprocessors 0 and 1 by setting the
* corresponding bits in the Coprocessor Access Control Register,
* then issues DSB and ISB barriers.
*
* @param None
* @retval None
*/
void Enable_Coprocessor(void);
#endif // COPROCESSOR_H

View File

@@ -0,0 +1,46 @@
/**
* @file delay.c
* @brief Millisecond delay functions based on a 14.5 MHz clock
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "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"
);
}

View File

@@ -0,0 +1,45 @@
/**
* @file delay.h
* @brief Millisecond delay functions based on a 14.5 MHz clock
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef DELAY_H
#define DELAY_H
#include <stdint.h>
/**
* @brief Delay for the specified number of milliseconds
*
* Busy-waits using a calibrated loop count (3600 iterations per ms)
* based on a 14.5 MHz clock. Returns immediately if ms is zero.
*
* @param ms Number of milliseconds to delay
*/
void Delay_MS(uint32_t ms);
#endif // DELAY_H

View File

@@ -0,0 +1,111 @@
/**
* @file gpio.c
* @brief GPIO configuration, set, clear, toggle, and read functions
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "gpio.h"
#include "constants.h"
#define SIO ((volatile uint32_t *)SIO_BASE)
/**
* @brief Configure pad control for a GPIO pin
*
* @details Clears OD (output disable), sets IE (input enable), and
* clears ISO (isolation) in PADS_BANK0.
*
* @param gpio_num GPIO pin number (0-29)
*/
static void _gpio_config_pad(uint32_t gpio_num) {
uint32_t value;
// read PAD value
value = PADS_BANK0->GPIO[gpio_num];
// clear OD bit (output disable)
value &= ~(1U << PADS_BANK0_OD_SHIFT);
// set IE bit (input enable)
value |= (1U << PADS_BANK0_IE_SHIFT);
// clear ISO bit (isolate)
value &= ~(1U << PADS_BANK0_ISO_SHIFT);
// store value into PAD
PADS_BANK0->GPIO[gpio_num] = value;
}
/**
* @brief Set IO_BANK0 FUNCSEL to SIO for a GPIO pin
*
* @details Reads the control register, clears FUNCSEL bits, sets
* FUNCSEL to SIO (0x05), and writes back.
*
* @param gpio_num GPIO pin number (0-29)
*/
static void _gpio_config_funcsel(uint32_t gpio_num) {
uint32_t value;
// read CTRL value
value = IO_BANK0->GPIO[gpio_num].CTRL;
// clear FUNCSEL bits
value &= ~IO_BANK0_CTRL_FUNCSEL_MASK;
// set FUNCSEL to SIO (0x05)
value |= IO_BANK0_CTRL_FUNCSEL_SIO;
// store value into CTRL
IO_BANK0->GPIO[gpio_num].CTRL = value;
}
/**
* @brief Enable the output driver for a GPIO pin via SIO
*
* @details Sets the corresponding bit in the SIO output-enable set
* register.
*
* @param gpio_num GPIO pin number (0-29)
*/
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;
}

View File

@@ -0,0 +1,86 @@
/**
* @file gpio.h
* @brief GPIO configuration, set, clear, toggle, and read functions
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef GPIO_H
#define GPIO_H
#include <stdint.h>
#include <stdbool.h>
/**
* @brief Configure a GPIO pin as SIO output
*
* Configures the pad control (clear OD, set IE, clear ISO), sets
* IO_BANK0 FUNCSEL to SIO (0x05), and enables the output driver
* via the SIO output-enable set register.
*
* @param gpio_num GPIO pin number (0-29)
*/
void GPIO_Config(uint32_t gpio_num);
/**
* @brief Drive a GPIO output high
*
* Sets the specified bit in the SIO GPIO output set register.
*
* @param gpio_num GPIO pin number (0-29)
*/
void GPIO_Set(uint32_t gpio_num);
/**
* @brief Drive a GPIO output low
*
* Sets the specified bit in the SIO GPIO output clear register.
*
* @param gpio_num GPIO pin number (0-29)
*/
void GPIO_Clear(uint32_t gpio_num);
/**
* @brief Toggle a GPIO output
*
* Sets the specified bit in the SIO GPIO output XOR register,
* which inverts the current output level.
*
* @param gpio_num GPIO pin number (0-29)
*/
void GPIO_Toggle(uint32_t gpio_num);
/**
* @brief Read the current input level of a GPIO pin
*
* Reads the SIO GPIO input register and returns the state of the
* specified pin.
*
* @param gpio_num GPIO pin number (0-29)
* @return bool true if pin is high, false if low
*/
bool GPIO_Get(uint32_t gpio_num);
#endif // GPIO_H

View File

@@ -0,0 +1,48 @@
/**
* @file image_def.c
* @brief RP2350 IMAGE_DEF block for boot ROM image recognition
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdint.h>
/**
* IMAGE_DEF block structure placed in flash.
* Must appear within the first 4 KB for the boot ROM to accept the image.
*/
__attribute__((section(".embedded_block"), used))
const uint8_t picobin_block[] = {
// PICOBIN_BLOCK_MARKER_START (word: 0xffffded3)
0xD3, 0xDE, 0xFF, 0xFF,
// PICOBIN_BLOCK_ITEM_1BS_IMAGE_TYPE
0x42, 0x01, 0x21, 0x10,
// PICOBIN_BLOCK_ITEM_2BS_LAST
0xFF, 0x01, 0x00, 0x00,
// Relative pointer to next block (loop to self)
0x00, 0x00, 0x00, 0x00,
// PICOBIN_BLOCK_MARKER_END (word: 0xab123579)
0x79, 0x35, 0x12, 0xAB
};

106
drivers/0x02_blink_cbm/linker.ld vendored Normal file
View File

@@ -0,0 +1,106 @@
/**
* @file linker.ld
* @brief Minimal linker script for bare-metal RP2350 development
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
ENTRY(Reset_Handler)
/**
* Define memory regions.
*/
__XIP_BASE = 0x10000000;
__XIP_SIZE = 32M;
__SRAM_BASE = 0x20000000;
__SRAM_SIZE = 512K;
__STACK_SIZE = 32K;
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
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 (NOLOAD) : { . = ALIGN(8); } > RAM
PROVIDE(__Vectors = ADDR(.vectors));
}

View File

@@ -0,0 +1,78 @@
/**
* @file main.c
* @brief Blink demonstration: toggle onboard LED every 500 ms
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* -----------------------------------------------------------------------------
*
* Demonstrates GPIO output control using the blink driver (blink.h / blink.c).
* The onboard LED on GPIO 25 is toggled every BLINK_DELAY_MS milliseconds and
* the current state is reported over UART.
*
* Wiring:
* GPIO25 -> Onboard LED (no external wiring needed)
*/
#include "blink.h"
#include "uart.h"
#include "delay.h"
#include "constants.h"
#define BLINK_DELAY_MS 500
/**
* @brief Print the current LED state over UART
*
* @details Queries the blink driver for the pin state and prints
* "LED: ON\r\n" or "LED: OFF\r\n" over UART0.
*
* @param pin GPIO pin number to query
*/
static void _print_led_state(uint32_t pin) {
if (blink_get_state(pin)) {
uart_driver_puts("LED: ON\r\n");
} else {
uart_driver_puts("LED: OFF\r\n");
}
}
/**
* @brief Application entry point for the LED blink demo
*
* Initializes the onboard LED and enters an infinite loop that
* toggles the LED state every BLINK_DELAY_MS milliseconds.
*
* @return int Does not return
*/
int main(void) {
blink_init(LED_PIN);
uart_driver_puts("Blink driver initialized on GPIO 25\r\n");
while (1) {
blink_toggle(LED_PIN);
_print_led_state(LED_PIN);
Delay_MS(BLINK_DELAY_MS);
}
}

View File

@@ -0,0 +1,45 @@
/**
* @file reset.c
* @brief Reset controller functions for subsystem initialization
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "reset.h"
#include "constants.h"
void Init_Subsystem(void) {
uint32_t value;
// read RESETS->RESET value
value = RESETS->RESET;
// clear IO_BANK0 bit
value &= ~(1U << RESETS_RESET_IO_BANK0_SHIFT);
// store value into RESETS->RESET address
RESETS->RESET = value;
// wait until done
while ((RESETS->RESET_DONE & (1U << RESETS_RESET_IO_BANK0_SHIFT)) == 0) {
}
}

View File

@@ -0,0 +1,44 @@
/**
* @file reset.h
* @brief Reset controller functions for subsystem initialization
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef RESET_H
#define RESET_H
/**
* @brief Initialize the IO_BANK0 subsystem by clearing its reset bit
*
* Clears the IO_BANK0 reset bit in the Reset controller and waits
* until the RESET_DONE register confirms the block is out of reset.
*
* @param None
* @retval None
*/
void Init_Subsystem(void);
#endif // RESET_H

View File

@@ -0,0 +1,50 @@
/**
* @file reset_handler.c
* @brief Reset handler entry point after power-on or system reset
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "reset_handler.h"
#include "stack.h"
#include "xosc.h"
#include "reset.h"
#include "uart.h"
#include "coprocessor.h"
extern int main(void);
void __attribute__((naked, noreturn)) Reset_Handler(void) {
__asm__ volatile (
"bl Init_Stack\n\t"
"bl Init_XOSC\n\t"
"bl Enable_XOSC_Peri_Clock\n\t"
"bl Init_Subsystem\n\t"
"bl UART_Release_Reset\n\t"
"bl UART_Init\n\t"
"bl Enable_Coprocessor\n\t"
"b main\n\t"
);
}

View File

@@ -0,0 +1,45 @@
/**
* @file reset_handler.h
* @brief Reset handler entry point after power-on or system reset
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef RESET_HANDLER_H
#define RESET_HANDLER_H
/**
* @brief Reset handler for the RP2350
*
* Entry point after reset. Performs stack initialization, XOSC setup,
* subsystem reset release, UART initialization, coprocessor enable,
* and branches to main().
*
* @param None
* @retval None
*/
void Reset_Handler(void) __attribute__((noreturn));
#endif // RESET_HANDLER_H

View File

@@ -0,0 +1,46 @@
/**
* @file stack.c
* @brief Stack pointer initialization for MSP/PSP and their limits
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "stack.h"
#include "constants.h"
void Init_Stack(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"
);
}

View File

@@ -0,0 +1,44 @@
/**
* @file stack.h
* @brief Stack pointer initialization for MSP/PSP and their limits
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef STACK_H
#define STACK_H
/**
* @brief Initialize stack pointers
*
* Sets Main and Process Stack Pointers (MSP/PSP) and their limits
* using the STACK_TOP and STACK_LIMIT values from constants.h.
*
* @param None
* @retval None
*/
void Init_Stack(void);
#endif // STACK_H

View File

@@ -0,0 +1,165 @@
/**
* @file uart.c
* @brief Implementation of the bare-metal UART0 driver
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "uart.h"
#include "constants.h"
#define UART_BASE ((volatile uint32_t *)UART0_BASE)
/**
* @brief Clear the UART0 reset bit in the reset controller
*
* @details Reads RESETS->RESET, clears bit 26 (UART0), and writes
* the value back.
*
* @param None
* @retval None
*/
static void _uart_clear_reset_bit(void) {
uint32_t value;
// read RESETS->RESET value
value = RESETS->RESET;
// clear UART0 reset bit (bit 26)
value &= ~(1U << RESETS_RESET_UART0_SHIFT);
// write value back to RESETS->RESET
RESETS->RESET = value;
}
/**
* @brief Wait until the UART0 block is out of reset
*
* @details Polls RESETS->RESET_DONE until bit 26 (UART0) is set.
*
* @param None
* @retval None
*/
static void _uart_wait_reset_done(void) {
// loop until UART0 is out of reset
while ((RESETS->RESET_DONE & (1U << RESETS_RESET_UART0_SHIFT)) == 0) {
}
}
/**
* @brief Configure GPIO pins 0 (TX) and 1 (RX) for UART function
*
* @details Sets IO_BANK0 FUNCSEL to UART (0x02) for both pins and
* programs the corresponding pad controls.
*
* @param None
* @retval None
*/
static void _uart_configure_pins(void) {
// FUNCSEL = 2 -> select UART function
IO_BANK0->GPIO[0].CTRL = IO_BANK0_CTRL_FUNCSEL_UART;
IO_BANK0->GPIO[1].CTRL = IO_BANK0_CTRL_FUNCSEL_UART;
// pad config value for TX (pull/func recommended)
PADS_BANK0->GPIO[0] = 0x04;
// pad config value for RX (input enable)
PADS_BANK0->GPIO[1] = 0x40;
}
/**
* @brief Set UART0 baud rate divisors for 115200 baud at 14.5 MHz
*
* @details Programs UARTIBRD = 6 and UARTFBRD = 33 for the integer
* and fractional baud rate divisors respectively.
*
* @param None
* @retval None
*/
static void _uart_set_baud(void) {
// disable UART while configuring
UART_BASE[UART_CR_OFFSET] = 0;
// set integer baud divisor
UART_BASE[UART_IBRD_OFFSET] = 6;
// set fractional baud divisor
UART_BASE[UART_FBRD_OFFSET] = 33;
}
/**
* @brief Configure line control and enable UART0
*
* @details Sets 8-bit word length with FIFOs enabled, then enables
* UART0 with both TX and RX.
*
* @param None
* @retval None
*/
static void _uart_enable(void) {
// configure line control: FIFO enable + 8-bit
UART_BASE[UART_LCR_H_OFFSET] = UART_LCR_H_8N1_FIFO;
// enable UART with TX and RX enabled
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_driver_is_readable(void) {
// test bit 4, RX FIFO empty (RXFE)
return (UART_BASE[UART_FR_OFFSET] & UART_FR_RXFE_MASK) == 0;
}
char uart_driver_getchar(void) {
// wait for RX FIFO to be not empty
while (UART_BASE[UART_FR_OFFSET] & UART_FR_RXFE_MASK) {
}
// read data from UARTDR
return (char)(UART_BASE[UART_DR_OFFSET] & 0xFF);
}
void uart_driver_putchar(char c) {
// wait for TX FIFO to be not full
while (UART_BASE[UART_FR_OFFSET] & UART_FR_TXFF_MASK) {
}
// write data to UARTDR
UART_BASE[UART_DR_OFFSET] = (uint32_t)c;
}
void uart_driver_puts(const char *str) {
while (*str) {
uart_driver_putchar(*str++);
}
}
char uart_driver_to_upper(char c) {
if (c >= 'a' && c <= 'z') {
return (char)(c - 32);
}
return c;
}

View File

@@ -0,0 +1,111 @@
/**
* @file uart.h
* @brief Header for bare-metal UART0 driver (raw TX/RX, GPIO 0/1)
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef UART_H
#define UART_H
#include <stdint.h>
#include <stdbool.h>
/**
* @brief Release UART0 from reset and wait until it is ready
*
* Clears the UART0 reset bit in the Reset controller and polls
* RESET_DONE until the UART0 block is out of reset.
*
* @param None
* @retval None
*/
void UART_Release_Reset(void);
/**
* @brief Initialize UART0 (pins, baud divisors, line control, enable)
*
* Configures IO_BANK0 pins 0 (TX) and 1 (RX) to the UART function,
* programs pad controls, sets baud rate divisors (IBRD=6, FBRD=33
* for 115200 baud at 14.5 MHz), configures 8N1 with FIFOs, and
* enables UART0 with TX and RX.
*
* @param None
* @retval None
*/
void UART_Init(void);
/**
* @brief Check whether a received character is waiting in the UART FIFO
*
* Returns immediately without blocking. Use this to poll for incoming
* data before calling uart_driver_getchar().
*
* @return bool true if at least one byte is available, false otherwise
*/
bool uart_driver_is_readable(void);
/**
* @brief Read one character from UART0 (blocking)
*
* Blocks until a byte arrives in the receive FIFO, then returns it.
* Prefer pairing with uart_driver_is_readable() to avoid indefinite blocking.
*
* @return char The received character
*/
char uart_driver_getchar(void);
/**
* @brief Transmit one character over UART0 (blocking)
*
* Waits until the transmit FIFO has space, then writes the character
* to UARTDR.
*
* @param c Character to transmit
*/
void uart_driver_putchar(char c);
/**
* @brief Transmit a null-terminated string over UART0
*
* Calls uart_driver_putchar() for every character in the string up to
* and not including the null terminator.
*
* @param str Pointer to the null-terminated ASCII string to send
*/
void uart_driver_puts(const char *str);
/**
* @brief Convert a lowercase ASCII character to uppercase
*
* Returns the uppercase equivalent if the character is in 'a'-'z';
* all other characters are passed through unchanged.
*
* @param c Input character
* @return char Uppercase equivalent, or the original character
*/
char uart_driver_to_upper(char c);
#endif // UART_H

365
drivers/0x02_blink_cbm/uf2conv.py vendored Normal file
View File

@@ -0,0 +1,365 @@
#!/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("<II", buf[0:8])
return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1
def is_hex(buf):
try:
w = buf[0:30].decode("utf-8")
except UnicodeDecodeError:
return False
if w[0] == ':' and re.match(rb"^[:0-9a-fA-F\r\n]+$", buf):
return True
return False
def convert_from_uf2(buf):
global appstartaddr
global familyid
numblocks = len(buf) // 512
curraddr = None
currfamilyid = None
families_found = {}
prev_flag = None
all_flags_same = True
outp = []
for blockno in range(numblocks):
ptr = blockno * 512
block = buf[ptr:ptr + 512]
hd = struct.unpack(b"<IIIIIIII", block[0:32])
if hd[0] != UF2_MAGIC_START0 or hd[1] != UF2_MAGIC_START1:
print("Skipping block at " + ptr + "; bad magic")
continue
if hd[2] & 1:
# NO-flash flag set; skip block
continue
datalen = hd[4]
if datalen > 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"<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
flags, ptr + appstartaddr, 256, blockno, numblocks, familyid)
while len(chunk) < 256:
chunk += b"\x00"
block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END)
assert len(block) == 512
outp.append(block)
return b"".join(outp)
class Block:
def __init__(self, addr, default_data=0xFF):
self.addr = addr
self.bytes = bytearray([default_data] * 256)
def encode(self, blockno, numblocks):
global familyid
flags = 0x0
if familyid:
flags |= 0x2000
hd = struct.pack("<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
flags, self.addr, 256, blockno, numblocks, familyid)
hd += self.bytes[0:256]
while len(hd) < 512 - 4:
hd += b"\x00"
hd += struct.pack("<I", UF2_MAGIC_END)
return hd
def convert_from_hex_to_uf2(buf):
global appstartaddr
appstartaddr = None
upper = 0
currblock = None
blocks = []
for line in buf.split('\n'):
if line[0] != ":":
continue
i = 1
rec = []
while i < len(line) - 1:
rec.append(int(line[i:i+2], 16))
i += 2
tp = rec[3]
if tp == 4:
upper = ((rec[4] << 8) | rec[5]) << 16
elif tp == 2:
upper = ((rec[4] << 8) | rec[5]) << 4
elif tp == 1:
break
elif tp == 0:
addr = upper + ((rec[1] << 8) | rec[2])
if appstartaddr == None:
appstartaddr = addr
i = 4
while i < len(rec) - 1:
if not currblock or currblock.addr & ~0xff != addr & ~0xff:
currblock = Block(addr & ~0xff)
blocks.append(currblock)
currblock.bytes[addr & 0xff] = rec[i]
addr += 1
i += 1
numblocks = len(blocks)
resfile = b""
for i in range(0, numblocks):
resfile += blocks[i].encode(i, numblocks)
return resfile
def to_str(b):
return b.decode("utf-8")
def get_drives():
drives = []
if sys.platform == "win32":
r = subprocess.check_output([
"powershell",
"-Command",
'(Get-WmiObject Win32_LogicalDisk -Filter "VolumeName=\'RPI-RP2\'").DeviceID'
])
drive = to_str(r).strip()
if drive:
drives.append(drive)
else:
searchpaths = ["/mnt", "/media"]
if sys.platform == "darwin":
searchpaths = ["/Volumes"]
elif sys.platform == "linux":
searchpaths += ["/media/" + os.environ["USER"], "/run/media/" + os.environ["USER"]]
if "SUDO_USER" in os.environ.keys():
searchpaths += ["/media/" + os.environ["SUDO_USER"]]
searchpaths += ["/run/media/" + os.environ["SUDO_USER"]]
for rootpath in searchpaths:
if os.path.isdir(rootpath):
for d in os.listdir(rootpath):
if os.path.isdir(os.path.join(rootpath, d)):
drives.append(os.path.join(rootpath, d))
def has_info(d):
try:
return os.path.isfile(d + INFO_FILE)
except:
return False
return list(filter(has_info, drives))
def board_id(path):
with open(path + INFO_FILE, mode='r') as file:
file_content = file.read()
return re.search(r"Board-ID: ([^\r\n]*)", file_content).group(1)
def list_drives():
for d in get_drives():
print(d, board_id(d))
def write_file(name, buf):
with open(name, "wb") as f:
f.write(buf)
print("Wrote %d bytes to %s" % (len(buf), name))
def load_families():
# The expectation is that the `uf2families.json` file is in the same
# directory as this script. Make a path that works using `__file__`
# which contains the full path to this script.
filename = "uf2families.json"
pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename)
with open(pathname) as f:
raw_families = json.load(f)
families = {}
for family in raw_families:
families[family["short_name"]] = int(family["id"], 0)
return families
def main():
global appstartaddr, familyid
def error(msg):
print(msg, file=sys.stderr)
sys.exit(1)
parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.')
parser.add_argument('input', metavar='INPUT', type=str, nargs='?',
help='input file (HEX, BIN or UF2)')
parser.add_argument('-b', '--base', dest='base', type=str,
default="0x2000",
help='set base address of application for BIN format (default: 0x2000)')
parser.add_argument('-f', '--family', dest='family', type=str,
default="0x0",
help='specify familyID - number or name (default: 0x0)')
parser.add_argument('-o', '--output', metavar="FILE", dest='output', type=str,
help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible')
parser.add_argument('-d', '--device', dest="device_path",
help='select a device path to flash')
parser.add_argument('-l', '--list', action='store_true',
help='list connected devices')
parser.add_argument('-c', '--convert', action='store_true',
help='do not flash, just convert')
parser.add_argument('-D', '--deploy', action='store_true',
help='just flash, do not convert')
parser.add_argument('-w', '--wait', action='store_true',
help='wait for device to flash')
parser.add_argument('-C', '--carray', action='store_true',
help='convert binary file to a C array, not UF2')
parser.add_argument('-i', '--info', action='store_true',
help='display header information from UF2, do not convert')
args = parser.parse_args()
appstartaddr = int(args.base, 0)
families = load_families()
if args.family.upper() in families:
familyid = families[args.family.upper()]
else:
try:
familyid = int(args.family, 0)
except ValueError:
error("Family ID needs to be a number or one of: " + ", ".join(families.keys()))
if args.list:
list_drives()
else:
if not args.input:
error("Need input file")
with open(args.input, mode='rb') as f:
inpbuf = f.read()
from_uf2 = is_uf2(inpbuf)
ext = "uf2"
if args.deploy:
outbuf = inpbuf
elif from_uf2 and not args.info:
outbuf = convert_from_uf2(inpbuf)
ext = "bin"
elif from_uf2 and args.info:
outbuf = ""
convert_from_uf2(inpbuf)
elif is_hex(inpbuf):
outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8"))
elif args.carray:
outbuf = convert_to_carray(inpbuf)
ext = "h"
else:
outbuf = convert_to_uf2(inpbuf)
if not args.deploy and not args.info:
print("Converted to %s, output size: %d, start address: 0x%x" %
(ext, len(outbuf), appstartaddr))
if args.convert or ext != "uf2":
if args.output == None:
args.output = "flash." + ext
if args.output:
write_file(args.output, outbuf)
if ext == "uf2" and not args.convert and not args.info:
drives = get_drives()
if len(drives) == 0:
if args.wait:
print("Waiting for drive to deploy...")
while len(drives) == 0:
sleep(0.1)
drives = get_drives()
elif not args.output:
error("No drive to deploy.")
for d in drives:
print("Flashing %s (%s)" % (d, board_id(d)))
write_file(d + "/NEW.UF2", outbuf)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,22 @@
[
{
"short_name": "RP2040",
"id": "0xe48bff56",
"description": "Raspberry Pi RP2040"
},
{
"short_name": "RP2350-ARM-S",
"id": "0xe48bff59",
"description": "Raspberry Pi RP2350, ARM, Secure"
},
{
"short_name": "RP2350-ARM-NS",
"id": "0xe48bff5a",
"description": "Raspberry Pi RP2350, ARM, Non-Secure"
},
{
"short_name": "RP2350-RISCV",
"id": "0xe48bff5b",
"description": "Raspberry Pi RP2350, RISC-V"
}
]

View File

@@ -0,0 +1,46 @@
/**
* @file vector_table.c
* @brief Vector table with initial stack pointer and reset handler
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdint.h>
extern uint32_t _stack_top;
extern void Reset_Handler(void);
typedef void (*vector_func_t)(void);
/**
* Vector table placed in .vectors section.
* The Thumb bit (bit 0 = 1) is automatically set by the linker
* for function pointers in Thumb mode.
*/
__attribute__((section(".vectors"), used))
const void *_vectors[2] = {
&_stack_top,
Reset_Handler
};

View File

@@ -0,0 +1,54 @@
/**
* @file xosc.c
* @brief External crystal oscillator (XOSC) initialization and clock enable
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "xosc.h"
#include "constants.h"
void Init_XOSC(void) {
// set delay 50,000 cycles
XOSC->STARTUP = 0x00C4U;
// set 1_15MHz, freq range, actual 14.5MHz
XOSC->CTRL = 0x00FABAA0U;
// wait until stable bit is set
while ((XOSC->STATUS & (1U << XOSC_STATUS_STABLE_SHIFT)) == 0) {
}
}
void Enable_XOSC_Peri_Clock(void) {
uint32_t value;
// read CLK_PERI_CTRL value
value = CLOCKS->CLK_PERI_CTRL;
// set ENABLE bit
value |= (1U << CLOCKS_CLK_PERI_CTRL_ENABLE_SHIFT);
// set AUXSRC: XOSC_CLKSRC
value |= (CLOCKS_CLK_PERI_CTRL_AUXSRC_XOSC << CLOCKS_CLK_PERI_CTRL_AUXSRC_SHIFT);
// store value into CLK_PERI_CTRL
CLOCKS->CLK_PERI_CTRL = value;
}

View File

@@ -0,0 +1,55 @@
/**
* @file xosc.h
* @brief External crystal oscillator (XOSC) initialization and clock enable
* @author Kevin Thomas
* @date 2025
*
* MIT License
*
* Copyright (c) 2025 Kevin Thomas
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef XOSC_H
#define XOSC_H
/**
* @brief Initialize the external crystal oscillator and wait until stable
*
* Configures the XOSC startup delay and frequency range, then polls
* the status register until the STABLE bit is set.
*
* @param None
* @retval None
*/
void Init_XOSC(void);
/**
* @brief Enable the XOSC peripheral clock
*
* Sets the peripheral clock to use XOSC as its auxiliary source and
* enables it via CLK_PERI_CTRL.
*
* @param None
* @retval None
*/
void Enable_XOSC_Peri_Clock(void);
#endif // XOSC_H