mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-04-01 09:00:18 +02:00
Added dyn cond chap
This commit is contained in:
7
0x0020_dynamic-conditionals/.gitignore
vendored
7
0x0020_dynamic-conditionals/.gitignore
vendored
@@ -1,7 +1,2 @@
|
||||
.idea
|
||||
.vscode
|
||||
_deps
|
||||
cmake-*
|
||||
build
|
||||
.DS_Store
|
||||
*.pdf
|
||||
!.vscode/*
|
||||
|
||||
22
0x0020_dynamic-conditionals/.vscode/c_cpp_properties.json
vendored
Normal file
22
0x0020_dynamic-conditionals/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Pico",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${userHome}/.pico-sdk/sdk/2.2.0/**"
|
||||
],
|
||||
"forcedInclude": [
|
||||
"${workspaceFolder}/build/generated/pico_base/pico/config_autogen.h",
|
||||
"${userHome}/.pico-sdk/sdk/2.2.0/src/common/pico_base_headers/include/pico.h"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "${userHome}/.pico-sdk/toolchain/14_2_Rel1/bin/arm-none-eabi-gcc.exe",
|
||||
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++14",
|
||||
"intelliSenseMode": "linux-gcc-arm"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
15
0x0020_dynamic-conditionals/.vscode/cmake-kits.json
vendored
Normal file
15
0x0020_dynamic-conditionals/.vscode/cmake-kits.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
[
|
||||
{
|
||||
"name": "Pico",
|
||||
"compilers": {
|
||||
"C": "${command:raspberry-pi-pico.getCompilerPath}",
|
||||
"CXX": "${command:raspberry-pi-pico.getCxxCompilerPath}"
|
||||
},
|
||||
"environmentVariables": {
|
||||
"PATH": "${command:raspberry-pi-pico.getEnvPath};${env:PATH}"
|
||||
},
|
||||
"cmakeSettings": {
|
||||
"Python3_EXECUTABLE": "${command:raspberry-pi-pico.getPythonPath}"
|
||||
}
|
||||
}
|
||||
]
|
||||
9
0x0020_dynamic-conditionals/.vscode/extensions.json
vendored
Normal file
9
0x0020_dynamic-conditionals/.vscode/extensions.json
vendored
Normal 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"
|
||||
]
|
||||
}
|
||||
50
0x0020_dynamic-conditionals/.vscode/launch.json
vendored
Normal file
50
0x0020_dynamic-conditionals/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Pico Debug (Cortex-Debug)",
|
||||
"cwd": "${userHome}/.pico-sdk/openocd/0.12.0+dev/scripts",
|
||||
"executable": "${command:raspberry-pi-pico.launchTargetPath}",
|
||||
"request": "launch",
|
||||
"type": "cortex-debug",
|
||||
"servertype": "openocd",
|
||||
"serverpath": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
||||
"gdbPath": "${command:raspberry-pi-pico.getGDBPath}",
|
||||
"device": "${command:raspberry-pi-pico.getChipUppercase}",
|
||||
"configFiles": [
|
||||
"interface/cmsis-dap.cfg",
|
||||
"target/${command:raspberry-pi-pico.getTarget}.cfg"
|
||||
],
|
||||
"svdFile": "${userHome}/.pico-sdk/sdk/2.2.0/src/${command:raspberry-pi-pico.getChip}/hardware_regs/${command:raspberry-pi-pico.getChipUppercase}.svd",
|
||||
"runToEntryPoint": "main",
|
||||
// Fix for no_flash binaries, where monitor reset halt doesn't do what is expected
|
||||
// Also works fine for flash binaries
|
||||
"overrideLaunchCommands": [
|
||||
"monitor reset init",
|
||||
"load \"${command:raspberry-pi-pico.launchTargetPath}\""
|
||||
],
|
||||
"openOCDLaunchCommands": [
|
||||
"adapter speed 5000"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Pico Debug (Cortex-Debug with external OpenOCD)",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"executable": "${command:raspberry-pi-pico.launchTargetPath}",
|
||||
"request": "launch",
|
||||
"type": "cortex-debug",
|
||||
"servertype": "external",
|
||||
"gdbTarget": "localhost:3333",
|
||||
"gdbPath": "${command:raspberry-pi-pico.getGDBPath}",
|
||||
"device": "${command:raspberry-pi-pico.getChipUppercase}",
|
||||
"svdFile": "${userHome}/.pico-sdk/sdk/2.2.0/src/${command:raspberry-pi-pico.getChip}/hardware_regs/${command:raspberry-pi-pico.getChipUppercase}.svd",
|
||||
"runToEntryPoint": "main",
|
||||
// Fix for no_flash binaries, where monitor reset halt doesn't do what is expected
|
||||
// Also works fine for flash binaries
|
||||
"overrideLaunchCommands": [
|
||||
"monitor reset init",
|
||||
"load \"${command:raspberry-pi-pico.launchTargetPath}\""
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
40
0x0020_dynamic-conditionals/.vscode/settings.json
vendored
Normal file
40
0x0020_dynamic-conditionals/.vscode/settings.json
vendored
Normal 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"
|
||||
}
|
||||
102
0x0020_dynamic-conditionals/.vscode/tasks.json
vendored
Normal file
102
0x0020_dynamic-conditionals/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Compile Project",
|
||||
"type": "process",
|
||||
"isBuildCommand": true,
|
||||
"command": "${userHome}/.pico-sdk/ninja/v1.12.1/ninja",
|
||||
"args": ["-C", "${workspaceFolder}/build"],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated"
|
||||
},
|
||||
"problemMatcher": "$gcc",
|
||||
"windows": {
|
||||
"command": "${env:USERPROFILE}/.pico-sdk/ninja/v1.12.1/ninja.exe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Run Project",
|
||||
"type": "process",
|
||||
"command": "${env:HOME}/.pico-sdk/picotool/2.2.0-a4/picotool/picotool",
|
||||
"args": [
|
||||
"load",
|
||||
"${command:raspberry-pi-pico.launchTargetPath}",
|
||||
"-fx"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated"
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"windows": {
|
||||
"command": "${env:USERPROFILE}/.pico-sdk/picotool/2.2.0-a4/picotool/picotool.exe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Flash",
|
||||
"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.getTarget}.cfg",
|
||||
"-c",
|
||||
"adapter speed 5000; program \"${command:raspberry-pi-pico.launchTargetPath}\" verify reset exit"
|
||||
],
|
||||
"problemMatcher": [],
|
||||
"windows": {
|
||||
"command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe",
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Rescue Reset",
|
||||
"type": "process",
|
||||
"command": "${userHome}/.pico-sdk/openocd/0.12.0+dev/openocd.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",
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "input.h"
|
||||
#include "servo.h"
|
||||
|
||||
#define ONE 0x31
|
||||
#define TWO 0x32
|
||||
#define SERVO_GPIO 6
|
||||
|
||||
int main(void) {
|
||||
stdio_init_all();
|
||||
uart0_init();
|
||||
|
||||
uint8_t choice = 0;
|
||||
|
||||
while (true) {
|
||||
choice = on_uart_rx();
|
||||
servo_init(SERVO_GPIO);
|
||||
|
||||
if (choice == ONE) {
|
||||
while (true) {
|
||||
choice = getchar();
|
||||
|
||||
if (choice == 0x31) {
|
||||
printf("1\r\n");
|
||||
} else if (choice == TWO) {
|
||||
} else if (choice == 0x32) {
|
||||
printf("2\r\n");
|
||||
} else {
|
||||
printf("??\r\n");
|
||||
@@ -25,9 +25,17 @@ int main(void) {
|
||||
switch (choice) {
|
||||
case '1':
|
||||
printf("one\r\n");
|
||||
servo_set_angle(0.0f);
|
||||
sleep_ms(500);
|
||||
servo_set_angle(180.0f);
|
||||
sleep_ms(500);
|
||||
break;
|
||||
case '2':
|
||||
printf("two\r\n");
|
||||
servo_set_angle(180.0f);
|
||||
sleep_ms(500);
|
||||
servo_set_angle(0.0f);
|
||||
sleep_ms(500);
|
||||
break;
|
||||
default:
|
||||
printf("??\r\n");
|
||||
@@ -1,22 +1,59 @@
|
||||
# Generated Cmake Pico project file
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
project(0x0020_dynamic-conditionals C CXX ASM)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# Initialise pico_sdk from installed location
|
||||
# (note this can come from environment, CMake cache etc)
|
||||
|
||||
# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work ==
|
||||
if(WIN32)
|
||||
set(USERHOME $ENV{USERPROFILE})
|
||||
else()
|
||||
set(USERHOME $ENV{HOME})
|
||||
endif()
|
||||
set(sdkVersion 2.2.0)
|
||||
set(toolchainVersion 14_2_Rel1)
|
||||
set(picotoolVersion 2.2.0-a4)
|
||||
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
|
||||
if (EXISTS ${picoVscode})
|
||||
include(${picoVscode})
|
||||
endif()
|
||||
# ====================================================================================
|
||||
set(PICO_BOARD pico2 CACHE STRING "Board type")
|
||||
|
||||
# Pull in Raspberry Pi Pico SDK (must be before project)
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(0x0020_dynamic-conditionals C CXX ASM)
|
||||
|
||||
# Initialise the Raspberry Pi Pico SDK
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(0x0020_dynamic-conditionals
|
||||
input.c
|
||||
main.c
|
||||
)
|
||||
# Add executable. Default name is the project name, version 0.1
|
||||
|
||||
pico_enable_stdio_usb(0x0020_dynamic-conditionals 1)
|
||||
add_executable(0x0020_dynamic-conditionals 0x0020_dynamic-conditionals.c servo.c)
|
||||
|
||||
pico_set_program_name(0x0020_dynamic-conditionals "0x0020_dynamic-conditionals")
|
||||
pico_set_program_version(0x0020_dynamic-conditionals "0.1")
|
||||
|
||||
# Modify the below lines to enable/disable output over UART/USB
|
||||
pico_enable_stdio_uart(0x0020_dynamic-conditionals 1)
|
||||
pico_enable_stdio_usb(0x0020_dynamic-conditionals 0)
|
||||
|
||||
# Add the standard library to the build
|
||||
target_link_libraries(0x0020_dynamic-conditionals
|
||||
pico_stdlib
|
||||
hardware_pwm
|
||||
hardware_clocks)
|
||||
|
||||
# Add the standard include files to the build
|
||||
target_include_directories(0x0020_dynamic-conditionals PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(0x0020_dynamic-conditionals)
|
||||
|
||||
target_link_libraries(0x0020_dynamic-conditionals
|
||||
pico_stdlib
|
||||
)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 My Techno Talent
|
||||
|
||||
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.
|
||||
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2024 My Techno Talent
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** @file input.h
|
||||
*
|
||||
* @brief Constant and function prototypes for the input driver.
|
||||
*
|
||||
* This contains the constants and function prototypes for the input driver which
|
||||
* will handle UART configuration in addition to capturing a character from the
|
||||
* UART terminal.
|
||||
*
|
||||
* @author Kevin Thomas
|
||||
* @date 04/20/2024
|
||||
*/
|
||||
|
||||
#ifndef _INPUT_H
|
||||
#define _INPUT_H
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/uart.h"
|
||||
#include "hardware/irq.h"
|
||||
|
||||
#define UART_ID uart0
|
||||
#define BAUD_RATE 115200
|
||||
#define UART_TX_PIN 0
|
||||
#define UART_RX_PIN 1
|
||||
|
||||
/**
|
||||
* @brief Initializes UART0 with specified baud rate and pin configurations.
|
||||
*
|
||||
* This function initializes UART0 with the specified baud rate and configures the GPIO pins
|
||||
* for UART transmission (TX) and reception (RX).
|
||||
*
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void uart0_init(void);
|
||||
|
||||
/**
|
||||
* @brief Handles a UART received character.
|
||||
*
|
||||
* This function checks if data is available to read from UART, and if so,
|
||||
* it reads and returns the received character. If no data is available,
|
||||
* it returns 0.
|
||||
*
|
||||
* @param None
|
||||
* @return The received character if available, or 0 if no data is available.
|
||||
*/
|
||||
uint8_t on_uart_rx(void);
|
||||
|
||||
#endif /* _INPUT_H */
|
||||
@@ -3,6 +3,28 @@
|
||||
# This can be dropped into an external project to help locate this SDK
|
||||
# It should be include()ed prior to project()
|
||||
|
||||
# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
# following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
||||
# disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
||||
@@ -18,9 +40,20 @@ if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_P
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
|
||||
set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
|
||||
endif ()
|
||||
|
||||
if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
|
||||
set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
|
||||
message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
|
||||
endif()
|
||||
|
||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK")
|
||||
|
||||
if (NOT PICO_SDK_PATH)
|
||||
if (PICO_SDK_FETCH_FROM_GIT)
|
||||
@@ -29,25 +62,40 @@ if (NOT PICO_SDK_PATH)
|
||||
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif ()
|
||||
# GIT_SUBMODULES_RECURSE was added in 3.17
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
GIT_SUBMODULES_RECURSE FALSE
|
||||
)
|
||||
else ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
)
|
||||
endif ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
|
||||
)
|
||||
|
||||
if (NOT pico_sdk)
|
||||
message("Downloading Raspberry Pi Pico SDK")
|
||||
FetchContent_Populate(pico_sdk)
|
||||
# GIT_SUBMODULES_RECURSE was added in 3.17
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
|
||||
FetchContent_Populate(
|
||||
pico_sdk
|
||||
QUIET
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
|
||||
GIT_SUBMODULES_RECURSE FALSE
|
||||
|
||||
SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src
|
||||
BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build
|
||||
SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild
|
||||
)
|
||||
else ()
|
||||
FetchContent_Populate(
|
||||
pico_sdk
|
||||
QUIET
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
|
||||
|
||||
SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src
|
||||
BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build
|
||||
SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild
|
||||
)
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
||||
endif ()
|
||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||
|
||||
89
0x0020_dynamic-conditionals/servo.c
Normal file
89
0x0020_dynamic-conditionals/servo.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @file servo.c
|
||||
* @brief Implementation of a simple SG90 servo driver using PWM (50Hz)
|
||||
* @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 "servo.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/pwm.h"
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
// Default servo pulse range (SG90 typical)
|
||||
static const uint16_t SERVO_DEFAULT_MIN_US = 1000;
|
||||
static const uint16_t SERVO_DEFAULT_MAX_US = 2000;
|
||||
|
||||
// internal state
|
||||
static uint8_t servo_pin = 0;
|
||||
static uint servo_slice = 0;
|
||||
static uint servo_chan = 0;
|
||||
static uint32_t servo_wrap = 20000 - 1; // wrap to map microseconds for 50Hz
|
||||
static float servo_hz = 50.0f;
|
||||
|
||||
// Convert microsecond pulse to PWM level based on wrap and frequency
|
||||
static uint32_t pulse_us_to_level(uint32_t pulse_us) {
|
||||
const float period_us = 1000000.0f / servo_hz; // 20000us
|
||||
float counts_per_us = (servo_wrap + 1) / period_us;
|
||||
return (uint32_t)(pulse_us * counts_per_us + 0.5f);
|
||||
}
|
||||
|
||||
void servo_init(uint8_t pin) {
|
||||
servo_pin = pin;
|
||||
|
||||
// Configure GPIO for PWM
|
||||
gpio_set_function(servo_pin, GPIO_FUNC_PWM);
|
||||
servo_slice = pwm_gpio_to_slice_num(servo_pin);
|
||||
servo_chan = pwm_gpio_to_channel(servo_pin);
|
||||
|
||||
pwm_config config = pwm_get_default_config();
|
||||
|
||||
// Calculate clock divider to achieve 50 Hz with our chosen wrap
|
||||
const uint32_t sys_clock_hz = clock_get_hz(clk_sys);
|
||||
float clock_div = (float)sys_clock_hz / (servo_hz * (servo_wrap + 1));
|
||||
|
||||
pwm_config_set_clkdiv(&config, clock_div);
|
||||
pwm_config_set_wrap(&config, servo_wrap);
|
||||
pwm_init(servo_slice, &config, true);
|
||||
}
|
||||
|
||||
void servo_set_pulse_us(uint16_t pulse_us) {
|
||||
if (servo_pin == 0) return; // not initialized
|
||||
// clamp to defaults
|
||||
if (pulse_us < SERVO_DEFAULT_MIN_US) pulse_us = SERVO_DEFAULT_MIN_US;
|
||||
if (pulse_us > SERVO_DEFAULT_MAX_US) pulse_us = SERVO_DEFAULT_MAX_US;
|
||||
uint32_t level = pulse_us_to_level(pulse_us);
|
||||
pwm_set_chan_level(servo_slice, servo_chan, level);
|
||||
}
|
||||
|
||||
void servo_set_angle(float degrees) {
|
||||
if (degrees < 0.0f) degrees = 0.0f;
|
||||
if (degrees > 180.0f) degrees = 180.0f;
|
||||
// linear map 0..180 -> min_us..max_us
|
||||
float ratio = degrees / 180.0f;
|
||||
uint16_t pulse = (uint16_t)(SERVO_DEFAULT_MIN_US + ratio * (SERVO_DEFAULT_MAX_US - SERVO_DEFAULT_MIN_US) + 0.5f);
|
||||
servo_set_pulse_us(pulse);
|
||||
}
|
||||
#
|
||||
@@ -1,18 +1,23 @@
|
||||
/**
|
||||
* @file servo.h
|
||||
* @brief Header for SG90 servo driver (PWM)
|
||||
* @author Kevin Thomas
|
||||
* @date 2025
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2024 My Techno Talent
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@@ -20,32 +25,38 @@
|
||||
* 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.
|
||||
*/
|
||||
*/
|
||||
|
||||
/** @file input.c
|
||||
*
|
||||
* @brief Functions for the input driver.
|
||||
*
|
||||
* This contains the functions for the input driver which will handle UART
|
||||
* configuration in addition to capturing a character from the UART terminal.
|
||||
*
|
||||
* @author Kevin Thomas
|
||||
* @date 04/20/2024
|
||||
*/
|
||||
#ifndef SERVO_H
|
||||
#define SERVO_H
|
||||
|
||||
#include "input.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void uart0_init(void) {
|
||||
uart_init(UART_ID, BAUD_RATE);
|
||||
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
|
||||
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
|
||||
}
|
||||
/**
|
||||
* @brief Initialize servo driver on a given GPIO pin
|
||||
*
|
||||
* Configures PWM for a 50 Hz servo (SG90). Call once before using other API.
|
||||
*
|
||||
* @param pin GPIO pin number to use for servo PWM
|
||||
*/
|
||||
void servo_init(uint8_t pin);
|
||||
|
||||
uint8_t on_uart_rx(void) {
|
||||
uint8_t c = 0;
|
||||
|
||||
while (!uart_is_readable(UART_ID)) {
|
||||
c = uart_getc(UART_ID);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Set servo pulse width in microseconds (typical 1000-2000)
|
||||
*
|
||||
* @param pulse_us Pulse width in microseconds
|
||||
*/
|
||||
void servo_set_pulse_us(uint16_t pulse_us);
|
||||
|
||||
/**
|
||||
* @brief Set servo angle in degrees (0 to 180)
|
||||
*
|
||||
* Maps 0..180 degrees to the configured pulse range (default 1000..2000 us).
|
||||
* Values outside [0,180] will be clamped.
|
||||
*
|
||||
* @param degrees Angle in degrees
|
||||
*/
|
||||
void servo_set_angle(float degrees);
|
||||
|
||||
#endif // SERVO_H
|
||||
Binary file not shown.
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,355 +0,0 @@
|
||||
<img src="https://github.com/mytechnotalent/RP2350_Blink_Driver/blob/main/RP2350_Blink_Driver.png?raw=true">
|
||||
|
||||
## FREE Reverse Engineering Self-Study Course [HERE](https://github.com/mytechnotalent/Reverse-Engineering-Tutorial)
|
||||
|
||||
<br>
|
||||
|
||||
# RP2350 Blink Driver
|
||||
An RP2350 blink driver written entirely in Assembler.
|
||||
|
||||
# Code
|
||||
```assembler
|
||||
/**
|
||||
* FILE: main.s
|
||||
*
|
||||
* DESCRIPTION:
|
||||
* RP2350 Bare-Metal GPIO16 Blink, Coprocessor Version.
|
||||
*
|
||||
* BRIEF:
|
||||
* Minimal bare‑metal LED blink on the RP2350 using the direct coprocessor
|
||||
* (MCRR) instructions to manipulate GPIO control registers. This bypasses
|
||||
* SDK abstractions and demonstrates register‑level control in assembler.
|
||||
* Clocks the external crystal oscillator (XOSC) at 14.5MHz.
|
||||
*
|
||||
* AUTHOR: Kevin Thomas
|
||||
* CREATION DATE: October 24, 2025
|
||||
* UPDATE DATE: October 25, 2025
|
||||
*/
|
||||
|
||||
.syntax unified // use unified assembly syntax
|
||||
.cpu cortex-m33 // target Cortex-M33 core
|
||||
.thumb // use Thumb instruction set
|
||||
|
||||
/**
|
||||
* Memory addresses and constants.
|
||||
*/
|
||||
.equ STACK_TOP, 0x20082000
|
||||
.equ STACK_LIMIT, 0x2007A000
|
||||
.equ XOSC_BASE, 0x40048000
|
||||
.equ XOSC_CTRL, XOSC_BASE + 0x00
|
||||
.equ XOSC_STATUS, XOSC_BASE + 0x04
|
||||
.equ XOSC_STARTUP, XOSC_BASE + 0x0C
|
||||
.equ PPB_BASE, 0xE0000000
|
||||
.equ CPACR, PPB_BASE + 0x0ED88
|
||||
.equ CLOCKS_BASE, 0x40010000
|
||||
.equ CLK_PERI_CTRL, CLOCKS_BASE + 0x48
|
||||
.equ RESETS_BASE, 0x40020000
|
||||
.equ RESETS_RESET, RESETS_BASE + 0x0
|
||||
.equ RESETS_RESET_CLEAR, RESETS_BASE + 0x3000
|
||||
.equ RESETS_RESET_DONE, RESETS_BASE + 0x8
|
||||
.equ IO_BANK0_BASE, 0x40028000
|
||||
.equ IO_BANK0_GPIO16_CTRL_OFFSET, 0x84
|
||||
.equ PADS_BANK0_BASE, 0x40038000
|
||||
.equ PADS_BANK0_GPIO16_OFFSET, 0x44
|
||||
|
||||
/**
|
||||
* Initialize the .vectors section. The .vectors section contains vector
|
||||
* table and Reset_Handler.
|
||||
*/
|
||||
.section .vectors, "ax" // vector table section
|
||||
.align 2 // align to 4-byte boundary
|
||||
|
||||
/**
|
||||
* Vector table section.
|
||||
*/
|
||||
.global _vectors // export _vectors symbol
|
||||
_vectors:
|
||||
.word STACK_TOP // initial stack pointer
|
||||
.word Reset_Handler + 1 // reset handler (Thumb bit set)
|
||||
|
||||
/**
|
||||
* @brief Reset handler for RP2350.
|
||||
*
|
||||
* @details Entry point after reset. Performs:
|
||||
* - Stack initialization
|
||||
* - Coprocessor enable
|
||||
* - GPIO16 pad/function configuration
|
||||
* - Branches to main() which contains the blink loop
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.global Reset_Handler // export Reset_Handler symbol
|
||||
.type Reset_Handler, %function
|
||||
Reset_Handler:
|
||||
BL Init_Stack // initialize MSP/PSP and limits
|
||||
BL Init_XOSC // initialize external crystal oscillator
|
||||
BL Enable_XOSC_Peri_Clock // enable XOSC peripheral clock
|
||||
BL Init_Subsystem // initialize subsystems
|
||||
BL Enable_Coprocessor // enable CP0 coprocessor
|
||||
B main // branch to main loop
|
||||
.size Reset_Handler, . - Reset_Handler
|
||||
|
||||
/**
|
||||
* @brief Initialize stack pointers.
|
||||
*
|
||||
* @details Sets Main and Process Stack Pointers (MSP/PSP) and their limits.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.type Init_Stack, %function
|
||||
Init_Stack:
|
||||
LDR R0, =STACK_TOP // load stack top
|
||||
MSR PSP, R0 // set PSP
|
||||
LDR R0, =STACK_LIMIT // load stack limit
|
||||
MSR MSPLIM, R0 // set MSP limit
|
||||
MSR PSPLIM, R0 // set PSP limit
|
||||
LDR R0, =STACK_TOP // reload stack top
|
||||
MSR MSP, R0 // set MSP
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief Init XOSC and wait until it is ready.
|
||||
*
|
||||
* @details Configures and initializes the external crystal oscillator (XOSC).
|
||||
* Waits for the XOSC to become stable before returning.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.type Init_XOSC, %function
|
||||
Init_XOSC:
|
||||
LDR R0, =XOSC_STARTUP // load XOSC_STARTUP address
|
||||
LDR R1, =0x00C4 // set delay 50,000 cycles
|
||||
STR R1, [R0] // store value into XOSC_STARTUP
|
||||
LDR R0, =XOSC_CTRL // load XOSC_CTRL address
|
||||
LDR R1, =0x00FABAA0 // set 1_15MHz, freq range, actual 14.5MHz
|
||||
STR R1, [R0] // store value into XOSC_CTRL
|
||||
.Init_XOSC_Wait:
|
||||
LDR R0, =XOSC_STATUS // load XOSC_STATUS address
|
||||
LDR R1, [R0] // read XOSC_STATUS value
|
||||
TST R1, #(1<<31) // test STABLE bit
|
||||
BEQ .Init_XOSC_Wait // wait until stable bit is set
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief Enable XOSC peripheral clock.
|
||||
*
|
||||
* @details Sets the peripheral clock to use XOSC as its AUXSRC.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.type Enable_XOSC_Peri_Clock, %function
|
||||
Enable_XOSC_Peri_Clock:
|
||||
LDR R0, =CLK_PERI_CTRL // load CLK_PERI_CTRL address
|
||||
LDR R1, [R0] // read CLK_PERI_CTRL value
|
||||
ORR R1, R1, #(1<<11) // set ENABLE bit
|
||||
ORR R1, R1, #(4<<5) // set AUXSRC: XOSC_CLKSRC bit
|
||||
STR R1, [R0] // store value into CLK_PERI_CTRL
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief Init subsystem.
|
||||
*
|
||||
* @details Initiates the various subsystems by clearing their reset bits.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.type Init_Subsystem, %function
|
||||
Init_Subsystem:
|
||||
.GPIO_Subsystem_Reset:
|
||||
LDR R0, =RESETS_RESET // load RESETS->RESET address
|
||||
LDR R1, [R0] // read RESETS->RESET value
|
||||
BIC R1, R1, #(1<<6) // clear IO_BANK0 bit
|
||||
STR R1, [R0] // store value into RESETS->RESET address
|
||||
.GPIO_Subsystem_Reset_Wait:
|
||||
LDR R0, =RESETS_RESET_DONE // load RESETS->RESET_DONE address
|
||||
LDR R1, [R0] // read RESETS->RESET_DONE value
|
||||
TST R1, #(1<<6) // test IO_BANK0 reset done
|
||||
BEQ .GPIO_Subsystem_Reset_Wait // wait until done
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief Enable coprocessor access.
|
||||
*
|
||||
* @details Grants full access to coprocessor 0 via CPACR.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.type Enable_Coprocessor , %function
|
||||
Enable_Coprocessor:
|
||||
LDR R0, =CPACR // load CPACR address
|
||||
LDR R1, [R0] // read CPACR value
|
||||
ORR R1, R1, #(1<<1) // set CP0: Ctrl access priv coproc 0 bit
|
||||
ORR R1, R1, #(1<<0) // set CP0: Ctrl access priv coproc 0 bit
|
||||
STR R1, [R0] // store value into CPACR
|
||||
DSB // data sync barrier
|
||||
ISB // instruction sync barrier
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* Initialize the .text section.
|
||||
* The .text section contains executable code.
|
||||
*/
|
||||
.section .text // code section
|
||||
.align 2 // align to 4-byte boundary
|
||||
|
||||
/**
|
||||
* @brief Main application entry point.
|
||||
*
|
||||
* @details Implements the infinite blink loop.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.global main // export main
|
||||
.type main, %function // mark as function
|
||||
main:
|
||||
.Push_Registers:
|
||||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||||
.GPIO16_Config:
|
||||
LDR R0, =PADS_BANK0_GPIO16_OFFSET // load PADS_BANK0_GPIO16_OFFSET
|
||||
LDR R1, =IO_BANK0_GPIO16_CTRL_OFFSET // load IO_BANK0_GPIO16_CTRL_OFFSET
|
||||
LDR R2, =16 // load GPIO number
|
||||
BL GPIO_Config // call GPIO_Config
|
||||
.Loop:
|
||||
LDR R0, =16 // load GPIO number
|
||||
BL GPIO_Set // call GPIO_Set
|
||||
LDR R0, =500 // 500ms
|
||||
BL Delay_MS // call Delay_MS
|
||||
LDR R0, =16 // load GPIO number
|
||||
BL GPIO_Clear // call GPIO_Clear
|
||||
LDR R0, =500 // 500ms
|
||||
BL Delay_MS // call Delay_MS
|
||||
B .Loop // loop forever
|
||||
.Pop_Registers:
|
||||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||||
BX LR // return to caller
|
||||
|
||||
/**
|
||||
* @brief Configure GPIO.
|
||||
*
|
||||
* @details Configures a GPIO pin's pad control and function select.
|
||||
*
|
||||
* @param R0 - PAD_OFFSET
|
||||
* @param R1 - CTRL_OFFSET
|
||||
* @param R2 - GPIO
|
||||
* @retval None
|
||||
*/
|
||||
.type GPIO_Config, %function
|
||||
GPIO_Config:
|
||||
.GPIO_Config_Push_Registers:
|
||||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||||
.GPIO_Config_Modify_Pad:
|
||||
LDR R4, =PADS_BANK0_BASE // load PADS_BANK0_BASE address
|
||||
ADD R4, R4, R0 // PADS_BANK0_BASE + PAD_OFFSET
|
||||
LDR R5, [R4] // read PAD_OFFSET value
|
||||
BIC R5, R5, #(1<<7) // clear OD bit
|
||||
ORR R5, R5, #(1<<6) // set IE bit
|
||||
BIC R5, R5, #(1<<8) // clear ISO bit
|
||||
STR R5, [R4] // store value into PAD_OFFSET
|
||||
.GPIO_Config_Modify_CTRL:
|
||||
LDR R4, =IO_BANK0_BASE // load IO_BANK0 base
|
||||
ADD R4, R4, R1 // IO_BANK0_BASE + CTRL_OFFSET
|
||||
LDR R5, [R4] // read CTRL_OFFSET value
|
||||
BIC R5, R5, #0x1F // clear FUNCSEL
|
||||
ORR R5, R5, #0x05 // set FUNCSEL 0x05->SIO_0
|
||||
STR R5, [R4] // store value into CTRL_OFFSET
|
||||
.GPIO_Config_Enable_OE:
|
||||
LDR R4, =1 // enable output
|
||||
MCRR P0, #4, R2, R4, C4 // gpioc_bit_oe_put(GPIO, 1)
|
||||
.GPIO_Config_Pop_Registers:
|
||||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief GPIO set.
|
||||
*
|
||||
* @details Drives GPIO output high via coprocessor.
|
||||
*
|
||||
* @param R0 - GPIO
|
||||
* @retval None
|
||||
*/
|
||||
.type GPIO_Set, %function
|
||||
GPIO_Set:
|
||||
.GPIO_Set_Push_Registers:
|
||||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||||
.GPIO_Set_Execute:
|
||||
LDR R4, =1 // enable output
|
||||
MCRR P0, #4, R0, R4, C0 // gpioc_bit_out_put(GPIO, 1)
|
||||
.GPIO_Set_Pop_Registers:
|
||||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief GPIO clear.
|
||||
*
|
||||
* @details Drives GPIO output high via coprocessor.
|
||||
*
|
||||
* @param R0 - GPIO
|
||||
* @retval None
|
||||
*/
|
||||
.type GPIO_Clear, %function
|
||||
GPIO_Clear:
|
||||
.GPIO_Clear_Push_Registers:
|
||||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||||
.GPIO_Clear_Execute:
|
||||
LDR R4, =0 // disable output
|
||||
MCRR P0, #4, R0, R4, C0 // gpioc_bit_out_put(GPIO, 1)
|
||||
.GPIO_Clear_Pop_Registers:
|
||||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief Delay_MS.
|
||||
*
|
||||
* @details Delays for R0 milliseconds. Conversion: loop_count = ms * 3600
|
||||
* based on a 14.5MHz clock.
|
||||
*
|
||||
* @param R0 - milliseconds
|
||||
* @retval None
|
||||
*/
|
||||
.type Delay_MS, %function
|
||||
Delay_MS:
|
||||
.Delay_MS_Push_Registers:
|
||||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||||
.Delay_MS_Check:
|
||||
CMP R0, #0 // if MS is not valid, return
|
||||
BLE .Delay_MS_Done // branch if less or equal to 0
|
||||
.Delay_MS_Setup:
|
||||
LDR R4, =3600 // loops per MS based on 14.5MHz clock
|
||||
MUL R5, R0, R4 // MS * 3600
|
||||
.Delay_MS_Loop:
|
||||
SUBS R5, R5, #1 // decrement counter
|
||||
BNE .Delay_MS_Loop // branch until zero
|
||||
.Delay_MS_Done:
|
||||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* Test data and constants.
|
||||
* The .rodata section is used for constants and static data.
|
||||
*/
|
||||
.section .rodata // read-only data section
|
||||
|
||||
/**
|
||||
* Initialized global data.
|
||||
* The .data section is used for initialized global or static variables.
|
||||
*/
|
||||
.section .data // data section
|
||||
|
||||
/**
|
||||
* Uninitialized global data.
|
||||
* The .bss section is used for uninitialized global or static variables.
|
||||
*/
|
||||
.section .bss // BSS section
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
## License
|
||||
[Apache License 2.0](https://github.com/mytechnotalent/RP2350_Blink_Driver/blob/main/LICENSE)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 925 KiB |
@@ -1,73 +0,0 @@
|
||||
@echo off
|
||||
REM ==============================================================================
|
||||
REM FILE: build.bat
|
||||
REM
|
||||
REM DESCRIPTION:
|
||||
REM Build script for RP2350.
|
||||
REM
|
||||
REM BRIEF:
|
||||
REM Automates the process of assembling, linking, and generating UF2 firmware.
|
||||
REM
|
||||
REM AUTHOR: Kevin Thomas
|
||||
REM CREATION DATE: October 5, 2025
|
||||
REM UPDATE DATE: October 5, 2025
|
||||
REM ==============================================================================
|
||||
|
||||
echo Building GPIO16 blink...
|
||||
|
||||
REM ==============================================================================
|
||||
REM Assemble Source Files
|
||||
REM ==============================================================================
|
||||
arm-none-eabi-as -mcpu=cortex-m33 -mthumb main.s -o gpio16_blink.o
|
||||
if errorlevel 1 goto error
|
||||
|
||||
arm-none-eabi-as -mcpu=cortex-m33 -mthumb image_def.s -o image_def.o
|
||||
if errorlevel 1 goto error
|
||||
|
||||
REM ==============================================================================
|
||||
REM Link Object Files
|
||||
REM ==============================================================================
|
||||
arm-none-eabi-ld -T linker.ld gpio16_blink.o image_def.o -o gpio16_blink.elf
|
||||
if errorlevel 1 goto error
|
||||
|
||||
REM ==============================================================================
|
||||
REM Create Raw Binary from ELF
|
||||
REM ==============================================================================
|
||||
arm-none-eabi-objcopy -O binary gpio16_blink.elf gpio16_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 gpio16_blink.uf2 gpio16_blink.bin
|
||||
if errorlevel 1 goto error
|
||||
|
||||
REM ==============================================================================
|
||||
REM Success Message and Flashing Instructions
|
||||
REM ==============================================================================
|
||||
echo.
|
||||
echo =================================
|
||||
echo SUCCESS! Created gpio16_blink.uf2
|
||||
echo =================================
|
||||
echo.
|
||||
echo To flash via UF2:
|
||||
echo 1. Hold BOOTSEL button
|
||||
echo 2. Plug in USB
|
||||
echo 3. Copy gpio16_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 gpio16_blink.elf verify reset exit"
|
||||
echo.
|
||||
goto end
|
||||
|
||||
REM ==============================================================================
|
||||
REM Error Handling
|
||||
REM ==============================================================================
|
||||
:error
|
||||
echo.
|
||||
echo BUILD FAILED!
|
||||
echo.
|
||||
|
||||
:end
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* FILE: image_def.s
|
||||
*
|
||||
* DESCRIPTION:
|
||||
* RP2350 IMAGE_DEF Block.
|
||||
*
|
||||
* BRIEF:
|
||||
* A minimum amount of metadata (a valid IMAGE_DEF block) must be embedded in any
|
||||
* binary for the bootrom to recognise it as a valid program image, as opposed to,
|
||||
* for example, blank flash contents or a disconnected flash device. This must
|
||||
* appear within the first 4 kB of a flash image, or anywhere in a RAM or OTP image.
|
||||
* Unlike RP2040, there is no requirement for flash binaries to have a checksummed
|
||||
* "boot2" flash setup function at flash address 0. The RP2350 bootrom performs a
|
||||
* simple best‑effort XIP setup during flash scanning, and a flash‑resident program
|
||||
* can continue executing in this state, or can choose to reconfigure the QSPI
|
||||
* interface at a later time for best performance.
|
||||
*
|
||||
* AUTHOR: Kevin Thomas
|
||||
* CREATION DATE: October 5, 2025
|
||||
* UPDATE DATE: October 5, 2025
|
||||
*/
|
||||
|
||||
.section .picobin_block, "a" // place IMAGE_DEF block in flash
|
||||
|
||||
.word 0xFFFFDED3 // PICOBIN_BLOCK_MARKER_START
|
||||
.byte 0x42 // PICOBIN_BLOCK_ITEM_1BS_IMAGE_TYPE
|
||||
.byte 0x1 // item is 1 word in size
|
||||
.hword 0b0001000000100001 // SECURE mode (0x1021)
|
||||
.byte 0xFF // PICOBIN_BLOCK_ITEM_2BS_LAST
|
||||
.hword 0x0001 // item is 1 word in size
|
||||
.byte 0x0 // pad
|
||||
.word 0x0 // relative pointer to next block (0 = loop to self)
|
||||
.word 0xAB123579 // PICOBIN_BLOCK_MARKER_END
|
||||
@@ -1,91 +0,0 @@
|
||||
/**
|
||||
* FILE: linker.ld
|
||||
*
|
||||
* DESCRIPTION:
|
||||
* RP2350 Minimal Linker Script for bare‑metal development.
|
||||
*
|
||||
* BRIEF:
|
||||
* Ensures the boot ROM accepts and runs the image by placing
|
||||
* the IMAGE_DEF block first at 0x10000000, aligning the vector
|
||||
* table to a 128‑byte boundary within the first 4 KB and defining
|
||||
* a non‑secure stack region in SRAM.
|
||||
*
|
||||
* AUTHOR: Kevin Thomas
|
||||
* CREATION DATE: October 5, 2025
|
||||
* UPDATE DATE: October 5, 2025
|
||||
*/
|
||||
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
/**
|
||||
* Define memory regions.
|
||||
*/
|
||||
__XIP_BASE = 0x10000000;
|
||||
__XIP_SIZE = 32M;
|
||||
|
||||
__SRAM_BASE = 0x20000000;
|
||||
__SRAM_SIZE = 512K; /* non-secure window */
|
||||
__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); /* RX */
|
||||
}
|
||||
|
||||
/**
|
||||
* Section placement.
|
||||
*/
|
||||
SECTIONS
|
||||
{
|
||||
. = ORIGIN(FLASH);
|
||||
|
||||
/**
|
||||
* Minimal IMAGE_DEF must be first.
|
||||
*/
|
||||
.embedded_block :
|
||||
{
|
||||
KEEP(*(.embedded_block))
|
||||
} > FLASH :text
|
||||
|
||||
/**
|
||||
* Force the vector table section start to a 128-byte boundary.
|
||||
*/
|
||||
.vectors ALIGN(128) :
|
||||
{
|
||||
KEEP(*(.vectors))
|
||||
} > FLASH :text
|
||||
|
||||
ASSERT(((ADDR(.vectors) - ORIGIN(FLASH)) < 0x1000),
|
||||
"Vector table must be in first 4KB of flash")
|
||||
|
||||
/**
|
||||
* Text and read-only data.
|
||||
*/
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
KEEP(*(.ARM.attributes))
|
||||
} > FLASH :text
|
||||
|
||||
/**
|
||||
* Non-secure stack symbols.
|
||||
*/
|
||||
__StackTop = ORIGIN(RAM) + LENGTH(RAM); /* 0x20080000 */
|
||||
__StackLimit = __StackTop - __STACK_SIZE;
|
||||
__stack = __StackTop;
|
||||
|
||||
.stack (NOLOAD) : { . = ALIGN(8); } > RAM
|
||||
|
||||
PROVIDE(__Vectors = ADDR(.vectors));
|
||||
}
|
||||
@@ -1,338 +0,0 @@
|
||||
/**
|
||||
* FILE: main.s
|
||||
*
|
||||
* DESCRIPTION:
|
||||
* RP2350 Bare-Metal GPIO16 Blink, Coprocessor Version.
|
||||
*
|
||||
* BRIEF:
|
||||
* Minimal bare‑metal LED blink on the RP2350 using the direct coprocessor
|
||||
* (MCRR) instructions to manipulate GPIO control registers. This bypasses
|
||||
* SDK abstractions and demonstrates register‑level control in assembler.
|
||||
* Clocks the external crystal oscillator (XOSC) at 14.5MHz.
|
||||
*
|
||||
* AUTHOR: Kevin Thomas
|
||||
* CREATION DATE: October 24, 2025
|
||||
* UPDATE DATE: October 25, 2025
|
||||
*/
|
||||
|
||||
.syntax unified // use unified assembly syntax
|
||||
.cpu cortex-m33 // target Cortex-M33 core
|
||||
.thumb // use Thumb instruction set
|
||||
|
||||
/**
|
||||
* Memory addresses and constants.
|
||||
*/
|
||||
.equ STACK_TOP, 0x20082000
|
||||
.equ STACK_LIMIT, 0x2007A000
|
||||
.equ XOSC_BASE, 0x40048000
|
||||
.equ XOSC_CTRL, XOSC_BASE + 0x00
|
||||
.equ XOSC_STATUS, XOSC_BASE + 0x04
|
||||
.equ XOSC_STARTUP, XOSC_BASE + 0x0C
|
||||
.equ PPB_BASE, 0xE0000000
|
||||
.equ CPACR, PPB_BASE + 0x0ED88
|
||||
.equ CLOCKS_BASE, 0x40010000
|
||||
.equ CLK_PERI_CTRL, CLOCKS_BASE + 0x48
|
||||
.equ RESETS_BASE, 0x40020000
|
||||
.equ RESETS_RESET, RESETS_BASE + 0x0
|
||||
.equ RESETS_RESET_CLEAR, RESETS_BASE + 0x3000
|
||||
.equ RESETS_RESET_DONE, RESETS_BASE + 0x8
|
||||
.equ IO_BANK0_BASE, 0x40028000
|
||||
.equ IO_BANK0_GPIO16_CTRL_OFFSET, 0x84
|
||||
.equ PADS_BANK0_BASE, 0x40038000
|
||||
.equ PADS_BANK0_GPIO16_OFFSET, 0x44
|
||||
|
||||
/**
|
||||
* Initialize the .vectors section. The .vectors section contains vector
|
||||
* table and Reset_Handler.
|
||||
*/
|
||||
.section .vectors, "ax" // vector table section
|
||||
.align 2 // align to 4-byte boundary
|
||||
|
||||
/**
|
||||
* Vector table section.
|
||||
*/
|
||||
.global _vectors // export _vectors symbol
|
||||
_vectors:
|
||||
.word STACK_TOP // initial stack pointer
|
||||
.word Reset_Handler + 1 // reset handler (Thumb bit set)
|
||||
|
||||
/**
|
||||
* @brief Reset handler for RP2350.
|
||||
*
|
||||
* @details Entry point after reset. Performs:
|
||||
* - Stack initialization
|
||||
* - Coprocessor enable
|
||||
* - GPIO16 pad/function configuration
|
||||
* - Branches to main() which contains the blink loop
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.global Reset_Handler // export Reset_Handler symbol
|
||||
.type Reset_Handler, %function
|
||||
Reset_Handler:
|
||||
BL Init_Stack // initialize MSP/PSP and limits
|
||||
BL Init_XOSC // initialize external crystal oscillator
|
||||
BL Enable_XOSC_Peri_Clock // enable XOSC peripheral clock
|
||||
BL Init_Subsystem // initialize subsystems
|
||||
BL Enable_Coprocessor // enable CP0 coprocessor
|
||||
B main // branch to main loop
|
||||
.size Reset_Handler, . - Reset_Handler
|
||||
|
||||
/**
|
||||
* @brief Initialize stack pointers.
|
||||
*
|
||||
* @details Sets Main and Process Stack Pointers (MSP/PSP) and their limits.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.type Init_Stack, %function
|
||||
Init_Stack:
|
||||
LDR R0, =STACK_TOP // load stack top
|
||||
MSR PSP, R0 // set PSP
|
||||
LDR R0, =STACK_LIMIT // load stack limit
|
||||
MSR MSPLIM, R0 // set MSP limit
|
||||
MSR PSPLIM, R0 // set PSP limit
|
||||
LDR R0, =STACK_TOP // reload stack top
|
||||
MSR MSP, R0 // set MSP
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief Init XOSC and wait until it is ready.
|
||||
*
|
||||
* @details Configures and initializes the external crystal oscillator (XOSC).
|
||||
* Waits for the XOSC to become stable before returning.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.type Init_XOSC, %function
|
||||
Init_XOSC:
|
||||
LDR R0, =XOSC_STARTUP // load XOSC_STARTUP address
|
||||
LDR R1, =0x00C4 // set delay 50,000 cycles
|
||||
STR R1, [R0] // store value into XOSC_STARTUP
|
||||
LDR R0, =XOSC_CTRL // load XOSC_CTRL address
|
||||
LDR R1, =0x00FABAA0 // set 1_15MHz, freq range, actual 14.5MHz
|
||||
STR R1, [R0] // store value into XOSC_CTRL
|
||||
.Init_XOSC_Wait:
|
||||
LDR R0, =XOSC_STATUS // load XOSC_STATUS address
|
||||
LDR R1, [R0] // read XOSC_STATUS value
|
||||
TST R1, #(1<<31) // test STABLE bit
|
||||
BEQ .Init_XOSC_Wait // wait until stable bit is set
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief Enable XOSC peripheral clock.
|
||||
*
|
||||
* @details Sets the peripheral clock to use XOSC as its AUXSRC.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.type Enable_XOSC_Peri_Clock, %function
|
||||
Enable_XOSC_Peri_Clock:
|
||||
LDR R0, =CLK_PERI_CTRL // load CLK_PERI_CTRL address
|
||||
LDR R1, [R0] // read CLK_PERI_CTRL value
|
||||
ORR R1, R1, #(1<<11) // set ENABLE bit
|
||||
ORR R1, R1, #(4<<5) // set AUXSRC: XOSC_CLKSRC bit
|
||||
STR R1, [R0] // store value into CLK_PERI_CTRL
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief Init subsystem.
|
||||
*
|
||||
* @details Initiates the various subsystems by clearing their reset bits.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.type Init_Subsystem, %function
|
||||
Init_Subsystem:
|
||||
.GPIO_Subsystem_Reset:
|
||||
LDR R0, =RESETS_RESET // load RESETS->RESET address
|
||||
LDR R1, [R0] // read RESETS->RESET value
|
||||
BIC R1, R1, #(1<<6) // clear IO_BANK0 bit
|
||||
STR R1, [R0] // store value into RESETS->RESET address
|
||||
.GPIO_Subsystem_Reset_Wait:
|
||||
LDR R0, =RESETS_RESET_DONE // load RESETS->RESET_DONE address
|
||||
LDR R1, [R0] // read RESETS->RESET_DONE value
|
||||
TST R1, #(1<<6) // test IO_BANK0 reset done
|
||||
BEQ .GPIO_Subsystem_Reset_Wait // wait until done
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief Enable coprocessor access.
|
||||
*
|
||||
* @details Grants full access to coprocessor 0 via CPACR.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.type Enable_Coprocessor , %function
|
||||
Enable_Coprocessor:
|
||||
LDR R0, =CPACR // load CPACR address
|
||||
LDR R1, [R0] // read CPACR value
|
||||
ORR R1, R1, #(1<<1) // set CP0: Ctrl access priv coproc 0 bit
|
||||
ORR R1, R1, #(1<<0) // set CP0: Ctrl access priv coproc 0 bit
|
||||
STR R1, [R0] // store value into CPACR
|
||||
DSB // data sync barrier
|
||||
ISB // instruction sync barrier
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* Initialize the .text section.
|
||||
* The .text section contains executable code.
|
||||
*/
|
||||
.section .text // code section
|
||||
.align 2 // align to 4-byte boundary
|
||||
|
||||
/**
|
||||
* @brief Main application entry point.
|
||||
*
|
||||
* @details Implements the infinite blink loop.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.global main // export main
|
||||
.type main, %function // mark as function
|
||||
main:
|
||||
.Push_Registers:
|
||||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||||
.GPIO16_Config:
|
||||
LDR R0, =PADS_BANK0_GPIO16_OFFSET // load PADS_BANK0_GPIO16_OFFSET
|
||||
LDR R1, =IO_BANK0_GPIO16_CTRL_OFFSET // load IO_BANK0_GPIO16_CTRL_OFFSET
|
||||
LDR R2, =16 // load GPIO number
|
||||
BL GPIO_Config // call GPIO_Config
|
||||
.Loop:
|
||||
LDR R0, =16 // load GPIO number
|
||||
BL GPIO_Set // call GPIO_Set
|
||||
LDR R0, =500 // 500ms
|
||||
BL Delay_MS // call Delay_MS
|
||||
LDR R0, =16 // load GPIO number
|
||||
BL GPIO_Clear // call GPIO_Clear
|
||||
LDR R0, =500 // 500ms
|
||||
BL Delay_MS // call Delay_MS
|
||||
B .Loop // loop forever
|
||||
.Pop_Registers:
|
||||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||||
BX LR // return to caller
|
||||
|
||||
/**
|
||||
* @brief Configure GPIO.
|
||||
*
|
||||
* @details Configures a GPIO pin's pad control and function select.
|
||||
*
|
||||
* @param R0 - PAD_OFFSET
|
||||
* @param R1 - CTRL_OFFSET
|
||||
* @param R2 - GPIO
|
||||
* @retval None
|
||||
*/
|
||||
.type GPIO_Config, %function
|
||||
GPIO_Config:
|
||||
.GPIO_Config_Push_Registers:
|
||||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||||
.GPIO_Config_Modify_Pad:
|
||||
LDR R4, =PADS_BANK0_BASE // load PADS_BANK0_BASE address
|
||||
ADD R4, R4, R0 // PADS_BANK0_BASE + PAD_OFFSET
|
||||
LDR R5, [R4] // read PAD_OFFSET value
|
||||
BIC R5, R5, #(1<<7) // clear OD bit
|
||||
ORR R5, R5, #(1<<6) // set IE bit
|
||||
BIC R5, R5, #(1<<8) // clear ISO bit
|
||||
STR R5, [R4] // store value into PAD_OFFSET
|
||||
.GPIO_Config_Modify_CTRL:
|
||||
LDR R4, =IO_BANK0_BASE // load IO_BANK0 base
|
||||
ADD R4, R4, R1 // IO_BANK0_BASE + CTRL_OFFSET
|
||||
LDR R5, [R4] // read CTRL_OFFSET value
|
||||
BIC R5, R5, #0x1F // clear FUNCSEL
|
||||
ORR R5, R5, #0x05 // set FUNCSEL 0x05->SIO_0
|
||||
STR R5, [R4] // store value into CTRL_OFFSET
|
||||
.GPIO_Config_Enable_OE:
|
||||
LDR R4, =1 // enable output
|
||||
MCRR P0, #4, R2, R4, C4 // gpioc_bit_oe_put(GPIO, 1)
|
||||
.GPIO_Config_Pop_Registers:
|
||||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief GPIO set.
|
||||
*
|
||||
* @details Drives GPIO output high via coprocessor.
|
||||
*
|
||||
* @param R0 - GPIO
|
||||
* @retval None
|
||||
*/
|
||||
.type GPIO_Set, %function
|
||||
GPIO_Set:
|
||||
.GPIO_Set_Push_Registers:
|
||||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||||
.GPIO_Set_Execute:
|
||||
LDR R4, =1 // enable output
|
||||
MCRR P0, #4, R0, R4, C0 // gpioc_bit_out_put(GPIO, 1)
|
||||
.GPIO_Set_Pop_Registers:
|
||||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief GPIO clear.
|
||||
*
|
||||
* @details Drives GPIO output high via coprocessor.
|
||||
*
|
||||
* @param R0 - GPIO
|
||||
* @retval None
|
||||
*/
|
||||
.type GPIO_Clear, %function
|
||||
GPIO_Clear:
|
||||
.GPIO_Clear_Push_Registers:
|
||||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||||
.GPIO_Clear_Execute:
|
||||
LDR R4, =0 // disable output
|
||||
MCRR P0, #4, R0, R4, C0 // gpioc_bit_out_put(GPIO, 1)
|
||||
.GPIO_Clear_Pop_Registers:
|
||||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* @brief Delay_MS.
|
||||
*
|
||||
* @details Delays for R0 milliseconds. Conversion: loop_count = ms * 3600
|
||||
* based on a 14.5MHz clock.
|
||||
*
|
||||
* @param R0 - milliseconds
|
||||
* @retval None
|
||||
*/
|
||||
.type Delay_MS, %function
|
||||
Delay_MS:
|
||||
.Delay_MS_Push_Registers:
|
||||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||||
.Delay_MS_Check:
|
||||
CMP R0, #0 // if MS is not valid, return
|
||||
BLE .Delay_MS_Done // branch if less or equal to 0
|
||||
.Delay_MS_Setup:
|
||||
LDR R4, =3600 // loops per MS based on 14.5MHz clock
|
||||
MUL R5, R0, R4 // MS * 3600
|
||||
.Delay_MS_Loop:
|
||||
SUBS R5, R5, #1 // decrement counter
|
||||
BNE .Delay_MS_Loop // branch until zero
|
||||
.Delay_MS_Done:
|
||||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||||
BX LR // return
|
||||
|
||||
/**
|
||||
* Test data and constants.
|
||||
* The .rodata section is used for constants and static data.
|
||||
*/
|
||||
.section .rodata // read-only data section
|
||||
|
||||
/**
|
||||
* Initialized global data.
|
||||
* The .data section is used for initialized global or static variables.
|
||||
*/
|
||||
.section .data // data section
|
||||
|
||||
/**
|
||||
* Uninitialized global data.
|
||||
* The .bss section is used for uninitialized global or static variables.
|
||||
*/
|
||||
.section .bss // BSS section
|
||||
@@ -1,365 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,382 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": "0x16573617",
|
||||
"short_name": "ATMEGA32",
|
||||
"description": "Microchip (Atmel) ATmega32"
|
||||
},
|
||||
{
|
||||
"id": "0x1851780a",
|
||||
"short_name": "SAML21",
|
||||
"description": "Microchip (Atmel) SAML21"
|
||||
},
|
||||
{
|
||||
"id": "0x1b57745f",
|
||||
"short_name": "NRF52",
|
||||
"description": "Nordic NRF52"
|
||||
},
|
||||
{
|
||||
"id": "0x1c5f21b0",
|
||||
"short_name": "ESP32",
|
||||
"description": "ESP32"
|
||||
},
|
||||
{
|
||||
"id": "0x1e1f432d",
|
||||
"short_name": "STM32L1",
|
||||
"description": "ST STM32L1xx"
|
||||
},
|
||||
{
|
||||
"id": "0x202e3a91",
|
||||
"short_name": "STM32L0",
|
||||
"description": "ST STM32L0xx"
|
||||
},
|
||||
{
|
||||
"id": "0x21460ff0",
|
||||
"short_name": "STM32WL",
|
||||
"description": "ST STM32WLxx"
|
||||
},
|
||||
{
|
||||
"id": "0x22e0d6fc",
|
||||
"short_name": "RTL8710B",
|
||||
"description": "Realtek AmebaZ RTL8710B"
|
||||
},
|
||||
{
|
||||
"id": "0x2abc77ec",
|
||||
"short_name": "LPC55",
|
||||
"description": "NXP LPC55xx"
|
||||
},
|
||||
{
|
||||
"id": "0x300f5633",
|
||||
"short_name": "STM32G0",
|
||||
"description": "ST STM32G0xx"
|
||||
},
|
||||
{
|
||||
"id": "0x31d228c6",
|
||||
"short_name": "GD32F350",
|
||||
"description": "GD32F350"
|
||||
},
|
||||
{
|
||||
"id": "0x3379CFE2",
|
||||
"short_name": "RTL8720D",
|
||||
"description": "Realtek AmebaD RTL8720D"
|
||||
},
|
||||
{
|
||||
"id": "0x04240bdf",
|
||||
"short_name": "STM32L5",
|
||||
"description": "ST STM32L5xx"
|
||||
},
|
||||
{
|
||||
"id": "0x4c71240a",
|
||||
"short_name": "STM32G4",
|
||||
"description": "ST STM32G4xx"
|
||||
},
|
||||
{
|
||||
"id": "0x4fb2d5bd",
|
||||
"short_name": "MIMXRT10XX",
|
||||
"description": "NXP i.MX RT10XX"
|
||||
},
|
||||
{
|
||||
"id": "0x51e903a8",
|
||||
"short_name": "XR809",
|
||||
"description": "Xradiotech 809"
|
||||
},
|
||||
{
|
||||
"id": "0x53b80f00",
|
||||
"short_name": "STM32F7",
|
||||
"description": "ST STM32F7xx"
|
||||
},
|
||||
{
|
||||
"id": "0x55114460",
|
||||
"short_name": "SAMD51",
|
||||
"description": "Microchip (Atmel) SAMD51"
|
||||
},
|
||||
{
|
||||
"id": "0x57755a57",
|
||||
"short_name": "STM32F4",
|
||||
"description": "ST STM32F4xx"
|
||||
},
|
||||
{
|
||||
"id": "0x5a18069b",
|
||||
"short_name": "FX2",
|
||||
"description": "Cypress FX2"
|
||||
},
|
||||
{
|
||||
"id": "0x5d1a0a2e",
|
||||
"short_name": "STM32F2",
|
||||
"description": "ST STM32F2xx"
|
||||
},
|
||||
{
|
||||
"id": "0x5ee21072",
|
||||
"short_name": "STM32F1",
|
||||
"description": "ST STM32F103"
|
||||
},
|
||||
{
|
||||
"id": "0x621e937a",
|
||||
"short_name": "NRF52833",
|
||||
"description": "Nordic NRF52833"
|
||||
},
|
||||
{
|
||||
"id": "0x647824b6",
|
||||
"short_name": "STM32F0",
|
||||
"description": "ST STM32F0xx"
|
||||
},
|
||||
{
|
||||
"id": "0x675a40b0",
|
||||
"short_name": "BK7231U",
|
||||
"description": "Beken 7231U/7231T"
|
||||
},
|
||||
{
|
||||
"id": "0x68ed2b88",
|
||||
"short_name": "SAMD21",
|
||||
"description": "Microchip (Atmel) SAMD21"
|
||||
},
|
||||
{
|
||||
"id": "0x6a82cc42",
|
||||
"short_name": "BK7251",
|
||||
"description": "Beken 7251/7252"
|
||||
},
|
||||
{
|
||||
"id": "0x6b846188",
|
||||
"short_name": "STM32F3",
|
||||
"description": "ST STM32F3xx"
|
||||
},
|
||||
{
|
||||
"id": "0x6d0922fa",
|
||||
"short_name": "STM32F407",
|
||||
"description": "ST STM32F407"
|
||||
},
|
||||
{
|
||||
"id": "0x4e8f1c5d",
|
||||
"short_name": "STM32H5",
|
||||
"description": "ST STM32H5xx"
|
||||
},
|
||||
{
|
||||
"id": "0x6db66082",
|
||||
"short_name": "STM32H7",
|
||||
"description": "ST STM32H7xx"
|
||||
},
|
||||
{
|
||||
"id": "0x70d16653",
|
||||
"short_name": "STM32WB",
|
||||
"description": "ST STM32WBxx"
|
||||
},
|
||||
{
|
||||
"id": "0x7b3ef230",
|
||||
"short_name": "BK7231N",
|
||||
"description": "Beken 7231N"
|
||||
},
|
||||
{
|
||||
"id": "0x7eab61ed",
|
||||
"short_name": "ESP8266",
|
||||
"description": "ESP8266"
|
||||
},
|
||||
{
|
||||
"id": "0x7f83e793",
|
||||
"short_name": "KL32L2",
|
||||
"description": "NXP KL32L2x"
|
||||
},
|
||||
{
|
||||
"id": "0x8fb060fe",
|
||||
"short_name": "STM32F407VG",
|
||||
"description": "ST STM32F407VG"
|
||||
},
|
||||
{
|
||||
"id": "0x9fffd543",
|
||||
"short_name": "RTL8710A",
|
||||
"description": "Realtek Ameba1 RTL8710A"
|
||||
},
|
||||
{
|
||||
"id": "0xada52840",
|
||||
"short_name": "NRF52840",
|
||||
"description": "Nordic NRF52840"
|
||||
},
|
||||
{
|
||||
"id": "0x820d9a5f",
|
||||
"short_name": "NRF52820",
|
||||
"description": "Nordic NRF52820_xxAA"
|
||||
},
|
||||
{
|
||||
"id": "0xbfdd4eee",
|
||||
"short_name": "ESP32S2",
|
||||
"description": "ESP32-S2"
|
||||
},
|
||||
{
|
||||
"id": "0xc47e5767",
|
||||
"short_name": "ESP32S3",
|
||||
"description": "ESP32-S3"
|
||||
},
|
||||
{
|
||||
"id": "0xd42ba06c",
|
||||
"short_name": "ESP32C3",
|
||||
"description": "ESP32-C3"
|
||||
},
|
||||
{
|
||||
"id": "0x2b88d29c",
|
||||
"short_name": "ESP32C2",
|
||||
"description": "ESP32-C2"
|
||||
},
|
||||
{
|
||||
"id": "0x332726f6",
|
||||
"short_name": "ESP32H2",
|
||||
"description": "ESP32-H2"
|
||||
},
|
||||
{
|
||||
"id": "0x540ddf62",
|
||||
"short_name": "ESP32C6",
|
||||
"description": "ESP32-C6"
|
||||
},
|
||||
{
|
||||
"id": "0x3d308e94",
|
||||
"short_name": "ESP32P4",
|
||||
"description": "ESP32-P4"
|
||||
},
|
||||
{
|
||||
"id": "0xf71c0343",
|
||||
"short_name": "ESP32C5",
|
||||
"description": "ESP32-C5"
|
||||
},
|
||||
{
|
||||
"id": "0x77d850c4",
|
||||
"short_name": "ESP32C61",
|
||||
"description": "ESP32-C61"
|
||||
},
|
||||
{
|
||||
"id": "0xb6dd00af",
|
||||
"short_name": "ESP32H21",
|
||||
"description": "ESP32-H21"
|
||||
},
|
||||
{
|
||||
"id": "0x9e0baa8a",
|
||||
"short_name": "ESP32H4",
|
||||
"description": "ESP32-H4"
|
||||
},
|
||||
{
|
||||
"id": "0xde1270b7",
|
||||
"short_name": "BL602",
|
||||
"description": "Boufallo 602"
|
||||
},
|
||||
{
|
||||
"id": "0xe08f7564",
|
||||
"short_name": "RTL8720C",
|
||||
"description": "Realtek AmebaZ2 RTL8720C"
|
||||
},
|
||||
{
|
||||
"id": "0xe48bff56",
|
||||
"short_name": "RP2040",
|
||||
"description": "Raspberry Pi RP2040"
|
||||
},
|
||||
{
|
||||
"id": "0xe48bff57",
|
||||
"short_name": "RP2XXX_ABSOLUTE",
|
||||
"description": "Raspberry Pi Microcontrollers: Absolute (unpartitioned) download"
|
||||
},
|
||||
{
|
||||
"id": "0xe48bff58",
|
||||
"short_name": "RP2XXX_DATA",
|
||||
"description": "Raspberry Pi Microcontrollers: Data partition download"
|
||||
},
|
||||
{
|
||||
"id": "0xe48bff59",
|
||||
"short_name": "RP2350_ARM_S",
|
||||
"description": "Raspberry Pi RP2350, Secure Arm image"
|
||||
},
|
||||
{
|
||||
"id": "0xe48bff5a",
|
||||
"short_name": "RP2350_RISCV",
|
||||
"description": "Raspberry Pi RP2350, RISC-V image"
|
||||
},
|
||||
{
|
||||
"id": "0xe48bff5b",
|
||||
"short_name": "RP2350_ARM_NS",
|
||||
"description": "Raspberry Pi RP2350, Non-secure Arm image"
|
||||
},
|
||||
{
|
||||
"id": "0x00ff6919",
|
||||
"short_name": "STM32L4",
|
||||
"description": "ST STM32L4xx"
|
||||
},
|
||||
{
|
||||
"id": "0x9af03e33",
|
||||
"short_name": "GD32VF103",
|
||||
"description": "GigaDevice GD32VF103"
|
||||
},
|
||||
{
|
||||
"id": "0x4f6ace52",
|
||||
"short_name": "CSK4",
|
||||
"description": "LISTENAI CSK300x/400x"
|
||||
},
|
||||
{
|
||||
"id": "0x6e7348a8",
|
||||
"short_name": "CSK6",
|
||||
"description": "LISTENAI CSK60xx"
|
||||
},
|
||||
{
|
||||
"id": "0x11de784a",
|
||||
"short_name": "M0SENSE",
|
||||
"description": "M0SENSE BL702"
|
||||
},
|
||||
{
|
||||
"id": "0x4b684d71",
|
||||
"short_name": "MaixPlay-U4",
|
||||
"description": "Sipeed MaixPlay-U4(BL618)"
|
||||
},
|
||||
{
|
||||
"id": "0x9517422f",
|
||||
"short_name": "RZA1LU",
|
||||
"description": "Renesas RZ/A1LU (R7S7210xx)"
|
||||
},
|
||||
{
|
||||
"id": "0x2dc309c5",
|
||||
"short_name": "STM32F411xE",
|
||||
"description": "ST STM32F411xE"
|
||||
},
|
||||
{
|
||||
"id": "0x06d1097b",
|
||||
"short_name": "STM32F411xC",
|
||||
"description": "ST STM32F411xC"
|
||||
},
|
||||
{
|
||||
"id": "0x72721d4e",
|
||||
"short_name": "NRF52832xxAA",
|
||||
"description": "Nordic NRF52832xxAA"
|
||||
},
|
||||
{
|
||||
"id": "0x6f752678",
|
||||
"short_name": "NRF52832xxAB",
|
||||
"description": "Nordic NRF52832xxAB"
|
||||
},
|
||||
{
|
||||
"id": "0xa0c97b8e",
|
||||
"short_name": "AT32F415",
|
||||
"description": "ArteryTek AT32F415"
|
||||
},
|
||||
{
|
||||
"id": "0x699b62ec",
|
||||
"short_name": "CH32V",
|
||||
"description": "WCH CH32V2xx and CH32V3xx"
|
||||
},
|
||||
{
|
||||
"id": "0x7be8976d",
|
||||
"short_name": "RA4M1",
|
||||
"description": "Renesas RA4M1"
|
||||
},
|
||||
{
|
||||
"id": "0x7410520a",
|
||||
"short_name": "MAX32690",
|
||||
"description": "Analog Devices MAX32690"
|
||||
},
|
||||
{
|
||||
"id": "0xd63f8632",
|
||||
"short_name": "MAX32650",
|
||||
"description": "Analog Devices MAX32650/1/2"
|
||||
},
|
||||
{
|
||||
"id": "0xf0c30d71",
|
||||
"short_name": "MAX32666",
|
||||
"description": "Analog Devices MAX32665/6"
|
||||
},
|
||||
{
|
||||
"id": "0x91d3fd18",
|
||||
"short_name": "MAX78002",
|
||||
"description": "Analog Devices MAX78002"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user