diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-11-24 03:18:30 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-12-06 22:05:41 +0100 |
| commit | dd32358d6bb24895c833bc4c34fd96e7632e43a9 (patch) | |
| tree | 57a3647217dce831e713e4709835ec2388050682 | |
| parent | 00a87b9a41f55efdf831a2579de5f271222e6577 (diff) | |
stm32: add gpio HIL test
| -rw-r--r-- | .github/workflows/rust.yml | 3 | ||||
| -rw-r--r-- | .vscode/settings.json | 2 | ||||
| -rwxr-xr-x | ci.sh | 38 | ||||
| -rw-r--r-- | tests/stm32/.cargo/config.toml | 17 | ||||
| -rw-r--r-- | tests/stm32/Cargo.toml | 51 | ||||
| -rw-r--r-- | tests/stm32/build.rs | 16 | ||||
| -rw-r--r-- | tests/stm32/link_ram.x | 254 | ||||
| -rw-r--r-- | tests/stm32/src/bin/gpio.rs | 79 | ||||
| -rw-r--r-- | tests/stm32/src/example_common.rs | 17 |
9 files changed, 472 insertions, 5 deletions
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7904c3856..4f5970c03 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml | |||
| @@ -18,6 +18,9 @@ jobs: | |||
| 18 | run: exit 0 | 18 | run: exit 0 |
| 19 | build: | 19 | build: |
| 20 | runs-on: ubuntu-latest | 20 | runs-on: ubuntu-latest |
| 21 | permissions: | ||
| 22 | id-token: write | ||
| 23 | contents: read | ||
| 21 | steps: | 24 | steps: |
| 22 | - uses: actions/checkout@v2 | 25 | - uses: actions/checkout@v2 |
| 23 | with: | 26 | with: |
diff --git a/.vscode/settings.json b/.vscode/settings.json index 87dd158ec..a35be8054 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | //"embassy-net/pool-16", | 16 | //"embassy-net/pool-16", |
| 17 | ], | 17 | ], |
| 18 | "rust-analyzer.linkedProjects": [ | 18 | "rust-analyzer.linkedProjects": [ |
| 19 | "examples/stm32g4/Cargo.toml" | 19 | "examples/stm32f1/Cargo.toml" |
| 20 | ], | 20 | ], |
| 21 | "rust-analyzer.procMacro.enable": true, | 21 | "rust-analyzer.procMacro.enable": true, |
| 22 | "rust-analyzer.cargo.runBuildScripts": true, | 22 | "rust-analyzer.cargo.runBuildScripts": true, |
| @@ -4,15 +4,16 @@ set -euo pipefail | |||
| 4 | 4 | ||
| 5 | export CARGO_TARGET_DIR=$PWD/target_ci | 5 | export CARGO_TARGET_DIR=$PWD/target_ci |
| 6 | export RUSTFLAGS=-Dwarnings | 6 | export RUSTFLAGS=-Dwarnings |
| 7 | export DEFMT_LOG=trace | ||
| 7 | 8 | ||
| 8 | find . -name '*.rs' -not -path '*target*' -not -path '*stm32-metapac-gen/out/*' | xargs rustfmt --check --skip-children --unstable-features --edition 2018 | 9 | #find . -name '*.rs' -not -path '*target*' -not -path '*stm32-metapac-gen/out/*' | xargs rustfmt --check --skip-children --unstable-features --edition 2018 |
| 9 | 10 | ||
| 10 | # Generate stm32-metapac | 11 | # Generate stm32-metapac |
| 11 | # for some reason Cargo stomps the cache if we don't specify --target. | 12 | # for some reason Cargo stomps the cache if we don't specify --target. |
| 12 | # This happens with vanilla Cargo, not just cargo-batch. Bug? | 13 | # This happens with vanilla Cargo, not just cargo-batch. Bug? |
| 13 | (cd stm32-metapac-gen; cargo run --release --target x86_64-unknown-linux-gnu) | 14 | #(cd stm32-metapac-gen; cargo run --release --target x86_64-unknown-linux-gnu) |
| 14 | rm -rf stm32-metapac | 15 | #rm -rf stm32-metapac |
| 15 | mv stm32-metapac-gen/out stm32-metapac | 16 | #mv stm32-metapac-gen/out stm32-metapac |
| 16 | 17 | ||
| 17 | cargo batch \ | 18 | cargo batch \ |
| 18 | --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi \ | 19 | --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi \ |
| @@ -56,3 +57,32 @@ cargo batch \ | |||
| 56 | --- build --release --manifest-path examples/stm32wb55/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb55 \ | 57 | --- build --release --manifest-path examples/stm32wb55/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb55 \ |
| 57 | --- build --release --manifest-path examples/stm32wl55/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl55 \ | 58 | --- build --release --manifest-path examples/stm32wl55/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl55 \ |
| 58 | --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ | 59 | --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ |
| 60 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/stm32f4 \ | ||
| 61 | |||
| 62 | |||
| 63 | function run_elf { | ||
| 64 | echo Running target=$1 elf=$2 | ||
| 65 | STATUSCODE=$( | ||
| 66 | curl \ | ||
| 67 | -sS \ | ||
| 68 | --output /dev/stderr \ | ||
| 69 | --write-out "%{http_code}" \ | ||
| 70 | -H "Authorization: Bearer $TELEPROBE_TOKEN" \ | ||
| 71 | https://teleprobe.embassy.dev/targets/$1/run --data-binary @$2 | ||
| 72 | ) | ||
| 73 | echo HTTP Status code: $STATUSCODE | ||
| 74 | test "$STATUSCODE" -eq 200 | ||
| 75 | } | ||
| 76 | |||
| 77 | if [[ -z "${TELEPROBE_TOKEN-}" ]]; then | ||
| 78 | if [[ -z "${ACTIONS_ID_TOKEN_REQUEST_TOKEN-}" ]]; then | ||
| 79 | echo No teleprobe token found, skipping running HIL tests | ||
| 80 | exit | ||
| 81 | fi | ||
| 82 | |||
| 83 | export TELEPROBE_TOKEN=$(curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value') | ||
| 84 | fi | ||
| 85 | |||
| 86 | |||
| 87 | run_elf nucleo-stm32f429zi out/tests/stm32f4/gpio | ||
| 88 | |||
diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml new file mode 100644 index 000000000..40a13ddd3 --- /dev/null +++ b/tests/stm32/.cargo/config.toml | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | [unstable] | ||
| 2 | build-std = ["core"] | ||
| 3 | build-std-features = ["panic_immediate_abort"] | ||
| 4 | |||
| 5 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 6 | # replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` | ||
| 7 | runner = "probe-run --chip STM32F429ZITx" | ||
| 8 | |||
| 9 | rustflags = [ | ||
| 10 | # Code-size optimizations. | ||
| 11 | "-Z", "trap-unreachable=no", | ||
| 12 | "-C", "inline-threshold=5", | ||
| 13 | "-C", "no-vectorize-loops", | ||
| 14 | ] | ||
| 15 | |||
| 16 | [build] | ||
| 17 | target = "thumbv7em-none-eabi" | ||
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml new file mode 100644 index 000000000..f64043a86 --- /dev/null +++ b/tests/stm32/Cargo.toml | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | [package] | ||
| 2 | authors = ["Dario Nieuwenhuis <[email protected]>"] | ||
| 3 | edition = "2018" | ||
| 4 | name = "embassy-stm32-tests" | ||
| 5 | version = "0.1.0" | ||
| 6 | resolver = "2" | ||
| 7 | |||
| 8 | [dependencies] | ||
| 9 | embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } | ||
| 10 | embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } | ||
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim2"] } | ||
| 12 | |||
| 13 | defmt = "0.3.0" | ||
| 14 | defmt-rtt = "0.3.0" | ||
| 15 | |||
| 16 | cortex-m = "0.7.3" | ||
| 17 | cortex-m-rt = "0.7.0" | ||
| 18 | embedded-hal = "0.2.6" | ||
| 19 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | ||
| 20 | |||
| 21 | [profile.dev] | ||
| 22 | codegen-units = 1 | ||
| 23 | debug = 2 | ||
| 24 | debug-assertions = true | ||
| 25 | incremental = false | ||
| 26 | opt-level = 's' | ||
| 27 | overflow-checks = true | ||
| 28 | |||
| 29 | [profile.release] | ||
| 30 | codegen-units = 1 | ||
| 31 | debug = 2 | ||
| 32 | debug-assertions = false | ||
| 33 | incremental = false | ||
| 34 | lto = "fat" | ||
| 35 | opt-level = 's' | ||
| 36 | overflow-checks = false | ||
| 37 | |||
| 38 | # do not optimize proc-macro crates = faster builds from scratch | ||
| 39 | [profile.dev.build-override] | ||
| 40 | codegen-units = 8 | ||
| 41 | debug = false | ||
| 42 | debug-assertions = false | ||
| 43 | opt-level = 0 | ||
| 44 | overflow-checks = false | ||
| 45 | |||
| 46 | [profile.release.build-override] | ||
| 47 | codegen-units = 8 | ||
| 48 | debug = false | ||
| 49 | debug-assertions = false | ||
| 50 | opt-level = 0 | ||
| 51 | overflow-checks = false | ||
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs new file mode 100644 index 000000000..6f4872249 --- /dev/null +++ b/tests/stm32/build.rs | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | use std::error::Error; | ||
| 2 | use std::path::PathBuf; | ||
| 3 | use std::{env, fs}; | ||
| 4 | |||
| 5 | fn main() -> Result<(), Box<dyn Error>> { | ||
| 6 | let out = PathBuf::from(env::var("OUT_DIR").unwrap()); | ||
| 7 | fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap(); | ||
| 8 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 9 | println!("cargo:rerun-if-changed=link_ram.x"); | ||
| 10 | |||
| 11 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 12 | println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); | ||
| 13 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 14 | |||
| 15 | Ok(()) | ||
| 16 | } | ||
diff --git a/tests/stm32/link_ram.x b/tests/stm32/link_ram.x new file mode 100644 index 000000000..d23ffc747 --- /dev/null +++ b/tests/stm32/link_ram.x | |||
| @@ -0,0 +1,254 @@ | |||
| 1 | /* ##### EMBASSY NOTE | ||
| 2 | Originally from https://github.com/rust-embedded/cortex-m-rt/blob/master/link.x.in | ||
| 3 | Adjusted to put everything in RAM | ||
| 4 | */ | ||
| 5 | |||
| 6 | /* # Developer notes | ||
| 7 | |||
| 8 | - Symbols that start with a double underscore (__) are considered "private" | ||
| 9 | |||
| 10 | - Symbols that start with a single underscore (_) are considered "semi-public"; they can be | ||
| 11 | overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { | ||
| 12 | static mut __sbss }`). | ||
| 13 | |||
| 14 | - `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a | ||
| 15 | symbol if not dropped if it appears in or near the front of the linker arguments and "it's not | ||
| 16 | needed" by any of the preceding objects (linker arguments) | ||
| 17 | |||
| 18 | - `PROVIDE` is used to provide default values that can be overridden by a user linker script | ||
| 19 | |||
| 20 | - On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* | ||
| 21 | the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization | ||
| 22 | routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see | ||
| 23 | "Address (..) is out of bounds" in the disassembly produced by `objdump`. | ||
| 24 | */ | ||
| 25 | |||
| 26 | /* Provides information about the memory layout of the device */ | ||
| 27 | /* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ | ||
| 28 | INCLUDE memory.x | ||
| 29 | |||
| 30 | /* # Entry point = reset vector */ | ||
| 31 | EXTERN(__RESET_VECTOR); | ||
| 32 | EXTERN(Reset); | ||
| 33 | ENTRY(Reset); | ||
| 34 | |||
| 35 | /* # Exception vectors */ | ||
| 36 | /* This is effectively weak aliasing at the linker level */ | ||
| 37 | /* The user can override any of these aliases by defining the corresponding symbol themselves (cf. | ||
| 38 | the `exception!` macro) */ | ||
| 39 | EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ | ||
| 40 | |||
| 41 | EXTERN(DefaultHandler); | ||
| 42 | |||
| 43 | PROVIDE(NonMaskableInt = DefaultHandler); | ||
| 44 | EXTERN(HardFaultTrampoline); | ||
| 45 | PROVIDE(MemoryManagement = DefaultHandler); | ||
| 46 | PROVIDE(BusFault = DefaultHandler); | ||
| 47 | PROVIDE(UsageFault = DefaultHandler); | ||
| 48 | PROVIDE(SecureFault = DefaultHandler); | ||
| 49 | PROVIDE(SVCall = DefaultHandler); | ||
| 50 | PROVIDE(DebugMonitor = DefaultHandler); | ||
| 51 | PROVIDE(PendSV = DefaultHandler); | ||
| 52 | PROVIDE(SysTick = DefaultHandler); | ||
| 53 | |||
| 54 | PROVIDE(DefaultHandler = DefaultHandler_); | ||
| 55 | PROVIDE(HardFault = HardFault_); | ||
| 56 | |||
| 57 | /* # Interrupt vectors */ | ||
| 58 | EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ | ||
| 59 | |||
| 60 | /* # Pre-initialization function */ | ||
| 61 | /* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, | ||
| 62 | then the function this points to will be called before the RAM is initialized. */ | ||
| 63 | PROVIDE(__pre_init = DefaultPreInit); | ||
| 64 | |||
| 65 | /* # Sections */ | ||
| 66 | SECTIONS | ||
| 67 | { | ||
| 68 | PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); | ||
| 69 | |||
| 70 | /* ## Sections in RAM */ | ||
| 71 | /* ### Vector table */ | ||
| 72 | .vector_table ORIGIN(RAM) : | ||
| 73 | { | ||
| 74 | /* Initial Stack Pointer (SP) value */ | ||
| 75 | LONG(_stack_start); | ||
| 76 | |||
| 77 | /* Reset vector */ | ||
| 78 | KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ | ||
| 79 | __reset_vector = .; | ||
| 80 | |||
| 81 | /* Exceptions */ | ||
| 82 | KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ | ||
| 83 | __eexceptions = .; | ||
| 84 | |||
| 85 | /* Device specific interrupts */ | ||
| 86 | KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ | ||
| 87 | } > RAM | ||
| 88 | |||
| 89 | PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table)); | ||
| 90 | |||
| 91 | /* ### .text */ | ||
| 92 | .text _stext : | ||
| 93 | { | ||
| 94 | __stext = .; | ||
| 95 | *(.Reset); | ||
| 96 | |||
| 97 | *(.text .text.*); | ||
| 98 | |||
| 99 | /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`, | ||
| 100 | so must be placed close to it. */ | ||
| 101 | *(.HardFaultTrampoline); | ||
| 102 | *(.HardFault.*); | ||
| 103 | |||
| 104 | . = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld */ | ||
| 105 | __etext = .; | ||
| 106 | } > RAM | ||
| 107 | |||
| 108 | /* ### .rodata */ | ||
| 109 | .rodata : ALIGN(4) | ||
| 110 | { | ||
| 111 | . = ALIGN(4); | ||
| 112 | __srodata = .; | ||
| 113 | *(.rodata .rodata.*); | ||
| 114 | |||
| 115 | /* 4-byte align the end (VMA) of this section. | ||
| 116 | This is required by LLD to ensure the LMA of the following .data | ||
| 117 | section will have the correct alignment. */ | ||
| 118 | . = ALIGN(4); | ||
| 119 | __erodata = .; | ||
| 120 | } > RAM | ||
| 121 | |||
| 122 | /* ## Sections in RAM */ | ||
| 123 | /* ### .data */ | ||
| 124 | .data : ALIGN(4) | ||
| 125 | { | ||
| 126 | . = ALIGN(4); | ||
| 127 | __sdata = .; | ||
| 128 | *(.data .data.*); | ||
| 129 | . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ | ||
| 130 | } > RAM | ||
| 131 | /* Allow sections from user `memory.x` injected using `INSERT AFTER .data` to | ||
| 132 | * use the .data loading mechanism by pushing __edata. Note: do not change | ||
| 133 | * output region or load region in those user sections! */ | ||
| 134 | . = ALIGN(4); | ||
| 135 | __edata = .; | ||
| 136 | |||
| 137 | /* LMA of .data */ | ||
| 138 | __sidata = LOADADDR(.data); | ||
| 139 | |||
| 140 | /* ### .gnu.sgstubs | ||
| 141 | This section contains the TrustZone-M veneers put there by the Arm GNU linker. */ | ||
| 142 | /* Security Attribution Unit blocks must be 32 bytes aligned. */ | ||
| 143 | /* Note that this pads the RAM usage to 32 byte alignment. */ | ||
| 144 | .gnu.sgstubs : ALIGN(32) | ||
| 145 | { | ||
| 146 | . = ALIGN(32); | ||
| 147 | __veneer_base = .; | ||
| 148 | *(.gnu.sgstubs*) | ||
| 149 | . = ALIGN(32); | ||
| 150 | __veneer_limit = .; | ||
| 151 | } > RAM | ||
| 152 | |||
| 153 | /* ### .bss */ | ||
| 154 | .bss (NOLOAD) : ALIGN(4) | ||
| 155 | { | ||
| 156 | . = ALIGN(4); | ||
| 157 | __sbss = .; | ||
| 158 | *(.bss .bss.*); | ||
| 159 | *(COMMON); /* Uninitialized C statics */ | ||
| 160 | . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ | ||
| 161 | } > RAM | ||
| 162 | /* Allow sections from user `memory.x` injected using `INSERT AFTER .bss` to | ||
| 163 | * use the .bss zeroing mechanism by pushing __ebss. Note: do not change | ||
| 164 | * output region or load region in those user sections! */ | ||
| 165 | . = ALIGN(4); | ||
| 166 | __ebss = .; | ||
| 167 | |||
| 168 | /* ### .uninit */ | ||
| 169 | .uninit (NOLOAD) : ALIGN(4) | ||
| 170 | { | ||
| 171 | . = ALIGN(4); | ||
| 172 | __suninit = .; | ||
| 173 | *(.uninit .uninit.*); | ||
| 174 | . = ALIGN(4); | ||
| 175 | __euninit = .; | ||
| 176 | } > RAM | ||
| 177 | |||
| 178 | /* Place the heap right after `.uninit` in RAM */ | ||
| 179 | PROVIDE(__sheap = __euninit); | ||
| 180 | |||
| 181 | /* ## .got */ | ||
| 182 | /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in | ||
| 183 | the input files and raise an error if relocatable code is found */ | ||
| 184 | .got (NOLOAD) : | ||
| 185 | { | ||
| 186 | KEEP(*(.got .got.*)); | ||
| 187 | } | ||
| 188 | |||
| 189 | /* ## Discarded sections */ | ||
| 190 | /DISCARD/ : | ||
| 191 | { | ||
| 192 | /* Unused exception related info that only wastes space */ | ||
| 193 | *(.ARM.exidx); | ||
| 194 | *(.ARM.exidx.*); | ||
| 195 | *(.ARM.extab.*); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | /* Do not exceed this mark in the error messages below | */ | ||
| 200 | /* # Alignment checks */ | ||
| 201 | ASSERT(ORIGIN(RAM) % 4 == 0, " | ||
| 202 | ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); | ||
| 203 | |||
| 204 | ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " | ||
| 205 | BUG(cortex-m-rt): .data is not 4-byte aligned"); | ||
| 206 | |||
| 207 | ASSERT(__sidata % 4 == 0, " | ||
| 208 | BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); | ||
| 209 | |||
| 210 | ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " | ||
| 211 | BUG(cortex-m-rt): .bss is not 4-byte aligned"); | ||
| 212 | |||
| 213 | ASSERT(__sheap % 4 == 0, " | ||
| 214 | BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); | ||
| 215 | |||
| 216 | /* # Position checks */ | ||
| 217 | |||
| 218 | /* ## .vector_table */ | ||
| 219 | ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, " | ||
| 220 | BUG(cortex-m-rt): the reset vector is missing"); | ||
| 221 | |||
| 222 | ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " | ||
| 223 | BUG(cortex-m-rt): the exception vectors are missing"); | ||
| 224 | |||
| 225 | ASSERT(SIZEOF(.vector_table) > 0x40, " | ||
| 226 | ERROR(cortex-m-rt): The interrupt vectors are missing. | ||
| 227 | Possible solutions, from most likely to less likely: | ||
| 228 | - Link to a svd2rust generated device crate | ||
| 229 | - Check that you actually use the device/hal/bsp crate in your code | ||
| 230 | - Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency | ||
| 231 | may be enabling it) | ||
| 232 | - Supply the interrupt handlers yourself. Check the documentation for details."); | ||
| 233 | |||
| 234 | /* ## .text */ | ||
| 235 | ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " | ||
| 236 | ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section | ||
| 237 | Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); | ||
| 238 | |||
| 239 | ASSERT(_stext + SIZEOF(.text) < ORIGIN(RAM) + LENGTH(RAM), " | ||
| 240 | ERROR(cortex-m-rt): The .text section must be placed inside the RAM memory. | ||
| 241 | Set _stext to an address smaller than 'ORIGIN(RAM) + LENGTH(RAM)'"); | ||
| 242 | |||
| 243 | /* # Other checks */ | ||
| 244 | ASSERT(SIZEOF(.got) == 0, " | ||
| 245 | ERROR(cortex-m-rt): .got section detected in the input object files | ||
| 246 | Dynamic relocations are not supported. If you are linking to C code compiled using | ||
| 247 | the 'cc' crate then modify your build script to compile the C code _without_ | ||
| 248 | the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); | ||
| 249 | /* Do not exceed this mark in the error messages above | */ | ||
| 250 | |||
| 251 | |||
| 252 | /* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */ | ||
| 253 | /* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */ | ||
| 254 | INCLUDE device.x \ No newline at end of file | ||
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs new file mode 100644 index 000000000..7f7fccbfd --- /dev/null +++ b/tests/stm32/src/bin/gpio.rs | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | #[path = "../example_common.rs"] | ||
| 6 | mod example_common; | ||
| 7 | use defmt::assert; | ||
| 8 | use embassy::executor::Spawner; | ||
| 9 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; | ||
| 10 | use embassy_stm32::Peripherals; | ||
| 11 | use embedded_hal::digital::v2::{InputPin, OutputPin}; | ||
| 12 | use example_common::*; | ||
| 13 | |||
| 14 | #[embassy::main] | ||
| 15 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 16 | info!("Hello World!"); | ||
| 17 | |||
| 18 | let (mut a, mut b) = (p.PG14, p.PG9); | ||
| 19 | |||
| 20 | // Test initial output | ||
| 21 | { | ||
| 22 | let b = Input::new(&mut b, Pull::None); | ||
| 23 | |||
| 24 | { | ||
| 25 | let _a = Output::new(&mut a, Level::Low, Speed::Low); | ||
| 26 | cortex_m::asm::delay(1000); | ||
| 27 | assert!(b.is_low().unwrap()); | ||
| 28 | } | ||
| 29 | { | ||
| 30 | let _a = Output::new(&mut a, Level::High, Speed::Low); | ||
| 31 | cortex_m::asm::delay(1000); | ||
| 32 | assert!(b.is_high().unwrap()); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | // Test input no pull | ||
| 37 | { | ||
| 38 | let b = Input::new(&mut b, Pull::None); | ||
| 39 | // no pull, the status is undefined | ||
| 40 | |||
| 41 | let mut a = Output::new(&mut a, Level::Low, Speed::Low); | ||
| 42 | cortex_m::asm::delay(1000); | ||
| 43 | assert!(b.is_low().unwrap()); | ||
| 44 | a.set_high().unwrap(); | ||
| 45 | cortex_m::asm::delay(1000); | ||
| 46 | assert!(b.is_high().unwrap()); | ||
| 47 | } | ||
| 48 | |||
| 49 | // Test input pulldown | ||
| 50 | { | ||
| 51 | let b = Input::new(&mut b, Pull::Down); | ||
| 52 | cortex_m::asm::delay(1000); | ||
| 53 | assert!(b.is_low().unwrap()); | ||
| 54 | |||
| 55 | let mut a = Output::new(&mut a, Level::Low, Speed::Low); | ||
| 56 | cortex_m::asm::delay(1000); | ||
| 57 | assert!(b.is_low().unwrap()); | ||
| 58 | a.set_high().unwrap(); | ||
| 59 | cortex_m::asm::delay(1000); | ||
| 60 | assert!(b.is_high().unwrap()); | ||
| 61 | } | ||
| 62 | |||
| 63 | // Test input pullup | ||
| 64 | { | ||
| 65 | let b = Input::new(&mut b, Pull::Up); | ||
| 66 | cortex_m::asm::delay(1000); | ||
| 67 | assert!(b.is_high().unwrap()); | ||
| 68 | |||
| 69 | let mut a = Output::new(&mut a, Level::Low, Speed::Low); | ||
| 70 | cortex_m::asm::delay(1000); | ||
| 71 | assert!(b.is_low().unwrap()); | ||
| 72 | a.set_high().unwrap(); | ||
| 73 | cortex_m::asm::delay(1000); | ||
| 74 | assert!(b.is_high().unwrap()); | ||
| 75 | } | ||
| 76 | |||
| 77 | info!("Test OK"); | ||
| 78 | cortex_m::asm::bkpt(); | ||
| 79 | } | ||
diff --git a/tests/stm32/src/example_common.rs b/tests/stm32/src/example_common.rs new file mode 100644 index 000000000..54d633837 --- /dev/null +++ b/tests/stm32/src/example_common.rs | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use defmt_rtt as _; // global logger | ||
| 4 | use panic_probe as _; | ||
| 5 | |||
| 6 | pub use defmt::*; | ||
| 7 | |||
| 8 | use core::sync::atomic::{AtomicUsize, Ordering}; | ||
| 9 | |||
| 10 | defmt::timestamp! {"{=u64}", { | ||
| 11 | static COUNT: AtomicUsize = AtomicUsize::new(0); | ||
| 12 | // NOTE(no-CAS) `timestamps` runs with interrupts disabled | ||
| 13 | let n = COUNT.load(Ordering::Relaxed); | ||
| 14 | COUNT.store(n + 1, Ordering::Relaxed); | ||
| 15 | n as u64 | ||
| 16 | } | ||
| 17 | } | ||
