mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-07-07 04:58:00 +02:00
Initial commit
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
[build]
|
||||
target = "thumbv8m.main-none-eabihf"
|
||||
|
||||
[target.thumbv6m-none-eabi]
|
||||
linker = "flip-link"
|
||||
rustflags = [
|
||||
"-C", "link-arg=--nmagic",
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "link-arg=-Tdefmt.x",
|
||||
"-C", "no-vectorize-loops",
|
||||
]
|
||||
runner = "${PICOTOOL_PATH} load -u -v -x -t elf"
|
||||
|
||||
[target.thumbv8m.main-none-eabihf]
|
||||
rustflags = [
|
||||
"-C", "link-arg=--nmagic",
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "link-arg=-Tdefmt.x",
|
||||
"-C", "target-cpu=cortex-m33",
|
||||
]
|
||||
runner = "${PICOTOOL_PATH} load -u -v -x -t elf"
|
||||
|
||||
[target.riscv32imac-unknown-none-elf]
|
||||
rustflags = [
|
||||
"-C", "link-arg=--nmagic",
|
||||
"-C", "link-arg=-Trp2350_riscv.x",
|
||||
"-C", "link-arg=-Tdefmt.x",
|
||||
]
|
||||
runner = "${PICOTOOL_PATH} load -u -v -x -t elf"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "debug"
|
||||
@@ -0,0 +1 @@
|
||||
rp2350
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"marus25.cortex-debug",
|
||||
"rust-lang.rust-analyzer",
|
||||
"probe-rs.probe-rs-debugger",
|
||||
"raspberry-pi.raspberry-pi-pico"
|
||||
]
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Pico Debug (probe-rs)",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"request": "launch",
|
||||
"type": "probe-rs-debug",
|
||||
"connectUnderReset": false,
|
||||
"speed": 5000,
|
||||
"runtimeExecutable": "probe-rs",
|
||||
"chip": "${command:raspberry-pi-pico.getChip}",
|
||||
"runtimeArgs": [
|
||||
"dap-server"
|
||||
],
|
||||
"flashingConfig": {
|
||||
"flashingEnabled": true,
|
||||
"haltAfterReset": false
|
||||
},
|
||||
"coreConfigs": [
|
||||
{
|
||||
"coreIndex": 0,
|
||||
"programBinary": "${command:raspberry-pi-pico.launchTargetPath}",
|
||||
"rttEnabled": true,
|
||||
"svdFile": "${command:raspberry-pi-pico.getSVDPath}",
|
||||
"rttChannelFormats": [
|
||||
{
|
||||
"channelNumber": 0,
|
||||
"dataFormat": "Defmt",
|
||||
"mode": "NoBlockSkip",
|
||||
"showTimestamps": true
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"preLaunchTask": "Build + Generate SBOM (debug)",
|
||||
"consoleLogLevel": "Debug",
|
||||
"wireProtocol": "Swd"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
|
||||
"rust-analyzer.check.allTargets": false,
|
||||
"editor.formatOnSave": true,
|
||||
"files.exclude": {
|
||||
".pico-rs": true
|
||||
}
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Compile Project",
|
||||
"type": "process",
|
||||
"isBuildCommand": true,
|
||||
"command": "cargo",
|
||||
"args": [
|
||||
"build",
|
||||
"--release"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated"
|
||||
},
|
||||
"problemMatcher": "$rustc",
|
||||
"options": {
|
||||
"env": {
|
||||
"PICOTOOL_PATH": "${command:raspberry-pi-pico.getPicotoolPath}",
|
||||
"CHIP": "${command:raspberry-pi-pico.getChip}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build + Generate SBOM (release)",
|
||||
"type": "shell",
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"-lc",
|
||||
"cargo sbom > ${command:raspberry-pi-pico.sbomTargetPathRelease}"
|
||||
],
|
||||
"windows": {
|
||||
"command": "powershell",
|
||||
"args": [
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-Command",
|
||||
"cargo sbom | Set-Content -Encoding utf8 ${command:raspberry-pi-pico.sbomTargetPathRelease}"
|
||||
]
|
||||
},
|
||||
"dependsOn": "Compile Project",
|
||||
"presentation": {
|
||||
"reveal": "silent",
|
||||
"panel": "shared"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Compile Project (debug)",
|
||||
"type": "process",
|
||||
"isBuildCommand": true,
|
||||
"command": "cargo",
|
||||
"args": [
|
||||
"build"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated"
|
||||
},
|
||||
"problemMatcher": "$rustc",
|
||||
"options": {
|
||||
"env": {
|
||||
"PICOTOOL_PATH": "${command:raspberry-pi-pico.getPicotoolPath}",
|
||||
"CHIP": "${command:raspberry-pi-pico.getChip}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build + Generate SBOM (debug)",
|
||||
"type": "shell",
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"-lc",
|
||||
"cargo sbom > ${command:raspberry-pi-pico.sbomTargetPathDebug}"
|
||||
],
|
||||
"windows": {
|
||||
"command": "powershell",
|
||||
"args": [
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-Command",
|
||||
"cargo sbom | Set-Content -Encoding utf8 ${command:raspberry-pi-pico.sbomTargetPathDebug}"
|
||||
]
|
||||
},
|
||||
"dependsOn": "Compile Project (debug)",
|
||||
"presentation": {
|
||||
"reveal": "silent",
|
||||
"panel": "shared"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Run Project",
|
||||
"type": "shell",
|
||||
"dependsOn": [
|
||||
"Build + Generate SBOM (release)"
|
||||
],
|
||||
"command": "${command:raspberry-pi-pico.getPicotoolPath}",
|
||||
"args": [
|
||||
"load",
|
||||
"-x",
|
||||
"${command:raspberry-pi-pico.launchTargetPathRelease}",
|
||||
"-t",
|
||||
"elf"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "dedicated"
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
+704
@@ -0,0 +1,704 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitfield"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
|
||||
|
||||
[[package]]
|
||||
name = "bitfield"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
||||
dependencies = [
|
||||
"bare-metal",
|
||||
"bitfield 0.13.2",
|
||||
"embedded-hal 0.2.7",
|
||||
"volatile-register",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rt"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6"
|
||||
dependencies = [
|
||||
"cortex-m-rt-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rt-macros"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-any"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a62ec9ff5f7965e4d7280bd5482acd20aadb50d632cf6c1d74493856b011fa73"
|
||||
dependencies = [
|
||||
"debug-helper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||
|
||||
[[package]]
|
||||
name = "debug-helper"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e"
|
||||
|
||||
[[package]]
|
||||
name = "defmt"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"defmt-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-macros"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e"
|
||||
dependencies = [
|
||||
"defmt-parser",
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-parser"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-rtt"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93d5a25c99d89c40f5676bec8cefe0614f17f0f40e916f98e345dae941807f9e"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"defmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-dma"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446"
|
||||
dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
|
||||
dependencies = [
|
||||
"nb 0.1.3",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal-async"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884"
|
||||
dependencies = [
|
||||
"embedded-hal 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal-nb"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605"
|
||||
dependencies = [
|
||||
"embedded-hal 1.0.0",
|
||||
"nb 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-io"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
|
||||
|
||||
[[package]]
|
||||
name = "frunk"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28aef0f9aa070bce60767c12ba9cb41efeaf1a2bc6427f87b7d83f11239a16d7"
|
||||
dependencies = [
|
||||
"frunk_core",
|
||||
"frunk_derives",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "frunk_core"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "476eeaa382e3462b84da5d6ba3da97b5786823c2d0d3a0d04ef088d073da225c"
|
||||
|
||||
[[package]]
|
||||
name = "frunk_derives"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0b4095fc99e1d858e5b8c7125d2638372ec85aa0fe6c807105cf10b0265ca6c"
|
||||
dependencies = [
|
||||
"frunk_proc_macro_helpers",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "frunk_proc_macro_helpers"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1952b802269f2db12ab7c0bd328d0ae8feaabf19f352a7b0af7bb0c5693abfce"
|
||||
dependencies = [
|
||||
"frunk_core",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fugit"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e639847d312d9a82d2e75b0edcc1e934efcc64e6cb7aa94f0b1fbec0bc231d6"
|
||||
dependencies = [
|
||||
"gcd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcd"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||
dependencies = [
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||
dependencies = [
|
||||
"nb 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panic-halt"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11"
|
||||
|
||||
[[package]]
|
||||
name = "panic-probe"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd402d00b0fb94c5aee000029204a46884b1262e0c443f166d86d2c0747e1a1a"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"defmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pio"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76e09694b50f89f302ed531c1f2a7569f0be5867aee4ab4f8f729bbeec0078e3"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"num_enum",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "riscv"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f5c1b8bf41ea746266cdee443d1d1e9125c86ce1447e1a2615abd34330d33a9"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"embedded-hal 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "riscv-rt"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0d35e32cf1383183e8885d8a9aa4402a087fd094dc34c2cb6df6687d0229dfe"
|
||||
dependencies = [
|
||||
"riscv",
|
||||
"riscv-rt-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "riscv-rt-macros"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30f19a85fe107b65031e0ba8ec60c34c2494069fe910d6c297f5e7cb5a6f76d0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp-binary-info"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f582261945fa215d40e2988b4df595d11c0908c0fff97a0fe23df766d117b790"
|
||||
|
||||
[[package]]
|
||||
name = "rp-hal-common"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8288358786b1458fb2caac8c4b40fb529ef4200d6c46467e2695b7a8ba573ae8"
|
||||
dependencies = [
|
||||
"fugit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp2040-boot2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c92f344f63f950ee36cf4080050e4dce850839b9175da38f9d2ffb69b4dbb21"
|
||||
dependencies = [
|
||||
"crc-any",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp2040-hal"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb79a4590775204387f334672e6f79c0d734d0a159da23d60677b3c10fa1245"
|
||||
dependencies = [
|
||||
"bitfield 0.14.0",
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
"embedded-dma",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
"embedded-hal-nb",
|
||||
"embedded-io",
|
||||
"frunk",
|
||||
"fugit",
|
||||
"itertools 0.10.5",
|
||||
"nb 1.1.0",
|
||||
"paste",
|
||||
"pio",
|
||||
"rand_core",
|
||||
"rp-binary-info",
|
||||
"rp-hal-common",
|
||||
"rp2040-hal-macros",
|
||||
"rp2040-pac",
|
||||
"usb-device",
|
||||
"vcell",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp2040-hal-macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86479063e497efe1ae81995ef9071f54fd1c7427e04d6c5b84cde545ff672a5e"
|
||||
dependencies = [
|
||||
"cortex-m-rt",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp2040-pac"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83cbcd3f7a0ca7bbe61dc4eb7e202842bee4e27b769a7bf3a4a72fa399d6e404"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"critical-section",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp235x-hal"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2939c82776b0b4ae110168b4298b5adf831e6cff249b057bf2a2187453b959c"
|
||||
dependencies = [
|
||||
"bitfield 0.14.0",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"critical-section",
|
||||
"embedded-dma",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
"embedded-hal-nb",
|
||||
"embedded-io",
|
||||
"frunk",
|
||||
"fugit",
|
||||
"gcd",
|
||||
"itertools 0.13.0",
|
||||
"nb 1.1.0",
|
||||
"paste",
|
||||
"pio",
|
||||
"rand_core",
|
||||
"riscv",
|
||||
"riscv-rt",
|
||||
"rp-binary-info",
|
||||
"rp-hal-common",
|
||||
"rp235x-hal-macros",
|
||||
"rp235x-pac",
|
||||
"sha2-const-stable",
|
||||
"usb-device",
|
||||
"vcell",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp235x-hal-macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74edd7a5979e9763bbb98e9746e711bac7464ee3397af7288e6c288ff0d3c764"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp235x-pac"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ffcb6931deee4242886b5a1df62db5e2555b0eb6ae1e8be101f3ea3e58e65c6"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"critical-section",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "sha2-const-stable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "timer"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"defmt",
|
||||
"defmt-rtt",
|
||||
"fugit",
|
||||
"panic-halt",
|
||||
"panic-probe",
|
||||
"rp2040-boot2",
|
||||
"rp2040-hal",
|
||||
"rp235x-hal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "usb-device"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcell"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "volatile-register"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
|
||||
dependencies = [
|
||||
"vcell",
|
||||
]
|
||||
@@ -0,0 +1,79 @@
|
||||
[package]
|
||||
edition = "2024"
|
||||
name = "timer"
|
||||
version = "0.1.0"
|
||||
license = "MIT or Apache-2.0"
|
||||
|
||||
[lib]
|
||||
name = "timer_lib"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "timer"
|
||||
path = "src/main.rs"
|
||||
|
||||
|
||||
[dependencies]
|
||||
cortex-m = "0.7"
|
||||
cortex-m-rt = "0.7"
|
||||
fugit = "0.3"
|
||||
defmt = "1"
|
||||
defmt-rtt = "1"
|
||||
|
||||
[target.'cfg( target_arch = "arm" )'.dependencies]
|
||||
panic-probe = { version = "1", features = ["print-defmt"] }
|
||||
|
||||
[target.'cfg( target_arch = "riscv32" )'.dependencies]
|
||||
panic-halt = { version = "1.0.0" }
|
||||
|
||||
[target.thumbv6m-none-eabi.dependencies]
|
||||
rp2040-boot2 = "0.3"
|
||||
rp2040-hal = { version = "0.11", features = ["rt", "critical-section-impl"] }
|
||||
|
||||
[target.riscv32imac-unknown-none-elf.dependencies]
|
||||
rp235x-hal = { version = "0.3", features = ["rt", "critical-section-impl"] }
|
||||
|
||||
[target."thumbv8m.main-none-eabihf".dependencies]
|
||||
rp235x-hal = { version = "0.3", features = ["rt", "critical-section-impl"] }
|
||||
|
||||
# cargo build/run
|
||||
[profile.dev]
|
||||
debug = 2
|
||||
debug-assertions = true
|
||||
opt-level = 2
|
||||
overflow-checks = true
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
debug = 2
|
||||
debug-assertions = false
|
||||
lto = "fat"
|
||||
opt-level = 2
|
||||
overflow-checks = false
|
||||
|
||||
# do not optimize proc-macro crates = faster builds from scratch
|
||||
[profile.dev.build-override]
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
overflow-checks = false
|
||||
opt-level = 0
|
||||
|
||||
[profile.release.build-override]
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
overflow-checks = false
|
||||
opt-level = 0
|
||||
|
||||
# cargo test
|
||||
[profile.test]
|
||||
debug = 2
|
||||
debug-assertions = true
|
||||
opt-level = 2
|
||||
overflow-checks = true
|
||||
|
||||
# cargo test --release
|
||||
[profile.bench]
|
||||
debug = 2
|
||||
debug-assertions = false
|
||||
lto = "fat"
|
||||
opt-level = 3
|
||||
@@ -0,0 +1,113 @@
|
||||
# 0x0d Timer Rust Driver
|
||||
|
||||
This repository contains a Bare-Metal Rust driver demonstrating **Hardware Timers** and **Periodic Execution** on the **RP2350** (and RP2040) microcontrollers.
|
||||
|
||||
It includes:
|
||||
- A demo (`src/main.rs`) that starts a 1000ms repeating timer and prints a heartbeat message to the UART console.
|
||||
- A reusable library module (`src/timer.rs`) providing a hardware-agnostic `timer_lib` containing the driver state machine and formatting helpers.
|
||||
- Board initialization logic (`src/board.rs`).
|
||||
|
||||
## 🚀 Getting Started from Scratch
|
||||
|
||||
If you're starting with a fresh machine, follow these exact steps to install the toolchain, build the code, and flash it to your microcontroller.
|
||||
|
||||
### 1. Install Rust
|
||||
First, install `rustup` (the Rust toolchain installer) if you haven't already:
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
```
|
||||
*Note: Restart your terminal or run `source $HOME/.cargo/env` after this finishes.*
|
||||
|
||||
Ensure your Rust compiler is up to date:
|
||||
```bash
|
||||
rustup update
|
||||
```
|
||||
|
||||
### 2. Install the Target Architecture
|
||||
This project is configured for the **RP2350** (ARM Cortex-M33). We need to install the cross-compilation target for it:
|
||||
```bash
|
||||
rustup target add thumbv8m.main-none-eabihf
|
||||
```
|
||||
*(If you were targeting the RP2040, you would use `thumbv6m-none-eabi` instead).*
|
||||
|
||||
### 3. Install Build Tools
|
||||
You will need a few extra tools to help link and format the firmware for the RP-series chips.
|
||||
|
||||
Install `flip-link` (adds zero-cost stack overflow protection):
|
||||
```bash
|
||||
cargo install flip-link
|
||||
```
|
||||
|
||||
Install `picotool` (used by `cargo run` to flash the chip):
|
||||
- **macOS:** `brew install picotool`
|
||||
- **Linux/Windows:** Follow the official Raspberry Pi documentation to install `picotool` or build it from source.
|
||||
|
||||
### 4. Building the Code
|
||||
To compile the code for the microcontroller, simply run:
|
||||
```bash
|
||||
cargo build
|
||||
```
|
||||
|
||||
To build a highly optimized release version (smaller and faster):
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
### 5. Flashing to the Microcontroller
|
||||
This project is pre-configured in `.cargo/config.toml` to use `picotool` as the custom runner.
|
||||
|
||||
To flash the code:
|
||||
1. Hold down the **BOOTSEL** button on your RP2350 board.
|
||||
2. Plug it into your computer via USB (or press the RUN/RESET button while holding BOOTSEL).
|
||||
3. Run the following command:
|
||||
|
||||
```bash
|
||||
cargo run --release
|
||||
```
|
||||
*`cargo` will compile the code and automatically use `picotool` to upload the `.elf` file directly to your board and start executing it!*
|
||||
|
||||
### 6. Testing on the Host
|
||||
Because the data manipulation and string formatting logic is separated into a reusable library without touching hardware registers, you can run the unit tests natively on your computer!
|
||||
|
||||
However, because this project sets a default bare-metal target (`thumbv8m.main-none-eabihf`) in `.cargo/config.toml`, running a plain `cargo test` will fail because the standard library doesn't exist on the microcontroller. You must explicitly tell Cargo to compile the tests for your host computer's processor architecture:
|
||||
|
||||
**Mac (Apple Silicon):**
|
||||
```bash
|
||||
cargo test --lib --target aarch64-apple-darwin
|
||||
```
|
||||
|
||||
**Linux (Intel/AMD 64-bit):**
|
||||
```bash
|
||||
cargo test --lib --target x86_64-unknown-linux-gnu
|
||||
```
|
||||
|
||||
**Windows (64-bit):**
|
||||
```bash
|
||||
cargo test --lib --target x86_64-pc-windows-msvc
|
||||
```
|
||||
|
||||
## 🧠 Code Walkthrough
|
||||
|
||||
This section explains exactly how the code works, where the entry point is, and traces the flow of execution as if you were stepping through it line-by-line.
|
||||
|
||||
### 1. The Entry Point (`src/main.rs`)
|
||||
Unlike a standard computer program, bare-metal microcontrollers do not have an operating system to call `main()`. Instead, we use the `#[entry]` macro from the HAL (Hardware Abstraction Layer) to define the very first function that runs after the chip boots up.
|
||||
|
||||
* **`main() -> !`**: This is the absolute start of our code. It takes ownership of all the hardware peripherals (`hal::pac::Peripherals::take().unwrap()`) and immediately passes them into `board::run(...)`. The `-> !` means this function never returns (because embedded devices run in an infinite loop).
|
||||
|
||||
### 2. Board Initialization (`src/board.rs`)
|
||||
Once execution enters `board.rs`, we initialize the system clocks, pins, UART (for logging), SysTick (for delay), and the hardware Timer peripheral.
|
||||
|
||||
* **`run(...)`**: The master setup function. Calls the helper initialization functions, gets a handle to the `hal::Timer`, initializes the driver state, and enters the infinite `heartbeat_loop`.
|
||||
* **`heartbeat_loop(...)`**: An infinite loop that polls the hardware timer's microsecond counter. It continuously checks if the elapsed time exceeds the configured period. When it does, it updates the checkpoint and fires the callback.
|
||||
* **`tick_elapsed(...)`**: A helper function that handles the 32-bit wrapping arithmetic required to safely calculate elapsed microseconds from the free-running hardware counter.
|
||||
* **`fire_heartbeat(...)`**: Called by the loop when the period elapses. It asks the driver state to record the fire event, and if active, formats and prints the heartbeat message over UART.
|
||||
|
||||
### 3. The Reusable Timer Library (`src/timer.rs`)
|
||||
While `board.rs` directly polls the hardware counter registers, `timer.rs` tracks the logical state of our repeating timer and handles string formatting for logging.
|
||||
|
||||
* **`TimerDriverState`**: A struct that acts as a state machine. It stores whether the timer is `active`, the configured `period_ms`, and the total `fire_count`. It abstracts away the global variables commonly used in C SDKs.
|
||||
* **`start(...)` / `cancel(...)`**: Methods to transition the driver state.
|
||||
* **`on_fire(&mut self)`**: Called by the board shim when the hardware triggers. It increments the fire count and returns whether the timer should continue repeating.
|
||||
* **`format_heartbeat(...)` / `format_started(...)`**: Helpers to generate the UART console messages.
|
||||
* **`format_u32(...)`**: Implements custom `u32` to decimal ASCII string conversion without allocating dynamic memory, enabling `core` library compatibility (`no_std`).
|
||||
@@ -0,0 +1,105 @@
|
||||
//! Implementation module
|
||||
//!
|
||||
//! **File:** `build.rs`
|
||||
//! **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.
|
||||
|
||||
// Import dependencies from std::fs
|
||||
use std::fs::{read_to_string, File};
|
||||
// Import std::io::Write
|
||||
use std::io::Write;
|
||||
// Import std::path::{Path, PathBuf}
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// The main entry point.
|
||||
fn main() {
|
||||
let out = PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
|
||||
let c = read_to_string(".pico-rs").unwrap_or_default().trim().to_lowercase();
|
||||
setup_target(&c, &out);
|
||||
write_riscv(&out);
|
||||
print_cfgs(&out);
|
||||
}
|
||||
|
||||
/// Executes the setup target operation.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `c` - Target string from config.
|
||||
/// * `out` - Output path.
|
||||
fn setup_target(c: &str, out: &Path) {
|
||||
if c == "rp2040" {
|
||||
write_rp2040(out);
|
||||
} else {
|
||||
write_rp2350(out);
|
||||
}
|
||||
}
|
||||
|
||||
/// Executes the write rp2040 operation.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `out` - Output path.
|
||||
fn write_rp2040(out: &Path) {
|
||||
let b = include_bytes!("rp2040.x");
|
||||
File::create(out.join("memory.x")).unwrap().write_all(b).unwrap();
|
||||
println!("cargo::rustc-cfg=rp2040");
|
||||
println!("cargo:rerun-if-changed=rp2040.x");
|
||||
}
|
||||
|
||||
/// Executes the write rp2350 operation.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `out` - Output path.
|
||||
fn write_rp2350(out: &Path) {
|
||||
let b = include_bytes!("rp2350.x");
|
||||
File::create(out.join("memory.x")).unwrap().write_all(b).unwrap();
|
||||
println!("cargo::rustc-cfg=rp2350");
|
||||
println!("cargo:rerun-if-changed=rp2350.x");
|
||||
}
|
||||
|
||||
/// Executes the write riscv operation.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `out` - Output path.
|
||||
fn write_riscv(out: &Path) {
|
||||
let b = include_bytes!("rp2350_riscv.x");
|
||||
File::create(out.join("rp2350_riscv.x")).unwrap().write_all(b).unwrap();
|
||||
}
|
||||
|
||||
/// Executes the print cfgs operation.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `out` - Output path.
|
||||
fn print_cfgs(out: &Path) {
|
||||
println!("cargo::rustc-check-cfg=cfg(rp2040)");
|
||||
println!("cargo::rustc-check-cfg=cfg(rp2350)");
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
println!("cargo:rerun-if-changed=.pico-rs");
|
||||
println!("cargo:rerun-if-changed=rp2350_riscv.x");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2021-2024 The rp-rs Developers
|
||||
* Copyright (c) 2021 rp-rs organization
|
||||
* Copyright (c) 2025 Raspberry Pi Ltd.
|
||||
*/
|
||||
|
||||
MEMORY {
|
||||
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
|
||||
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 256K
|
||||
SRAM4 : ORIGIN = 0x20040000, LENGTH = 4k
|
||||
SRAM5 : ORIGIN = 0x20041000, LENGTH = 4k
|
||||
}
|
||||
|
||||
EXTERN(BOOT2_FIRMWARE)
|
||||
|
||||
SECTIONS {
|
||||
.boot2 ORIGIN(BOOT2) :
|
||||
{
|
||||
KEEP(*(.boot2));
|
||||
} > BOOT2
|
||||
} INSERT BEFORE .text;
|
||||
|
||||
SECTIONS {
|
||||
.boot_info : ALIGN(4)
|
||||
{
|
||||
KEEP(*(.boot_info));
|
||||
} > FLASH
|
||||
|
||||
} INSERT AFTER .vector_table;
|
||||
|
||||
_stext = ADDR(.boot_info) + SIZEOF(.boot_info);
|
||||
|
||||
SECTIONS {
|
||||
.bi_entries : ALIGN(4)
|
||||
{
|
||||
__bi_entries_start = .;
|
||||
KEEP(*(.bi_entries));
|
||||
. = ALIGN(4);
|
||||
__bi_entries_end = .;
|
||||
} > FLASH
|
||||
} INSERT AFTER .text;
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2021-2024 The rp-rs Developers
|
||||
* Copyright (c) 2021 rp-rs organization
|
||||
* Copyright (c) 2025 Raspberry Pi Ltd.
|
||||
*/
|
||||
|
||||
MEMORY {
|
||||
FLASH : ORIGIN = 0x10000000, LENGTH = 2048K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 512K
|
||||
SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K
|
||||
SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K
|
||||
}
|
||||
|
||||
SECTIONS {
|
||||
.start_block : ALIGN(4)
|
||||
{
|
||||
__start_block_addr = .;
|
||||
KEEP(*(.start_block));
|
||||
} > FLASH
|
||||
|
||||
} INSERT AFTER .vector_table;
|
||||
|
||||
_stext = ADDR(.start_block) + SIZEOF(.start_block);
|
||||
|
||||
SECTIONS {
|
||||
.bi_entries : ALIGN(4)
|
||||
{
|
||||
__bi_entries_start = .;
|
||||
KEEP(*(.bi_entries));
|
||||
. = ALIGN(4);
|
||||
__bi_entries_end = .;
|
||||
} > FLASH
|
||||
} INSERT AFTER .text;
|
||||
|
||||
SECTIONS {
|
||||
.end_block : ALIGN(4)
|
||||
{
|
||||
__end_block_addr = .;
|
||||
KEEP(*(.end_block));
|
||||
} > FLASH
|
||||
|
||||
} INSERT AFTER .uninit;
|
||||
|
||||
PROVIDE(start_to_end = __end_block_addr - __start_block_addr);
|
||||
PROVIDE(end_to_start = __start_block_addr - __end_block_addr);
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2021-2024 The rp-rs Developers
|
||||
* Copyright (c) 2021 rp-rs organization
|
||||
* Copyright (c) 2025 Raspberry Pi Ltd.
|
||||
*/
|
||||
|
||||
MEMORY {
|
||||
FLASH : ORIGIN = 0x10000000, LENGTH = 2048K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 512K
|
||||
SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K
|
||||
SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K
|
||||
}
|
||||
|
||||
PROVIDE(_stext = ORIGIN(FLASH));
|
||||
PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM));
|
||||
PROVIDE(_max_hart_id = 0);
|
||||
PROVIDE(_hart_stack_size = 2K);
|
||||
PROVIDE(_heap_size = 0);
|
||||
|
||||
PROVIDE(InstructionMisaligned = ExceptionHandler);
|
||||
PROVIDE(InstructionFault = ExceptionHandler);
|
||||
PROVIDE(IllegalInstruction = ExceptionHandler);
|
||||
PROVIDE(Breakpoint = ExceptionHandler);
|
||||
PROVIDE(LoadMisaligned = ExceptionHandler);
|
||||
PROVIDE(LoadFault = ExceptionHandler);
|
||||
PROVIDE(StoreMisaligned = ExceptionHandler);
|
||||
PROVIDE(StoreFault = ExceptionHandler);
|
||||
PROVIDE(UserEnvCall = ExceptionHandler);
|
||||
PROVIDE(SupervisorEnvCall = ExceptionHandler);
|
||||
PROVIDE(MachineEnvCall = ExceptionHandler);
|
||||
PROVIDE(InstructionPageFault = ExceptionHandler);
|
||||
PROVIDE(LoadPageFault = ExceptionHandler);
|
||||
PROVIDE(StorePageFault = ExceptionHandler);
|
||||
|
||||
PROVIDE(SupervisorSoft = DefaultHandler);
|
||||
PROVIDE(MachineSoft = DefaultHandler);
|
||||
PROVIDE(SupervisorTimer = DefaultHandler);
|
||||
PROVIDE(MachineTimer = DefaultHandler);
|
||||
PROVIDE(SupervisorExternal = DefaultHandler);
|
||||
PROVIDE(MachineExternal = DefaultHandler);
|
||||
|
||||
PROVIDE(DefaultHandler = DefaultInterruptHandler);
|
||||
PROVIDE(ExceptionHandler = DefaultExceptionHandler);
|
||||
|
||||
PROVIDE(__pre_init = default_pre_init);
|
||||
PROVIDE(_setup_interrupts = default_setup_interrupts);
|
||||
PROVIDE(_mp_hook = default_mp_hook);
|
||||
PROVIDE(_start_trap = default_start_trap);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text.dummy (NOLOAD) :
|
||||
{
|
||||
. = ABSOLUTE(_stext);
|
||||
} > FLASH
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
//! Implementation module
|
||||
//!
|
||||
//! **File:** `board.rs`
|
||||
//! **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.
|
||||
|
||||
// Timer driver pure-logic functions and constants
|
||||
use timer_lib::timer;
|
||||
// Rate extension trait for .Hz() baud rate construction
|
||||
use fugit::RateExtU32;
|
||||
// Clock trait for accessing system clock frequency
|
||||
use hal::Clock;
|
||||
// GPIO pin types and function selectors
|
||||
use hal::gpio::{FunctionNull, FunctionUart, Pin, PullDown, PullNone};
|
||||
// UART configuration and peripheral types
|
||||
use hal::uart::{DataBits, Enabled, StopBits, UartConfig, UartPeripheral};
|
||||
// Alias our HAL crate
|
||||
#[cfg(rp2350)]
|
||||
// Import rp235x_hal as hal
|
||||
use rp235x_hal as hal;
|
||||
#[cfg(rp2040)]
|
||||
// Import rp2040_hal as hal
|
||||
use rp2040_hal as hal;
|
||||
|
||||
/// Timer device type for the HAL timer peripheral.
|
||||
#[cfg(rp2350)]
|
||||
pub(crate) type HalTimer = hal::Timer<hal::timer::CopyableTimer0>;
|
||||
/// Timer type alias for RP2040 (non-generic).
|
||||
#[cfg(rp2040)]
|
||||
pub(crate) type HalTimer = hal::Timer;
|
||||
|
||||
/// External crystal frequency in Hz (12 MHz).
|
||||
pub(crate) const XTAL_FREQ_HZ: u32 = 12_000_000u32;
|
||||
|
||||
/// UART baud rate in bits per second.
|
||||
pub(crate) const UART_BAUD: u32 = 115_200;
|
||||
|
||||
/// Type alias for the configured TX pin (GPIO 0, UART function, no pull).
|
||||
pub(crate) type TxPin = Pin<hal::gpio::bank0::Gpio0, FunctionUart, PullNone>;
|
||||
|
||||
/// Type alias for the configured RX pin (GPIO 1, UART function, no pull).
|
||||
pub(crate) type RxPin = Pin<hal::gpio::bank0::Gpio1, FunctionUart, PullNone>;
|
||||
|
||||
/// Type alias for the default TX pin state from `Pins::new()`.
|
||||
pub(crate) type TxPinDefault = Pin<hal::gpio::bank0::Gpio0, FunctionNull, PullDown>;
|
||||
|
||||
/// Type alias for the default RX pin state from `Pins::new()`.
|
||||
pub(crate) type RxPinDefault = Pin<hal::gpio::bank0::Gpio1, FunctionNull, PullDown>;
|
||||
|
||||
/// Type alias for the fully-enabled UART0 peripheral with TX/RX p.
|
||||
pub(crate) type EnabledUart = UartPeripheral<Enabled, hal::pac::UART0, (TxPin, RxPin)>;
|
||||
|
||||
/// Initialise system clocks and PLLs from the external 12 MHz crystal.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `xosc` - XOSC peripheral singleton.
|
||||
/// * `clocks` - CLOCKS peripheral singleton.
|
||||
/// * `pll_sys` - PLL_SYS peripheral singleton.
|
||||
/// * `pll_usb` - PLL_USB peripheral singleton.
|
||||
/// * `resets` - Mutable reference to the RESETS peripheral.
|
||||
/// * `watchdog` - Mutable reference to the watchdog timer.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Configured clocks manager.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if clock initialisation fails.
|
||||
pub(crate) fn init_clocks(
|
||||
xosc: hal::pac::XOSC, clocks: hal::pac::CLOCKS, pll_sys: hal::pac::PLL_SYS, pll_usb: hal::pac::PLL_USB,
|
||||
resets: &mut hal::pac::RESETS, watchdog: &mut hal::Watchdog,
|
||||
) -> hal::clocks::ClocksManager {
|
||||
hal::clocks::init_clocks_and_plls(XTAL_FREQ_HZ, xosc, clocks, pll_sys, pll_usb, resets, watchdog).unwrap()
|
||||
}
|
||||
|
||||
/// Unlock the GPIO bank and return the pin set.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `io_bank0` - IO_BANK0 peripheral singleton.
|
||||
/// * `pads_bank0` - PADS_BANK0 peripheral singleton.
|
||||
/// * `sio` - SIO peripheral singleton.
|
||||
/// * `resets` - Mutable reference to the RESETS peripheral.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// GPIO pin set for the entire bank.
|
||||
pub(crate) fn init_pins(
|
||||
io: hal::pac::IO_BANK0, pads: hal::pac::PADS_BANK0, sio: hal::pac::SIO, rst: &mut hal::pac::RESETS
|
||||
) -> hal::gpio::Pins {
|
||||
hal::gpio::Pins::new(io, pads, hal::Sio::new(sio).gpio_bank0, rst)
|
||||
}
|
||||
|
||||
/// Initialise UART0 for serial output (stdio equivalent).
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `uart0` - PAC UART0 peripheral singleton.
|
||||
/// * `tx_pin` - GPIO pin to use as UART0 TX (GPIO 0).
|
||||
/// * `rx_pin` - GPIO pin to use as UART0 RX (GPIO 1).
|
||||
/// * `resets` - Mutable reference to the RESETS peripheral.
|
||||
/// * `clocks` - Reference to the initialised clock configuration.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Enabled UART0 peripheral ready for blocking writes.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the HAL cannot achieve the requested baud rate.
|
||||
pub(crate) fn init_uart(
|
||||
uart0: hal::pac::UART0, tx: TxPinDefault, rx: RxPinDefault, rst: &mut hal::pac::RESETS, c: &hal::clocks::ClocksManager
|
||||
) -> EnabledUart {
|
||||
let pins = (tx.reconfigure::<FunctionUart, PullNone>(), rx.reconfigure::<FunctionUart, PullNone>());
|
||||
let cfg = UartConfig::new(UART_BAUD.Hz(), DataBits::Eight, None, StopBits::One);
|
||||
UartPeripheral::new(uart0, pins, rst).enable(cfg, c.peripheral_clock.freq()).unwrap()
|
||||
}
|
||||
|
||||
/// Create a blocking delay timer from the ARM SysTick peripheral.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `clocks` - Reference to the initialised clock configuration.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Blocking delay provider.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the cortex-m core peripherals have already been taken.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `clocks` - The `clocks` parameter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `cortex_m::delay::Delay`.
|
||||
pub(crate) fn init_delay(clocks: &hal::clocks::ClocksManager) -> cortex_m::delay::Delay {
|
||||
let core = cortex_m::Peripherals::take().unwrap();
|
||||
cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz())
|
||||
}
|
||||
|
||||
/// Run the repeating timer heartbeat loop.
|
||||
///
|
||||
/// Polls the HAL timer, and each time the configured period elapses,
|
||||
/// fires the driver state callback and prints the heartbeat message
|
||||
/// over UART. This mirrors the C demo's `_heartbeat_callback` being
|
||||
/// invoked by the Pico SDK repeating timer.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `uart` - Reference to the enabled UART peripheral for serial output.
|
||||
/// * `timer` - Reference to the HAL timer for microsecond measurement.
|
||||
/// * `delay` - Mutable reference to the blocking delay provider.
|
||||
/// * `state` - Mutable reference to the timer driver state.
|
||||
pub(crate) fn heartbeat_loop(
|
||||
uart: &EnabledUart, timer: &HalTimer, delay: &mut cortex_m::delay::Delay, state: &mut timer::TimerDriverState
|
||||
) -> ! {
|
||||
let (mut last_us, period_us) = (timer.get_counter().ticks() as u32, state.period_ms() as u64 * 1_000);
|
||||
loop {
|
||||
let (now, elapsed) = tick_elapsed(timer, last_us);
|
||||
if elapsed >= period_us { last_us = now; fire_heartbeat(uart, state); }
|
||||
delay.delay_us(100);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute elapsed microseconds since last checkpoint.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `timer` - The `timer` parameter.
|
||||
/// * `last_us` - The `last_us` parameter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `(u32, u64)`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `timer` - The `timer` parameter.
|
||||
/// * `last_us` - The `last_us` parameter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `(u32, u64)`.
|
||||
fn tick_elapsed(timer: &HalTimer, last_us: u32) -> (u32, u64) {
|
||||
let now = timer.get_counter().ticks() as u32; (now, now.wrapping_sub(last_us) as u64)
|
||||
}
|
||||
|
||||
/// Fire the heartbeat callback and print the message over UART.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `uart` - The `uart` parameter.
|
||||
/// * `state` - The state to set.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `uart` - The `uart` parameter.
|
||||
/// * `state` - The state to set.
|
||||
fn fire_heartbeat(uart: &EnabledUart, state: &mut timer::TimerDriverState) {
|
||||
if state.on_fire() {
|
||||
let mut buf = [0u8; 32];
|
||||
let n = timer::format_heartbeat(&mut buf); uart.write_full_blocking(&buf[..n]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialise all peripherals and run the repeating timer demo.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `pac` - PAC Peripherals singleton (consumed).
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `!`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `pac` - The `pac` parameter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `!`.
|
||||
pub(crate) fn run(mut p: hal::pac::Peripherals) -> ! {
|
||||
let c = init_clocks(p.XOSC, p.CLOCKS, p.PLL_SYS, p.PLL_USB, &mut p.RESETS, &mut hal::Watchdog::new(p.WATCHDOG));
|
||||
let pins = init_pins(p.IO_BANK0, p.PADS_BANK0, p.SIO, &mut p.RESETS);
|
||||
let (u, mut d) = (init_uart(p.UART0, pins.gpio0, pins.gpio1, &mut p.RESETS, &c), init_delay(&c));
|
||||
#[cfg(rp2350)] let t = hal::Timer::new_timer0(p.TIMER0, &mut p.RESETS, &c); #[cfg(rp2040)] let t = hal::Timer::new(p.TIMER, &mut p.RESETS);
|
||||
let mut state = start_timer(&u);
|
||||
heartbeat_loop(&u, &t, &mut d, &mut state)
|
||||
}
|
||||
|
||||
/// Create the timer driver state, start it, and report over UART.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `uart` - Reference to the enabled UART peripheral for serial output.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Initialised timer driver state.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `uart` - The `uart` parameter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `timer::TimerDriverState`.
|
||||
fn start_timer(uart: &EnabledUart) -> timer::TimerDriverState {
|
||||
let mut state = timer::TimerDriverState::new(); state.start(timer::DEFAULT_PERIOD_MS);
|
||||
let mut buf = [0u8; 64]; let n = timer::format_started(&mut buf, timer::DEFAULT_PERIOD_MS);
|
||||
uart.write_full_blocking(&buf[..n]); state
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
//! Driver crate
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(clippy::missing_docs_in_private_items)]
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
pub mod timer;
|
||||
@@ -0,0 +1,102 @@
|
||||
//! Driver crate
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(clippy::missing_docs_in_private_items)]
|
||||
|
||||
//! Implementation module
|
||||
//!
|
||||
//! **File:** `main.rs`
|
||||
//! **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.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
// Board-level helpers: constants, type aliases, and init functions
|
||||
mod board;
|
||||
// Timer driver module — suppress warnings for unused public API functions
|
||||
|
||||
// Debugging output over RTT
|
||||
use defmt_rtt as _;
|
||||
// Panic handler for RISC-V targets
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
// Import panic_halt as _
|
||||
use panic_halt as _;
|
||||
// Panic handler for ARM targets
|
||||
#[cfg(target_arch = "arm")]
|
||||
// Import panic_probe as _
|
||||
use panic_probe as _;
|
||||
// HAL entry-point macro
|
||||
use hal::entry;
|
||||
// Alias our HAL crate
|
||||
#[cfg(rp2350)]
|
||||
// Import rp235x_hal as hal
|
||||
use rp235x_hal as hal;
|
||||
#[cfg(rp2040)]
|
||||
// Import rp2040_hal as hal
|
||||
use rp2040_hal as hal;
|
||||
|
||||
/// Second-stage boot loader for RP2040
|
||||
#[unsafe(link_section = ".boot2")]
|
||||
#[used]
|
||||
#[cfg(rp2040)]
|
||||
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
|
||||
|
||||
/// Boot metadata for the RP2350 Boot ROM
|
||||
#[unsafe(link_section = ".start_block")]
|
||||
#[used]
|
||||
#[cfg(rp2350)]
|
||||
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
|
||||
|
||||
/// Application entry point for the repeating timer demo.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `!`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `!`.
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
board::run(hal::pac::Peripherals::take().unwrap())
|
||||
}
|
||||
|
||||
/// Picotool binary info metadata
|
||||
#[unsafe(link_section = ".bi_entries")]
|
||||
#[used]
|
||||
pub static PICOTOOL_ENTRIES: [hal::binary_info::EntryAddr; 5] = [
|
||||
hal::binary_info::rp_cargo_bin_name!(),
|
||||
hal::binary_info::rp_cargo_version!(),
|
||||
hal::binary_info::rp_program_description!(c"Repeating Timer Demo"),
|
||||
hal::binary_info::rp_cargo_homepage_url!(),
|
||||
hal::binary_info::rp_program_build_attribute!(),
|
||||
];
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// Import all parent module items
|
||||
use super::*;
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
//! Implementation module
|
||||
//!
|
||||
//! **File:** `timer.rs`
|
||||
//! **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.
|
||||
|
||||
/// Default heartbeat message printed by the timer callback.
|
||||
pub const HEARTBEAT_MSG: &[u8] = b"Timer heartbeat\r\n";
|
||||
|
||||
/// Default timer period in milliseconds.
|
||||
pub const DEFAULT_PERIOD_MS: u32 = 1_000;
|
||||
|
||||
/// Timer driver state tracking whether the repeating timer is active.
|
||||
///
|
||||
/// Mirrors the C driver's `g_timer_active` / `g_user_callback` globals
|
||||
/// as a structured state machine testable on the host.
|
||||
pub struct TimerDriverState {
|
||||
/// Whether the repeating timer is currently active.
|
||||
active: bool,
|
||||
/// Configured period in milliseconds.
|
||||
period_ms: u32,
|
||||
/// Number of times the callback has fired.
|
||||
fire_count: u32,
|
||||
}
|
||||
|
||||
impl TimerDriverState {
|
||||
/// Create a new idle timer driver state.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A `TimerDriverState` in the inactive state with zero fire count.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A new instance of the struct.
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self { active: false, period_ms: 0, fire_count: 0 }
|
||||
}
|
||||
|
||||
/// Start the repeating timer with the given period.
|
||||
///
|
||||
/// If the timer is already active it is first cancelled, matching
|
||||
/// the C driver's `timer_driver_start()` behaviour.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `period_ms` - Interval between callbacks in milliseconds.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `period_ms` - The `period_ms` parameter.
|
||||
#[inline]
|
||||
pub fn start(&mut self, period_ms: u32) {
|
||||
if self.active { self.cancel(); }
|
||||
self.period_ms = period_ms; self.active = true;
|
||||
}
|
||||
|
||||
/// Cancel the active repeating timer.
|
||||
///
|
||||
/// Safe to call even if the timer is already inactive, matching
|
||||
/// the C driver's `timer_driver_cancel()` behaviour.
|
||||
#[inline]
|
||||
pub fn cancel(&mut self) {
|
||||
self.active = false;
|
||||
}
|
||||
|
||||
/// Return whether the timer is currently active.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// `true` if a repeating timer is running, `false` otherwise.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// `true` if successful or set, `false` otherwise.
|
||||
#[inline]
|
||||
pub fn is_active(&self) -> bool {
|
||||
self.active
|
||||
}
|
||||
|
||||
/// Return the configured timer period in milliseconds.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// The period set by the most recent `start()` call.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A 32-bit unsigned integer value.
|
||||
#[inline]
|
||||
pub fn period_ms(&self) -> u32 {
|
||||
self.period_ms
|
||||
}
|
||||
|
||||
/// Return the total number of times the callback has fired.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Cumulative fire count since construction.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A 32-bit unsigned integer value.
|
||||
#[inline]
|
||||
pub fn fire_count(&self) -> u32 {
|
||||
self.fire_count
|
||||
}
|
||||
|
||||
/// Record that the callback has fired once.
|
||||
///
|
||||
/// Called by the board-level shim each time the hardware alarm
|
||||
/// triggers. Returns `true` to keep the timer repeating (matching
|
||||
/// the C `_heartbeat_callback` return value).
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// `true` if the timer should continue repeating.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// `true` if successful or set, `false` otherwise.
|
||||
#[inline]
|
||||
pub fn on_fire(&mut self) -> bool {
|
||||
if !self.active { return false; }
|
||||
self.fire_count += 1; true
|
||||
}
|
||||
}
|
||||
|
||||
/// Format the heartbeat message into a caller-supplied buffer.
|
||||
///
|
||||
/// Writes the fixed `HEARTBEAT_MSG` bytes and returns the number
|
||||
/// of bytes written.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `buf` - Destination buffer (must be at least `HEARTBEAT_MSG.len()` bytes).
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Number of bytes written to `buf`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `buf` - The `buf` parameter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `usize`.
|
||||
#[inline]
|
||||
pub fn format_heartbeat(buf: &mut [u8]) -> usize {
|
||||
let len = HEARTBEAT_MSG.len(); buf[..len].copy_from_slice(HEARTBEAT_MSG); len
|
||||
}
|
||||
|
||||
/// Format a timer-started banner message.
|
||||
///
|
||||
/// Writes "Repeating timer started (XXXX ms)\r\n" into `buf` and
|
||||
/// returns the number of bytes written.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `buf` - Destination buffer (must be at least 40 bytes).
|
||||
/// * `period_ms` - Timer period to include in the message.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Number of bytes written to `buf`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `buf` - The `buf` parameter.
|
||||
/// * `period_ms` - The `period_ms` parameter.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `usize`.
|
||||
#[inline]
|
||||
pub fn format_started(buf: &mut [u8], period_ms: u32) -> usize {
|
||||
let mut pos = b"Repeating timer started (".len(); buf[..pos].copy_from_slice(b"Repeating timer started (");
|
||||
pos += format_u32(&mut buf[pos..], period_ms);
|
||||
buf[pos..pos + 6].copy_from_slice(b" ms)\r\n"); pos + 6
|
||||
}
|
||||
|
||||
/// Format an unsigned 32-bit integer as decimal ASCII.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `buf` - Destination buffer.
|
||||
/// * `value` - Value to format.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Number of ASCII digits written.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `buf` - The `buf` parameter.
|
||||
/// * `value` - Value to use.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `usize`.
|
||||
#[inline]
|
||||
fn format_u32(buf: &mut [u8], value: u32) -> usize {
|
||||
if value == 0 { buf[0] = b'0'; return 1; }
|
||||
let mut tmp = [0u8; 10]; let n = u32_to_digits_reversed(&mut tmp, value); reverse_copy(buf, &tmp, n); n
|
||||
}
|
||||
|
||||
/// Convert a u32 to reversed decimal digits in a temporary buffer.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `tmp` - The `tmp` parameter.
|
||||
/// * `value` - Value to use.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `usize`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `tmp` - The `tmp` parameter.
|
||||
/// * `value` - Value to use.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A value of type `usize`.
|
||||
#[inline]
|
||||
fn u32_to_digits_reversed(tmp: &mut [u8; 10], mut value: u32) -> usize {
|
||||
let mut n = 0usize;
|
||||
while value > 0 { tmp[n] = b'0' + (value % 10) as u8; value /= 10; n += 1; }
|
||||
n
|
||||
}
|
||||
|
||||
/// Copy digits from a reversed temporary buffer into the output buffer.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `buf` - The `buf` parameter.
|
||||
/// * `tmp` - The `tmp` parameter.
|
||||
/// * `n` - Nibble or number.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `buf` - The `buf` parameter.
|
||||
/// * `tmp` - The `tmp` parameter.
|
||||
/// * `n` - Nibble or number.
|
||||
#[inline]
|
||||
fn reverse_copy(buf: &mut [u8], tmp: &[u8], n: usize) {
|
||||
for i in 0..n { buf[i] = tmp[n - 1 - i]; }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// Import all parent module items
|
||||
use super::*;
|
||||
|
||||
/// Executes the new state is inactive operation.
|
||||
#[test]
|
||||
fn new_state_is_inactive() {
|
||||
let state = TimerDriverState::new();
|
||||
assert!(!state.is_active());
|
||||
assert_eq!(state.period_ms(), 0);
|
||||
assert_eq!(state.fire_count(), 0);
|
||||
}
|
||||
|
||||
/// Executes the start activates timer operation.
|
||||
#[test]
|
||||
fn start_activates_timer() {
|
||||
let mut state = TimerDriverState::new();
|
||||
state.start(1_000);
|
||||
assert!(state.is_active());
|
||||
assert_eq!(state.period_ms(), 1_000);
|
||||
}
|
||||
|
||||
/// Executes the cancel deactivates timer operation.
|
||||
#[test]
|
||||
fn cancel_deactivates_timer() {
|
||||
let mut state = TimerDriverState::new();
|
||||
state.start(1_000);
|
||||
state.cancel();
|
||||
assert!(!state.is_active());
|
||||
}
|
||||
|
||||
/// Executes the cancel when inactive is safe operation.
|
||||
#[test]
|
||||
fn cancel_when_inactive_is_safe() {
|
||||
let mut state = TimerDriverState::new();
|
||||
state.cancel();
|
||||
assert!(!state.is_active());
|
||||
}
|
||||
|
||||
/// Executes the start while active cancels and restarts operation.
|
||||
#[test]
|
||||
fn start_while_active_cancels_and_restarts() {
|
||||
let mut state = TimerDriverState::new();
|
||||
state.start(500);
|
||||
state.start(2_000);
|
||||
assert!(state.is_active());
|
||||
assert_eq!(state.period_ms(), 2_000);
|
||||
}
|
||||
|
||||
/// Executes the on fire increments count operation.
|
||||
#[test]
|
||||
fn on_fire_increments_count() {
|
||||
let mut state = TimerDriverState::new();
|
||||
state.start(1_000);
|
||||
assert!(state.on_fire());
|
||||
assert_eq!(state.fire_count(), 1);
|
||||
assert!(state.on_fire());
|
||||
assert_eq!(state.fire_count(), 2);
|
||||
}
|
||||
|
||||
/// Executes the on fire returns false when inactive operation.
|
||||
#[test]
|
||||
fn on_fire_returns_false_when_inactive() {
|
||||
let mut state = TimerDriverState::new();
|
||||
assert!(!state.on_fire());
|
||||
assert_eq!(state.fire_count(), 0);
|
||||
}
|
||||
|
||||
/// Executes the on fire after cancel returns false operation.
|
||||
#[test]
|
||||
fn on_fire_after_cancel_returns_false() {
|
||||
let mut state = TimerDriverState::new();
|
||||
state.start(1_000);
|
||||
assert!(state.on_fire());
|
||||
state.cancel();
|
||||
assert!(!state.on_fire());
|
||||
assert_eq!(state.fire_count(), 1);
|
||||
}
|
||||
|
||||
/// Executes the format heartbeat matches c output operation.
|
||||
#[test]
|
||||
fn format_heartbeat_matches_c_output() {
|
||||
let mut buf = [0u8; 32];
|
||||
let n = format_heartbeat(&mut buf);
|
||||
assert_eq!(&buf[..n], b"Timer heartbeat\r\n");
|
||||
}
|
||||
|
||||
/// Executes the format started 1000ms operation.
|
||||
#[test]
|
||||
fn format_started_1000ms() {
|
||||
let mut buf = [0u8; 48];
|
||||
let n = format_started(&mut buf, 1_000);
|
||||
assert_eq!(&buf[..n], b"Repeating timer started (1000 ms)\r\n");
|
||||
}
|
||||
|
||||
/// Executes the format started single digit operation.
|
||||
#[test]
|
||||
fn format_started_single_digit() {
|
||||
let mut buf = [0u8; 48];
|
||||
let n = format_started(&mut buf, 5);
|
||||
assert_eq!(&buf[..n], b"Repeating timer started (5 ms)\r\n");
|
||||
}
|
||||
|
||||
/// Executes the format u32 zero operation.
|
||||
#[test]
|
||||
fn format_u32_zero() {
|
||||
let mut buf = [0u8; 10];
|
||||
let n = format_u32(&mut buf, 0);
|
||||
assert_eq!(&buf[..n], b"0");
|
||||
}
|
||||
|
||||
/// Executes the format u32 large value operation.
|
||||
#[test]
|
||||
fn format_u32_large_value() {
|
||||
let mut buf = [0u8; 10];
|
||||
let n = format_u32(&mut buf, 123456);
|
||||
assert_eq!(&buf[..n], b"123456");
|
||||
}
|
||||
|
||||
/// Executes the default period matches c demo operation.
|
||||
#[test]
|
||||
fn default_period_matches_c_demo() {
|
||||
assert_eq!(DEFAULT_PERIOD_MS, 1_000);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user