diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 251475f..03682dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: nightly-2021-04-24 override: true components: rust-src, llvm-tools-preview target: aarch64-unknown-linux-gnu @@ -54,7 +54,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: nightly-2021-04-24 override: true components: rust-src, llvm-tools-preview target: aarch64-unknown-linux-gnu @@ -155,7 +155,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: nightly-2021-04-24 override: true components: rust-src, llvm-tools-preview target: aarch64-unknown-linux-gnu @@ -195,7 +195,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly + toolchain: nightly-2021-04-24 override: true components: rust-src, llvm-tools-preview target: aarch64-unknown-linux-gnu diff --git a/.gitignore b/.gitignore index 5ed61d2..d8df9ac 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,4 @@ **/*/target **/*.rs.bk **/release -.vscode -*.lock \ No newline at end of file +.vscode \ No newline at end of file diff --git a/interrupt/.rustfmt.toml b/.rustfmt.toml similarity index 100% rename from interrupt/.rustfmt.toml rename to .rustfmt.toml diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c0f994..de4c0c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## :dog: v0.4.2 + +- ### :wrench: Maintenance + + Some minor cleanup has been done. The major addition is to provide a minimal example of how the crate is intended to be used to implement an interrupt handler based on the ARM system timer. + ## :cat: v0.4.1 - ### :bulb: Features diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..92b99a1 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,146 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "futures-core" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" + +[[package]] +name = "futures-task" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" + +[[package]] +name = "futures-util" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "paste" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" + +[[package]] +name = "pin-project-lite" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ruspiro-arch-aarch64" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585439e7a06c60294325fd1016cf5841ecf39bc388088d7fe09938a5e8050" +dependencies = [ + "ruspiro-register", +] + +[[package]] +name = "ruspiro-channel" +version = "0.1.1" +source = "git+https://github.com/RusPiRo/ruspiro-channel.git?branch=development#c059c824b38e4ce50f624cecbcc8e1b3c4620a94" +dependencies = [ + "futures-util", + "ruspiro-arch-aarch64", +] + +[[package]] +name = "ruspiro-interrupt" +version = "0.4.3" +dependencies = [ + "futures-util", + "paste", + "ruspiro-channel", + "ruspiro-interrupt-macros", + "ruspiro-mmio-register", + "ruspiro-singleton", +] + +[[package]] +name = "ruspiro-interrupt-macros" +version = "0.3.2" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ruspiro-lock" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173b1c02f49d11313eede4e63d03c2125f5f13f2119f98a213edbb03b20740bd" + +[[package]] +name = "ruspiro-mmio-register" +version = "0.1.2" +source = "git+https://github.com/RusPiRo/ruspiro-mmio-register.git?branch=development#2a17a256a038306ab0cdf19b6927d1e9ba67b5e0" +dependencies = [ + "ruspiro-register", +] + +[[package]] +name = "ruspiro-register" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161d5f7992ad812a4cf78301846265fb34ba86db288d17aa35d36c5ec72ee349" + +[[package]] +name = "ruspiro-singleton" +version = "0.4.2" +source = "git+https://github.com/RusPiRo/ruspiro-singleton.git?branch=development#3c6d79781cfc03af4c2166ff41250f6bd724dbf2" +dependencies = [ + "ruspiro-lock", +] + +[[package]] +name = "syn" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/Cargo.toml b/Cargo.toml index 57946c2..8be8033 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,12 @@ members = [ "./interrupt" ] +exclude = [ + "./interrupt/examples/minimal" +] + [patch.crates-io] ruspiro-interrupt-macros = { path = "./macros" } -ruspiro-mmio-register = { git = "https://github.com/RusPiRo/ruspiro-mmio-register.git" } -ruspiro-singleton = { git ="https://github.com/RusPiRo/ruspiro-singleton.git" } +ruspiro-mmio-register = { git = "https://github.com/RusPiRo/ruspiro-mmio-register.git", branch = "development" } +ruspiro-singleton = { git ="https://github.com/RusPiRo/ruspiro-singleton.git", branch = "development" } ruspiro-channel = { git = "https://github.com/RusPiRo/ruspiro-channel.git", branch = "development" } \ No newline at end of file diff --git a/README.md b/README.md index 16f0c83..8ccb5ff 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,12 @@ unsafe fn my_handler_for_source(tx: Option>>) { The currently only implemented shared source interrupt line is the ``AUX`` interrupt. There the source could be one of: ``Uart1``, ``Spi1`` or ``Spi2``. +## Features + +Feature | Description +----------|------------- +**async** | Enables the `async` version of the interrupt handling implementation. + ## License Licensed under Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) or MIT ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)) at your choice. diff --git a/interrupt/Cargo.toml b/interrupt/Cargo.toml index a0d2784..3b64821 100644 --- a/interrupt/Cargo.toml +++ b/interrupt/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ruspiro-interrupt" authors = ["Andre Borrmann "] -version = "0.4.2" # remember to update html_root_url +version = "0.4.3" # remember to update html_root_url description = """ Providing a simple and convinient way to implement interrupt handler for Raspberry Pi interrupts. """ @@ -12,7 +12,7 @@ readme = "../README.md" keywords = ["RusPiRo", "baremetal", "raspberrypi", "interrupt"] categories = ["no-std", "embedded"] edition = "2018" -exclude = [".travis.yml", "Makefile.toml"] +exclude = ["Makefile.toml"] links = "ruspiro_interrupt" [badges] @@ -21,13 +21,12 @@ maintenance = { status = "actively-developed" } [lib] [dependencies] -# get functions like memset, memcpy into the binary paste = "~1.0" -futures-util = { version = "~0.3", default-features = false, optional = true } -ruspiro-mmio-register = "~0.1" +futures-util = { version = "~0.3.14", default-features = false, optional = true } +ruspiro-mmio-register = "~0.1.2" ruspiro-interrupt-macros = { path = "../macros", version = "~0.3" } -ruspiro-singleton = "~0.4" -ruspiro-channel = "~0.1" +ruspiro-singleton = "~0.4.2" +ruspiro-channel = "~0.1.1" [features] ruspiro_pi3 = [] diff --git a/interrupt/Makefile.toml b/interrupt/Makefile.toml index 4724800..97206a7 100644 --- a/interrupt/Makefile.toml +++ b/interrupt/Makefile.toml @@ -30,10 +30,17 @@ env = { FEATURES = "ruspiro_pi3, async" } command = "cargo" args = ["doc", "--features", "${FEATURES}", "--open"] -[tasks.pi3] +[tasks.pi3_blocking] +env = { FEATURES = "ruspiro_pi3" } +run_task = "build" + +[tasks.pi3_async] env = { FEATURES = "ruspiro_pi3, async" } run_task = "build" +[tasks.pi3] +dependencies = ["pi3_blocking", "pi3_async"] + [tasks.clean] command = "cargo" args = ["clean"] diff --git a/interrupt/build.rs b/interrupt/build.rs index 40796f7..6461937 100644 --- a/interrupt/build.rs +++ b/interrupt/build.rs @@ -5,5 +5,6 @@ * License: Apache License 2.0 **********************************************************************************************************************/ -// build script only required to be able to provide a linking name for this crate +// build script only required to be able to provide a linking name for this crate which prevents from different versions +// of the same crate to be allowed as dependency as this would break how this crate is linked into the final binary. fn main() {} diff --git a/interrupt/examples/minimal/.cargo/aarch64-ruspiro.json b/interrupt/examples/minimal/.cargo/aarch64-ruspiro.json new file mode 100644 index 0000000..8ca177f --- /dev/null +++ b/interrupt/examples/minimal/.cargo/aarch64-ruspiro.json @@ -0,0 +1,34 @@ +{ + "arch": "aarch64", + "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + "executables": true, + "is-builtin": false, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "llvm-target": "aarch64-unknown-none", + "max-atomic-width": 128, + "os": "none", + "pre-link-args": { + "gcc": [ + "-Wl,--as-needed", + "-Wl,-z,noexecstack" + ] + }, + "target-c-int-width": "32", + "target-endian": "little", + "target-family": "unix", + "target-mcount": "\u0001_mcount", + "target-pointer-width": "64", + "unsupported-abis": [ + "stdcall", + "fastcall", + "vectorcall", + "thiscall", + "win64", + "sysv64" + ], + "vendor": "unknown", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "" + } \ No newline at end of file diff --git a/interrupt/examples/minimal/.cargo/config.toml b/interrupt/examples/minimal/.cargo/config.toml new file mode 100644 index 0000000..17d98ca --- /dev/null +++ b/interrupt/examples/minimal/.cargo/config.toml @@ -0,0 +1,5 @@ +[build] +target = "aarch64-ruspiro.json" + +[unstable] +build-std = ["core", "compiler_builtins", "alloc"] diff --git a/interrupt/examples/minimal/Cargo.lock b/interrupt/examples/minimal/Cargo.lock new file mode 100644 index 0000000..b4a4048 --- /dev/null +++ b/interrupt/examples/minimal/Cargo.lock @@ -0,0 +1,188 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cc" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "irq-example" +version = "0.0.1" +dependencies = [ + "cc", + "ruspiro-allocator", + "ruspiro-boot", + "ruspiro-interrupt", + "ruspiro-mmio-register", + "ruspiro-mmu", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "paste" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rlibc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" + +[[package]] +name = "ruspiro-allocator" +version = "0.4.5" +dependencies = [ + "rlibc", +] + +[[package]] +name = "ruspiro-arch-aarch64" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585439e7a06c60294325fd1016cf5841ecf39bc388088d7fe09938a5e8050" +dependencies = [ + "ruspiro-register", +] + +[[package]] +name = "ruspiro-boot" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240bd72c4a519d7487ad124267d842e57577efd97d2ae1c944e2b7b617c5f4d7" +dependencies = [ + "cc", + "log", + "ruspiro-cache", + "ruspiro-register", +] + +[[package]] +name = "ruspiro-cache" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ebe25a7a5c319cf5a58f368c5bc0dd3a672e4a66d0d86382194a28bc9ad92f1" +dependencies = [ + "cc", + "ruspiro-arch-aarch64", +] + +[[package]] +name = "ruspiro-channel" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03089c61a4a2fc311b8a2b83cbba2cae31f83efe85e07bed256ac4564cdbac2b" +dependencies = [ + "ruspiro-arch-aarch64", +] + +[[package]] +name = "ruspiro-interrupt" +version = "0.4.3" +dependencies = [ + "paste", + "ruspiro-channel", + "ruspiro-interrupt-macros", + "ruspiro-mmio-register", + "ruspiro-singleton", +] + +[[package]] +name = "ruspiro-interrupt-macros" +version = "0.3.1" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ruspiro-lock" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173b1c02f49d11313eede4e63d03c2125f5f13f2119f98a213edbb03b20740bd" + +[[package]] +name = "ruspiro-mmio-register" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89465de88f06814e1a2a5568bf74e27aa8e57524161a67a2edfff73becbfc54b" +dependencies = [ + "ruspiro-register", +] + +[[package]] +name = "ruspiro-mmu" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5ccf761748f8bb59fca6d9130c8f41124f205ee7ed0ebed968a6741bd5b1da9" +dependencies = [ + "ruspiro-arch-aarch64", +] + +[[package]] +name = "ruspiro-register" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161d5f7992ad812a4cf78301846265fb34ba86db288d17aa35d36c5ec72ee349" + +[[package]] +name = "ruspiro-singleton" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1200cd47b70e308765b86464e92ae42f95020a06219aa7415c3fcb211e5e91" +dependencies = [ + "ruspiro-lock", +] + +[[package]] +name = "syn" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/interrupt/examples/minimal/Cargo.toml b/interrupt/examples/minimal/Cargo.toml new file mode 100644 index 0000000..1fe6867 --- /dev/null +++ b/interrupt/examples/minimal/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "irq-example" +version = "0.0.1" +edition = "2018" + +[workspace] + +[[bin]] +name = "kernel" +path = "./src/main.rs" + +[build-dependencies] +cc = "~1.0" + +[dependencies] +ruspiro-allocator = "~0.4.5" +ruspiro-boot = { version = "~0.5.3", features = ["multicore"] } +ruspiro-interrupt = { path = "../../", features = ["ruspiro_pi3"] } +ruspiro-mmio-register = "~0.1.2" +ruspiro-mmu = "~0.1.1" diff --git a/interrupt/examples/minimal/Makefile.toml b/interrupt/examples/minimal/Makefile.toml new file mode 100644 index 0000000..44d98df --- /dev/null +++ b/interrupt/examples/minimal/Makefile.toml @@ -0,0 +1,41 @@ +#*********************************************************************************************************************** +# cargo make tasks to build the example for the Raspberry Pi +#*********************************************************************************************************************** +[env.development] +CC = "aarch64-none-elf-gcc" +AR = "aarch64-none-elf-ar" +CFLAGS = "-march=armv8-a -Wall -O3 -nostdlib -nostartfiles -ffreestanding -mtune=cortex-a53" +RUSTFLAGS = "-C target-cpu=cortex-a53 -C target-feature=+strict-align,+a53,+fp-armv8,+neon -C link-arg=-T./link64.ld" + +[tasks.build] +command = "cargo" +args = ["build", "--release", "--features", "${FEATURES}"] + +[tasks.kernel] +command = "aarch64-none-elf-objcopy" +args = ["-O", "binary", "./target/aarch64-ruspiro/release/kernel", "./target/kernel8.img"] +dependencies = [ + "build" +] + +[tasks.pi3] +env = { FEATURES = "" } +run_task = "kernel" + +[tasks.qemu] +command = "qemu-system-aarch64" +args = ["-M", "raspi3", "-kernel", "./target/kernel8.img", "-nographic", "-serial", "null", "-serial", "mon:stdio", "-d", "int,mmu", "-D", "qemu.log"] +dependencies = [ + "pi3" +] + +[tasks.deploy] +command = "cargo" +args = ["ruspiro-push", "-k", "./target/kernel8.img", "-p", "COM3"] +dependencies = [ + "pi3" +] + +[tasks.clean] +command = "cargo" +args = ["clean"] diff --git a/interrupt/examples/minimal/aarch64-ruspiro.json b/interrupt/examples/minimal/aarch64-ruspiro.json new file mode 100644 index 0000000..8ca177f --- /dev/null +++ b/interrupt/examples/minimal/aarch64-ruspiro.json @@ -0,0 +1,34 @@ +{ + "arch": "aarch64", + "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + "executables": true, + "is-builtin": false, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "llvm-target": "aarch64-unknown-none", + "max-atomic-width": 128, + "os": "none", + "pre-link-args": { + "gcc": [ + "-Wl,--as-needed", + "-Wl,-z,noexecstack" + ] + }, + "target-c-int-width": "32", + "target-endian": "little", + "target-family": "unix", + "target-mcount": "\u0001_mcount", + "target-pointer-width": "64", + "unsupported-abis": [ + "stdcall", + "fastcall", + "vectorcall", + "thiscall", + "win64", + "sysv64" + ], + "vendor": "unknown", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "" + } \ No newline at end of file diff --git a/interrupt/examples/minimal/build.rs b/interrupt/examples/minimal/build.rs new file mode 100644 index 0000000..16f76fb --- /dev/null +++ b/interrupt/examples/minimal/build.rs @@ -0,0 +1,28 @@ +/*************************************************************************************************** + * Copyright (c) 2019 by the authors + * + * Author: André Borrmann + * License: Apache License 2.0 + **************************************************************************************************/ +//! Build Script to copy the required linker script from the dependent `ruspiro-boot` crate to the +//! current build folder +//! + +use std::{env, fs, path::Path}; + +fn main() { + // copy the linker script from the boot crate to the current directory + // so it will be invoked by the linker + if let Some(source) = env::var_os("DEP_RUSPIRO_BOOT_LINKERSCRIPT") { + println!("found boot dependency"); + let ld_source = source.to_str().unwrap().replace("\\", "/"); + let src_file = Path::new(&ld_source); + let trg_file = format!( + "{}/{}", + env::current_dir().unwrap().display(), + src_file.file_name().unwrap().to_str().unwrap() + ); + println!("Copy linker script from {:?}, to {:?}", src_file, trg_file); + fs::copy(src_file, trg_file).unwrap(); + } +} diff --git a/interrupt/examples/minimal/src/main.rs b/interrupt/examples/minimal/src/main.rs new file mode 100644 index 0000000..a319c6b --- /dev/null +++ b/interrupt/examples/minimal/src/main.rs @@ -0,0 +1,168 @@ +//! # Interrupt Handler Usage Example +//! +//! This minimal example uses the ARM system timer to trigger an interrupt. +//! The implementation demonstrates how the corresponding interrupt handler +//! could be written and how the ISR channel can be used to notify the +//! normal processing that the interrupt has happened. +//! +//! When this example is build and deployed to the Raspberry Pi it will blink an +//! LED connected to GPIO pin 21. +//! + +#![no_std] +#![no_main] + +extern crate alloc; +extern crate ruspiro_allocator; +extern crate ruspiro_boot; +extern crate ruspiro_interrupt; + +use alloc::boxed::Box; +use ruspiro_boot::{come_alive_with, run_with}; +use ruspiro_interrupt::{self as irq, IrqHandler, isr_channel}; +use ruspiro_mmio_register::define_mmio_register; +use ruspiro_mmu as mmu; + +come_alive_with!(alive); +run_with!(running); + +fn alive(core: u32) { + // do one-time initialization here + // configure the mmu as we will deal with atomic operations (within the memory + // allocator that is used by the isr channel under the hood to store the data + // within the HEAP) + // use some arbitrary values for VideoCore memory start and size. This is fine + // as we will use a small lower amount of the ARM memory only. + unsafe { mmu::initialize(core, 0x3000_0000, 0x001_000) }; + + // initialize interrupt handling + irq::initialize(); + + // configure the timer + SYS_TIMERCS::Register.write_value(SYS_TIMERCS::M1::MATCH); + // set the match value to the current free-running counter + some delta + // the delta is one tick per micro second + let current = SYS_TIMERCLO::Register.get(); + // set the match value to 1s after now + SYS_TIMERC1::Register.set(current + 1_000_000); + + // globally enable interrupts + irq::enable_interrupts(); + + // now create the ISR channel and register the same with the interrupt + let (timer_tx, timer_rx) = isr_channel(); + irq::activate(irq::Interrupt::SystemTimer1, Some(timer_tx.clone())); + + loop { + // wait for the interrupt to send stuff through the channel and lit a led + // on GPIO 21 to indicate this + while timer_rx.recv().is_err() {}; + unsafe { lit_debug_led(21) }; + + // wait for the interrupt to send stuff through the channel and clear a led + // on GPIO 21 to indicate this + while timer_rx.recv().is_err() {}; + unsafe { clear_debug_led(21) }; + } +} + +fn running(_core: u32) -> ! { + // do any processing here and ensure you never return from this function + loop { } +} + + +// provide the interrupt handler implementation for a specific interrupt +#[IrqHandler(SystemTimer1)] +fn isr_system_timer(tx: Option>>) { + // as soon as the interupt was raised we need to acknowledge the same + // as we could configure up to 4 compare match values we need to check + // which one actually raised this IRQ. We only deal with match value 1 here + if SYS_TIMERCS::Register.read(SYS_TIMERCS::M1) == 1 { + SYS_TIMERCS::Register.write_value(SYS_TIMERCS::M1::MATCH); + // in case of a channel being present just send an empty message + tx.map(|channel| channel.send(Box::new(()))); + // once we have received the timer interrupt update the match value + // to trigger the interrupt again + // set the match value to the current free-running counter + some delta + // the delta is one tick per micro second + let current = SYS_TIMERCLO::Register.get(); + // set the match value to 1s after now + SYS_TIMERC1::Register.set(current + 1_000_000); + } +} + +// Define some MMIO registers required for accessing the timer device +const PERIPHERAL_BASE: usize = 0x3F00_0000; +// Base address of system timer MMIO register +const SYS_TIMER_BASE: usize = PERIPHERAL_BASE + 0x3000; + +define_mmio_register![ + /// system timer control register, keep in mind that actually only timer 1 and 3 are free on RPi + pub SYS_TIMERCS@(SYS_TIMER_BASE)> { + /// system timer 0 match flag + M0 OFFSET(0) [ + MATCH = 1, + CLEAR = 0 + ], + /// system timer 1 match flag + M1 OFFSET(1) [ + MATCH = 1, + CLEAR = 0 + ], + /// system timer 2 match flag + M2 OFFSET(2) [ + MATCH = 1, + CLEAR = 0 + ], + /// system timer 3 match flag + M3 OFFSET(3) [ + MATCH = 1, + CLEAR = 0 + ] + }, + /// system timer free running counter lower 32Bit value + pub SYS_TIMERCLO@(SYS_TIMER_BASE + 0x04)>, + /// system timer compare value register + pub SYS_TIMERC1@(SYS_TIMER_BASE + 0x10)> +]; + +// This minimal example should not have a big dependency tree just to provide a simplified version of how the interrupt +// crate is intended to be used. But to be able to see any feedback once this example is deployed to the Raspberry Pi +// we use an unsafe and direct way to manipulate a GPIO pin to lit a LED to visualize the interrupt has been raised +use core::ptr::{read_volatile, write_volatile}; +/// Lit a LED connected to the given GPIO number +/// +/// # Safety +/// This access is unsafe as it directly writes to MMIO registers. +unsafe fn lit_debug_led(num: u32) { + let fsel_num = num / 10; + let fsel_shift = (num % 10) * 3; + let fsel_addr = PERIPHERAL_BASE as u32 + 0x0020_0000 + 4 * fsel_num; + let set_addr = PERIPHERAL_BASE as u32 + 0x0020_001c + num / 32; + let mut fsel: u32 = read_volatile(fsel_addr as *const u32); + fsel &= !(7 << fsel_shift); + fsel |= 1 << fsel_shift; + write_volatile(fsel_addr as *mut u32, fsel); + + let set: u32 = 1 << (num & 0x1F); + write_volatile(set_addr as *mut u32, set); +} + +/// Clear a LED connected to the given GPIO number +/// +/// # Safety +/// This access is unsafe as it directly writes to MMIO registers. +unsafe fn clear_debug_led(num: u32) { + let fsel_num = num / 10; + let fsel_shift = (num % 10) * 3; + let fsel_addr = PERIPHERAL_BASE as u32 + 0x0020_0000 + 4 * fsel_num; + let clr_addr = PERIPHERAL_BASE as u32 + 0x0020_0028 + num / 32; + let mut fsel: u32 = read_volatile(fsel_addr as *const u32); + fsel &= !(7 << fsel_shift); + fsel |= 1 << fsel_shift; + write_volatile(fsel_addr as *mut u32, fsel); + + let clear: u32 = 1 << (num & 0x1F); + write_volatile(clr_addr as *mut u32, clear); +} \ No newline at end of file diff --git a/interrupt/src/lib.rs b/interrupt/src/lib.rs index 15a9ee0..2f311a2 100644 --- a/interrupt/src/lib.rs +++ b/interrupt/src/lib.rs @@ -26,7 +26,7 @@ //! //! // implement stuff that shall be executed if the interrupt is raised... //! // be careful when this code uses spinlocks as this might lead to dead-locks if the -//! // executing code interrupted currently helds a lock the code inside this handler tries to aquire the same one +//! // executing code interrupted currently holds a lock the code inside this handler tries to aquire as well //! } //! ``` //! @@ -43,7 +43,7 @@ //! } //! ``` //! -//! With the actual interrupt handling routines in place they the corresponding interrupts need to be configured and +//! With the actual interrupt handling routines in place the corresponding interrupts need to be configured and //! activated like the following. //! //! ```no_run @@ -51,13 +51,12 @@ //! // as we have an interrupt handler defined we need to enable interrupt handling globally as well //! // as the specific interrupt we have a handler implemented for //! irq::initialize(); -//! // activate an irq that use a channel to allow notification to flow from the interrupt handler to the "normal" +//! // activate an irq that uses a channel to allow data to flow from the interrupt handler to the "normal" //! // processing //! let (timer_tx, mut timer_rx) = isr_channel::<()>(); //! irq::activate(Interrupt::ArmTimer, timer_tx); //! // activate an irq that does not use a channel as all processing is done inside it's handler //! irq::activate(Interrupt::Aux, None); -//! }); //! //! enable_interrupts(); //! @@ -72,7 +71,7 @@ //! } //! ``` //! -//! # Limitations +//! ## Limitations for shared interrupt lines //! //! However, only a limited ammount of shared interrupt lines implementation is available with the current version - //! which is only the **Aux** interrupt at the moment. @@ -89,8 +88,8 @@ mod irqtypes; use alloc::boxed::Box; use auxhandler::{set_aux_isrsender, AuxDevice}; use core::{any::Any, cell::RefCell}; -pub use irqtypes::*; -pub use ruspiro_interrupt_macros::*; +pub use irqtypes::Interrupt; +pub use ruspiro_interrupt_macros::IrqHandler; #[cfg(feature = "async")] pub use ruspiro_channel::mpmc::async_channel as isr_channel; @@ -118,11 +117,23 @@ pub fn disable_interrupts() { interface::disable_fiq(); } -/// activate a specific interrupt to be raised and handled (id a handler is implemented) -/// if there is no handler implemented for this interrupt it may lead to an endless interrupt +/// Activate a specific interrupt to be raised and handled (if a handler is implemented). +/// If there is no handler implemented for this interrupt it may lead to an endless interrupt /// loop as the interrupt never gets acknowledged by the handler. -/// The is unfortunately no generic way of acknowledgement implementation possible as the acknowledge -/// register and process differs for the individual interrupts. +/// There is unfortunately no generic way of acknowledgement implementation possible as the acknowledge +/// register and process differs for the individual interrupts and thus need to be implemented in the specific +/// handler. +/// +/// You might want to pass a sender of an interrupt service routine channel. This channel can be used within the +/// interrupt handler implementation to pass data from the ISR to the normal processing. An example for this could be +/// an interrupt handler triggered by incomming data on the UART peripheral. The interrupt handler could read the +/// incomming data and push it into the channel for further processing that should take place outside of the interrupt +/// handler because this one should run as fast as possible. +/// To register an interrupt handler for a shared interrupt line the specialized respective function should be used. +/// +/// # Panics +/// The function panics if it is called for a known shared interrupt line +/// pub fn activate(irq: Interrupt, tx: Option>>) { // Aux interrupts share one interrupt line - thus special handling for setting the IsrSender // Aux interrupt activation is done in a separate function @@ -140,24 +151,29 @@ pub fn activate(irq: Interrupt, tx: Option>>) { }); interface::activate(irq); - //println!("enabled Irq's: {:X}, {:X}, {:X}", self.enabled[0], self.enabled[1], self.enabled[2]); #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] unsafe { llvm_asm!("dmb sy") }; } -/// activate the AUX interrupt line. This line is shared between three aux devices. The miniUART, SPI1 and SPI2. +/// Activate the AUX interrupt line. This line is shared between three aux devices. The miniUART, SPI1 and SPI2. /// The interrupts for those devices can't be enabled individually. However, we allow to register different IsrSender /// for the individual device as the interrupt provisioning is based on the AUXIRQ status register that indicates the /// correct device having raised the interrupt. The only way to suppress interrups for an individual device would /// require disabling of the device with the AUXENB register. +/// +/// You might want to pass a sender of an interrupt service routine channel. This channel can be used within the +/// interrupt handler implementation to pass data from the ISR to the normal processing. An example for this could be +/// an interrupt handler triggered by incomming data on the UART peripheral. The interrupt handler could read the +/// incomming data and push it into the channel for further processing that should take place outside of the interrupt +/// handler because this one should run as fast as possible. +/// To register an interrupt handler for a shared interrupt line the specialized respective function should be used. pub fn activate_aux(aux: AuxDevice, tx: IsrSender>) { // Aux interrupts share one interrupt line - thus special handling for setting the IsrSender set_aux_isrsender(aux, tx); interface::activate(Interrupt::Aux); - //println!("enabled Irq's: {:X}, {:X}, {:X}", self.enabled[0], self.enabled[1], self.enabled[2]); #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] unsafe { llvm_asm!("dmb sy") @@ -197,7 +213,6 @@ extern "C" fn __isr_default() { for (&pending_bank, handler_bank) in pendings.iter().zip(ISR_LIST.0.iter()) { for irq in bitset::BitSet32(pending_bank).iter() { handler_bank.get(irq as usize).map(|(handler, tx)| { - //let tx = tx.borrow().as_ref().unwrap().clone(); handler(tx.borrow().clone()); }); } diff --git a/macros/Cargo.lock b/macros/Cargo.lock new file mode 100644 index 0000000..c4ff8f1 --- /dev/null +++ b/macros/Cargo.lock @@ -0,0 +1,44 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ruspiro-interrupt-macros" +version = "0.2.2" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/macros/Cargo.toml b/macros/Cargo.toml index b0a28e0..4bc46e4 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ruspiro-interrupt-macros" authors = ["Andre Borrmann "] -version = "0.3.1" # remember to update html_root_url +version = "0.3.2" # remember to update html_root_url description = """ Macros used to implement interrupt handler. !!This crate is only useful in conjunction with the `ruspiro-interrupt` crate and shall never be used standalone!! diff --git a/macros/Makefile.toml b/macros/Makefile.toml index e451e46..5bf8308 100644 --- a/macros/Makefile.toml +++ b/macros/Makefile.toml @@ -19,7 +19,7 @@ args = ["clean"] [tasks.publish_dry] command = "cargo" -args = ["publish", "--dry-run"] +args = ["publish", "--dry-run", "--allow-dirty"] [tasks.publish] command = "cargo" diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 5e547e1..f498128 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -100,20 +100,20 @@ pub fn IrqHandler(attr: TokenStream, item: TokenStream) -> TokenStream { let irq_name_s = format!("__irq_handler__{}", irq_func_suffix); return quote!( - // use a fixed export name to ensure the same irq handler is not implemented twice - #[allow(non_snake_case)] - #[export_name = #irq_name_s] - #(#attrs)* - #[no_mangle] - pub unsafe extern "C" fn #ident( - tx: Option>> - ) { - // force compiler error if the irq_name does not appear in the Interrupt enum that need to be - // referred to in the crate using this attribute - ruspiro_interrupt::Interrupt::#irq_name; + // use a fixed export name to ensure the same irq handler is not implemented twice + #[allow(non_snake_case)] + #[export_name = #irq_name_s] + #(#attrs)* + #[no_mangle] + pub unsafe extern "C" fn #ident( + tx: Option>> + ) { + // force compiler error if the irq_name does not appear in the Interrupt enum that need to be + // referred to in the crate using this attribute + ruspiro_interrupt::Interrupt::#irq_name; - #(#stmts)* - } - ) - .into(); + #(#stmts)* + } + ) + .into(); } diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..923013b --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2021-04-24" +components = [ "rustfmt", "clippy", "rust-src", "llvm-tools-preview" ] +profile = "minimal" \ No newline at end of file