diff options
| author | xoviat <[email protected]> | 2023-06-19 15:52:33 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2023-06-19 15:52:33 -0500 |
| commit | aaad9068156305e5f6f41ee4013e025083bd0668 (patch) | |
| tree | 67a08c8a512e8791433891a3b6deec813fc4c578 | |
| parent | 35083b262b364387713f4273649b62180123182c (diff) | |
| parent | 3c70f799a28f5f28d84fa8ee8b4b232f5e9aad82 (diff) | |
Merge branch 'main' of https://github.com/embassy-rs/embassy into can
253 files changed, 8664 insertions, 8403 deletions
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh new file mode 100755 index 000000000..1402e742f --- /dev/null +++ b/.github/ci/doc.sh | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | ## on push branch=main | ||
| 3 | |||
| 4 | set -euo pipefail | ||
| 5 | |||
| 6 | export RUSTUP_HOME=/ci/cache/rustup | ||
| 7 | export CARGO_HOME=/ci/cache/cargo | ||
| 8 | export CARGO_TARGET_DIR=/ci/cache/target | ||
| 9 | export BUILDER_THREADS=6 | ||
| 10 | export BUILDER_COMPRESS=true | ||
| 11 | |||
| 12 | # force rustup to download the toolchain before starting building. | ||
| 13 | # Otherwise, the docs builder is running multiple instances of cargo rustdoc concurrently. | ||
| 14 | # They all see the toolchain is not installed and try to install it in parallel | ||
| 15 | # which makes rustup very sad | ||
| 16 | rustc --version > /dev/null | ||
| 17 | |||
| 18 | docserver-builder -i ./embassy-stm32 -o crates/embassy-stm32/git.zup | ||
| 19 | docserver-builder -i ./embassy-boot/boot -o crates/embassy-boot/git.zup | ||
| 20 | docserver-builder -i ./embassy-boot/nrf -o crates/embassy-boot-nrf/git.zup | ||
| 21 | docserver-builder -i ./embassy-boot/rp -o crates/embassy-boot-rp/git.zup | ||
| 22 | docserver-builder -i ./embassy-boot/stm32 -o crates/embassy-boot-stm32/git.zup | ||
| 23 | docserver-builder -i ./embassy-embedded-hal -o crates/embassy-embedded-hal/git.zup | ||
| 24 | docserver-builder -i ./embassy-executor -o crates/embassy-executor/git.zup | ||
| 25 | docserver-builder -i ./embassy-futures -o crates/embassy-futures/git.zup | ||
| 26 | docserver-builder -i ./embassy-lora -o crates/embassy-lora/git.zup | ||
| 27 | docserver-builder -i ./embassy-net -o crates/embassy-net/git.zup | ||
| 28 | docserver-builder -i ./embassy-net-driver -o crates/embassy-net-driver/git.zup | ||
| 29 | docserver-builder -i ./embassy-net-driver-channel -o crates/embassy-net-driver-channel/git.zup | ||
| 30 | docserver-builder -i ./embassy-nrf -o crates/embassy-nrf/git.zup | ||
| 31 | docserver-builder -i ./embassy-rp -o crates/embassy-rp/git.zup | ||
| 32 | docserver-builder -i ./embassy-sync -o crates/embassy-sync/git.zup | ||
| 33 | docserver-builder -i ./embassy-time -o crates/embassy-time/git.zup | ||
| 34 | docserver-builder -i ./embassy-usb -o crates/embassy-usb/git.zup | ||
| 35 | docserver-builder -i ./embassy-usb-driver -o crates/embassy-usb-driver/git.zup | ||
| 36 | docserver-builder -i ./embassy-usb-logger -o crates/embassy-usb-logger/git.zup | ||
| 37 | docserver-builder -i ./cyw43 -o crates/cyw43/git.zup | ||
| 38 | docserver-builder -i ./cyw43-pio -o crates/cyw43-pio/git.zup | ||
| 39 | docserver-builder -i ./embassy-net-w5500 -o crates/embassy-net-w5500/git.zup | ||
| 40 | docserver-builder -i ./embassy-stm32-wpan -o crates/embassy-stm32-wpan/git.zup | ||
| 41 | |||
| 42 | export KUBECONFIG=/ci/secrets/kubeconfig.yml | ||
| 43 | POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) | ||
| 44 | kubectl cp crates $POD:/data | ||
diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml deleted file mode 100644 index a69a49718..000000000 --- a/.github/workflows/doc.yml +++ /dev/null | |||
| @@ -1,87 +0,0 @@ | |||
| 1 | name: Docs | ||
| 2 | |||
| 3 | on: | ||
| 4 | push: | ||
| 5 | branches: [main] | ||
| 6 | |||
| 7 | env: | ||
| 8 | BUILDER_THREADS: '1' | ||
| 9 | |||
| 10 | jobs: | ||
| 11 | doc: | ||
| 12 | runs-on: ubuntu-latest | ||
| 13 | |||
| 14 | # Since stm32 crates take SO LONG to build, we split them | ||
| 15 | # into a separate job. This way it doesn't slow down updating | ||
| 16 | # the rest. | ||
| 17 | strategy: | ||
| 18 | matrix: | ||
| 19 | crates: | ||
| 20 | #- stm32 # runs out of disk space... | ||
| 21 | - rest | ||
| 22 | |||
| 23 | # This will ensure at most one doc build job is running at a time | ||
| 24 | # (for stm32 and non-stm32 independently). | ||
| 25 | # If another job is already running, the new job will wait. | ||
| 26 | # If another job is already waiting, it'll be canceled. | ||
| 27 | # This means some commits will be skipped, but that's fine because | ||
| 28 | # we only care that the latest gets built. | ||
| 29 | concurrency: doc-${{ matrix.crates }} | ||
| 30 | |||
| 31 | steps: | ||
| 32 | - uses: actions/checkout@v3 | ||
| 33 | with: | ||
| 34 | submodules: true | ||
| 35 | - name: Install Rust targets | ||
| 36 | run: | | ||
| 37 | rustup target add x86_64-unknown-linux-gnu | ||
| 38 | rustup target add wasm32-unknown-unknown | ||
| 39 | rustup target add thumbv6m-none-eabi | ||
| 40 | rustup target add thumbv7m-none-eabi | ||
| 41 | rustup target add thumbv7em-none-eabi | ||
| 42 | rustup target add thumbv7em-none-eabihf | ||
| 43 | rustup target add thumbv8m.base-none-eabi | ||
| 44 | rustup target add thumbv8m.main-none-eabi | ||
| 45 | rustup target add thumbv8m.main-none-eabihf | ||
| 46 | |||
| 47 | - name: Install docserver | ||
| 48 | run: | | ||
| 49 | wget -q -O /usr/local/bin/builder "https://github.com/embassy-rs/docserver/releases/download/v0.4/builder" | ||
| 50 | chmod +x /usr/local/bin/builder | ||
| 51 | |||
| 52 | - name: build-stm32 | ||
| 53 | if: ${{ matrix.crates=='stm32' }} | ||
| 54 | run: | | ||
| 55 | mkdir crates | ||
| 56 | builder ./embassy-stm32 crates/embassy-stm32/git.zup | ||
| 57 | |||
| 58 | - name: build-rest | ||
| 59 | if: ${{ matrix.crates=='rest' }} | ||
| 60 | run: | | ||
| 61 | mkdir crates | ||
| 62 | builder ./embassy-boot/boot crates/embassy-boot/git.zup | ||
| 63 | builder ./embassy-boot/nrf crates/embassy-boot-nrf/git.zup | ||
| 64 | builder ./embassy-boot/rp crates/embassy-boot-rp/git.zup | ||
| 65 | builder ./embassy-boot/stm32 crates/embassy-boot-stm32/git.zup | ||
| 66 | builder ./embassy-cortex-m crates/embassy-cortex-m/git.zup | ||
| 67 | builder ./embassy-embedded-hal crates/embassy-embedded-hal/git.zup | ||
| 68 | builder ./embassy-executor crates/embassy-executor/git.zup | ||
| 69 | builder ./embassy-futures crates/embassy-futures/git.zup | ||
| 70 | builder ./embassy-lora crates/embassy-lora/git.zup | ||
| 71 | builder ./embassy-net crates/embassy-net/git.zup | ||
| 72 | builder ./embassy-net-driver crates/embassy-net-driver/git.zup | ||
| 73 | builder ./embassy-net-driver-channel crates/embassy-net-driver-channel/git.zup | ||
| 74 | builder ./embassy-nrf crates/embassy-nrf/git.zup | ||
| 75 | builder ./embassy-rp crates/embassy-rp/git.zup | ||
| 76 | builder ./embassy-sync crates/embassy-sync/git.zup | ||
| 77 | builder ./embassy-time crates/embassy-time/git.zup | ||
| 78 | builder ./embassy-usb crates/embassy-usb/git.zup | ||
| 79 | builder ./embassy-usb-driver crates/embassy-usb-driver/git.zup | ||
| 80 | builder ./embassy-usb-logger crates/embassy-usb-logger/git.zup | ||
| 81 | |||
| 82 | - name: upload | ||
| 83 | run: | | ||
| 84 | mkdir -p ~/.kube | ||
| 85 | echo "${{secrets.KUBECONFIG}}" > ~/.kube/config | ||
| 86 | POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) | ||
| 87 | kubectl cp crates $POD:/data | ||
| @@ -3,7 +3,7 @@ | |||
| 3 | set -euo pipefail | 3 | set -euo pipefail |
| 4 | 4 | ||
| 5 | export RUSTFLAGS=-Dwarnings | 5 | export RUSTFLAGS=-Dwarnings |
| 6 | export DEFMT_LOG=trace | 6 | export DEFMT_LOG=trace,cyw43=info,cyw43_pio=info,smoltcp=info |
| 7 | 7 | ||
| 8 | # needed by wifi examples | 8 | # needed by wifi examples |
| 9 | export WIFI_NETWORK=x | 9 | export WIFI_NETWORK=x |
| @@ -25,11 +25,19 @@ cargo batch \ | |||
| 25 | --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ | 25 | --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ |
| 26 | --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ | 26 | --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ |
| 27 | --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ | 27 | --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ |
| 28 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,medium-ethernet \ | 28 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ |
| 29 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ | 29 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ |
| 30 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \ | 30 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \ |
| 31 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \ | 31 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \ |
| 32 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits,nightly \ | 32 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits,nightly \ |
| 33 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \ | ||
| 34 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits \ | ||
| 35 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,nightly \ | ||
| 36 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits,nightly \ | ||
| 37 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \ | ||
| 38 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,unstable-traits \ | ||
| 39 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,nightly \ | ||
| 40 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,unstable-traits,nightly \ | ||
| 33 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \ | 41 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \ |
| 34 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \ | 42 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \ |
| 35 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \ | 43 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \ |
| @@ -71,6 +79,7 @@ cargo batch \ | |||
| 71 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ | 79 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ |
| 72 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \ | 80 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \ |
| 73 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \ | 81 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \ |
| 82 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits \ | ||
| 74 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \ | 83 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \ |
| 75 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \ | 84 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \ |
| 76 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \ | 85 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \ |
| @@ -103,6 +112,7 @@ cargo batch \ | |||
| 103 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \ | 112 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \ |
| 104 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \ | 113 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \ |
| 105 | --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ | 114 | --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ |
| 115 | --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \ | ||
| 106 | --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ | 116 | --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ |
| 107 | --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ | 117 | --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ |
| 108 | --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ | 118 | --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ |
| @@ -158,4 +168,4 @@ if [[ -z "${TELEPROBE_TOKEN-}" ]]; then | |||
| 158 | exit | 168 | exit |
| 159 | fi | 169 | fi |
| 160 | 170 | ||
| 161 | teleprobe client run -r out/tests \ No newline at end of file | 171 | teleprobe client run -r out/tests |
diff --git a/ci_stable.sh b/ci_stable.sh index a67087ffb..daae98961 100755 --- a/ci_stable.sh +++ b/ci_stable.sh | |||
| @@ -14,9 +14,11 @@ cargo batch \ | |||
| 14 | --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \ | 14 | --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \ |
| 15 | --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \ | 15 | --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \ |
| 16 | --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \ | 16 | --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \ |
| 17 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,medium-ethernet \ | 17 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ |
| 18 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ | 18 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ |
| 19 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \ | 19 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \ |
| 20 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \ | ||
| 21 | --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits \ | ||
| 20 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \ | 22 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \ |
| 21 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \ | 23 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \ |
| 22 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \ | 24 | --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \ |
diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 6e9e784a0..14c07178f 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml | |||
| @@ -15,3 +15,8 @@ pio-proc = "0.2" | |||
| 15 | pio = "0.2.1" | 15 | pio = "0.2.1" |
| 16 | fixed = "1.23.1" | 16 | fixed = "1.23.1" |
| 17 | defmt = { version = "0.3", optional = true } | 17 | defmt = { version = "0.3", optional = true } |
| 18 | |||
| 19 | [package.metadata.embassy_docs] | ||
| 20 | src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-pio-v$VERSION/cyw43-pio/src/" | ||
| 21 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43-pio/src/" | ||
| 22 | target = "thumbv6m-none-eabi" | ||
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index c7f8816f5..61caa0272 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml | |||
| @@ -26,3 +26,9 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa | |||
| 26 | 26 | ||
| 27 | embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.10" } | 27 | embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.10" } |
| 28 | num_enum = { version = "0.5.7", default-features = false } | 28 | num_enum = { version = "0.5.7", default-features = false } |
| 29 | |||
| 30 | [package.metadata.embassy_docs] | ||
| 31 | src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" | ||
| 32 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/" | ||
| 33 | target = "thumbv6m-none-eabi" | ||
| 34 | features = ["defmt", "firmware-logs"] \ No newline at end of file | ||
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 6919d569e..c67614dd6 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs | |||
| @@ -381,10 +381,7 @@ impl<'a> Control<'a> { | |||
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | let ioctl = CancelOnDrop(self.ioctl_state); | 383 | let ioctl = CancelOnDrop(self.ioctl_state); |
| 384 | 384 | let resp_len = ioctl.0.do_ioctl(kind, cmd, iface, buf).await; | |
| 385 | ioctl.0.do_ioctl(kind, cmd, iface, buf).await; | ||
| 386 | let resp_len = ioctl.0.wait_complete().await; | ||
| 387 | |||
| 388 | ioctl.defuse(); | 385 | ioctl.defuse(); |
| 389 | 386 | ||
| 390 | resp_len | 387 | resp_len |
diff --git a/cyw43/src/fmt.rs b/cyw43/src/fmt.rs index 5730447b3..9534c101c 100644 --- a/cyw43/src/fmt.rs +++ b/cyw43/src/fmt.rs | |||
| @@ -197,9 +197,6 @@ macro_rules! unwrap { | |||
| 197 | } | 197 | } |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | #[cfg(feature = "defmt-timestamp-uptime")] | ||
| 201 | defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() } | ||
| 202 | |||
| 203 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 200 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 204 | pub struct NoneError; | 201 | pub struct NoneError; |
| 205 | 202 | ||
diff --git a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs b/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs index 743d0c342..aecba0755 100644 --- a/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs +++ b/docs/modules/ROOT/examples/layer-by-layer/blinky-irq/src/main.rs | |||
| @@ -20,13 +20,13 @@ fn main() -> ! { | |||
| 20 | let led = Output::new(p.PB14, Level::Low, Speed::Low); | 20 | let led = Output::new(p.PB14, Level::Low, Speed::Low); |
| 21 | let mut button = Input::new(p.PC13, Pull::Up); | 21 | let mut button = Input::new(p.PC13, Pull::Up); |
| 22 | 22 | ||
| 23 | cortex_m::interrupt::free(|cs| unsafe { | 23 | cortex_m::interrupt::free(|cs| { |
| 24 | enable_interrupt(&mut button); | 24 | enable_interrupt(&mut button); |
| 25 | 25 | ||
| 26 | LED.borrow(cs).borrow_mut().replace(led); | 26 | LED.borrow(cs).borrow_mut().replace(led); |
| 27 | BUTTON.borrow(cs).borrow_mut().replace(button); | 27 | BUTTON.borrow(cs).borrow_mut().replace(button); |
| 28 | 28 | ||
| 29 | NVIC::unmask(pac::Interrupt::EXTI15_10); | 29 | unsafe { NVIC::unmask(pac::Interrupt::EXTI15_10) }; |
| 30 | }); | 30 | }); |
| 31 | 31 | ||
| 32 | loop { | 32 | loop { |
| @@ -64,25 +64,21 @@ const PORT: u8 = 2; | |||
| 64 | const PIN: usize = 13; | 64 | const PIN: usize = 13; |
| 65 | fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool { | 65 | fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool { |
| 66 | let exti = pac::EXTI; | 66 | let exti = pac::EXTI; |
| 67 | unsafe { | 67 | let pin = PIN; |
| 68 | let pin = PIN; | 68 | let lines = exti.pr(0).read(); |
| 69 | let lines = exti.pr(0).read(); | 69 | lines.line(pin) |
| 70 | lines.line(pin) | ||
| 71 | } | ||
| 72 | } | 70 | } |
| 73 | 71 | ||
| 74 | fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { | 72 | fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { |
| 75 | let exti = pac::EXTI; | 73 | let exti = pac::EXTI; |
| 76 | unsafe { | 74 | let pin = PIN; |
| 77 | let pin = PIN; | 75 | let mut lines = exti.pr(0).read(); |
| 78 | let mut lines = exti.pr(0).read(); | 76 | lines.set_line(pin, true); |
| 79 | lines.set_line(pin, true); | 77 | exti.pr(0).write_value(lines); |
| 80 | exti.pr(0).write_value(lines); | ||
| 81 | } | ||
| 82 | } | 78 | } |
| 83 | 79 | ||
| 84 | fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { | 80 | fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) { |
| 85 | cortex_m::interrupt::free(|_| unsafe { | 81 | cortex_m::interrupt::free(|_| { |
| 86 | let rcc = pac::RCC; | 82 | let rcc = pac::RCC; |
| 87 | rcc.apb2enr().modify(|w| w.set_syscfgen(true)); | 83 | rcc.apb2enr().modify(|w| w.set_syscfgen(true)); |
| 88 | 84 | ||
diff --git a/embassy-cortex-m/Cargo.toml b/embassy-cortex-m/Cargo.toml deleted file mode 100644 index 2eb0cce2a..000000000 --- a/embassy-cortex-m/Cargo.toml +++ /dev/null | |||
| @@ -1,47 +0,0 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-cortex-m" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [package.metadata.embassy_docs] | ||
| 8 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-cortex-m-v$VERSION/embassy-cortex-m/src/" | ||
| 9 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-cortex-m/src/" | ||
| 10 | features = ["prio-bits-3"] | ||
| 11 | flavors = [ | ||
| 12 | { name = "thumbv6m-none-eabi", target = "thumbv6m-none-eabi", features = [] }, | ||
| 13 | { name = "thumbv7m-none-eabi", target = "thumbv7m-none-eabi", features = [] }, | ||
| 14 | { name = "thumbv7em-none-eabi", target = "thumbv7em-none-eabi", features = [] }, | ||
| 15 | { name = "thumbv7em-none-eabihf", target = "thumbv7em-none-eabihf", features = [] }, | ||
| 16 | { name = "thumbv8m.base-none-eabi", target = "thumbv8m.base-none-eabi", features = [] }, | ||
| 17 | { name = "thumbv8m.main-none-eabi", target = "thumbv8m.main-none-eabi", features = [] }, | ||
| 18 | { name = "thumbv8m.main-none-eabihf", target = "thumbv8m.main-none-eabihf", features = [] }, | ||
| 19 | ] | ||
| 20 | |||
| 21 | [features] | ||
| 22 | default = [] | ||
| 23 | |||
| 24 | # Define the number of NVIC priority bits. | ||
| 25 | prio-bits-0 = [] | ||
| 26 | prio-bits-1 = [] | ||
| 27 | prio-bits-2 = [] | ||
| 28 | prio-bits-3 = [] | ||
| 29 | prio-bits-4 = [] | ||
| 30 | prio-bits-5 = [] | ||
| 31 | prio-bits-6 = [] | ||
| 32 | prio-bits-7 = [] | ||
| 33 | prio-bits-8 = [] | ||
| 34 | |||
| 35 | [dependencies] | ||
| 36 | defmt = { version = "0.3", optional = true } | ||
| 37 | log = { version = "0.4.14", optional = true } | ||
| 38 | |||
| 39 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } | ||
| 40 | embassy-executor = { version = "0.2.0", path = "../embassy-executor"} | ||
| 41 | embassy-macros = { version = "0.2.0", path = "../embassy-macros"} | ||
| 42 | embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common"} | ||
| 43 | atomic-polyfill = "1.0.1" | ||
| 44 | critical-section = "1.1" | ||
| 45 | cfg-if = "1.0.0" | ||
| 46 | cortex-m = "0.7.6" | ||
| 47 | |||
diff --git a/embassy-cortex-m/src/lib.rs b/embassy-cortex-m/src/lib.rs deleted file mode 100644 index e4b713a06..000000000 --- a/embassy-cortex-m/src/lib.rs +++ /dev/null | |||
| @@ -1,10 +0,0 @@ | |||
| 1 | //! Embassy executor and interrupt handling specific to cortex-m devices. | ||
| 2 | #![no_std] | ||
| 3 | #![warn(missing_docs)] | ||
| 4 | |||
| 5 | // This mod MUST go first, so that the others see its macros. | ||
| 6 | pub(crate) mod fmt; | ||
| 7 | |||
| 8 | pub use embassy_executor as executor; | ||
| 9 | pub mod interrupt; | ||
| 10 | pub mod peripheral; | ||
diff --git a/embassy-cortex-m/src/peripheral.rs b/embassy-cortex-m/src/peripheral.rs deleted file mode 100644 index e2f295579..000000000 --- a/embassy-cortex-m/src/peripheral.rs +++ /dev/null | |||
| @@ -1,144 +0,0 @@ | |||
| 1 | //! Peripheral interrupt handling specific to cortex-m devices. | ||
| 2 | use core::mem::MaybeUninit; | ||
| 3 | |||
| 4 | use cortex_m::peripheral::scb::VectActive; | ||
| 5 | use cortex_m::peripheral::{NVIC, SCB}; | ||
| 6 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | ||
| 7 | |||
| 8 | use crate::interrupt::{Interrupt, InterruptExt, Priority}; | ||
| 9 | |||
| 10 | /// A type which can be used as state with `PeripheralMutex`. | ||
| 11 | /// | ||
| 12 | /// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt, | ||
| 13 | /// and `&mut T` is only `Send` where `T: Send`. | ||
| 14 | pub trait PeripheralState: Send { | ||
| 15 | /// The interrupt that is used for this peripheral. | ||
| 16 | type Interrupt: Interrupt; | ||
| 17 | |||
| 18 | /// The interrupt handler that should be invoked for the peripheral. Implementations need to clear the appropriate interrupt flags to ensure the handle will not be called again. | ||
| 19 | fn on_interrupt(&mut self); | ||
| 20 | } | ||
| 21 | |||
| 22 | /// A type for storing the state of a peripheral that can be stored in a static. | ||
| 23 | pub struct StateStorage<S>(MaybeUninit<S>); | ||
| 24 | |||
| 25 | impl<S> StateStorage<S> { | ||
| 26 | /// Create a new instance for storing peripheral state. | ||
| 27 | pub const fn new() -> Self { | ||
| 28 | Self(MaybeUninit::uninit()) | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | /// A type for a peripheral that keeps the state of a peripheral that can be accessed from thread mode and an interrupt handler in | ||
| 33 | /// a safe way. | ||
| 34 | pub struct PeripheralMutex<'a, S: PeripheralState> { | ||
| 35 | state: *mut S, | ||
| 36 | irq: PeripheralRef<'a, S::Interrupt>, | ||
| 37 | } | ||
| 38 | |||
| 39 | /// Whether `irq` can be preempted by the current interrupt. | ||
| 40 | pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool { | ||
| 41 | match SCB::vect_active() { | ||
| 42 | // Thread mode can't preempt anything. | ||
| 43 | VectActive::ThreadMode => false, | ||
| 44 | // Exceptions don't always preempt interrupts, | ||
| 45 | // but there isn't much of a good reason to be keeping a `PeripheralMutex` in an exception anyway. | ||
| 46 | VectActive::Exception(_) => true, | ||
| 47 | VectActive::Interrupt { irqn } => { | ||
| 48 | #[derive(Clone, Copy)] | ||
| 49 | struct NrWrap(u16); | ||
| 50 | unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap { | ||
| 51 | fn number(self) -> u16 { | ||
| 52 | self.0 | ||
| 53 | } | ||
| 54 | } | ||
| 55 | NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into() | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | impl<'a, S: PeripheralState> PeripheralMutex<'a, S> { | ||
| 61 | /// Create a new `PeripheralMutex` wrapping `irq`, with `init` initializing the initial state. | ||
| 62 | /// | ||
| 63 | /// Registers `on_interrupt` as the `irq`'s handler, and enables it. | ||
| 64 | pub fn new( | ||
| 65 | irq: impl Peripheral<P = S::Interrupt> + 'a, | ||
| 66 | storage: &'a mut StateStorage<S>, | ||
| 67 | init: impl FnOnce() -> S, | ||
| 68 | ) -> Self { | ||
| 69 | into_ref!(irq); | ||
| 70 | |||
| 71 | if can_be_preempted(&*irq) { | ||
| 72 | panic!( | ||
| 73 | "`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps" | ||
| 74 | ); | ||
| 75 | } | ||
| 76 | |||
| 77 | let state_ptr = storage.0.as_mut_ptr(); | ||
| 78 | |||
| 79 | // Safety: The pointer is valid and not used by anyone else | ||
| 80 | // because we have the `&mut StateStorage`. | ||
| 81 | unsafe { state_ptr.write(init()) }; | ||
| 82 | |||
| 83 | irq.disable(); | ||
| 84 | irq.set_handler(|p| unsafe { | ||
| 85 | // Safety: it's OK to get a &mut to the state, since | ||
| 86 | // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`. | ||
| 87 | // Interrupts' priorities can only be changed with raw embassy `Interrupts`, | ||
| 88 | // which can't safely store a `PeripheralMutex` across invocations. | ||
| 89 | // - We can't have preempted a with() call because the irq is disabled during it. | ||
| 90 | let state = &mut *(p as *mut S); | ||
| 91 | state.on_interrupt(); | ||
| 92 | }); | ||
| 93 | irq.set_handler_context(state_ptr as *mut ()); | ||
| 94 | irq.enable(); | ||
| 95 | |||
| 96 | Self { irq, state: state_ptr } | ||
| 97 | } | ||
| 98 | |||
| 99 | /// Access the peripheral state ensuring interrupts are disabled so that the state can be | ||
| 100 | /// safely accessed. | ||
| 101 | pub fn with<R>(&mut self, f: impl FnOnce(&mut S) -> R) -> R { | ||
| 102 | self.irq.disable(); | ||
| 103 | |||
| 104 | // Safety: it's OK to get a &mut to the state, since the irq is disabled. | ||
| 105 | let state = unsafe { &mut *self.state }; | ||
| 106 | let r = f(state); | ||
| 107 | |||
| 108 | self.irq.enable(); | ||
| 109 | |||
| 110 | r | ||
| 111 | } | ||
| 112 | |||
| 113 | /// Returns whether the wrapped interrupt is currently in a pending state. | ||
| 114 | pub fn is_pending(&self) -> bool { | ||
| 115 | self.irq.is_pending() | ||
| 116 | } | ||
| 117 | |||
| 118 | /// Forces the wrapped interrupt into a pending state. | ||
| 119 | pub fn pend(&self) { | ||
| 120 | self.irq.pend() | ||
| 121 | } | ||
| 122 | |||
| 123 | /// Forces the wrapped interrupt out of a pending state. | ||
| 124 | pub fn unpend(&self) { | ||
| 125 | self.irq.unpend() | ||
| 126 | } | ||
| 127 | |||
| 128 | /// Gets the priority of the wrapped interrupt. | ||
| 129 | pub fn priority(&self) -> Priority { | ||
| 130 | self.irq.get_priority() | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | impl<'a, S: PeripheralState> Drop for PeripheralMutex<'a, S> { | ||
| 135 | fn drop(&mut self) { | ||
| 136 | self.irq.disable(); | ||
| 137 | self.irq.remove_handler(); | ||
| 138 | |||
| 139 | // safety: | ||
| 140 | // - we initialized the state in `new`, so we know it's initialized. | ||
| 141 | // - the irq is disabled, so it won't preempt us while dropping. | ||
| 142 | unsafe { self.state.drop_in_place() } | ||
| 143 | } | ||
| 144 | } | ||
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index ce032479d..1e5494ef8 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml | |||
| @@ -65,7 +65,7 @@ embassy-macros = { version = "0.2.0", path = "../embassy-macros" } | |||
| 65 | embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true} | 65 | embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true} |
| 66 | atomic-polyfill = "1.0.1" | 66 | atomic-polyfill = "1.0.1" |
| 67 | critical-section = "1.1" | 67 | critical-section = "1.1" |
| 68 | static_cell = "1.0" | 68 | static_cell = "1.1" |
| 69 | 69 | ||
| 70 | # arch-cortex-m dependencies | 70 | # arch-cortex-m dependencies |
| 71 | cortex-m = { version = "0.7.6", optional = true } | 71 | cortex-m = { version = "0.7.6", optional = true } |
diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index d6a55c4c7..94c8134d6 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs | |||
| @@ -205,5 +205,20 @@ mod interrupt { | |||
| 205 | 205 | ||
| 206 | executor.spawner().make_send() | 206 | executor.spawner().make_send() |
| 207 | } | 207 | } |
| 208 | |||
| 209 | /// Get a SendSpawner for this executor | ||
| 210 | /// | ||
| 211 | /// This returns a [`SendSpawner`] you can use to spawn tasks on this | ||
| 212 | /// executor. | ||
| 213 | /// | ||
| 214 | /// This MUST only be called on an executor that has already been spawned. | ||
| 215 | /// The function will panic otherwise. | ||
| 216 | pub fn spawner(&'static self) -> crate::SendSpawner { | ||
| 217 | if !self.started.load(Ordering::Acquire) { | ||
| 218 | panic!("InterruptExecutor::spawner() called on uninitialized executor."); | ||
| 219 | } | ||
| 220 | let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; | ||
| 221 | executor.spawner().make_send() | ||
| 222 | } | ||
| 208 | } | 223 | } |
| 209 | } | 224 | } |
diff --git a/embassy-futures/src/block_on.rs b/embassy-futures/src/block_on.rs index da90351ec..77695216c 100644 --- a/embassy-futures/src/block_on.rs +++ b/embassy-futures/src/block_on.rs | |||
| @@ -31,3 +31,15 @@ pub fn block_on<F: Future>(mut fut: F) -> F::Output { | |||
| 31 | } | 31 | } |
| 32 | } | 32 | } |
| 33 | } | 33 | } |
| 34 | |||
| 35 | /// Poll a future once. | ||
| 36 | pub fn poll_once<F: Future>(mut fut: F) -> Poll<F::Output> { | ||
| 37 | // safety: we don't move the future after this line. | ||
| 38 | let mut fut = unsafe { Pin::new_unchecked(&mut fut) }; | ||
| 39 | |||
| 40 | let raw_waker = RawWaker::new(ptr::null(), &VTABLE); | ||
| 41 | let waker = unsafe { Waker::from_raw(raw_waker) }; | ||
| 42 | let mut cx = Context::from_waker(&waker); | ||
| 43 | |||
| 44 | fut.as_mut().poll(&mut cx) | ||
| 45 | } | ||
diff --git a/embassy-futures/src/fmt.rs b/embassy-futures/src/fmt.rs index f8bb0a035..066970813 100644 --- a/embassy-futures/src/fmt.rs +++ b/embassy-futures/src/fmt.rs | |||
| @@ -195,9 +195,6 @@ macro_rules! unwrap { | |||
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | #[cfg(feature = "defmt-timestamp-uptime")] | ||
| 199 | defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() } | ||
| 200 | |||
| 201 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 202 | pub struct NoneError; | 199 | pub struct NoneError; |
| 203 | 200 | ||
diff --git a/embassy-hal-common/Cargo.toml b/embassy-hal-common/Cargo.toml index e8617c02f..18c758d7b 100644 --- a/embassy-hal-common/Cargo.toml +++ b/embassy-hal-common/Cargo.toml | |||
| @@ -6,8 +6,24 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [features] | 7 | [features] |
| 8 | 8 | ||
| 9 | # Define the number of NVIC priority bits. | ||
| 10 | prio-bits-0 = [] | ||
| 11 | prio-bits-1 = [] | ||
| 12 | prio-bits-2 = [] | ||
| 13 | prio-bits-3 = [] | ||
| 14 | prio-bits-4 = [] | ||
| 15 | prio-bits-5 = [] | ||
| 16 | prio-bits-6 = [] | ||
| 17 | prio-bits-7 = [] | ||
| 18 | prio-bits-8 = [] | ||
| 19 | |||
| 20 | cortex-m = ["dep:cortex-m", "dep:critical-section"] | ||
| 21 | |||
| 9 | [dependencies] | 22 | [dependencies] |
| 10 | defmt = { version = "0.3", optional = true } | 23 | defmt = { version = "0.3", optional = true } |
| 11 | log = { version = "0.4.14", optional = true } | 24 | log = { version = "0.4.14", optional = true } |
| 12 | 25 | ||
| 13 | num-traits = { version = "0.2.14", default-features = false } | 26 | num-traits = { version = "0.2.14", default-features = false } |
| 27 | |||
| 28 | cortex-m = { version = "0.7.6", optional = true } | ||
| 29 | critical-section = { version = "1", optional = true } \ No newline at end of file | ||
diff --git a/embassy-cortex-m/build.rs b/embassy-hal-common/build.rs index 6fe82b44f..6fe82b44f 100644 --- a/embassy-cortex-m/build.rs +++ b/embassy-hal-common/build.rs | |||
diff --git a/embassy-cortex-m/src/interrupt.rs b/embassy-hal-common/src/interrupt.rs index 3a82726df..b970aa2cd 100644 --- a/embassy-cortex-m/src/interrupt.rs +++ b/embassy-hal-common/src/interrupt.rs | |||
| @@ -1,215 +1,209 @@ | |||
| 1 | //! Interrupt handling for cortex-m devices. | 1 | //! Interrupt handling for cortex-m devices. |
| 2 | use core::{mem, ptr}; | 2 | use core::mem; |
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 3 | 4 | ||
| 4 | use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering}; | 5 | use cortex_m::interrupt::InterruptNumber; |
| 5 | use cortex_m::peripheral::NVIC; | 6 | use cortex_m::peripheral::NVIC; |
| 6 | use embassy_hal_common::Peripheral; | ||
| 7 | pub use embassy_macros::cortex_m_interrupt_take as take; | ||
| 8 | |||
| 9 | /// Do not use. Used for macros and HALs only. Not covered by semver guarantees. | ||
| 10 | #[doc(hidden)] | ||
| 11 | pub mod _export { | ||
| 12 | pub use atomic_polyfill as atomic; | ||
| 13 | pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare}; | ||
| 14 | } | ||
| 15 | |||
| 16 | /// Interrupt handler trait. | ||
| 17 | /// | ||
| 18 | /// Drivers that need to handle interrupts implement this trait. | ||
| 19 | /// The user must ensure `on_interrupt()` is called every time the interrupt fires. | ||
| 20 | /// Drivers must use use [`Binding`] to assert at compile time that the user has done so. | ||
| 21 | pub trait Handler<I: Interrupt> { | ||
| 22 | /// Interrupt handler function. | ||
| 23 | /// | ||
| 24 | /// Must be called every time the `I` interrupt fires, synchronously from | ||
| 25 | /// the interrupt handler context. | ||
| 26 | /// | ||
| 27 | /// # Safety | ||
| 28 | /// | ||
| 29 | /// This function must ONLY be called from the interrupt handler for `I`. | ||
| 30 | unsafe fn on_interrupt(); | ||
| 31 | } | ||
| 32 | |||
| 33 | /// Compile-time assertion that an interrupt has been bound to a handler. | ||
| 34 | /// | ||
| 35 | /// For the vast majority of cases, you should use the `bind_interrupts!` | ||
| 36 | /// macro instead of writing `unsafe impl`s of this trait. | ||
| 37 | /// | ||
| 38 | /// # Safety | ||
| 39 | /// | ||
| 40 | /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` | ||
| 41 | /// to be called every time the `I` interrupt fires. | ||
| 42 | /// | ||
| 43 | /// This allows drivers to check bindings at compile-time. | ||
| 44 | pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {} | ||
| 45 | |||
| 46 | /// Implementation detail, do not use outside embassy crates. | ||
| 47 | #[doc(hidden)] | ||
| 48 | pub struct DynHandler { | ||
| 49 | pub func: AtomicPtr<()>, | ||
| 50 | pub ctx: AtomicPtr<()>, | ||
| 51 | } | ||
| 52 | 7 | ||
| 53 | impl DynHandler { | 8 | /// Generate a standard `mod interrupt` for a HAL. |
| 54 | pub const fn new() -> Self { | 9 | #[macro_export] |
| 55 | Self { | 10 | macro_rules! interrupt_mod { |
| 56 | func: AtomicPtr::new(ptr::null_mut()), | 11 | ($($irqs:ident),* $(,)?) => { |
| 57 | ctx: AtomicPtr::new(ptr::null_mut()), | 12 | #[cfg(feature = "rt")] |
| 13 | pub use cortex_m_rt::interrupt; | ||
| 14 | |||
| 15 | /// Interrupt definitions. | ||
| 16 | pub mod interrupt { | ||
| 17 | pub use $crate::interrupt::{InterruptExt, Priority}; | ||
| 18 | pub use crate::pac::Interrupt::*; | ||
| 19 | pub use crate::pac::Interrupt; | ||
| 20 | |||
| 21 | /// Type-level interrupt infrastructure. | ||
| 22 | /// | ||
| 23 | /// This module contains one *type* per interrupt. This is used for checking at compile time that | ||
| 24 | /// the interrupts are correctly bound to HAL drivers. | ||
| 25 | /// | ||
| 26 | /// As an end user, you shouldn't need to use this module directly. Use the [`crate::bind_interrupts!`] macro | ||
| 27 | /// to bind interrupts, and the [`crate::interrupt`] module to manually register interrupt handlers and manipulate | ||
| 28 | /// interrupts directly (pending/unpending, enabling/disabling, setting the priority, etc...) | ||
| 29 | pub mod typelevel { | ||
| 30 | use super::InterruptExt; | ||
| 31 | |||
| 32 | mod sealed { | ||
| 33 | pub trait Interrupt {} | ||
| 34 | } | ||
| 35 | |||
| 36 | /// Type-level interrupt. | ||
| 37 | /// | ||
| 38 | /// This trait is implemented for all typelevel interrupt types in this module. | ||
| 39 | pub trait Interrupt: sealed::Interrupt { | ||
| 40 | |||
| 41 | /// Interrupt enum variant. | ||
| 42 | /// | ||
| 43 | /// This allows going from typelevel interrupts (one type per interrupt) to | ||
| 44 | /// non-typelevel interrupts (a single `Interrupt` enum type, with one variant per interrupt). | ||
| 45 | const IRQ: super::Interrupt; | ||
| 46 | |||
| 47 | /// Enable the interrupt. | ||
| 48 | #[inline] | ||
| 49 | unsafe fn enable() { | ||
| 50 | Self::IRQ.enable() | ||
| 51 | } | ||
| 52 | |||
| 53 | /// Disable the interrupt. | ||
| 54 | #[inline] | ||
| 55 | fn disable() { | ||
| 56 | Self::IRQ.disable() | ||
| 57 | } | ||
| 58 | |||
| 59 | /// Check if interrupt is enabled. | ||
| 60 | #[inline] | ||
| 61 | fn is_enabled() -> bool { | ||
| 62 | Self::IRQ.is_enabled() | ||
| 63 | } | ||
| 64 | |||
| 65 | /// Check if interrupt is pending. | ||
| 66 | #[inline] | ||
| 67 | fn is_pending() -> bool { | ||
| 68 | Self::IRQ.is_pending() | ||
| 69 | } | ||
| 70 | |||
| 71 | /// Set interrupt pending. | ||
| 72 | #[inline] | ||
| 73 | fn pend() { | ||
| 74 | Self::IRQ.pend() | ||
| 75 | } | ||
| 76 | |||
| 77 | /// Unset interrupt pending. | ||
| 78 | #[inline] | ||
| 79 | fn unpend() { | ||
| 80 | Self::IRQ.unpend() | ||
| 81 | } | ||
| 82 | |||
| 83 | /// Get the priority of the interrupt. | ||
| 84 | #[inline] | ||
| 85 | fn get_priority() -> crate::interrupt::Priority { | ||
| 86 | Self::IRQ.get_priority() | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Set the interrupt priority. | ||
| 90 | #[inline] | ||
| 91 | fn set_priority(prio: crate::interrupt::Priority) { | ||
| 92 | Self::IRQ.set_priority(prio) | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | $( | ||
| 97 | #[allow(non_camel_case_types)] | ||
| 98 | #[doc=stringify!($irqs)] | ||
| 99 | #[doc=" typelevel interrupt."] | ||
| 100 | pub enum $irqs {} | ||
| 101 | impl sealed::Interrupt for $irqs{} | ||
| 102 | impl Interrupt for $irqs { | ||
| 103 | const IRQ: super::Interrupt = super::Interrupt::$irqs; | ||
| 104 | } | ||
| 105 | )* | ||
| 106 | |||
| 107 | /// Interrupt handler trait. | ||
| 108 | /// | ||
| 109 | /// Drivers that need to handle interrupts implement this trait. | ||
| 110 | /// The user must ensure `on_interrupt()` is called every time the interrupt fires. | ||
| 111 | /// Drivers must use use [`Binding`] to assert at compile time that the user has done so. | ||
| 112 | pub trait Handler<I: Interrupt> { | ||
| 113 | /// Interrupt handler function. | ||
| 114 | /// | ||
| 115 | /// Must be called every time the `I` interrupt fires, synchronously from | ||
| 116 | /// the interrupt handler context. | ||
| 117 | /// | ||
| 118 | /// # Safety | ||
| 119 | /// | ||
| 120 | /// This function must ONLY be called from the interrupt handler for `I`. | ||
| 121 | unsafe fn on_interrupt(); | ||
| 122 | } | ||
| 123 | |||
| 124 | /// Compile-time assertion that an interrupt has been bound to a handler. | ||
| 125 | /// | ||
| 126 | /// For the vast majority of cases, you should use the `bind_interrupts!` | ||
| 127 | /// macro instead of writing `unsafe impl`s of this trait. | ||
| 128 | /// | ||
| 129 | /// # Safety | ||
| 130 | /// | ||
| 131 | /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()` | ||
| 132 | /// to be called every time the `I` interrupt fires. | ||
| 133 | /// | ||
| 134 | /// This allows drivers to check bindings at compile-time. | ||
| 135 | pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {} | ||
| 136 | } | ||
| 58 | } | 137 | } |
| 59 | } | 138 | }; |
| 60 | } | ||
| 61 | |||
| 62 | #[derive(Clone, Copy)] | ||
| 63 | pub(crate) struct NrWrap(pub(crate) u16); | ||
| 64 | unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap { | ||
| 65 | fn number(self) -> u16 { | ||
| 66 | self.0 | ||
| 67 | } | ||
| 68 | } | 139 | } |
| 69 | 140 | ||
| 70 | /// Represents an interrupt type that can be configured by embassy to handle | 141 | /// Represents an interrupt type that can be configured by embassy to handle |
| 71 | /// interrupts. | 142 | /// interrupts. |
| 72 | pub unsafe trait Interrupt: Peripheral<P = Self> { | 143 | pub unsafe trait InterruptExt: InterruptNumber + Copy { |
| 73 | /// Return the NVIC interrupt number for this interrupt. | 144 | /// Enable the interrupt. |
| 74 | fn number(&self) -> u16; | ||
| 75 | /// Steal an instance of this interrupt | ||
| 76 | /// | ||
| 77 | /// # Safety | ||
| 78 | /// | ||
| 79 | /// This may panic if the interrupt has already been stolen and configured. | ||
| 80 | unsafe fn steal() -> Self; | ||
| 81 | |||
| 82 | /// Implementation detail, do not use outside embassy crates. | ||
| 83 | #[doc(hidden)] | ||
| 84 | unsafe fn __handler(&self) -> &'static DynHandler; | ||
| 85 | } | ||
| 86 | |||
| 87 | /// Represents additional behavior for all interrupts. | ||
| 88 | pub trait InterruptExt: Interrupt { | ||
| 89 | /// Configure the interrupt handler for this interrupt. | ||
| 90 | /// | ||
| 91 | /// # Safety | ||
| 92 | /// | ||
| 93 | /// It is the responsibility of the caller to ensure the handler | ||
| 94 | /// points to a valid handler as long as interrupts are enabled. | ||
| 95 | fn set_handler(&self, func: unsafe fn(*mut ())); | ||
| 96 | |||
| 97 | /// Remove the interrupt handler for this interrupt. | ||
| 98 | fn remove_handler(&self); | ||
| 99 | |||
| 100 | /// Set point to a context that is passed to the interrupt handler when | ||
| 101 | /// an interrupt is pending. | ||
| 102 | /// | ||
| 103 | /// # Safety | ||
| 104 | /// | ||
| 105 | /// It is the responsibility of the caller to ensure the context | ||
| 106 | /// points to a valid handler as long as interrupts are enabled. | ||
| 107 | fn set_handler_context(&self, ctx: *mut ()); | ||
| 108 | |||
| 109 | /// Enable the interrupt. Once enabled, the interrupt handler may | ||
| 110 | /// be called "any time". | ||
| 111 | fn enable(&self); | ||
| 112 | |||
| 113 | /// Disable the interrupt. | ||
| 114 | fn disable(&self); | ||
| 115 | |||
| 116 | /// Check if interrupt is being handled. | ||
| 117 | #[cfg(not(armv6m))] | ||
| 118 | fn is_active(&self) -> bool; | ||
| 119 | |||
| 120 | /// Check if interrupt is enabled. | ||
| 121 | fn is_enabled(&self) -> bool; | ||
| 122 | |||
| 123 | /// Check if interrupt is pending. | ||
| 124 | fn is_pending(&self) -> bool; | ||
| 125 | |||
| 126 | /// Set interrupt pending. | ||
| 127 | fn pend(&self); | ||
| 128 | |||
| 129 | /// Unset interrupt pending. | ||
| 130 | fn unpend(&self); | ||
| 131 | |||
| 132 | /// Get the priority of the interrupt. | ||
| 133 | fn get_priority(&self) -> Priority; | ||
| 134 | |||
| 135 | /// Set the interrupt priority. | ||
| 136 | fn set_priority(&self, prio: Priority); | ||
| 137 | } | ||
| 138 | |||
| 139 | impl<T: Interrupt + ?Sized> InterruptExt for T { | ||
| 140 | fn set_handler(&self, func: unsafe fn(*mut ())) { | ||
| 141 | compiler_fence(Ordering::SeqCst); | ||
| 142 | let handler = unsafe { self.__handler() }; | ||
| 143 | handler.func.store(func as *mut (), Ordering::Relaxed); | ||
| 144 | compiler_fence(Ordering::SeqCst); | ||
| 145 | } | ||
| 146 | |||
| 147 | fn remove_handler(&self) { | ||
| 148 | compiler_fence(Ordering::SeqCst); | ||
| 149 | let handler = unsafe { self.__handler() }; | ||
| 150 | handler.func.store(ptr::null_mut(), Ordering::Relaxed); | ||
| 151 | compiler_fence(Ordering::SeqCst); | ||
| 152 | } | ||
| 153 | |||
| 154 | fn set_handler_context(&self, ctx: *mut ()) { | ||
| 155 | let handler = unsafe { self.__handler() }; | ||
| 156 | handler.ctx.store(ctx, Ordering::Relaxed); | ||
| 157 | } | ||
| 158 | |||
| 159 | #[inline] | 145 | #[inline] |
| 160 | fn enable(&self) { | 146 | unsafe fn enable(self) { |
| 161 | compiler_fence(Ordering::SeqCst); | 147 | compiler_fence(Ordering::SeqCst); |
| 162 | unsafe { | 148 | NVIC::unmask(self) |
| 163 | NVIC::unmask(NrWrap(self.number())); | ||
| 164 | } | ||
| 165 | } | 149 | } |
| 166 | 150 | ||
| 151 | /// Disable the interrupt. | ||
| 167 | #[inline] | 152 | #[inline] |
| 168 | fn disable(&self) { | 153 | fn disable(self) { |
| 169 | NVIC::mask(NrWrap(self.number())); | 154 | NVIC::mask(self); |
| 170 | compiler_fence(Ordering::SeqCst); | 155 | compiler_fence(Ordering::SeqCst); |
| 171 | } | 156 | } |
| 172 | 157 | ||
| 158 | /// Check if interrupt is being handled. | ||
| 173 | #[inline] | 159 | #[inline] |
| 174 | #[cfg(not(armv6m))] | 160 | #[cfg(not(armv6m))] |
| 175 | fn is_active(&self) -> bool { | 161 | fn is_active(self) -> bool { |
| 176 | NVIC::is_active(NrWrap(self.number())) | 162 | NVIC::is_active(self) |
| 177 | } | 163 | } |
| 178 | 164 | ||
| 165 | /// Check if interrupt is enabled. | ||
| 179 | #[inline] | 166 | #[inline] |
| 180 | fn is_enabled(&self) -> bool { | 167 | fn is_enabled(self) -> bool { |
| 181 | NVIC::is_enabled(NrWrap(self.number())) | 168 | NVIC::is_enabled(self) |
| 182 | } | 169 | } |
| 183 | 170 | ||
| 171 | /// Check if interrupt is pending. | ||
| 184 | #[inline] | 172 | #[inline] |
| 185 | fn is_pending(&self) -> bool { | 173 | fn is_pending(self) -> bool { |
| 186 | NVIC::is_pending(NrWrap(self.number())) | 174 | NVIC::is_pending(self) |
| 187 | } | 175 | } |
| 188 | 176 | ||
| 177 | /// Set interrupt pending. | ||
| 189 | #[inline] | 178 | #[inline] |
| 190 | fn pend(&self) { | 179 | fn pend(self) { |
| 191 | NVIC::pend(NrWrap(self.number())) | 180 | NVIC::pend(self) |
| 192 | } | 181 | } |
| 193 | 182 | ||
| 183 | /// Unset interrupt pending. | ||
| 194 | #[inline] | 184 | #[inline] |
| 195 | fn unpend(&self) { | 185 | fn unpend(self) { |
| 196 | NVIC::unpend(NrWrap(self.number())) | 186 | NVIC::unpend(self) |
| 197 | } | 187 | } |
| 198 | 188 | ||
| 189 | /// Get the priority of the interrupt. | ||
| 199 | #[inline] | 190 | #[inline] |
| 200 | fn get_priority(&self) -> Priority { | 191 | fn get_priority(self) -> Priority { |
| 201 | Priority::from(NVIC::get_priority(NrWrap(self.number()))) | 192 | Priority::from(NVIC::get_priority(self)) |
| 202 | } | 193 | } |
| 203 | 194 | ||
| 195 | /// Set the interrupt priority. | ||
| 204 | #[inline] | 196 | #[inline] |
| 205 | fn set_priority(&self, prio: Priority) { | 197 | fn set_priority(self, prio: Priority) { |
| 206 | unsafe { | 198 | critical_section::with(|_| unsafe { |
| 207 | let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); | 199 | let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); |
| 208 | nvic.set_priority(NrWrap(self.number()), prio.into()) | 200 | nvic.set_priority(self, prio.into()) |
| 209 | } | 201 | }) |
| 210 | } | 202 | } |
| 211 | } | 203 | } |
| 212 | 204 | ||
| 205 | unsafe impl<T: InterruptNumber + Copy> InterruptExt for T {} | ||
| 206 | |||
| 213 | impl From<u8> for Priority { | 207 | impl From<u8> for Priority { |
| 214 | fn from(priority: u8) -> Self { | 208 | fn from(priority: u8) -> Self { |
| 215 | unsafe { mem::transmute(priority & PRIO_MASK) } | 209 | unsafe { mem::transmute(priority & PRIO_MASK) } |
diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs index b2a35cd35..235964aa4 100644 --- a/embassy-hal-common/src/lib.rs +++ b/embassy-hal-common/src/lib.rs | |||
| @@ -11,3 +11,6 @@ mod peripheral; | |||
| 11 | pub mod ratio; | 11 | pub mod ratio; |
| 12 | pub mod ring_buffer; | 12 | pub mod ring_buffer; |
| 13 | pub use peripheral::{Peripheral, PeripheralRef}; | 13 | pub use peripheral::{Peripheral, PeripheralRef}; |
| 14 | |||
| 15 | #[cfg(feature = "cortex-m")] | ||
| 16 | pub mod interrupt; | ||
diff --git a/embassy-lora/src/iv.rs b/embassy-lora/src/iv.rs index d515bc365..136973fe3 100644 --- a/embassy-lora/src/iv.rs +++ b/embassy-lora/src/iv.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #[cfg(feature = "stm32wl")] | 1 | #[cfg(feature = "stm32wl")] |
| 2 | use embassy_stm32::interrupt; | 2 | use embassy_stm32::interrupt; |
| 3 | #[cfg(feature = "stm32wl")] | 3 | #[cfg(feature = "stm32wl")] |
| 4 | use embassy_stm32::interrupt::*; | 4 | use embassy_stm32::interrupt::InterruptExt; |
| 5 | #[cfg(feature = "stm32wl")] | 5 | #[cfg(feature = "stm32wl")] |
| 6 | use embassy_stm32::pac; | 6 | use embassy_stm32::pac; |
| 7 | #[cfg(feature = "stm32wl")] | 7 | #[cfg(feature = "stm32wl")] |
| @@ -20,9 +20,9 @@ use lora_phy::mod_traits::InterfaceVariant; | |||
| 20 | pub struct InterruptHandler {} | 20 | pub struct InterruptHandler {} |
| 21 | 21 | ||
| 22 | #[cfg(feature = "stm32wl")] | 22 | #[cfg(feature = "stm32wl")] |
| 23 | impl interrupt::Handler<interrupt::SUBGHZ_RADIO> for InterruptHandler { | 23 | impl interrupt::typelevel::Handler<interrupt::typelevel::SUBGHZ_RADIO> for InterruptHandler { |
| 24 | unsafe fn on_interrupt() { | 24 | unsafe fn on_interrupt() { |
| 25 | unsafe { SUBGHZ_RADIO::steal() }.disable(); | 25 | interrupt::SUBGHZ_RADIO.disable(); |
| 26 | IRQ_SIGNAL.signal(()); | 26 | IRQ_SIGNAL.signal(()); |
| 27 | } | 27 | } |
| 28 | } | 28 | } |
| @@ -45,11 +45,11 @@ where | |||
| 45 | { | 45 | { |
| 46 | /// Create an InterfaceVariant instance for an stm32wl/sx1262 combination | 46 | /// Create an InterfaceVariant instance for an stm32wl/sx1262 combination |
| 47 | pub fn new( | 47 | pub fn new( |
| 48 | _irq: impl interrupt::Binding<interrupt::SUBGHZ_RADIO, InterruptHandler>, | 48 | _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SUBGHZ_RADIO, InterruptHandler>, |
| 49 | rf_switch_rx: Option<CTRL>, | 49 | rf_switch_rx: Option<CTRL>, |
| 50 | rf_switch_tx: Option<CTRL>, | 50 | rf_switch_tx: Option<CTRL>, |
| 51 | ) -> Result<Self, RadioError> { | 51 | ) -> Result<Self, RadioError> { |
| 52 | unsafe { interrupt::SUBGHZ_RADIO::steal() }.disable(); | 52 | interrupt::SUBGHZ_RADIO.disable(); |
| 53 | Ok(Self { | 53 | Ok(Self { |
| 54 | board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board | 54 | board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board |
| 55 | rf_switch_rx, | 55 | rf_switch_rx, |
| @@ -68,34 +68,28 @@ where | |||
| 68 | } | 68 | } |
| 69 | async fn set_nss_low(&mut self) -> Result<(), RadioError> { | 69 | async fn set_nss_low(&mut self) -> Result<(), RadioError> { |
| 70 | let pwr = pac::PWR; | 70 | let pwr = pac::PWR; |
| 71 | unsafe { | 71 | pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW)); |
| 72 | pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW)); | ||
| 73 | } | ||
| 74 | Ok(()) | 72 | Ok(()) |
| 75 | } | 73 | } |
| 76 | async fn set_nss_high(&mut self) -> Result<(), RadioError> { | 74 | async fn set_nss_high(&mut self) -> Result<(), RadioError> { |
| 77 | let pwr = pac::PWR; | 75 | let pwr = pac::PWR; |
| 78 | unsafe { | 76 | pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH)); |
| 79 | pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH)); | ||
| 80 | } | ||
| 81 | Ok(()) | 77 | Ok(()) |
| 82 | } | 78 | } |
| 83 | async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> { | 79 | async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> { |
| 84 | let rcc = pac::RCC; | 80 | let rcc = pac::RCC; |
| 85 | unsafe { | 81 | rcc.csr().modify(|w| w.set_rfrst(true)); |
| 86 | rcc.csr().modify(|w| w.set_rfrst(true)); | 82 | rcc.csr().modify(|w| w.set_rfrst(false)); |
| 87 | rcc.csr().modify(|w| w.set_rfrst(false)); | ||
| 88 | } | ||
| 89 | Ok(()) | 83 | Ok(()) |
| 90 | } | 84 | } |
| 91 | async fn wait_on_busy(&mut self) -> Result<(), RadioError> { | 85 | async fn wait_on_busy(&mut self) -> Result<(), RadioError> { |
| 92 | let pwr = pac::PWR; | 86 | let pwr = pac::PWR; |
| 93 | while unsafe { pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY } {} | 87 | while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {} |
| 94 | Ok(()) | 88 | Ok(()) |
| 95 | } | 89 | } |
| 96 | 90 | ||
| 97 | async fn await_irq(&mut self) -> Result<(), RadioError> { | 91 | async fn await_irq(&mut self) -> Result<(), RadioError> { |
| 98 | unsafe { interrupt::SUBGHZ_RADIO::steal() }.enable(); | 92 | unsafe { interrupt::SUBGHZ_RADIO.enable() }; |
| 99 | IRQ_SIGNAL.wait().await; | 93 | IRQ_SIGNAL.wait().await; |
| 100 | Ok(()) | 94 | Ok(()) |
| 101 | } | 95 | } |
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs index dc5b519ff..ba4f13b77 100644 --- a/embassy-macros/src/lib.rs +++ b/embassy-macros/src/lib.rs | |||
| @@ -156,27 +156,3 @@ pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 156 | let f = syn::parse_macro_input!(item as syn::ItemFn); | 156 | let f = syn::parse_macro_input!(item as syn::ItemFn); |
| 157 | main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into() | 157 | main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into() |
| 158 | } | 158 | } |
| 159 | |||
| 160 | #[proc_macro_attribute] | ||
| 161 | pub fn cortex_m_interrupt(args: TokenStream, item: TokenStream) -> TokenStream { | ||
| 162 | let args = syn::parse_macro_input!(args as syn::AttributeArgs); | ||
| 163 | let f = syn::parse_macro_input!(item as syn::ItemFn); | ||
| 164 | cortex_m_interrupt::run(args, f).unwrap_or_else(|x| x).into() | ||
| 165 | } | ||
| 166 | |||
| 167 | #[proc_macro] | ||
| 168 | pub fn cortex_m_interrupt_declare(item: TokenStream) -> TokenStream { | ||
| 169 | let name = syn::parse_macro_input!(item as syn::Ident); | ||
| 170 | cortex_m_interrupt_declare::run(name).unwrap_or_else(|x| x).into() | ||
| 171 | } | ||
| 172 | |||
| 173 | /// # interrupt_take procedural macro | ||
| 174 | /// | ||
| 175 | /// core::panic! is used as a default way to panic in this macro as there is no sensible way of enabling/disabling defmt for macro generation. | ||
| 176 | /// We are aware that this brings bloat in the form of core::fmt, but the bloat is already included with e.g. array indexing panics. | ||
| 177 | /// To get rid of this bloat, use the compiler flags `-Zbuild-std=core -Zbuild-std-features=panic_immediate_abort`. | ||
| 178 | #[proc_macro] | ||
| 179 | pub fn cortex_m_interrupt_take(item: TokenStream) -> TokenStream { | ||
| 180 | let name = syn::parse_macro_input!(item as syn::Ident); | ||
| 181 | cortex_m_interrupt_take::run(name).unwrap_or_else(|x| x).into() | ||
| 182 | } | ||
diff --git a/embassy-macros/src/macros/cortex_m_interrupt.rs b/embassy-macros/src/macros/cortex_m_interrupt.rs deleted file mode 100644 index 13af8ca07..000000000 --- a/embassy-macros/src/macros/cortex_m_interrupt.rs +++ /dev/null | |||
| @@ -1,66 +0,0 @@ | |||
| 1 | use std::iter; | ||
| 2 | |||
| 3 | use darling::FromMeta; | ||
| 4 | use proc_macro2::TokenStream; | ||
| 5 | use quote::quote; | ||
| 6 | use syn::{ReturnType, Type, Visibility}; | ||
| 7 | |||
| 8 | use crate::util::ctxt::Ctxt; | ||
| 9 | |||
| 10 | #[derive(Debug, FromMeta)] | ||
| 11 | struct Args {} | ||
| 12 | |||
| 13 | pub fn run(args: syn::AttributeArgs, mut f: syn::ItemFn) -> Result<TokenStream, TokenStream> { | ||
| 14 | let _args = Args::from_list(&args).map_err(|e| e.write_errors())?; | ||
| 15 | |||
| 16 | let ident = f.sig.ident.clone(); | ||
| 17 | let ident_s = ident.to_string(); | ||
| 18 | |||
| 19 | // XXX should we blacklist other attributes? | ||
| 20 | |||
| 21 | let valid_signature = f.sig.constness.is_none() | ||
| 22 | && f.vis == Visibility::Inherited | ||
| 23 | && f.sig.abi.is_none() | ||
| 24 | && f.sig.inputs.is_empty() | ||
| 25 | && f.sig.generics.params.is_empty() | ||
| 26 | && f.sig.generics.where_clause.is_none() | ||
| 27 | && f.sig.variadic.is_none() | ||
| 28 | && match f.sig.output { | ||
| 29 | ReturnType::Default => true, | ||
| 30 | ReturnType::Type(_, ref ty) => match **ty { | ||
| 31 | Type::Tuple(ref tuple) => tuple.elems.is_empty(), | ||
| 32 | Type::Never(..) => true, | ||
| 33 | _ => false, | ||
| 34 | }, | ||
| 35 | }; | ||
| 36 | |||
| 37 | let ctxt = Ctxt::new(); | ||
| 38 | |||
| 39 | if !valid_signature { | ||
| 40 | ctxt.error_spanned_by( | ||
| 41 | &f.sig, | ||
| 42 | "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`", | ||
| 43 | ); | ||
| 44 | } | ||
| 45 | |||
| 46 | ctxt.check()?; | ||
| 47 | |||
| 48 | f.block.stmts = iter::once( | ||
| 49 | syn::parse2(quote! {{ | ||
| 50 | // Check that this interrupt actually exists | ||
| 51 | let __irq_exists_check: interrupt::#ident; | ||
| 52 | }}) | ||
| 53 | .unwrap(), | ||
| 54 | ) | ||
| 55 | .chain(f.block.stmts) | ||
| 56 | .collect(); | ||
| 57 | |||
| 58 | let result = quote!( | ||
| 59 | #[doc(hidden)] | ||
| 60 | #[export_name = #ident_s] | ||
| 61 | #[allow(non_snake_case)] | ||
| 62 | #f | ||
| 63 | ); | ||
| 64 | |||
| 65 | Ok(result) | ||
| 66 | } | ||
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_declare.rs b/embassy-macros/src/macros/cortex_m_interrupt_declare.rs deleted file mode 100644 index 699883efa..000000000 --- a/embassy-macros/src/macros/cortex_m_interrupt_declare.rs +++ /dev/null | |||
| @@ -1,34 +0,0 @@ | |||
| 1 | use proc_macro2::TokenStream; | ||
| 2 | use quote::{format_ident, quote}; | ||
| 3 | |||
| 4 | pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> { | ||
| 5 | let name = format_ident!("{}", name); | ||
| 6 | let name_interrupt = format_ident!("{}", name); | ||
| 7 | let name_handler = format!("__EMBASSY_{}_HANDLER", name); | ||
| 8 | |||
| 9 | let doc = format!("{} interrupt singleton.", name); | ||
| 10 | |||
| 11 | let result = quote! { | ||
| 12 | #[doc = #doc] | ||
| 13 | #[allow(non_camel_case_types)] | ||
| 14 | pub struct #name_interrupt(()); | ||
| 15 | unsafe impl ::embassy_cortex_m::interrupt::Interrupt for #name_interrupt { | ||
| 16 | fn number(&self) -> u16 { | ||
| 17 | use cortex_m::interrupt::InterruptNumber; | ||
| 18 | let irq = InterruptEnum::#name; | ||
| 19 | irq.number() as u16 | ||
| 20 | } | ||
| 21 | unsafe fn steal() -> Self { | ||
| 22 | Self(()) | ||
| 23 | } | ||
| 24 | unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::DynHandler { | ||
| 25 | #[export_name = #name_handler] | ||
| 26 | static HANDLER: ::embassy_cortex_m::interrupt::DynHandler = ::embassy_cortex_m::interrupt::DynHandler::new(); | ||
| 27 | &HANDLER | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | ::embassy_hal_common::impl_peripheral!(#name_interrupt); | ||
| 32 | }; | ||
| 33 | Ok(result) | ||
| 34 | } | ||
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_take.rs b/embassy-macros/src/macros/cortex_m_interrupt_take.rs deleted file mode 100644 index 4806d1c12..000000000 --- a/embassy-macros/src/macros/cortex_m_interrupt_take.rs +++ /dev/null | |||
| @@ -1,57 +0,0 @@ | |||
| 1 | use proc_macro2::TokenStream; | ||
| 2 | use quote::{format_ident, quote}; | ||
| 3 | |||
| 4 | pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> { | ||
| 5 | let name = format!("{}", name); | ||
| 6 | let name_interrupt = format_ident!("{}", name); | ||
| 7 | let name_handler = format!("__EMBASSY_{}_HANDLER", name); | ||
| 8 | |||
| 9 | #[cfg(feature = "rtos-trace-interrupt")] | ||
| 10 | let (isr_enter, isr_exit) = ( | ||
| 11 | quote! { | ||
| 12 | ::embassy_executor::rtos_trace_interrupt! { | ||
| 13 | ::embassy_executor::_export::trace::isr_enter(); | ||
| 14 | } | ||
| 15 | }, | ||
| 16 | quote! { | ||
| 17 | ::embassy_executor::rtos_trace_interrupt! { | ||
| 18 | ::embassy_executor::_export::trace::isr_exit(); | ||
| 19 | } | ||
| 20 | }, | ||
| 21 | ); | ||
| 22 | |||
| 23 | #[cfg(not(feature = "rtos-trace-interrupt"))] | ||
| 24 | let (isr_enter, isr_exit) = (quote! {}, quote! {}); | ||
| 25 | |||
| 26 | let result = quote! { | ||
| 27 | { | ||
| 28 | #[allow(non_snake_case)] | ||
| 29 | #[export_name = #name] | ||
| 30 | pub unsafe extern "C" fn trampoline() { | ||
| 31 | extern "C" { | ||
| 32 | #[link_name = #name_handler] | ||
| 33 | static HANDLER: interrupt::DynHandler; | ||
| 34 | } | ||
| 35 | |||
| 36 | let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed); | ||
| 37 | let ctx = HANDLER.ctx.load(interrupt::_export::atomic::Ordering::Relaxed); | ||
| 38 | let func: fn(*mut ()) = ::core::mem::transmute(func); | ||
| 39 | #isr_enter | ||
| 40 | |||
| 41 | func(ctx); | ||
| 42 | #isr_exit | ||
| 43 | |||
| 44 | } | ||
| 45 | |||
| 46 | static TAKEN: interrupt::_export::atomic::AtomicBool = interrupt::_export::atomic::AtomicBool::new(false); | ||
| 47 | |||
| 48 | if TAKEN.compare_exchange(false, true, interrupt::_export::atomic::Ordering::AcqRel, interrupt::_export::atomic::Ordering::Acquire).is_err() { | ||
| 49 | core::panic!("IRQ Already taken"); | ||
| 50 | } | ||
| 51 | |||
| 52 | let irq: interrupt::#name_interrupt = unsafe { ::core::mem::transmute(()) }; | ||
| 53 | irq | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | Ok(result) | ||
| 57 | } | ||
diff --git a/embassy-macros/src/macros/mod.rs b/embassy-macros/src/macros/mod.rs index e547736fc..572094ca6 100644 --- a/embassy-macros/src/macros/mod.rs +++ b/embassy-macros/src/macros/mod.rs | |||
| @@ -1,5 +1,2 @@ | |||
| 1 | pub mod cortex_m_interrupt; | ||
| 2 | pub mod cortex_m_interrupt_declare; | ||
| 3 | pub mod cortex_m_interrupt_take; | ||
| 4 | pub mod main; | 1 | pub mod main; |
| 5 | pub mod task; | 2 | pub mod task; |
diff --git a/embassy-net-w5500/Cargo.toml b/embassy-net-w5500/Cargo.toml index 3f19e3d39..37d15c7ac 100644 --- a/embassy-net-w5500/Cargo.toml +++ b/embassy-net-w5500/Cargo.toml | |||
| @@ -14,3 +14,8 @@ embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver- | |||
| 14 | embassy-time = { version = "0.1.0" } | 14 | embassy-time = { version = "0.1.0" } |
| 15 | embassy-futures = { version = "0.1.0" } | 15 | embassy-futures = { version = "0.1.0" } |
| 16 | defmt = { version = "0.3", optional = true } | 16 | defmt = { version = "0.3", optional = true } |
| 17 | |||
| 18 | [package.metadata.embassy_docs] | ||
| 19 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-w5500-v$VERSION/embassy-net-w5500/src/" | ||
| 20 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-w5500/src/" | ||
| 21 | target = "thumbv7em-none-eabi" \ No newline at end of file | ||
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 0a47c5d94..4ac572577 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml | |||
| @@ -26,7 +26,8 @@ unstable-traits = [] | |||
| 26 | udp = ["smoltcp/socket-udp"] | 26 | udp = ["smoltcp/socket-udp"] |
| 27 | tcp = ["smoltcp/socket-tcp"] | 27 | tcp = ["smoltcp/socket-tcp"] |
| 28 | dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] | 28 | dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] |
| 29 | dhcpv4 = ["medium-ethernet", "smoltcp/socket-dhcpv4"] | 29 | dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"] |
| 30 | proto-ipv4 = ["smoltcp/proto-ipv4"] | ||
| 30 | proto-ipv6 = ["smoltcp/proto-ipv6"] | 31 | proto-ipv6 = ["smoltcp/proto-ipv6"] |
| 31 | medium-ethernet = ["smoltcp/medium-ethernet"] | 32 | medium-ethernet = ["smoltcp/medium-ethernet"] |
| 32 | medium-ip = ["smoltcp/medium-ip"] | 33 | medium-ip = ["smoltcp/medium-ip"] |
| @@ -38,7 +39,6 @@ defmt = { version = "0.3", optional = true } | |||
| 38 | log = { version = "0.4.14", optional = true } | 39 | log = { version = "0.4.14", optional = true } |
| 39 | 40 | ||
| 40 | smoltcp = { version = "0.9.0", default-features = false, features = [ | 41 | smoltcp = { version = "0.9.0", default-features = false, features = [ |
| 41 | "proto-ipv4", | ||
| 42 | "socket", | 42 | "socket", |
| 43 | "async", | 43 | "async", |
| 44 | ]} | 44 | ]} |
diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index 5daa00544..583cdc87f 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs | |||
| @@ -59,7 +59,10 @@ where | |||
| 59 | smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4); | 59 | smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4); |
| 60 | smolcaps.checksum.tcp = convert(caps.checksum.tcp); | 60 | smolcaps.checksum.tcp = convert(caps.checksum.tcp); |
| 61 | smolcaps.checksum.udp = convert(caps.checksum.udp); | 61 | smolcaps.checksum.udp = convert(caps.checksum.udp); |
| 62 | smolcaps.checksum.icmpv4 = convert(caps.checksum.icmpv4); | 62 | #[cfg(feature = "proto-ipv4")] |
| 63 | { | ||
| 64 | smolcaps.checksum.icmpv4 = convert(caps.checksum.icmpv4); | ||
| 65 | } | ||
| 63 | #[cfg(feature = "proto-ipv6")] | 66 | #[cfg(feature = "proto-ipv6")] |
| 64 | { | 67 | { |
| 65 | smolcaps.checksum.icmpv6 = convert(caps.checksum.icmpv6); | 68 | smolcaps.checksum.icmpv6 = convert(caps.checksum.icmpv6); |
diff --git a/embassy-net/src/dns.rs b/embassy-net/src/dns.rs index 3fd235b2c..94f75f108 100644 --- a/embassy-net/src/dns.rs +++ b/embassy-net/src/dns.rs | |||
| @@ -88,6 +88,7 @@ where | |||
| 88 | let addrs = self.query(host, qtype).await?; | 88 | let addrs = self.query(host, qtype).await?; |
| 89 | if let Some(first) = addrs.get(0) { | 89 | if let Some(first) = addrs.get(0) { |
| 90 | Ok(match first { | 90 | Ok(match first { |
| 91 | #[cfg(feature = "proto-ipv4")] | ||
| 91 | IpAddress::Ipv4(addr) => IpAddr::V4(addr.0.into()), | 92 | IpAddress::Ipv4(addr) => IpAddr::V4(addr.0.into()), |
| 92 | #[cfg(feature = "proto-ipv6")] | 93 | #[cfg(feature = "proto-ipv6")] |
| 93 | IpAddress::Ipv6(addr) => IpAddr::V6(addr.0.into()), | 94 | IpAddress::Ipv6(addr) => IpAddr::V6(addr.0.into()), |
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index bccbad521..7e8f765f9 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs | |||
| @@ -34,7 +34,9 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig}; | |||
| 34 | pub use smoltcp::wire::IpListenEndpoint; | 34 | pub use smoltcp::wire::IpListenEndpoint; |
| 35 | #[cfg(feature = "medium-ethernet")] | 35 | #[cfg(feature = "medium-ethernet")] |
| 36 | pub use smoltcp::wire::{EthernetAddress, HardwareAddress}; | 36 | pub use smoltcp::wire::{EthernetAddress, HardwareAddress}; |
| 37 | pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; | 37 | pub use smoltcp::wire::{IpAddress, IpCidr}; |
| 38 | #[cfg(feature = "proto-ipv4")] | ||
| 39 | pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr}; | ||
| 38 | #[cfg(feature = "proto-ipv6")] | 40 | #[cfg(feature = "proto-ipv6")] |
| 39 | pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; | 41 | pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; |
| 40 | 42 | ||
| @@ -67,8 +69,9 @@ impl<const SOCK: usize> StackResources<SOCK> { | |||
| 67 | } | 69 | } |
| 68 | 70 | ||
| 69 | /// Static IP address configuration. | 71 | /// Static IP address configuration. |
| 72 | #[cfg(feature = "proto-ipv4")] | ||
| 70 | #[derive(Debug, Clone, PartialEq, Eq)] | 73 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 71 | pub struct StaticConfig { | 74 | pub struct StaticConfigV4 { |
| 72 | /// IP address and subnet mask. | 75 | /// IP address and subnet mask. |
| 73 | pub address: Ipv4Cidr, | 76 | pub address: Ipv4Cidr, |
| 74 | /// Default gateway. | 77 | /// Default gateway. |
| @@ -77,6 +80,18 @@ pub struct StaticConfig { | |||
| 77 | pub dns_servers: Vec<Ipv4Address, 3>, | 80 | pub dns_servers: Vec<Ipv4Address, 3>, |
| 78 | } | 81 | } |
| 79 | 82 | ||
| 83 | /// Static IPv6 address configuration | ||
| 84 | #[cfg(feature = "proto-ipv6")] | ||
| 85 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 86 | pub struct StaticConfigV6 { | ||
| 87 | /// IP address and subnet mask. | ||
| 88 | pub address: Ipv6Cidr, | ||
| 89 | /// Default gateway. | ||
| 90 | pub gateway: Option<Ipv6Address>, | ||
| 91 | /// DNS servers. | ||
| 92 | pub dns_servers: Vec<Ipv6Address, 3>, | ||
| 93 | } | ||
| 94 | |||
| 80 | /// DHCP configuration. | 95 | /// DHCP configuration. |
| 81 | #[cfg(feature = "dhcpv4")] | 96 | #[cfg(feature = "dhcpv4")] |
| 82 | #[derive(Debug, Clone, PartialEq, Eq)] | 97 | #[derive(Debug, Clone, PartialEq, Eq)] |
| @@ -112,12 +127,71 @@ impl Default for DhcpConfig { | |||
| 112 | } | 127 | } |
| 113 | 128 | ||
| 114 | /// Network stack configuration. | 129 | /// Network stack configuration. |
| 115 | pub enum Config { | 130 | pub struct Config { |
| 116 | /// Use a static IP address configuration. | 131 | /// IPv4 configuration |
| 117 | Static(StaticConfig), | 132 | #[cfg(feature = "proto-ipv4")] |
| 133 | pub ipv4: ConfigV4, | ||
| 134 | /// IPv6 configuration | ||
| 135 | #[cfg(feature = "proto-ipv6")] | ||
| 136 | pub ipv6: ConfigV6, | ||
| 137 | } | ||
| 138 | |||
| 139 | impl Config { | ||
| 140 | /// IPv4 configuration with static addressing. | ||
| 141 | #[cfg(feature = "proto-ipv4")] | ||
| 142 | pub fn ipv4_static(config: StaticConfigV4) -> Self { | ||
| 143 | Self { | ||
| 144 | ipv4: ConfigV4::Static(config), | ||
| 145 | #[cfg(feature = "proto-ipv6")] | ||
| 146 | ipv6: ConfigV6::None, | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | /// IPv6 configuration with static addressing. | ||
| 151 | #[cfg(feature = "proto-ipv6")] | ||
| 152 | pub fn ipv6_static(config: StaticConfigV6) -> Self { | ||
| 153 | Self { | ||
| 154 | #[cfg(feature = "proto-ipv4")] | ||
| 155 | ipv4: ConfigV4::None, | ||
| 156 | ipv6: ConfigV6::Static(config), | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | /// IPv6 configuration with dynamic addressing. | ||
| 161 | /// | ||
| 162 | /// # Example | ||
| 163 | /// ```rust | ||
| 164 | /// let _cfg = Config::dhcpv4(Default::default()); | ||
| 165 | /// ``` | ||
| 166 | #[cfg(feature = "dhcpv4")] | ||
| 167 | pub fn dhcpv4(config: DhcpConfig) -> Self { | ||
| 168 | Self { | ||
| 169 | ipv4: ConfigV4::Dhcp(config), | ||
| 170 | #[cfg(feature = "proto-ipv6")] | ||
| 171 | ipv6: ConfigV6::None, | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | /// Network stack IPv4 configuration. | ||
| 177 | #[cfg(feature = "proto-ipv4")] | ||
| 178 | pub enum ConfigV4 { | ||
| 179 | /// Use a static IPv4 address configuration. | ||
| 180 | Static(StaticConfigV4), | ||
| 118 | /// Use DHCP to obtain an IP address configuration. | 181 | /// Use DHCP to obtain an IP address configuration. |
| 119 | #[cfg(feature = "dhcpv4")] | 182 | #[cfg(feature = "dhcpv4")] |
| 120 | Dhcp(DhcpConfig), | 183 | Dhcp(DhcpConfig), |
| 184 | /// Do not configure IPv6. | ||
| 185 | None, | ||
| 186 | } | ||
| 187 | |||
| 188 | /// Network stack IPv6 configuration. | ||
| 189 | #[cfg(feature = "proto-ipv6")] | ||
| 190 | pub enum ConfigV6 { | ||
| 191 | /// Use a static IPv6 address configuration. | ||
| 192 | Static(StaticConfigV6), | ||
| 193 | /// Do not configure IPv6. | ||
| 194 | None, | ||
| 121 | } | 195 | } |
| 122 | 196 | ||
| 123 | /// A network stack. | 197 | /// A network stack. |
| @@ -131,7 +205,10 @@ pub struct Stack<D: Driver> { | |||
| 131 | struct Inner<D: Driver> { | 205 | struct Inner<D: Driver> { |
| 132 | device: D, | 206 | device: D, |
| 133 | link_up: bool, | 207 | link_up: bool, |
| 134 | config: Option<StaticConfig>, | 208 | #[cfg(feature = "proto-ipv4")] |
| 209 | static_v4: Option<StaticConfigV4>, | ||
| 210 | #[cfg(feature = "proto-ipv6")] | ||
| 211 | static_v6: Option<StaticConfigV6>, | ||
| 135 | #[cfg(feature = "dhcpv4")] | 212 | #[cfg(feature = "dhcpv4")] |
| 136 | dhcp_socket: Option<SocketHandle>, | 213 | dhcp_socket: Option<SocketHandle>, |
| 137 | #[cfg(feature = "dns")] | 214 | #[cfg(feature = "dns")] |
| @@ -187,7 +264,10 @@ impl<D: Driver + 'static> Stack<D> { | |||
| 187 | let mut inner = Inner { | 264 | let mut inner = Inner { |
| 188 | device, | 265 | device, |
| 189 | link_up: false, | 266 | link_up: false, |
| 190 | config: None, | 267 | #[cfg(feature = "proto-ipv4")] |
| 268 | static_v4: None, | ||
| 269 | #[cfg(feature = "proto-ipv6")] | ||
| 270 | static_v6: None, | ||
| 191 | #[cfg(feature = "dhcpv4")] | 271 | #[cfg(feature = "dhcpv4")] |
| 192 | dhcp_socket: None, | 272 | dhcp_socket: None, |
| 193 | #[cfg(feature = "dns")] | 273 | #[cfg(feature = "dns")] |
| @@ -199,17 +279,26 @@ impl<D: Driver + 'static> Stack<D> { | |||
| 199 | dns_waker: WakerRegistration::new(), | 279 | dns_waker: WakerRegistration::new(), |
| 200 | }; | 280 | }; |
| 201 | 281 | ||
| 202 | match config { | 282 | #[cfg(feature = "proto-ipv4")] |
| 203 | Config::Static(config) => { | 283 | match config.ipv4 { |
| 204 | inner.apply_config(&mut socket, config); | 284 | ConfigV4::Static(config) => { |
| 285 | inner.apply_config_v4(&mut socket, config); | ||
| 205 | } | 286 | } |
| 206 | #[cfg(feature = "dhcpv4")] | 287 | #[cfg(feature = "dhcpv4")] |
| 207 | Config::Dhcp(config) => { | 288 | ConfigV4::Dhcp(config) => { |
| 208 | let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); | 289 | let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); |
| 209 | inner.apply_dhcp_config(&mut dhcp_socket, config); | 290 | inner.apply_dhcp_config(&mut dhcp_socket, config); |
| 210 | let handle = socket.sockets.add(dhcp_socket); | 291 | let handle = socket.sockets.add(dhcp_socket); |
| 211 | inner.dhcp_socket = Some(handle); | 292 | inner.dhcp_socket = Some(handle); |
| 212 | } | 293 | } |
| 294 | ConfigV4::None => {} | ||
| 295 | } | ||
| 296 | #[cfg(feature = "proto-ipv6")] | ||
| 297 | match config.ipv6 { | ||
| 298 | ConfigV6::Static(config) => { | ||
| 299 | inner.apply_config_v6(&mut socket, config); | ||
| 300 | } | ||
| 301 | ConfigV6::None => {} | ||
| 213 | } | 302 | } |
| 214 | 303 | ||
| 215 | Self { | 304 | Self { |
| @@ -239,12 +328,40 @@ impl<D: Driver + 'static> Stack<D> { | |||
| 239 | /// Get whether the network stack has a valid IP configuration. | 328 | /// Get whether the network stack has a valid IP configuration. |
| 240 | /// This is true if the network stack has a static IP configuration or if DHCP has completed | 329 | /// This is true if the network stack has a static IP configuration or if DHCP has completed |
| 241 | pub fn is_config_up(&self) -> bool { | 330 | pub fn is_config_up(&self) -> bool { |
| 242 | self.with(|_s, i| i.config.is_some()) | 331 | let v4_up; |
| 332 | let v6_up; | ||
| 333 | |||
| 334 | #[cfg(feature = "proto-ipv4")] | ||
| 335 | { | ||
| 336 | v4_up = self.config_v4().is_some(); | ||
| 337 | } | ||
| 338 | #[cfg(not(feature = "proto-ipv4"))] | ||
| 339 | { | ||
| 340 | v4_up = false; | ||
| 341 | } | ||
| 342 | |||
| 343 | #[cfg(feature = "proto-ipv6")] | ||
| 344 | { | ||
| 345 | v6_up = self.config_v6().is_some(); | ||
| 346 | } | ||
| 347 | #[cfg(not(feature = "proto-ipv6"))] | ||
| 348 | { | ||
| 349 | v6_up = false; | ||
| 350 | } | ||
| 351 | |||
| 352 | v4_up || v6_up | ||
| 243 | } | 353 | } |
| 244 | 354 | ||
| 245 | /// Get the current IP configuration. | 355 | /// Get the current IPv4 configuration. |
| 246 | pub fn config(&self) -> Option<StaticConfig> { | 356 | #[cfg(feature = "proto-ipv4")] |
| 247 | self.with(|_s, i| i.config.clone()) | 357 | pub fn config_v4(&self) -> Option<StaticConfigV4> { |
| 358 | self.with(|_s, i| i.static_v4.clone()) | ||
| 359 | } | ||
| 360 | |||
| 361 | /// Get the current IPv6 configuration. | ||
| 362 | #[cfg(feature = "proto-ipv6")] | ||
| 363 | pub fn config_v6(&self) -> Option<StaticConfigV6> { | ||
| 364 | self.with(|_s, i| i.static_v6.clone()) | ||
| 248 | } | 365 | } |
| 249 | 366 | ||
| 250 | /// Run the network stack. | 367 | /// Run the network stack. |
| @@ -264,6 +381,7 @@ impl<D: Driver + 'static> Stack<D> { | |||
| 264 | pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> { | 381 | pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> { |
| 265 | // For A and AAAA queries we try detect whether `name` is just an IP address | 382 | // For A and AAAA queries we try detect whether `name` is just an IP address |
| 266 | match qtype { | 383 | match qtype { |
| 384 | #[cfg(feature = "proto-ipv4")] | ||
| 267 | dns::DnsQueryType::A => { | 385 | dns::DnsQueryType::A => { |
| 268 | if let Ok(ip) = name.parse().map(IpAddress::Ipv4) { | 386 | if let Ok(ip) = name.parse().map(IpAddress::Ipv4) { |
| 269 | return Ok([ip].into_iter().collect()); | 387 | return Ok([ip].into_iter().collect()); |
| @@ -374,7 +492,8 @@ impl SocketStack { | |||
| 374 | } | 492 | } |
| 375 | 493 | ||
| 376 | impl<D: Driver + 'static> Inner<D> { | 494 | impl<D: Driver + 'static> Inner<D> { |
| 377 | fn apply_config(&mut self, s: &mut SocketStack, config: StaticConfig) { | 495 | #[cfg(feature = "proto-ipv4")] |
| 496 | fn apply_config_v4(&mut self, s: &mut SocketStack, config: StaticConfigV4) { | ||
| 378 | #[cfg(feature = "medium-ethernet")] | 497 | #[cfg(feature = "medium-ethernet")] |
| 379 | let medium = self.device.capabilities().medium; | 498 | let medium = self.device.capabilities().medium; |
| 380 | 499 | ||
| @@ -403,14 +522,86 @@ impl<D: Driver + 'static> Inner<D> { | |||
| 403 | debug!(" DNS server {}: {}", i, s); | 522 | debug!(" DNS server {}: {}", i, s); |
| 404 | } | 523 | } |
| 405 | 524 | ||
| 525 | self.static_v4 = Some(config); | ||
| 526 | |||
| 406 | #[cfg(feature = "dns")] | 527 | #[cfg(feature = "dns")] |
| 407 | { | 528 | { |
| 408 | let socket = s.sockets.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket); | 529 | self.update_dns_servers(s) |
| 409 | let servers: Vec<IpAddress, 3> = config.dns_servers.iter().map(|c| IpAddress::Ipv4(*c)).collect(); | 530 | } |
| 410 | socket.update_servers(&servers[..]); | 531 | } |
| 532 | |||
| 533 | /// Replaces the current IPv6 static configuration with a newly supplied config. | ||
| 534 | #[cfg(feature = "proto-ipv6")] | ||
| 535 | fn apply_config_v6(&mut self, s: &mut SocketStack, config: StaticConfigV6) { | ||
| 536 | #[cfg(feature = "medium-ethernet")] | ||
| 537 | let medium = self.device.capabilities().medium; | ||
| 538 | |||
| 539 | debug!("Acquired IPv6 configuration:"); | ||
| 540 | |||
| 541 | debug!(" IP address: {}", config.address); | ||
| 542 | s.iface.update_ip_addrs(|addrs| { | ||
| 543 | if addrs.is_empty() { | ||
| 544 | addrs.push(IpCidr::Ipv6(config.address)).unwrap(); | ||
| 545 | } else { | ||
| 546 | addrs[0] = IpCidr::Ipv6(config.address); | ||
| 547 | } | ||
| 548 | }); | ||
| 549 | |||
| 550 | #[cfg(feature = "medium-ethernet")] | ||
| 551 | if Medium::Ethernet == medium { | ||
| 552 | if let Some(gateway) = config.gateway { | ||
| 553 | debug!(" Default gateway: {}", gateway); | ||
| 554 | s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap(); | ||
| 555 | } else { | ||
| 556 | debug!(" Default gateway: None"); | ||
| 557 | s.iface.routes_mut().remove_default_ipv6_route(); | ||
| 558 | } | ||
| 559 | } | ||
| 560 | for (i, s) in config.dns_servers.iter().enumerate() { | ||
| 561 | debug!(" DNS server {}: {}", i, s); | ||
| 411 | } | 562 | } |
| 412 | 563 | ||
| 413 | self.config = Some(config) | 564 | self.static_v6 = Some(config); |
| 565 | |||
| 566 | #[cfg(feature = "dns")] | ||
| 567 | { | ||
| 568 | self.update_dns_servers(s) | ||
| 569 | } | ||
| 570 | } | ||
| 571 | |||
| 572 | #[cfg(feature = "dns")] | ||
| 573 | fn update_dns_servers(&mut self, s: &mut SocketStack) { | ||
| 574 | let socket = s.sockets.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket); | ||
| 575 | |||
| 576 | let servers_v4; | ||
| 577 | #[cfg(feature = "proto-ipv4")] | ||
| 578 | { | ||
| 579 | servers_v4 = self | ||
| 580 | .static_v4 | ||
| 581 | .iter() | ||
| 582 | .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv4(*c))); | ||
| 583 | }; | ||
| 584 | #[cfg(not(feature = "proto-ipv4"))] | ||
| 585 | { | ||
| 586 | servers_v4 = core::iter::empty(); | ||
| 587 | } | ||
| 588 | |||
| 589 | let servers_v6; | ||
| 590 | #[cfg(feature = "proto-ipv6")] | ||
| 591 | { | ||
| 592 | servers_v6 = self | ||
| 593 | .static_v6 | ||
| 594 | .iter() | ||
| 595 | .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv6(*c))); | ||
| 596 | } | ||
| 597 | #[cfg(not(feature = "proto-ipv6"))] | ||
| 598 | { | ||
| 599 | servers_v6 = core::iter::empty(); | ||
| 600 | } | ||
| 601 | |||
| 602 | // Prefer the v6 DNS servers over the v4 servers | ||
| 603 | let servers: Vec<IpAddress, 6> = servers_v6.chain(servers_v4).collect(); | ||
| 604 | socket.update_servers(&servers[..]); | ||
| 414 | } | 605 | } |
| 415 | 606 | ||
| 416 | #[cfg(feature = "dhcpv4")] | 607 | #[cfg(feature = "dhcpv4")] |
| @@ -430,9 +621,15 @@ impl<D: Driver + 'static> Inner<D> { | |||
| 430 | s.iface.update_ip_addrs(|ip_addrs| ip_addrs.clear()); | 621 | s.iface.update_ip_addrs(|ip_addrs| ip_addrs.clear()); |
| 431 | #[cfg(feature = "medium-ethernet")] | 622 | #[cfg(feature = "medium-ethernet")] |
| 432 | if medium == Medium::Ethernet { | 623 | if medium == Medium::Ethernet { |
| 433 | s.iface.routes_mut().remove_default_ipv4_route(); | 624 | #[cfg(feature = "proto-ipv4")] |
| 625 | { | ||
| 626 | s.iface.routes_mut().remove_default_ipv4_route(); | ||
| 627 | } | ||
| 628 | } | ||
| 629 | #[cfg(feature = "proto-ipv4")] | ||
| 630 | { | ||
| 631 | self.static_v4 = None | ||
| 434 | } | 632 | } |
| 435 | self.config = None | ||
| 436 | } | 633 | } |
| 437 | 634 | ||
| 438 | fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { | 635 | fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { |
| @@ -470,12 +667,12 @@ impl<D: Driver + 'static> Inner<D> { | |||
| 470 | None => {} | 667 | None => {} |
| 471 | Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), | 668 | Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), |
| 472 | Some(dhcpv4::Event::Configured(config)) => { | 669 | Some(dhcpv4::Event::Configured(config)) => { |
| 473 | let config = StaticConfig { | 670 | let config = StaticConfigV4 { |
| 474 | address: config.address, | 671 | address: config.address, |
| 475 | gateway: config.router, | 672 | gateway: config.router, |
| 476 | dns_servers: config.dns_servers, | 673 | dns_servers: config.dns_servers, |
| 477 | }; | 674 | }; |
| 478 | self.apply_config(s, config) | 675 | self.apply_config_v4(s, config) |
| 479 | } | 676 | } |
| 480 | } | 677 | } |
| 481 | } else if old_link_up { | 678 | } else if old_link_up { |
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 7babb5293..367675b13 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs | |||
| @@ -278,10 +278,18 @@ impl<'a> TcpSocket<'a> { | |||
| 278 | self.io.with(|s, _| s.may_send()) | 278 | self.io.with(|s, _| s.may_send()) |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | /// Get whether the socket is ready to receive data, i.e. whether there is some pending data in the receive buffer. | 281 | /// return whether the recieve half of the full-duplex connection is open. |
| 282 | /// This function returns true if it’s possible to receive data from the remote endpoint. | ||
| 283 | /// It will return true while there is data in the receive buffer, and if there isn’t, | ||
| 284 | /// as long as the remote endpoint has not closed the connection. | ||
| 282 | pub fn may_recv(&self) -> bool { | 285 | pub fn may_recv(&self) -> bool { |
| 283 | self.io.with(|s, _| s.may_recv()) | 286 | self.io.with(|s, _| s.may_recv()) |
| 284 | } | 287 | } |
| 288 | |||
| 289 | /// Get whether the socket is ready to receive data, i.e. whether there is some pending data in the receive buffer. | ||
| 290 | pub fn can_recv(&self) -> bool { | ||
| 291 | self.io.with(|s, _| s.can_recv()) | ||
| 292 | } | ||
| 285 | } | 293 | } |
| 286 | 294 | ||
| 287 | impl<'a> Drop for TcpSocket<'a> { | 295 | impl<'a> Drop for TcpSocket<'a> { |
| @@ -472,7 +480,10 @@ pub mod client { | |||
| 472 | Self: 'a, | 480 | Self: 'a, |
| 473 | { | 481 | { |
| 474 | let addr: crate::IpAddress = match remote.ip() { | 482 | let addr: crate::IpAddress = match remote.ip() { |
| 483 | #[cfg(feature = "proto-ipv4")] | ||
| 475 | IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())), | 484 | IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())), |
| 485 | #[cfg(not(feature = "proto-ipv4"))] | ||
| 486 | IpAddr::V4(_) => panic!("ipv4 support not enabled"), | ||
| 476 | #[cfg(feature = "proto-ipv6")] | 487 | #[cfg(feature = "proto-ipv6")] |
| 477 | IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())), | 488 | IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())), |
| 478 | #[cfg(not(feature = "proto-ipv6"))] | 489 | #[cfg(not(feature = "proto-ipv6"))] |
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 83900d4d0..3e858f854 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -16,7 +16,8 @@ flavors = [ | |||
| 16 | ] | 16 | ] |
| 17 | 17 | ||
| 18 | [features] | 18 | [features] |
| 19 | default = [ | 19 | default = ["rt"] |
| 20 | rt = [ | ||
| 20 | "nrf52805-pac?/rt", | 21 | "nrf52805-pac?/rt", |
| 21 | "nrf52810-pac?/rt", | 22 | "nrf52810-pac?/rt", |
| 22 | "nrf52811-pac?/rt", | 23 | "nrf52811-pac?/rt", |
| @@ -31,7 +32,7 @@ default = [ | |||
| 31 | 32 | ||
| 32 | time = ["dep:embassy-time"] | 33 | time = ["dep:embassy-time"] |
| 33 | 34 | ||
| 34 | defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"] | 35 | defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"] |
| 35 | 36 | ||
| 36 | # Enable nightly-only features | 37 | # Enable nightly-only features |
| 37 | nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"] | 38 | nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"] |
| @@ -90,11 +91,9 @@ _dppi = [] | |||
| 90 | _gpio-p1 = [] | 91 | _gpio-p1 = [] |
| 91 | 92 | ||
| 92 | [dependencies] | 93 | [dependencies] |
| 93 | embassy-executor = { version = "0.2.0", path = "../embassy-executor", optional = true } | ||
| 94 | embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } | 94 | embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } |
| 95 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } | 95 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } |
| 96 | embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]} | 96 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-3"] } |
| 97 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } | ||
| 98 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } | 97 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } |
| 99 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } | 98 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } |
| 100 | 99 | ||
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 4d053c023..9bc1c1e7a 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs | |||
| @@ -15,7 +15,6 @@ use core::slice; | |||
| 15 | use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; | 15 | use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; |
| 16 | use core::task::Poll; | 16 | use core::task::Poll; |
| 17 | 17 | ||
| 18 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 19 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; | 18 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; |
| 20 | use embassy_hal_common::{into_ref, PeripheralRef}; | 19 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 21 | use embassy_sync::waitqueue::AtomicWaker; | 20 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -24,13 +23,13 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari | |||
| 24 | 23 | ||
| 25 | use crate::gpio::sealed::Pin; | 24 | use crate::gpio::sealed::Pin; |
| 26 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | 25 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; |
| 27 | use crate::interrupt::{self, InterruptExt}; | 26 | use crate::interrupt::typelevel::Interrupt; |
| 28 | use crate::ppi::{ | 27 | use crate::ppi::{ |
| 29 | self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, | 28 | self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, |
| 30 | }; | 29 | }; |
| 31 | use crate::timer::{Instance as TimerInstance, Timer}; | 30 | use crate::timer::{Instance as TimerInstance, Timer}; |
| 32 | use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; | 31 | use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; |
| 33 | use crate::{pac, Peripheral}; | 32 | use crate::{interrupt, pac, Peripheral}; |
| 34 | 33 | ||
| 35 | mod sealed { | 34 | mod sealed { |
| 36 | use super::*; | 35 | use super::*; |
| @@ -77,7 +76,7 @@ pub struct InterruptHandler<U: UarteInstance> { | |||
| 77 | _phantom: PhantomData<U>, | 76 | _phantom: PhantomData<U>, |
| 78 | } | 77 | } |
| 79 | 78 | ||
| 80 | impl<U: UarteInstance> interrupt::Handler<U::Interrupt> for InterruptHandler<U> { | 79 | impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for InterruptHandler<U> { |
| 81 | unsafe fn on_interrupt() { | 80 | unsafe fn on_interrupt() { |
| 82 | //trace!("irq: start"); | 81 | //trace!("irq: start"); |
| 83 | let r = U::regs(); | 82 | let r = U::regs(); |
| @@ -202,7 +201,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 202 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, | 201 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, |
| 203 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, | 202 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, |
| 204 | ppi_group: impl Peripheral<P = impl Group> + 'd, | 203 | ppi_group: impl Peripheral<P = impl Group> + 'd, |
| 205 | _irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd, | 204 | _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd, |
| 206 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 205 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 207 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 206 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 208 | config: Config, | 207 | config: Config, |
| @@ -237,7 +236,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 237 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, | 236 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, |
| 238 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, | 237 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, |
| 239 | ppi_group: impl Peripheral<P = impl Group> + 'd, | 238 | ppi_group: impl Peripheral<P = impl Group> + 'd, |
| 240 | _irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd, | 239 | _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd, |
| 241 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 240 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 242 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 241 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 243 | cts: impl Peripheral<P = impl GpioPin> + 'd, | 242 | cts: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -362,8 +361,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 362 | ppi_ch2.disable(); | 361 | ppi_ch2.disable(); |
| 363 | ppi_group.add_channel(&ppi_ch2); | 362 | ppi_group.add_channel(&ppi_ch2); |
| 364 | 363 | ||
| 365 | unsafe { U::Interrupt::steal() }.pend(); | 364 | U::Interrupt::pend(); |
| 366 | unsafe { U::Interrupt::steal() }.enable(); | 365 | unsafe { U::Interrupt::enable() }; |
| 367 | 366 | ||
| 368 | Self { | 367 | Self { |
| 369 | _peri: peri, | 368 | _peri: peri, |
| @@ -375,7 +374,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 375 | } | 374 | } |
| 376 | 375 | ||
| 377 | fn pend_irq() { | 376 | fn pend_irq() { |
| 378 | unsafe { <U::Interrupt as Interrupt>::steal() }.pend() | 377 | U::Interrupt::pend() |
| 379 | } | 378 | } |
| 380 | 379 | ||
| 381 | /// Adjust the baud rate to the provided value. | 380 | /// Adjust the baud rate to the provided value. |
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index e406c081b..8776000c8 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs | |||
| @@ -208,33 +208,29 @@ impl_ppi_channel!(PPI_CH31, 31 => static); | |||
| 208 | impl_saadc_input!(P0_04, ANALOG_INPUT2); | 208 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 209 | impl_saadc_input!(P0_05, ANALOG_INPUT3); | 209 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 210 | 210 | ||
| 211 | pub mod irqs { | 211 | embassy_hal_common::interrupt_mod!( |
| 212 | use embassy_cortex_m::interrupt::_export::declare; | 212 | POWER_CLOCK, |
| 213 | 213 | RADIO, | |
| 214 | use crate::pac::Interrupt as InterruptEnum; | 214 | UARTE0_UART0, |
| 215 | 215 | TWIM0_TWIS0_TWI0, | |
| 216 | declare!(POWER_CLOCK); | 216 | SPIM0_SPIS0_SPI0, |
| 217 | declare!(RADIO); | 217 | GPIOTE, |
| 218 | declare!(UARTE0_UART0); | 218 | SAADC, |
| 219 | declare!(TWIM0_TWIS0_TWI0); | 219 | TIMER0, |
| 220 | declare!(SPIM0_SPIS0_SPI0); | 220 | TIMER1, |
| 221 | declare!(GPIOTE); | 221 | TIMER2, |
| 222 | declare!(SAADC); | 222 | RTC0, |
| 223 | declare!(TIMER0); | 223 | TEMP, |
| 224 | declare!(TIMER1); | 224 | RNG, |
| 225 | declare!(TIMER2); | 225 | ECB, |
| 226 | declare!(RTC0); | 226 | CCM_AAR, |
| 227 | declare!(TEMP); | 227 | WDT, |
| 228 | declare!(RNG); | 228 | RTC1, |
| 229 | declare!(ECB); | 229 | QDEC, |
| 230 | declare!(CCM_AAR); | 230 | SWI0_EGU0, |
| 231 | declare!(WDT); | 231 | SWI1_EGU1, |
| 232 | declare!(RTC1); | 232 | SWI2, |
| 233 | declare!(QDEC); | 233 | SWI3, |
| 234 | declare!(SWI0_EGU0); | 234 | SWI4, |
| 235 | declare!(SWI1_EGU1); | 235 | SWI5, |
| 236 | declare!(SWI2); | 236 | ); |
| 237 | declare!(SWI3); | ||
| 238 | declare!(SWI4); | ||
| 239 | declare!(SWI5); | ||
| 240 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 153795e54..5519e8953 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs | |||
| @@ -234,36 +234,32 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); | |||
| 234 | impl_saadc_input!(P0_30, ANALOG_INPUT6); | 234 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 235 | impl_saadc_input!(P0_31, ANALOG_INPUT7); | 235 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 236 | 236 | ||
| 237 | pub mod irqs { | 237 | embassy_hal_common::interrupt_mod!( |
| 238 | use embassy_cortex_m::interrupt::_export::declare; | 238 | POWER_CLOCK, |
| 239 | 239 | RADIO, | |
| 240 | use crate::pac::Interrupt as InterruptEnum; | 240 | UARTE0_UART0, |
| 241 | 241 | TWIM0_TWIS0_TWI0, | |
| 242 | declare!(POWER_CLOCK); | 242 | SPIM0_SPIS0_SPI0, |
| 243 | declare!(RADIO); | 243 | GPIOTE, |
| 244 | declare!(UARTE0_UART0); | 244 | SAADC, |
| 245 | declare!(TWIM0_TWIS0_TWI0); | 245 | TIMER0, |
| 246 | declare!(SPIM0_SPIS0_SPI0); | 246 | TIMER1, |
| 247 | declare!(GPIOTE); | 247 | TIMER2, |
| 248 | declare!(SAADC); | 248 | RTC0, |
| 249 | declare!(TIMER0); | 249 | TEMP, |
| 250 | declare!(TIMER1); | 250 | RNG, |
| 251 | declare!(TIMER2); | 251 | ECB, |
| 252 | declare!(RTC0); | 252 | CCM_AAR, |
| 253 | declare!(TEMP); | 253 | WDT, |
| 254 | declare!(RNG); | 254 | RTC1, |
| 255 | declare!(ECB); | 255 | QDEC, |
| 256 | declare!(CCM_AAR); | 256 | COMP, |
| 257 | declare!(WDT); | 257 | SWI0_EGU0, |
| 258 | declare!(RTC1); | 258 | SWI1_EGU1, |
| 259 | declare!(QDEC); | 259 | SWI2, |
| 260 | declare!(COMP); | 260 | SWI3, |
| 261 | declare!(SWI0_EGU0); | 261 | SWI4, |
| 262 | declare!(SWI1_EGU1); | 262 | SWI5, |
| 263 | declare!(SWI2); | 263 | PWM0, |
| 264 | declare!(SWI3); | 264 | PDM, |
| 265 | declare!(SWI4); | 265 | ); |
| 266 | declare!(SWI5); | ||
| 267 | declare!(PWM0); | ||
| 268 | declare!(PDM); | ||
| 269 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index a7a7cf58c..d5367c59a 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs | |||
| @@ -236,36 +236,32 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); | |||
| 236 | impl_saadc_input!(P0_30, ANALOG_INPUT6); | 236 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 237 | impl_saadc_input!(P0_31, ANALOG_INPUT7); | 237 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 238 | 238 | ||
| 239 | pub mod irqs { | 239 | embassy_hal_common::interrupt_mod!( |
| 240 | use embassy_cortex_m::interrupt::_export::declare; | 240 | POWER_CLOCK, |
| 241 | 241 | RADIO, | |
| 242 | use crate::pac::Interrupt as InterruptEnum; | 242 | UARTE0_UART0, |
| 243 | 243 | TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0, | |
| 244 | declare!(POWER_CLOCK); | 244 | SPIM1_SPIS1_SPI1, |
| 245 | declare!(RADIO); | 245 | GPIOTE, |
| 246 | declare!(UARTE0_UART0); | 246 | SAADC, |
| 247 | declare!(TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | 247 | TIMER0, |
| 248 | declare!(SPIM1_SPIS1_SPI1); | 248 | TIMER1, |
| 249 | declare!(GPIOTE); | 249 | TIMER2, |
| 250 | declare!(SAADC); | 250 | RTC0, |
| 251 | declare!(TIMER0); | 251 | TEMP, |
| 252 | declare!(TIMER1); | 252 | RNG, |
| 253 | declare!(TIMER2); | 253 | ECB, |
| 254 | declare!(RTC0); | 254 | CCM_AAR, |
| 255 | declare!(TEMP); | 255 | WDT, |
| 256 | declare!(RNG); | 256 | RTC1, |
| 257 | declare!(ECB); | 257 | QDEC, |
| 258 | declare!(CCM_AAR); | 258 | COMP, |
| 259 | declare!(WDT); | 259 | SWI0_EGU0, |
| 260 | declare!(RTC1); | 260 | SWI1_EGU1, |
| 261 | declare!(QDEC); | 261 | SWI2, |
| 262 | declare!(COMP); | 262 | SWI3, |
| 263 | declare!(SWI0_EGU0); | 263 | SWI4, |
| 264 | declare!(SWI1_EGU1); | 264 | SWI5, |
| 265 | declare!(SWI2); | 265 | PWM0, |
| 266 | declare!(SWI3); | 266 | PDM, |
| 267 | declare!(SWI4); | 267 | ); |
| 268 | declare!(SWI5); | ||
| 269 | declare!(PWM0); | ||
| 270 | declare!(PDM); | ||
| 271 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 14a1b8cc9..785170447 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs | |||
| @@ -224,35 +224,31 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 224 | impl_ppi_channel!(PPI_CH30, 30 => static); | 224 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 225 | impl_ppi_channel!(PPI_CH31, 31 => static); | 225 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 226 | 226 | ||
| 227 | pub mod irqs { | 227 | embassy_hal_common::interrupt_mod!( |
| 228 | use embassy_cortex_m::interrupt::_export::declare; | 228 | POWER_CLOCK, |
| 229 | 229 | RADIO, | |
| 230 | use crate::pac::Interrupt as InterruptEnum; | 230 | UARTE0_UART0, |
| 231 | 231 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, | |
| 232 | declare!(POWER_CLOCK); | 232 | SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, |
| 233 | declare!(RADIO); | 233 | GPIOTE, |
| 234 | declare!(UARTE0_UART0); | 234 | TIMER0, |
| 235 | declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 235 | TIMER1, |
| 236 | declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 236 | TIMER2, |
| 237 | declare!(GPIOTE); | 237 | RTC0, |
| 238 | declare!(TIMER0); | 238 | TEMP, |
| 239 | declare!(TIMER1); | 239 | RNG, |
| 240 | declare!(TIMER2); | 240 | ECB, |
| 241 | declare!(RTC0); | 241 | CCM_AAR, |
| 242 | declare!(TEMP); | 242 | WDT, |
| 243 | declare!(RNG); | 243 | RTC1, |
| 244 | declare!(ECB); | 244 | QDEC, |
| 245 | declare!(CCM_AAR); | 245 | COMP, |
| 246 | declare!(WDT); | 246 | SWI0_EGU0, |
| 247 | declare!(RTC1); | 247 | SWI1_EGU1, |
| 248 | declare!(QDEC); | 248 | SWI2_EGU2, |
| 249 | declare!(COMP); | 249 | SWI3_EGU3, |
| 250 | declare!(SWI0_EGU0); | 250 | SWI4_EGU4, |
| 251 | declare!(SWI1_EGU1); | 251 | SWI5_EGU5, |
| 252 | declare!(SWI2_EGU2); | 252 | TIMER3, |
| 253 | declare!(SWI3_EGU3); | 253 | USBD, |
| 254 | declare!(SWI4_EGU4); | 254 | ); |
| 255 | declare!(SWI5_EGU5); | ||
| 256 | declare!(TIMER3); | ||
| 257 | declare!(USBD); | ||
| 258 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 83ecd0deb..b77564a5c 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs | |||
| @@ -263,46 +263,42 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); | |||
| 263 | 263 | ||
| 264 | impl_i2s!(I2S, I2S, I2S); | 264 | impl_i2s!(I2S, I2S, I2S); |
| 265 | 265 | ||
| 266 | pub mod irqs { | 266 | embassy_hal_common::interrupt_mod!( |
| 267 | use embassy_cortex_m::interrupt::_export::declare; | 267 | POWER_CLOCK, |
| 268 | 268 | RADIO, | |
| 269 | use crate::pac::Interrupt as InterruptEnum; | 269 | UARTE0_UART0, |
| 270 | 270 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, | |
| 271 | declare!(POWER_CLOCK); | 271 | SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, |
| 272 | declare!(RADIO); | 272 | NFCT, |
| 273 | declare!(UARTE0_UART0); | 273 | GPIOTE, |
| 274 | declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 274 | SAADC, |
| 275 | declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 275 | TIMER0, |
| 276 | declare!(NFCT); | 276 | TIMER1, |
| 277 | declare!(GPIOTE); | 277 | TIMER2, |
| 278 | declare!(SAADC); | 278 | RTC0, |
| 279 | declare!(TIMER0); | 279 | TEMP, |
| 280 | declare!(TIMER1); | 280 | RNG, |
| 281 | declare!(TIMER2); | 281 | ECB, |
| 282 | declare!(RTC0); | 282 | CCM_AAR, |
| 283 | declare!(TEMP); | 283 | WDT, |
| 284 | declare!(RNG); | 284 | RTC1, |
| 285 | declare!(ECB); | 285 | QDEC, |
| 286 | declare!(CCM_AAR); | 286 | COMP_LPCOMP, |
| 287 | declare!(WDT); | 287 | SWI0_EGU0, |
| 288 | declare!(RTC1); | 288 | SWI1_EGU1, |
| 289 | declare!(QDEC); | 289 | SWI2_EGU2, |
| 290 | declare!(COMP_LPCOMP); | 290 | SWI3_EGU3, |
| 291 | declare!(SWI0_EGU0); | 291 | SWI4_EGU4, |
| 292 | declare!(SWI1_EGU1); | 292 | SWI5_EGU5, |
| 293 | declare!(SWI2_EGU2); | 293 | TIMER3, |
| 294 | declare!(SWI3_EGU3); | 294 | TIMER4, |
| 295 | declare!(SWI4_EGU4); | 295 | PWM0, |
| 296 | declare!(SWI5_EGU5); | 296 | PDM, |
| 297 | declare!(TIMER3); | 297 | MWU, |
| 298 | declare!(TIMER4); | 298 | PWM1, |
| 299 | declare!(PWM0); | 299 | PWM2, |
| 300 | declare!(PDM); | 300 | SPIM2_SPIS2_SPI2, |
| 301 | declare!(MWU); | 301 | RTC2, |
| 302 | declare!(PWM1); | 302 | FPU, |
| 303 | declare!(PWM2); | 303 | I2S, |
| 304 | declare!(SPIM2_SPIS2_SPI2); | 304 | ); |
| 305 | declare!(RTC2); | ||
| 306 | declare!(FPU); | ||
| 307 | declare!(I2S); | ||
| 308 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 5e5db04de..bff7f4ebb 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs | |||
| @@ -306,50 +306,46 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); | |||
| 306 | 306 | ||
| 307 | impl_i2s!(I2S, I2S, I2S); | 307 | impl_i2s!(I2S, I2S, I2S); |
| 308 | 308 | ||
| 309 | pub mod irqs { | 309 | embassy_hal_common::interrupt_mod!( |
| 310 | use embassy_cortex_m::interrupt::_export::declare; | 310 | POWER_CLOCK, |
| 311 | 311 | RADIO, | |
| 312 | use crate::pac::Interrupt as InterruptEnum; | 312 | UARTE0_UART0, |
| 313 | 313 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, | |
| 314 | declare!(POWER_CLOCK); | 314 | SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, |
| 315 | declare!(RADIO); | 315 | NFCT, |
| 316 | declare!(UARTE0_UART0); | 316 | GPIOTE, |
| 317 | declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 317 | SAADC, |
| 318 | declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 318 | TIMER0, |
| 319 | declare!(NFCT); | 319 | TIMER1, |
| 320 | declare!(GPIOTE); | 320 | TIMER2, |
| 321 | declare!(SAADC); | 321 | RTC0, |
| 322 | declare!(TIMER0); | 322 | TEMP, |
| 323 | declare!(TIMER1); | 323 | RNG, |
| 324 | declare!(TIMER2); | 324 | ECB, |
| 325 | declare!(RTC0); | 325 | CCM_AAR, |
| 326 | declare!(TEMP); | 326 | WDT, |
| 327 | declare!(RNG); | 327 | RTC1, |
| 328 | declare!(ECB); | 328 | QDEC, |
| 329 | declare!(CCM_AAR); | 329 | COMP_LPCOMP, |
| 330 | declare!(WDT); | 330 | SWI0_EGU0, |
| 331 | declare!(RTC1); | 331 | SWI1_EGU1, |
| 332 | declare!(QDEC); | 332 | SWI2_EGU2, |
| 333 | declare!(COMP_LPCOMP); | 333 | SWI3_EGU3, |
| 334 | declare!(SWI0_EGU0); | 334 | SWI4_EGU4, |
| 335 | declare!(SWI1_EGU1); | 335 | SWI5_EGU5, |
| 336 | declare!(SWI2_EGU2); | 336 | TIMER3, |
| 337 | declare!(SWI3_EGU3); | 337 | TIMER4, |
| 338 | declare!(SWI4_EGU4); | 338 | PWM0, |
| 339 | declare!(SWI5_EGU5); | 339 | PDM, |
| 340 | declare!(TIMER3); | 340 | MWU, |
| 341 | declare!(TIMER4); | 341 | PWM1, |
| 342 | declare!(PWM0); | 342 | PWM2, |
| 343 | declare!(PDM); | 343 | SPIM2_SPIS2_SPI2, |
| 344 | declare!(MWU); | 344 | RTC2, |
| 345 | declare!(PWM1); | 345 | FPU, |
| 346 | declare!(PWM2); | 346 | USBD, |
| 347 | declare!(SPIM2_SPIS2_SPI2); | 347 | UARTE1, |
| 348 | declare!(RTC2); | 348 | PWM3, |
| 349 | declare!(FPU); | 349 | SPIM3, |
| 350 | declare!(USBD); | 350 | I2S, |
| 351 | declare!(UARTE1); | 351 | ); |
| 352 | declare!(PWM3); | ||
| 353 | declare!(SPIM3); | ||
| 354 | declare!(I2S); | ||
| 355 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index f6d33f85c..9b0050823 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs | |||
| @@ -311,52 +311,48 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); | |||
| 311 | 311 | ||
| 312 | impl_i2s!(I2S, I2S, I2S); | 312 | impl_i2s!(I2S, I2S, I2S); |
| 313 | 313 | ||
| 314 | pub mod irqs { | 314 | embassy_hal_common::interrupt_mod!( |
| 315 | use embassy_cortex_m::interrupt::_export::declare; | 315 | POWER_CLOCK, |
| 316 | 316 | RADIO, | |
| 317 | use crate::pac::Interrupt as InterruptEnum; | 317 | UARTE0_UART0, |
| 318 | 318 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, | |
| 319 | declare!(POWER_CLOCK); | 319 | SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, |
| 320 | declare!(RADIO); | 320 | NFCT, |
| 321 | declare!(UARTE0_UART0); | 321 | GPIOTE, |
| 322 | declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 322 | SAADC, |
| 323 | declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 323 | TIMER0, |
| 324 | declare!(NFCT); | 324 | TIMER1, |
| 325 | declare!(GPIOTE); | 325 | TIMER2, |
| 326 | declare!(SAADC); | 326 | RTC0, |
| 327 | declare!(TIMER0); | 327 | TEMP, |
| 328 | declare!(TIMER1); | 328 | RNG, |
| 329 | declare!(TIMER2); | 329 | ECB, |
| 330 | declare!(RTC0); | 330 | CCM_AAR, |
| 331 | declare!(TEMP); | 331 | WDT, |
| 332 | declare!(RNG); | 332 | RTC1, |
| 333 | declare!(ECB); | 333 | QDEC, |
| 334 | declare!(CCM_AAR); | 334 | COMP_LPCOMP, |
| 335 | declare!(WDT); | 335 | SWI0_EGU0, |
| 336 | declare!(RTC1); | 336 | SWI1_EGU1, |
| 337 | declare!(QDEC); | 337 | SWI2_EGU2, |
| 338 | declare!(COMP_LPCOMP); | 338 | SWI3_EGU3, |
| 339 | declare!(SWI0_EGU0); | 339 | SWI4_EGU4, |
| 340 | declare!(SWI1_EGU1); | 340 | SWI5_EGU5, |
| 341 | declare!(SWI2_EGU2); | 341 | TIMER3, |
| 342 | declare!(SWI3_EGU3); | 342 | TIMER4, |
| 343 | declare!(SWI4_EGU4); | 343 | PWM0, |
| 344 | declare!(SWI5_EGU5); | 344 | PDM, |
| 345 | declare!(TIMER3); | 345 | MWU, |
| 346 | declare!(TIMER4); | 346 | PWM1, |
| 347 | declare!(PWM0); | 347 | PWM2, |
| 348 | declare!(PDM); | 348 | SPIM2_SPIS2_SPI2, |
| 349 | declare!(MWU); | 349 | RTC2, |
| 350 | declare!(PWM1); | 350 | FPU, |
| 351 | declare!(PWM2); | 351 | USBD, |
| 352 | declare!(SPIM2_SPIS2_SPI2); | 352 | UARTE1, |
| 353 | declare!(RTC2); | 353 | QSPI, |
| 354 | declare!(FPU); | 354 | CRYPTOCELL, |
| 355 | declare!(USBD); | 355 | PWM3, |
| 356 | declare!(UARTE1); | 356 | SPIM3, |
| 357 | declare!(QSPI); | 357 | I2S, |
| 358 | declare!(CRYPTOCELL); | 358 | ); |
| 359 | declare!(PWM3); | ||
| 360 | declare!(SPIM3); | ||
| 361 | declare!(I2S); | ||
| 362 | } | ||
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 34f96800f..410ae921c 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs | |||
| @@ -5,6 +5,8 @@ pub mod pac { | |||
| 5 | // The nRF5340 has a secure and non-secure (NS) mode. | 5 | // The nRF5340 has a secure and non-secure (NS) mode. |
| 6 | // To avoid cfg spam, we remove _ns or _s suffixes here. | 6 | // To avoid cfg spam, we remove _ns or _s suffixes here. |
| 7 | 7 | ||
| 8 | pub use nrf5340_app_pac::NVIC_PRIO_BITS; | ||
| 9 | |||
| 8 | #[doc(no_inline)] | 10 | #[doc(no_inline)] |
| 9 | pub use nrf5340_app_pac::{ | 11 | pub use nrf5340_app_pac::{ |
| 10 | interrupt, | 12 | interrupt, |
| @@ -504,50 +506,46 @@ impl_saadc_input!(P0_18, ANALOG_INPUT5); | |||
| 504 | impl_saadc_input!(P0_19, ANALOG_INPUT6); | 506 | impl_saadc_input!(P0_19, ANALOG_INPUT6); |
| 505 | impl_saadc_input!(P0_20, ANALOG_INPUT7); | 507 | impl_saadc_input!(P0_20, ANALOG_INPUT7); |
| 506 | 508 | ||
| 507 | pub mod irqs { | 509 | embassy_hal_common::interrupt_mod!( |
| 508 | use embassy_cortex_m::interrupt::_export::declare; | 510 | FPU, |
| 509 | 511 | CACHE, | |
| 510 | use crate::pac::Interrupt as InterruptEnum; | 512 | SPU, |
| 511 | 513 | CLOCK_POWER, | |
| 512 | declare!(FPU); | 514 | SERIAL0, |
| 513 | declare!(CACHE); | 515 | SERIAL1, |
| 514 | declare!(SPU); | 516 | SPIM4, |
| 515 | declare!(CLOCK_POWER); | 517 | SERIAL2, |
| 516 | declare!(SERIAL0); | 518 | SERIAL3, |
| 517 | declare!(SERIAL1); | 519 | GPIOTE0, |
| 518 | declare!(SPIM4); | 520 | SAADC, |
| 519 | declare!(SERIAL2); | 521 | TIMER0, |
| 520 | declare!(SERIAL3); | 522 | TIMER1, |
| 521 | declare!(GPIOTE0); | 523 | TIMER2, |
| 522 | declare!(SAADC); | 524 | RTC0, |
| 523 | declare!(TIMER0); | 525 | RTC1, |
| 524 | declare!(TIMER1); | 526 | WDT0, |
| 525 | declare!(TIMER2); | 527 | WDT1, |
| 526 | declare!(RTC0); | 528 | COMP_LPCOMP, |
| 527 | declare!(RTC1); | 529 | EGU0, |
| 528 | declare!(WDT0); | 530 | EGU1, |
| 529 | declare!(WDT1); | 531 | EGU2, |
| 530 | declare!(COMP_LPCOMP); | 532 | EGU3, |
| 531 | declare!(EGU0); | 533 | EGU4, |
| 532 | declare!(EGU1); | 534 | EGU5, |
| 533 | declare!(EGU2); | 535 | PWM0, |
| 534 | declare!(EGU3); | 536 | PWM1, |
| 535 | declare!(EGU4); | 537 | PWM2, |
| 536 | declare!(EGU5); | 538 | PWM3, |
| 537 | declare!(PWM0); | 539 | PDM0, |
| 538 | declare!(PWM1); | 540 | I2S0, |
| 539 | declare!(PWM2); | 541 | IPC, |
| 540 | declare!(PWM3); | 542 | QSPI, |
| 541 | declare!(PDM0); | 543 | NFCT, |
| 542 | declare!(I2S0); | 544 | GPIOTE1, |
| 543 | declare!(IPC); | 545 | QDEC0, |
| 544 | declare!(QSPI); | 546 | QDEC1, |
| 545 | declare!(NFCT); | 547 | USBD, |
| 546 | declare!(GPIOTE1); | 548 | USBREGULATOR, |
| 547 | declare!(QDEC0); | 549 | KMU, |
| 548 | declare!(QDEC1); | 550 | CRYPTOCELL, |
| 549 | declare!(USBD); | 551 | ); |
| 550 | declare!(USBREGULATOR); | ||
| 551 | declare!(KMU); | ||
| 552 | declare!(CRYPTOCELL); | ||
| 553 | } | ||
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index 1e59528cb..6ac783085 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs | |||
| @@ -5,6 +5,8 @@ pub mod pac { | |||
| 5 | // The nRF5340 has a secure and non-secure (NS) mode. | 5 | // The nRF5340 has a secure and non-secure (NS) mode. |
| 6 | // To avoid cfg spam, we remove _ns or _s suffixes here. | 6 | // To avoid cfg spam, we remove _ns or _s suffixes here. |
| 7 | 7 | ||
| 8 | pub use nrf5340_net_pac::NVIC_PRIO_BITS; | ||
| 9 | |||
| 8 | #[doc(no_inline)] | 10 | #[doc(no_inline)] |
| 9 | pub use nrf5340_net_pac::{ | 11 | pub use nrf5340_net_pac::{ |
| 10 | interrupt, | 12 | interrupt, |
| @@ -340,29 +342,25 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable); | |||
| 340 | impl_ppi_channel!(PPI_CH30, 30 => configurable); | 342 | impl_ppi_channel!(PPI_CH30, 30 => configurable); |
| 341 | impl_ppi_channel!(PPI_CH31, 31 => configurable); | 343 | impl_ppi_channel!(PPI_CH31, 31 => configurable); |
| 342 | 344 | ||
| 343 | pub mod irqs { | 345 | embassy_hal_common::interrupt_mod!( |
| 344 | use embassy_cortex_m::interrupt::_export::declare; | 346 | CLOCK_POWER, |
| 345 | 347 | RADIO, | |
| 346 | use crate::pac::Interrupt as InterruptEnum; | 348 | RNG, |
| 347 | 349 | GPIOTE, | |
| 348 | declare!(CLOCK_POWER); | 350 | WDT, |
| 349 | declare!(RADIO); | 351 | TIMER0, |
| 350 | declare!(RNG); | 352 | ECB, |
| 351 | declare!(GPIOTE); | 353 | AAR_CCM, |
| 352 | declare!(WDT); | 354 | TEMP, |
| 353 | declare!(TIMER0); | 355 | RTC0, |
| 354 | declare!(ECB); | 356 | IPC, |
| 355 | declare!(AAR_CCM); | 357 | SERIAL0, |
| 356 | declare!(TEMP); | 358 | EGU0, |
| 357 | declare!(RTC0); | 359 | RTC1, |
| 358 | declare!(IPC); | 360 | TIMER1, |
| 359 | declare!(SERIAL0); | 361 | TIMER2, |
| 360 | declare!(EGU0); | 362 | SWI0, |
| 361 | declare!(RTC1); | 363 | SWI1, |
| 362 | declare!(TIMER1); | 364 | SWI2, |
| 363 | declare!(TIMER2); | 365 | SWI3, |
| 364 | declare!(SWI0); | 366 | ); |
| 365 | declare!(SWI1); | ||
| 366 | declare!(SWI2); | ||
| 367 | declare!(SWI3); | ||
| 368 | } | ||
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index d2b45114f..67ea032ff 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs | |||
| @@ -5,6 +5,8 @@ pub mod pac { | |||
| 5 | // The nRF9160 has a secure and non-secure (NS) mode. | 5 | // The nRF9160 has a secure and non-secure (NS) mode. |
| 6 | // To avoid cfg spam, we remove _ns or _s suffixes here. | 6 | // To avoid cfg spam, we remove _ns or _s suffixes here. |
| 7 | 7 | ||
| 8 | pub use nrf9160_pac::NVIC_PRIO_BITS; | ||
| 9 | |||
| 8 | #[doc(no_inline)] | 10 | #[doc(no_inline)] |
| 9 | pub use nrf9160_pac::{ | 11 | pub use nrf9160_pac::{ |
| 10 | interrupt, | 12 | interrupt, |
| @@ -366,40 +368,36 @@ impl_saadc_input!(P0_18, ANALOG_INPUT5); | |||
| 366 | impl_saadc_input!(P0_19, ANALOG_INPUT6); | 368 | impl_saadc_input!(P0_19, ANALOG_INPUT6); |
| 367 | impl_saadc_input!(P0_20, ANALOG_INPUT7); | 369 | impl_saadc_input!(P0_20, ANALOG_INPUT7); |
| 368 | 370 | ||
| 369 | pub mod irqs { | 371 | embassy_hal_common::interrupt_mod!( |
| 370 | use embassy_cortex_m::interrupt::_export::declare; | 372 | SPU, |
| 371 | 373 | CLOCK_POWER, | |
| 372 | use crate::pac::Interrupt as InterruptEnum; | 374 | UARTE0_SPIM0_SPIS0_TWIM0_TWIS0, |
| 373 | 375 | UARTE1_SPIM1_SPIS1_TWIM1_TWIS1, | |
| 374 | declare!(SPU); | 376 | UARTE2_SPIM2_SPIS2_TWIM2_TWIS2, |
| 375 | declare!(CLOCK_POWER); | 377 | UARTE3_SPIM3_SPIS3_TWIM3_TWIS3, |
| 376 | declare!(UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); | 378 | GPIOTE0, |
| 377 | declare!(UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); | 379 | SAADC, |
| 378 | declare!(UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | 380 | TIMER0, |
| 379 | declare!(UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | 381 | TIMER1, |
| 380 | declare!(GPIOTE0); | 382 | TIMER2, |
| 381 | declare!(SAADC); | 383 | RTC0, |
| 382 | declare!(TIMER0); | 384 | RTC1, |
| 383 | declare!(TIMER1); | 385 | WDT, |
| 384 | declare!(TIMER2); | 386 | EGU0, |
| 385 | declare!(RTC0); | 387 | EGU1, |
| 386 | declare!(RTC1); | 388 | EGU2, |
| 387 | declare!(WDT); | 389 | EGU3, |
| 388 | declare!(EGU0); | 390 | EGU4, |
| 389 | declare!(EGU1); | 391 | EGU5, |
| 390 | declare!(EGU2); | 392 | PWM0, |
| 391 | declare!(EGU3); | 393 | PWM1, |
| 392 | declare!(EGU4); | 394 | PWM2, |
| 393 | declare!(EGU5); | 395 | PDM, |
| 394 | declare!(PWM0); | 396 | PWM3, |
| 395 | declare!(PWM1); | 397 | I2S, |
| 396 | declare!(PWM2); | 398 | IPC, |
| 397 | declare!(PDM); | 399 | FPU, |
| 398 | declare!(PWM3); | 400 | GPIOTE1, |
| 399 | declare!(I2S); | 401 | KMU, |
| 400 | declare!(IPC); | 402 | CRYPTOCELL, |
| 401 | declare!(FPU); | 403 | ); |
| 402 | declare!(GPIOTE1); | ||
| 403 | declare!(KMU); | ||
| 404 | declare!(CRYPTOCELL); | ||
| 405 | } | ||
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 66c682b43..21d0d9564 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs | |||
| @@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 9 | 9 | ||
| 10 | use crate::gpio::sealed::Pin as _; | 10 | use crate::gpio::sealed::Pin as _; |
| 11 | use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin}; | 11 | use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin}; |
| 12 | use crate::interrupt::{Interrupt, InterruptExt}; | 12 | use crate::interrupt::InterruptExt; |
| 13 | use crate::ppi::{Event, Task}; | 13 | use crate::ppi::{Event, Task}; |
| 14 | use crate::{interrupt, pac, peripherals}; | 14 | use crate::{interrupt, pac, peripherals}; |
| 15 | 15 | ||
| @@ -74,42 +74,41 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { | |||
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | // Enable interrupts | 76 | // Enable interrupts |
| 77 | cfg_if::cfg_if! { | 77 | #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))] |
| 78 | if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] { | 78 | let irq = interrupt::GPIOTE0; |
| 79 | let irq = unsafe { interrupt::GPIOTE0::steal() }; | 79 | #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))] |
| 80 | } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] { | 80 | let irq = interrupt::GPIOTE1; |
| 81 | let irq = unsafe { interrupt::GPIOTE1::steal() }; | 81 | #[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))] |
| 82 | } else { | 82 | let irq = interrupt::GPIOTE; |
| 83 | let irq = unsafe { interrupt::GPIOTE::steal() }; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | 83 | ||
| 87 | irq.unpend(); | 84 | irq.unpend(); |
| 88 | irq.set_priority(irq_prio); | 85 | irq.set_priority(irq_prio); |
| 89 | irq.enable(); | 86 | unsafe { irq.enable() }; |
| 90 | 87 | ||
| 91 | let g = regs(); | 88 | let g = regs(); |
| 92 | g.events_port.write(|w| w); | 89 | g.events_port.write(|w| w); |
| 93 | g.intenset.write(|w| w.port().set()); | 90 | g.intenset.write(|w| w.port().set()); |
| 94 | } | 91 | } |
| 95 | 92 | ||
| 96 | cfg_if::cfg_if! { | 93 | #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))] |
| 97 | if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] { | 94 | #[cfg(feature = "rt")] |
| 98 | #[interrupt] | 95 | #[interrupt] |
| 99 | fn GPIOTE0() { | 96 | fn GPIOTE0() { |
| 100 | unsafe { handle_gpiote_interrupt() }; | 97 | unsafe { handle_gpiote_interrupt() }; |
| 101 | } | 98 | } |
| 102 | } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] { | 99 | |
| 103 | #[interrupt] | 100 | #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))] |
| 104 | fn GPIOTE1() { | 101 | #[cfg(feature = "rt")] |
| 105 | unsafe { handle_gpiote_interrupt() }; | 102 | #[interrupt] |
| 106 | } | 103 | fn GPIOTE1() { |
| 107 | } else { | 104 | unsafe { handle_gpiote_interrupt() }; |
| 108 | #[interrupt] | 105 | } |
| 109 | fn GPIOTE() { | 106 | |
| 110 | unsafe { handle_gpiote_interrupt() }; | 107 | #[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))] |
| 111 | } | 108 | #[cfg(feature = "rt")] |
| 112 | } | 109 | #[interrupt] |
| 110 | fn GPIOTE() { | ||
| 111 | unsafe { handle_gpiote_interrupt() }; | ||
| 113 | } | 112 | } |
| 114 | 113 | ||
| 115 | unsafe fn handle_gpiote_interrupt() { | 114 | unsafe fn handle_gpiote_interrupt() { |
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 8a1188ce4..fea38c4c0 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs | |||
| @@ -9,15 +9,14 @@ use core::ops::{Deref, DerefMut}; | |||
| 9 | use core::sync::atomic::{compiler_fence, Ordering}; | 9 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 10 | use core::task::Poll; | 10 | use core::task::Poll; |
| 11 | 11 | ||
| 12 | use embassy_cortex_m::interrupt::InterruptExt; | ||
| 13 | use embassy_hal_common::drop::OnDrop; | 12 | use embassy_hal_common::drop::OnDrop; |
| 14 | use embassy_hal_common::{into_ref, PeripheralRef}; | 13 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 15 | 14 | ||
| 16 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 15 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 17 | use crate::interrupt::{self, Interrupt}; | 16 | use crate::interrupt::typelevel::Interrupt; |
| 18 | use crate::pac::i2s::RegisterBlock; | 17 | use crate::pac::i2s::RegisterBlock; |
| 19 | use crate::util::{slice_in_ram_or, slice_ptr_parts}; | 18 | use crate::util::{slice_in_ram_or, slice_ptr_parts}; |
| 20 | use crate::{Peripheral, EASY_DMA_SIZE}; | 19 | use crate::{interrupt, Peripheral, EASY_DMA_SIZE}; |
| 21 | 20 | ||
| 22 | /// Type alias for `MultiBuffering` with 2 buffers. | 21 | /// Type alias for `MultiBuffering` with 2 buffers. |
| 23 | pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>; | 22 | pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>; |
| @@ -368,7 +367,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 368 | _phantom: PhantomData<T>, | 367 | _phantom: PhantomData<T>, |
| 369 | } | 368 | } |
| 370 | 369 | ||
| 371 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 370 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 372 | unsafe fn on_interrupt() { | 371 | unsafe fn on_interrupt() { |
| 373 | let device = Device::<T>::new(); | 372 | let device = Device::<T>::new(); |
| 374 | let s = T::state(); | 373 | let s = T::state(); |
| @@ -409,7 +408,7 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 409 | /// Create a new I2S in master mode | 408 | /// Create a new I2S in master mode |
| 410 | pub fn new_master( | 409 | pub fn new_master( |
| 411 | i2s: impl Peripheral<P = T> + 'd, | 410 | i2s: impl Peripheral<P = T> + 'd, |
| 412 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 411 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 413 | mck: impl Peripheral<P = impl GpioPin> + 'd, | 412 | mck: impl Peripheral<P = impl GpioPin> + 'd, |
| 414 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 413 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 415 | lrck: impl Peripheral<P = impl GpioPin> + 'd, | 414 | lrck: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -432,7 +431,7 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 432 | /// Create a new I2S in slave mode | 431 | /// Create a new I2S in slave mode |
| 433 | pub fn new_slave( | 432 | pub fn new_slave( |
| 434 | i2s: impl Peripheral<P = T> + 'd, | 433 | i2s: impl Peripheral<P = T> + 'd, |
| 435 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 434 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 436 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 435 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 437 | lrck: impl Peripheral<P = impl GpioPin> + 'd, | 436 | lrck: impl Peripheral<P = impl GpioPin> + 'd, |
| 438 | config: Config, | 437 | config: Config, |
| @@ -564,8 +563,8 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 564 | } | 563 | } |
| 565 | 564 | ||
| 566 | fn setup_interrupt(&self) { | 565 | fn setup_interrupt(&self) { |
| 567 | unsafe { T::Interrupt::steal() }.unpend(); | 566 | T::Interrupt::unpend(); |
| 568 | unsafe { T::Interrupt::steal() }.enable(); | 567 | unsafe { T::Interrupt::enable() }; |
| 569 | 568 | ||
| 570 | let device = Device::<T>::new(); | 569 | let device = Device::<T>::new(); |
| 571 | device.disable_tx_ptr_interrupt(); | 570 | device.disable_tx_ptr_interrupt(); |
| @@ -1174,7 +1173,7 @@ pub(crate) mod sealed { | |||
| 1174 | /// I2S peripheral instance. | 1173 | /// I2S peripheral instance. |
| 1175 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 1174 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 1176 | /// Interrupt for this peripheral. | 1175 | /// Interrupt for this peripheral. |
| 1177 | type Interrupt: Interrupt; | 1176 | type Interrupt: interrupt::typelevel::Interrupt; |
| 1178 | } | 1177 | } |
| 1179 | 1178 | ||
| 1180 | macro_rules! impl_i2s { | 1179 | macro_rules! impl_i2s { |
| @@ -1189,7 +1188,7 @@ macro_rules! impl_i2s { | |||
| 1189 | } | 1188 | } |
| 1190 | } | 1189 | } |
| 1191 | impl crate::i2s::Instance for peripherals::$type { | 1190 | impl crate::i2s::Instance for peripherals::$type { |
| 1192 | type Interrupt = crate::interrupt::$irq; | 1191 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 1193 | } | 1192 | } |
| 1194 | }; | 1193 | }; |
| 1195 | } | 1194 | } |
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index d4d7a1cad..691545662 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -93,21 +93,14 @@ pub mod wdt; | |||
| 93 | #[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] | 93 | #[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] |
| 94 | mod chip; | 94 | mod chip; |
| 95 | 95 | ||
| 96 | pub mod interrupt { | 96 | /// Macro to bind interrupts to handlers. |
| 97 | //! Interrupt definitions and macros to bind them. | 97 | /// |
| 98 | pub use cortex_m::interrupt::{CriticalSection, Mutex}; | 98 | /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) |
| 99 | pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority}; | 99 | /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to |
| 100 | 100 | /// prove at compile-time that the right interrupts have been bound. | |
| 101 | pub use crate::chip::irqs::*; | 101 | // developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`. |
| 102 | 102 | #[macro_export] | |
| 103 | /// Macro to bind interrupts to handlers. | 103 | macro_rules! bind_interrupts { |
| 104 | /// | ||
| 105 | /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) | ||
| 106 | /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to | ||
| 107 | /// prove at compile-time that the right interrupts have been bound. | ||
| 108 | // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`. | ||
| 109 | #[macro_export] | ||
| 110 | macro_rules! bind_interrupts { | ||
| 111 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { | 104 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { |
| 112 | $vis struct $name; | 105 | $vis struct $name; |
| 113 | 106 | ||
| @@ -116,17 +109,16 @@ pub mod interrupt { | |||
| 116 | #[no_mangle] | 109 | #[no_mangle] |
| 117 | unsafe extern "C" fn $irq() { | 110 | unsafe extern "C" fn $irq() { |
| 118 | $( | 111 | $( |
| 119 | <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt(); | 112 | <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); |
| 120 | )* | 113 | )* |
| 121 | } | 114 | } |
| 122 | 115 | ||
| 123 | $( | 116 | $( |
| 124 | unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {} | 117 | unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} |
| 125 | )* | 118 | )* |
| 126 | )* | 119 | )* |
| 127 | }; | 120 | }; |
| 128 | } | 121 | } |
| 129 | } | ||
| 130 | 122 | ||
| 131 | // Reexports | 123 | // Reexports |
| 132 | 124 | ||
| @@ -135,10 +127,11 @@ pub use chip::pac; | |||
| 135 | #[cfg(not(feature = "unstable-pac"))] | 127 | #[cfg(not(feature = "unstable-pac"))] |
| 136 | pub(crate) use chip::pac; | 128 | pub(crate) use chip::pac; |
| 137 | pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; | 129 | pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; |
| 138 | pub use embassy_cortex_m::executor; | ||
| 139 | pub use embassy_cortex_m::interrupt::_export::interrupt; | ||
| 140 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 130 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
| 141 | 131 | ||
| 132 | pub use crate::chip::interrupt; | ||
| 133 | pub use crate::pac::NVIC_PRIO_BITS; | ||
| 134 | |||
| 142 | pub mod config { | 135 | pub mod config { |
| 143 | //! Configuration options used when initializing the HAL. | 136 | //! Configuration options used when initializing the HAL. |
| 144 | 137 | ||
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index 8815bb316..0e30f7002 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs | |||
| @@ -6,7 +6,6 @@ use core::marker::PhantomData; | |||
| 6 | use core::sync::atomic::{compiler_fence, Ordering}; | 6 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 7 | use core::task::Poll; | 7 | use core::task::Poll; |
| 8 | 8 | ||
| 9 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 10 | use embassy_hal_common::drop::OnDrop; | 9 | use embassy_hal_common::drop::OnDrop; |
| 11 | use embassy_hal_common::{into_ref, PeripheralRef}; | 10 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 12 | use futures::future::poll_fn; | 11 | use futures::future::poll_fn; |
| @@ -14,15 +13,15 @@ use futures::future::poll_fn; | |||
| 14 | use crate::chip::EASY_DMA_SIZE; | 13 | use crate::chip::EASY_DMA_SIZE; |
| 15 | use crate::gpio::sealed::Pin; | 14 | use crate::gpio::sealed::Pin; |
| 16 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 15 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 17 | use crate::interrupt::{self, InterruptExt}; | 16 | use crate::interrupt::typelevel::Interrupt; |
| 18 | use crate::Peripheral; | 17 | use crate::{interrupt, Peripheral}; |
| 19 | 18 | ||
| 20 | /// Interrupt handler. | 19 | /// Interrupt handler. |
| 21 | pub struct InterruptHandler<T: Instance> { | 20 | pub struct InterruptHandler<T: Instance> { |
| 22 | _phantom: PhantomData<T>, | 21 | _phantom: PhantomData<T>, |
| 23 | } | 22 | } |
| 24 | 23 | ||
| 25 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 24 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 26 | unsafe fn on_interrupt() { | 25 | unsafe fn on_interrupt() { |
| 27 | T::regs().intenclr.write(|w| w.end().clear()); | 26 | T::regs().intenclr.write(|w| w.end().clear()); |
| 28 | T::state().waker.wake(); | 27 | T::state().waker.wake(); |
| @@ -53,7 +52,7 @@ impl<'d, T: Instance> Pdm<'d, T> { | |||
| 53 | /// Create PDM driver | 52 | /// Create PDM driver |
| 54 | pub fn new( | 53 | pub fn new( |
| 55 | pdm: impl Peripheral<P = T> + 'd, | 54 | pdm: impl Peripheral<P = T> + 'd, |
| 56 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 55 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 57 | clk: impl Peripheral<P = impl GpioPin> + 'd, | 56 | clk: impl Peripheral<P = impl GpioPin> + 'd, |
| 58 | din: impl Peripheral<P = impl GpioPin> + 'd, | 57 | din: impl Peripheral<P = impl GpioPin> + 'd, |
| 59 | config: Config, | 58 | config: Config, |
| @@ -94,8 +93,8 @@ impl<'d, T: Instance> Pdm<'d, T> { | |||
| 94 | r.gainr.write(|w| w.gainr().default_gain()); | 93 | r.gainr.write(|w| w.gainr().default_gain()); |
| 95 | 94 | ||
| 96 | // IRQ | 95 | // IRQ |
| 97 | unsafe { T::Interrupt::steal() }.unpend(); | 96 | T::Interrupt::unpend(); |
| 98 | unsafe { T::Interrupt::steal() }.enable(); | 97 | unsafe { T::Interrupt::enable() }; |
| 99 | 98 | ||
| 100 | r.enable.write(|w| w.enable().set_bit()); | 99 | r.enable.write(|w| w.enable().set_bit()); |
| 101 | 100 | ||
| @@ -274,7 +273,7 @@ pub(crate) mod sealed { | |||
| 274 | /// PDM peripheral instance. | 273 | /// PDM peripheral instance. |
| 275 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 274 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 276 | /// Interrupt for this peripheral. | 275 | /// Interrupt for this peripheral. |
| 277 | type Interrupt: Interrupt; | 276 | type Interrupt: interrupt::typelevel::Interrupt; |
| 278 | } | 277 | } |
| 279 | 278 | ||
| 280 | macro_rules! impl_pdm { | 279 | macro_rules! impl_pdm { |
| @@ -289,7 +288,7 @@ macro_rules! impl_pdm { | |||
| 289 | } | 288 | } |
| 290 | } | 289 | } |
| 291 | impl crate::pdm::Instance for peripherals::$type { | 290 | impl crate::pdm::Instance for peripherals::$type { |
| 292 | type Interrupt = crate::interrupt::$irq; | 291 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 293 | } | 292 | } |
| 294 | }; | 293 | }; |
| 295 | } | 294 | } |
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 708f23104..363a255d5 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs | |||
| @@ -8,10 +8,9 @@ use embassy_hal_common::{into_ref, PeripheralRef}; | |||
| 8 | 8 | ||
| 9 | use crate::gpio::sealed::Pin as _; | 9 | use crate::gpio::sealed::Pin as _; |
| 10 | use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; | 10 | use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; |
| 11 | use crate::interrupt::Interrupt; | ||
| 12 | use crate::ppi::{Event, Task}; | 11 | use crate::ppi::{Event, Task}; |
| 13 | use crate::util::slice_in_ram_or; | 12 | use crate::util::slice_in_ram_or; |
| 14 | use crate::{pac, Peripheral}; | 13 | use crate::{interrupt, pac, Peripheral}; |
| 15 | 14 | ||
| 16 | /// SimplePwm is the traditional pwm interface you're probably used to, allowing | 15 | /// SimplePwm is the traditional pwm interface you're probably used to, allowing |
| 17 | /// to simply set a duty cycle across up to four channels. | 16 | /// to simply set a duty cycle across up to four channels. |
| @@ -843,7 +842,7 @@ pub(crate) mod sealed { | |||
| 843 | /// PWM peripheral instance. | 842 | /// PWM peripheral instance. |
| 844 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 843 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { |
| 845 | /// Interrupt for this peripheral. | 844 | /// Interrupt for this peripheral. |
| 846 | type Interrupt: Interrupt; | 845 | type Interrupt: interrupt::typelevel::Interrupt; |
| 847 | } | 846 | } |
| 848 | 847 | ||
| 849 | macro_rules! impl_pwm { | 848 | macro_rules! impl_pwm { |
| @@ -854,7 +853,7 @@ macro_rules! impl_pwm { | |||
| 854 | } | 853 | } |
| 855 | } | 854 | } |
| 856 | impl crate::pwm::Instance for peripherals::$type { | 855 | impl crate::pwm::Instance for peripherals::$type { |
| 857 | type Interrupt = crate::interrupt::$irq; | 856 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 858 | } | 857 | } |
| 859 | }; | 858 | }; |
| 860 | } | 859 | } |
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs index c845492fc..8bac87d37 100644 --- a/embassy-nrf/src/qdec.rs +++ b/embassy-nrf/src/qdec.rs | |||
| @@ -6,12 +6,11 @@ use core::future::poll_fn; | |||
| 6 | use core::marker::PhantomData; | 6 | use core::marker::PhantomData; |
| 7 | use core::task::Poll; | 7 | use core::task::Poll; |
| 8 | 8 | ||
| 9 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 10 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 11 | 10 | ||
| 12 | use crate::gpio::sealed::Pin as _; | 11 | use crate::gpio::sealed::Pin as _; |
| 13 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 12 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 14 | use crate::interrupt::InterruptExt; | 13 | use crate::interrupt::typelevel::Interrupt; |
| 15 | use crate::{interrupt, Peripheral}; | 14 | use crate::{interrupt, Peripheral}; |
| 16 | 15 | ||
| 17 | /// Quadrature decoder driver. | 16 | /// Quadrature decoder driver. |
| @@ -51,7 +50,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 51 | _phantom: PhantomData<T>, | 50 | _phantom: PhantomData<T>, |
| 52 | } | 51 | } |
| 53 | 52 | ||
| 54 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 53 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 55 | unsafe fn on_interrupt() { | 54 | unsafe fn on_interrupt() { |
| 56 | T::regs().intenclr.write(|w| w.reportrdy().clear()); | 55 | T::regs().intenclr.write(|w| w.reportrdy().clear()); |
| 57 | T::state().waker.wake(); | 56 | T::state().waker.wake(); |
| @@ -62,7 +61,7 @@ impl<'d, T: Instance> Qdec<'d, T> { | |||
| 62 | /// Create a new QDEC. | 61 | /// Create a new QDEC. |
| 63 | pub fn new( | 62 | pub fn new( |
| 64 | qdec: impl Peripheral<P = T> + 'd, | 63 | qdec: impl Peripheral<P = T> + 'd, |
| 65 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 64 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 66 | a: impl Peripheral<P = impl GpioPin> + 'd, | 65 | a: impl Peripheral<P = impl GpioPin> + 'd, |
| 67 | b: impl Peripheral<P = impl GpioPin> + 'd, | 66 | b: impl Peripheral<P = impl GpioPin> + 'd, |
| 68 | config: Config, | 67 | config: Config, |
| @@ -74,7 +73,7 @@ impl<'d, T: Instance> Qdec<'d, T> { | |||
| 74 | /// Create a new QDEC, with a pin for LED output. | 73 | /// Create a new QDEC, with a pin for LED output. |
| 75 | pub fn new_with_led( | 74 | pub fn new_with_led( |
| 76 | qdec: impl Peripheral<P = T> + 'd, | 75 | qdec: impl Peripheral<P = T> + 'd, |
| 77 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 76 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 78 | a: impl Peripheral<P = impl GpioPin> + 'd, | 77 | a: impl Peripheral<P = impl GpioPin> + 'd, |
| 79 | b: impl Peripheral<P = impl GpioPin> + 'd, | 78 | b: impl Peripheral<P = impl GpioPin> + 'd, |
| 80 | led: impl Peripheral<P = impl GpioPin> + 'd, | 79 | led: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -134,8 +133,8 @@ impl<'d, T: Instance> Qdec<'d, T> { | |||
| 134 | SamplePeriod::_131ms => w.sampleper()._131ms(), | 133 | SamplePeriod::_131ms => w.sampleper()._131ms(), |
| 135 | }); | 134 | }); |
| 136 | 135 | ||
| 137 | unsafe { T::Interrupt::steal() }.unpend(); | 136 | T::Interrupt::unpend(); |
| 138 | unsafe { T::Interrupt::steal() }.enable(); | 137 | unsafe { T::Interrupt::enable() }; |
| 139 | 138 | ||
| 140 | // Enable peripheral | 139 | // Enable peripheral |
| 141 | r.enable.write(|w| w.enable().set_bit()); | 140 | r.enable.write(|w| w.enable().set_bit()); |
| @@ -272,7 +271,7 @@ pub(crate) mod sealed { | |||
| 272 | /// qdec peripheral instance. | 271 | /// qdec peripheral instance. |
| 273 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 272 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 274 | /// Interrupt for this peripheral. | 273 | /// Interrupt for this peripheral. |
| 275 | type Interrupt: Interrupt; | 274 | type Interrupt: interrupt::typelevel::Interrupt; |
| 276 | } | 275 | } |
| 277 | 276 | ||
| 278 | macro_rules! impl_qdec { | 277 | macro_rules! impl_qdec { |
| @@ -287,7 +286,7 @@ macro_rules! impl_qdec { | |||
| 287 | } | 286 | } |
| 288 | } | 287 | } |
| 289 | impl crate::qdec::Instance for peripherals::$type { | 288 | impl crate::qdec::Instance for peripherals::$type { |
| 290 | type Interrupt = crate::interrupt::$irq; | 289 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 291 | } | 290 | } |
| 292 | }; | 291 | }; |
| 293 | } | 292 | } |
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 2e16c2ff5..baefc7967 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs | |||
| @@ -12,12 +12,12 @@ use embassy_hal_common::{into_ref, PeripheralRef}; | |||
| 12 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | 12 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; |
| 13 | 13 | ||
| 14 | use crate::gpio::{self, Pin as GpioPin}; | 14 | use crate::gpio::{self, Pin as GpioPin}; |
| 15 | use crate::interrupt::{self, Interrupt, InterruptExt}; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 16 | pub use crate::pac::qspi::ifconfig0::{ | 16 | pub use crate::pac::qspi::ifconfig0::{ |
| 17 | ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, | 17 | ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, |
| 18 | }; | 18 | }; |
| 19 | pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; | 19 | pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; |
| 20 | use crate::Peripheral; | 20 | use crate::{interrupt, Peripheral}; |
| 21 | 21 | ||
| 22 | /// Deep power-down config. | 22 | /// Deep power-down config. |
| 23 | pub struct DeepPowerDownConfig { | 23 | pub struct DeepPowerDownConfig { |
| @@ -120,7 +120,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 120 | _phantom: PhantomData<T>, | 120 | _phantom: PhantomData<T>, |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 123 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 124 | unsafe fn on_interrupt() { | 124 | unsafe fn on_interrupt() { |
| 125 | let r = T::regs(); | 125 | let r = T::regs(); |
| 126 | let s = T::state(); | 126 | let s = T::state(); |
| @@ -143,7 +143,7 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 143 | /// Create a new QSPI driver. | 143 | /// Create a new QSPI driver. |
| 144 | pub fn new( | 144 | pub fn new( |
| 145 | qspi: impl Peripheral<P = T> + 'd, | 145 | qspi: impl Peripheral<P = T> + 'd, |
| 146 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 146 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 147 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 147 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 148 | csn: impl Peripheral<P = impl GpioPin> + 'd, | 148 | csn: impl Peripheral<P = impl GpioPin> + 'd, |
| 149 | io0: impl Peripheral<P = impl GpioPin> + 'd, | 149 | io0: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -207,8 +207,8 @@ impl<'d, T: Instance> Qspi<'d, T> { | |||
| 207 | w | 207 | w |
| 208 | }); | 208 | }); |
| 209 | 209 | ||
| 210 | unsafe { T::Interrupt::steal() }.unpend(); | 210 | T::Interrupt::unpend(); |
| 211 | unsafe { T::Interrupt::steal() }.enable(); | 211 | unsafe { T::Interrupt::enable() }; |
| 212 | 212 | ||
| 213 | // Enable it | 213 | // Enable it |
| 214 | r.enable.write(|w| w.enable().enabled()); | 214 | r.enable.write(|w| w.enable().enabled()); |
| @@ -644,7 +644,7 @@ pub(crate) mod sealed { | |||
| 644 | /// QSPI peripheral instance. | 644 | /// QSPI peripheral instance. |
| 645 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 645 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 646 | /// Interrupt for this peripheral. | 646 | /// Interrupt for this peripheral. |
| 647 | type Interrupt: Interrupt; | 647 | type Interrupt: interrupt::typelevel::Interrupt; |
| 648 | } | 648 | } |
| 649 | 649 | ||
| 650 | macro_rules! impl_qspi { | 650 | macro_rules! impl_qspi { |
| @@ -659,7 +659,7 @@ macro_rules! impl_qspi { | |||
| 659 | } | 659 | } |
| 660 | } | 660 | } |
| 661 | impl crate::qspi::Instance for peripherals::$type { | 661 | impl crate::qspi::Instance for peripherals::$type { |
| 662 | type Interrupt = crate::interrupt::$irq; | 662 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 663 | } | 663 | } |
| 664 | }; | 664 | }; |
| 665 | } | 665 | } |
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index a5602248d..923b8b467 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs | |||
| @@ -8,12 +8,11 @@ use core::ptr; | |||
| 8 | use core::sync::atomic::{AtomicPtr, Ordering}; | 8 | use core::sync::atomic::{AtomicPtr, Ordering}; |
| 9 | use core::task::Poll; | 9 | use core::task::Poll; |
| 10 | 10 | ||
| 11 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 12 | use embassy_hal_common::drop::OnDrop; | 11 | use embassy_hal_common::drop::OnDrop; |
| 13 | use embassy_hal_common::{into_ref, PeripheralRef}; | 12 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 14 | use embassy_sync::waitqueue::AtomicWaker; | 13 | use embassy_sync::waitqueue::AtomicWaker; |
| 15 | 14 | ||
| 16 | use crate::interrupt::InterruptExt; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 17 | use crate::{interrupt, Peripheral}; | 16 | use crate::{interrupt, Peripheral}; |
| 18 | 17 | ||
| 19 | /// Interrupt handler. | 18 | /// Interrupt handler. |
| @@ -21,7 +20,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 21 | _phantom: PhantomData<T>, | 20 | _phantom: PhantomData<T>, |
| 22 | } | 21 | } |
| 23 | 22 | ||
| 24 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 23 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 25 | unsafe fn on_interrupt() { | 24 | unsafe fn on_interrupt() { |
| 26 | let s = T::state(); | 25 | let s = T::state(); |
| 27 | let r = T::regs(); | 26 | let r = T::regs(); |
| @@ -90,7 +89,7 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 90 | /// The synchronous API is safe. | 89 | /// The synchronous API is safe. |
| 91 | pub fn new( | 90 | pub fn new( |
| 92 | rng: impl Peripheral<P = T> + 'd, | 91 | rng: impl Peripheral<P = T> + 'd, |
| 93 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 92 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 94 | ) -> Self { | 93 | ) -> Self { |
| 95 | into_ref!(rng); | 94 | into_ref!(rng); |
| 96 | 95 | ||
| @@ -99,8 +98,8 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 99 | this.stop(); | 98 | this.stop(); |
| 100 | this.disable_irq(); | 99 | this.disable_irq(); |
| 101 | 100 | ||
| 102 | unsafe { T::Interrupt::steal() }.unpend(); | 101 | T::Interrupt::unpend(); |
| 103 | unsafe { T::Interrupt::steal() }.enable(); | 102 | unsafe { T::Interrupt::enable() }; |
| 104 | 103 | ||
| 105 | this | 104 | this |
| 106 | } | 105 | } |
| @@ -256,7 +255,7 @@ pub(crate) mod sealed { | |||
| 256 | /// RNG peripheral instance. | 255 | /// RNG peripheral instance. |
| 257 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 256 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 258 | /// Interrupt for this peripheral. | 257 | /// Interrupt for this peripheral. |
| 259 | type Interrupt: Interrupt; | 258 | type Interrupt: interrupt::typelevel::Interrupt; |
| 260 | } | 259 | } |
| 261 | 260 | ||
| 262 | macro_rules! impl_rng { | 261 | macro_rules! impl_rng { |
| @@ -271,7 +270,7 @@ macro_rules! impl_rng { | |||
| 271 | } | 270 | } |
| 272 | } | 271 | } |
| 273 | impl crate::rng::Instance for peripherals::$type { | 272 | impl crate::rng::Instance for peripherals::$type { |
| 274 | type Interrupt = crate::interrupt::$irq; | 273 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 275 | } | 274 | } |
| 276 | }; | 275 | }; |
| 277 | } | 276 | } |
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index 8aff7df16..cf3fb9993 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs | |||
| @@ -6,7 +6,6 @@ use core::future::poll_fn; | |||
| 6 | use core::sync::atomic::{compiler_fence, Ordering}; | 6 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 7 | use core::task::Poll; | 7 | use core::task::Poll; |
| 8 | 8 | ||
| 9 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 10 | use embassy_hal_common::drop::OnDrop; | 9 | use embassy_hal_common::drop::OnDrop; |
| 11 | use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; | 10 | use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; |
| 12 | use embassy_sync::waitqueue::AtomicWaker; | 11 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -18,6 +17,7 @@ use saadc::oversample::OVERSAMPLE_A; | |||
| 18 | use saadc::resolution::VAL_A; | 17 | use saadc::resolution::VAL_A; |
| 19 | 18 | ||
| 20 | use self::sealed::Input as _; | 19 | use self::sealed::Input as _; |
| 20 | use crate::interrupt::InterruptExt; | ||
| 21 | use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; | 21 | use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; |
| 22 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 22 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; |
| 23 | use crate::{interrupt, pac, peripherals, Peripheral}; | 23 | use crate::{interrupt, pac, peripherals, Peripheral}; |
| @@ -33,7 +33,7 @@ pub struct InterruptHandler { | |||
| 33 | _private: (), | 33 | _private: (), |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | impl interrupt::Handler<interrupt::SAADC> for InterruptHandler { | 36 | impl interrupt::typelevel::Handler<interrupt::typelevel::SAADC> for InterruptHandler { |
| 37 | unsafe fn on_interrupt() { | 37 | unsafe fn on_interrupt() { |
| 38 | let r = unsafe { &*SAADC::ptr() }; | 38 | let r = unsafe { &*SAADC::ptr() }; |
| 39 | 39 | ||
| @@ -144,7 +144,7 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 144 | /// Create a new SAADC driver. | 144 | /// Create a new SAADC driver. |
| 145 | pub fn new( | 145 | pub fn new( |
| 146 | saadc: impl Peripheral<P = peripherals::SAADC> + 'd, | 146 | saadc: impl Peripheral<P = peripherals::SAADC> + 'd, |
| 147 | _irq: impl interrupt::Binding<interrupt::SAADC, InterruptHandler> + 'd, | 147 | _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SAADC, InterruptHandler> + 'd, |
| 148 | config: Config, | 148 | config: Config, |
| 149 | channel_configs: [ChannelConfig; N], | 149 | channel_configs: [ChannelConfig; N], |
| 150 | ) -> Self { | 150 | ) -> Self { |
| @@ -189,8 +189,8 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 189 | // Disable all events interrupts | 189 | // Disable all events interrupts |
| 190 | r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); | 190 | r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); |
| 191 | 191 | ||
| 192 | unsafe { interrupt::SAADC::steal() }.unpend(); | 192 | interrupt::SAADC.unpend(); |
| 193 | unsafe { interrupt::SAADC::steal() }.enable(); | 193 | unsafe { interrupt::SAADC.enable() }; |
| 194 | 194 | ||
| 195 | Self { _p: saadc } | 195 | Self { _p: saadc } |
| 196 | } | 196 | } |
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 89cbdfee9..66bbd1a8f 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs | |||
| @@ -15,9 +15,9 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency; | |||
| 15 | use crate::chip::FORCE_COPY_BUFFER_SIZE; | 15 | use crate::chip::FORCE_COPY_BUFFER_SIZE; |
| 16 | use crate::gpio::sealed::Pin as _; | 16 | use crate::gpio::sealed::Pin as _; |
| 17 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | 17 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; |
| 18 | use crate::interrupt::{self, Interrupt, InterruptExt}; | 18 | use crate::interrupt::typelevel::Interrupt; |
| 19 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; | 19 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; |
| 20 | use crate::{pac, Peripheral}; | 20 | use crate::{interrupt, pac, Peripheral}; |
| 21 | 21 | ||
| 22 | /// SPIM error | 22 | /// SPIM error |
| 23 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 23 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| @@ -63,7 +63,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 63 | _phantom: PhantomData<T>, | 63 | _phantom: PhantomData<T>, |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 66 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 67 | unsafe fn on_interrupt() { | 67 | unsafe fn on_interrupt() { |
| 68 | let r = T::regs(); | 68 | let r = T::regs(); |
| 69 | let s = T::state(); | 69 | let s = T::state(); |
| @@ -84,7 +84,7 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 84 | /// Create a new SPIM driver. | 84 | /// Create a new SPIM driver. |
| 85 | pub fn new( | 85 | pub fn new( |
| 86 | spim: impl Peripheral<P = T> + 'd, | 86 | spim: impl Peripheral<P = T> + 'd, |
| 87 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 87 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 88 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 88 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 89 | miso: impl Peripheral<P = impl GpioPin> + 'd, | 89 | miso: impl Peripheral<P = impl GpioPin> + 'd, |
| 90 | mosi: impl Peripheral<P = impl GpioPin> + 'd, | 90 | mosi: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -103,7 +103,7 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 103 | /// Create a new SPIM driver, capable of TX only (MOSI only). | 103 | /// Create a new SPIM driver, capable of TX only (MOSI only). |
| 104 | pub fn new_txonly( | 104 | pub fn new_txonly( |
| 105 | spim: impl Peripheral<P = T> + 'd, | 105 | spim: impl Peripheral<P = T> + 'd, |
| 106 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 106 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 107 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 107 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 108 | mosi: impl Peripheral<P = impl GpioPin> + 'd, | 108 | mosi: impl Peripheral<P = impl GpioPin> + 'd, |
| 109 | config: Config, | 109 | config: Config, |
| @@ -115,7 +115,7 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 115 | /// Create a new SPIM driver, capable of RX only (MISO only). | 115 | /// Create a new SPIM driver, capable of RX only (MISO only). |
| 116 | pub fn new_rxonly( | 116 | pub fn new_rxonly( |
| 117 | spim: impl Peripheral<P = T> + 'd, | 117 | spim: impl Peripheral<P = T> + 'd, |
| 118 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 118 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 119 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 119 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 120 | miso: impl Peripheral<P = impl GpioPin> + 'd, | 120 | miso: impl Peripheral<P = impl GpioPin> + 'd, |
| 121 | config: Config, | 121 | config: Config, |
| @@ -207,8 +207,8 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 207 | // Disable all events interrupts | 207 | // Disable all events interrupts |
| 208 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | 208 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); |
| 209 | 209 | ||
| 210 | unsafe { T::Interrupt::steal() }.unpend(); | 210 | T::Interrupt::unpend(); |
| 211 | unsafe { T::Interrupt::steal() }.enable(); | 211 | unsafe { T::Interrupt::enable() }; |
| 212 | 212 | ||
| 213 | Self { _p: spim } | 213 | Self { _p: spim } |
| 214 | } | 214 | } |
| @@ -408,7 +408,7 @@ pub(crate) mod sealed { | |||
| 408 | /// SPIM peripheral instance | 408 | /// SPIM peripheral instance |
| 409 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 409 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { |
| 410 | /// Interrupt for this peripheral. | 410 | /// Interrupt for this peripheral. |
| 411 | type Interrupt: Interrupt; | 411 | type Interrupt: interrupt::typelevel::Interrupt; |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | macro_rules! impl_spim { | 414 | macro_rules! impl_spim { |
| @@ -423,7 +423,7 @@ macro_rules! impl_spim { | |||
| 423 | } | 423 | } |
| 424 | } | 424 | } |
| 425 | impl crate::spim::Instance for peripherals::$type { | 425 | impl crate::spim::Instance for peripherals::$type { |
| 426 | type Interrupt = crate::interrupt::$irq; | 426 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 427 | } | 427 | } |
| 428 | }; | 428 | }; |
| 429 | } | 429 | } |
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 55b5e060e..aa438415a 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs | |||
| @@ -13,9 +13,9 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO | |||
| 13 | use crate::chip::FORCE_COPY_BUFFER_SIZE; | 13 | use crate::chip::FORCE_COPY_BUFFER_SIZE; |
| 14 | use crate::gpio::sealed::Pin as _; | 14 | use crate::gpio::sealed::Pin as _; |
| 15 | use crate::gpio::{self, AnyPin, Pin as GpioPin}; | 15 | use crate::gpio::{self, AnyPin, Pin as GpioPin}; |
| 16 | use crate::interrupt::{self, Interrupt, InterruptExt}; | 16 | use crate::interrupt::typelevel::Interrupt; |
| 17 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; | 17 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; |
| 18 | use crate::{pac, Peripheral}; | 18 | use crate::{interrupt, pac, Peripheral}; |
| 19 | 19 | ||
| 20 | /// SPIS error | 20 | /// SPIS error |
| 21 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 21 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| @@ -68,7 +68,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 68 | _phantom: PhantomData<T>, | 68 | _phantom: PhantomData<T>, |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 71 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 72 | unsafe fn on_interrupt() { | 72 | unsafe fn on_interrupt() { |
| 73 | let r = T::regs(); | 73 | let r = T::regs(); |
| 74 | let s = T::state(); | 74 | let s = T::state(); |
| @@ -94,7 +94,7 @@ impl<'d, T: Instance> Spis<'d, T> { | |||
| 94 | /// Create a new SPIS driver. | 94 | /// Create a new SPIS driver. |
| 95 | pub fn new( | 95 | pub fn new( |
| 96 | spis: impl Peripheral<P = T> + 'd, | 96 | spis: impl Peripheral<P = T> + 'd, |
| 97 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 97 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 98 | cs: impl Peripheral<P = impl GpioPin> + 'd, | 98 | cs: impl Peripheral<P = impl GpioPin> + 'd, |
| 99 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 99 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 100 | miso: impl Peripheral<P = impl GpioPin> + 'd, | 100 | miso: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -115,7 +115,7 @@ impl<'d, T: Instance> Spis<'d, T> { | |||
| 115 | /// Create a new SPIS driver, capable of TX only (MISO only). | 115 | /// Create a new SPIS driver, capable of TX only (MISO only). |
| 116 | pub fn new_txonly( | 116 | pub fn new_txonly( |
| 117 | spis: impl Peripheral<P = T> + 'd, | 117 | spis: impl Peripheral<P = T> + 'd, |
| 118 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 118 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 119 | cs: impl Peripheral<P = impl GpioPin> + 'd, | 119 | cs: impl Peripheral<P = impl GpioPin> + 'd, |
| 120 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 120 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 121 | miso: impl Peripheral<P = impl GpioPin> + 'd, | 121 | miso: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -128,7 +128,7 @@ impl<'d, T: Instance> Spis<'d, T> { | |||
| 128 | /// Create a new SPIS driver, capable of RX only (MOSI only). | 128 | /// Create a new SPIS driver, capable of RX only (MOSI only). |
| 129 | pub fn new_rxonly( | 129 | pub fn new_rxonly( |
| 130 | spis: impl Peripheral<P = T> + 'd, | 130 | spis: impl Peripheral<P = T> + 'd, |
| 131 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 131 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 132 | cs: impl Peripheral<P = impl GpioPin> + 'd, | 132 | cs: impl Peripheral<P = impl GpioPin> + 'd, |
| 133 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 133 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 134 | mosi: impl Peripheral<P = impl GpioPin> + 'd, | 134 | mosi: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -214,8 +214,8 @@ impl<'d, T: Instance> Spis<'d, T> { | |||
| 214 | // Disable all events interrupts. | 214 | // Disable all events interrupts. |
| 215 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | 215 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); |
| 216 | 216 | ||
| 217 | unsafe { T::Interrupt::steal() }.unpend(); | 217 | T::Interrupt::unpend(); |
| 218 | unsafe { T::Interrupt::steal() }.enable(); | 218 | unsafe { T::Interrupt::enable() }; |
| 219 | 219 | ||
| 220 | Self { _p: spis } | 220 | Self { _p: spis } |
| 221 | } | 221 | } |
| @@ -480,7 +480,7 @@ pub(crate) mod sealed { | |||
| 480 | /// SPIS peripheral instance | 480 | /// SPIS peripheral instance |
| 481 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 481 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { |
| 482 | /// Interrupt for this peripheral. | 482 | /// Interrupt for this peripheral. |
| 483 | type Interrupt: Interrupt; | 483 | type Interrupt: interrupt::typelevel::Interrupt; |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | macro_rules! impl_spis { | 486 | macro_rules! impl_spis { |
| @@ -495,7 +495,7 @@ macro_rules! impl_spis { | |||
| 495 | } | 495 | } |
| 496 | } | 496 | } |
| 497 | impl crate::spis::Instance for peripherals::$type { | 497 | impl crate::spis::Instance for peripherals::$type { |
| 498 | type Interrupt = crate::interrupt::$irq; | 498 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 499 | } | 499 | } |
| 500 | }; | 500 | }; |
| 501 | } | 501 | } |
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index 0653710af..491e92c04 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | use core::future::poll_fn; | 3 | use core::future::poll_fn; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 7 | use embassy_hal_common::drop::OnDrop; | 6 | use embassy_hal_common::drop::OnDrop; |
| 8 | use embassy_hal_common::{into_ref, PeripheralRef}; | 7 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -18,7 +17,7 @@ pub struct InterruptHandler { | |||
| 18 | _private: (), | 17 | _private: (), |
| 19 | } | 18 | } |
| 20 | 19 | ||
| 21 | impl interrupt::Handler<interrupt::TEMP> for InterruptHandler { | 20 | impl interrupt::typelevel::Handler<interrupt::typelevel::TEMP> for InterruptHandler { |
| 22 | unsafe fn on_interrupt() { | 21 | unsafe fn on_interrupt() { |
| 23 | let r = unsafe { &*pac::TEMP::PTR }; | 22 | let r = unsafe { &*pac::TEMP::PTR }; |
| 24 | r.intenclr.write(|w| w.datardy().clear()); | 23 | r.intenclr.write(|w| w.datardy().clear()); |
| @@ -37,13 +36,13 @@ impl<'d> Temp<'d> { | |||
| 37 | /// Create a new temperature sensor driver. | 36 | /// Create a new temperature sensor driver. |
| 38 | pub fn new( | 37 | pub fn new( |
| 39 | _peri: impl Peripheral<P = TEMP> + 'd, | 38 | _peri: impl Peripheral<P = TEMP> + 'd, |
| 40 | _irq: impl interrupt::Binding<interrupt::TEMP, InterruptHandler> + 'd, | 39 | _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::TEMP, InterruptHandler> + 'd, |
| 41 | ) -> Self { | 40 | ) -> Self { |
| 42 | into_ref!(_peri); | 41 | into_ref!(_peri); |
| 43 | 42 | ||
| 44 | // Enable interrupt that signals temperature values | 43 | // Enable interrupt that signals temperature values |
| 45 | unsafe { interrupt::TEMP::steal() }.unpend(); | 44 | interrupt::TEMP.unpend(); |
| 46 | unsafe { interrupt::TEMP::steal() }.enable(); | 45 | unsafe { interrupt::TEMP.enable() }; |
| 47 | 46 | ||
| 48 | Self { _peri } | 47 | Self { _peri } |
| 49 | } | 48 | } |
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index c82c238cc..f1ab4f8fd 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs | |||
| @@ -7,7 +7,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | |||
| 7 | use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; | 7 | use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; |
| 8 | use embassy_time::driver::{AlarmHandle, Driver}; | 8 | use embassy_time::driver::{AlarmHandle, Driver}; |
| 9 | 9 | ||
| 10 | use crate::interrupt::{Interrupt, InterruptExt}; | 10 | use crate::interrupt::InterruptExt; |
| 11 | use crate::{interrupt, pac}; | 11 | use crate::{interrupt, pac}; |
| 12 | 12 | ||
| 13 | fn rtc() -> &'static pac::rtc0::RegisterBlock { | 13 | fn rtc() -> &'static pac::rtc0::RegisterBlock { |
| @@ -142,9 +142,8 @@ impl RtcDriver { | |||
| 142 | // Wait for clear | 142 | // Wait for clear |
| 143 | while r.counter.read().bits() != 0 {} | 143 | while r.counter.read().bits() != 0 {} |
| 144 | 144 | ||
| 145 | let irq = unsafe { interrupt::RTC1::steal() }; | 145 | interrupt::RTC1.set_priority(irq_prio); |
| 146 | irq.set_priority(irq_prio); | 146 | unsafe { interrupt::RTC1.enable() }; |
| 147 | irq.enable(); | ||
| 148 | } | 147 | } |
| 149 | 148 | ||
| 150 | fn on_interrupt(&self) { | 149 | fn on_interrupt(&self) { |
| @@ -296,6 +295,7 @@ impl Driver for RtcDriver { | |||
| 296 | } | 295 | } |
| 297 | } | 296 | } |
| 298 | 297 | ||
| 298 | #[cfg(feature = "rt")] | ||
| 299 | #[interrupt] | 299 | #[interrupt] |
| 300 | fn RTC1() { | 300 | fn RTC1() { |
| 301 | DRIVER.on_interrupt() | 301 | DRIVER.on_interrupt() |
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 2a0e16a50..dc3757856 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | 8 | ||
| 9 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 10 | 10 | ||
| 11 | use crate::interrupt::Interrupt; | ||
| 12 | use crate::ppi::{Event, Task}; | 11 | use crate::ppi::{Event, Task}; |
| 13 | use crate::{pac, Peripheral}; | 12 | use crate::{pac, Peripheral}; |
| 14 | 13 | ||
| @@ -29,7 +28,7 @@ pub(crate) mod sealed { | |||
| 29 | /// Basic Timer instance. | 28 | /// Basic Timer instance. |
| 30 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 29 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 31 | /// Interrupt for this peripheral. | 30 | /// Interrupt for this peripheral. |
| 32 | type Interrupt: Interrupt; | 31 | type Interrupt: crate::interrupt::typelevel::Interrupt; |
| 33 | } | 32 | } |
| 34 | 33 | ||
| 35 | /// Extended timer instance. | 34 | /// Extended timer instance. |
| @@ -44,7 +43,7 @@ macro_rules! impl_timer { | |||
| 44 | } | 43 | } |
| 45 | } | 44 | } |
| 46 | impl crate::timer::Instance for peripherals::$type { | 45 | impl crate::timer::Instance for peripherals::$type { |
| 47 | type Interrupt = crate::interrupt::$irq; | 46 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 48 | } | 47 | } |
| 49 | }; | 48 | }; |
| 50 | ($type:ident, $pac_type:ident, $irq:ident) => { | 49 | ($type:ident, $pac_type:ident, $irq:ident) => { |
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index cab36884f..2ad0d19b1 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs | |||
| @@ -16,9 +16,9 @@ use embassy_time::{Duration, Instant}; | |||
| 16 | 16 | ||
| 17 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 17 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 18 | use crate::gpio::Pin as GpioPin; | 18 | use crate::gpio::Pin as GpioPin; |
| 19 | use crate::interrupt::{self, Interrupt, InterruptExt}; | 19 | use crate::interrupt::typelevel::Interrupt; |
| 20 | use crate::util::{slice_in_ram, slice_in_ram_or}; | 20 | use crate::util::{slice_in_ram, slice_in_ram_or}; |
| 21 | use crate::{gpio, pac, Peripheral}; | 21 | use crate::{gpio, interrupt, pac, Peripheral}; |
| 22 | 22 | ||
| 23 | /// TWI frequency | 23 | /// TWI frequency |
| 24 | #[derive(Clone, Copy)] | 24 | #[derive(Clone, Copy)] |
| @@ -98,7 +98,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 98 | _phantom: PhantomData<T>, | 98 | _phantom: PhantomData<T>, |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 101 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 102 | unsafe fn on_interrupt() { | 102 | unsafe fn on_interrupt() { |
| 103 | let r = T::regs(); | 103 | let r = T::regs(); |
| 104 | let s = T::state(); | 104 | let s = T::state(); |
| @@ -123,7 +123,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 123 | /// Create a new TWI driver. | 123 | /// Create a new TWI driver. |
| 124 | pub fn new( | 124 | pub fn new( |
| 125 | twim: impl Peripheral<P = T> + 'd, | 125 | twim: impl Peripheral<P = T> + 'd, |
| 126 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 126 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 127 | sda: impl Peripheral<P = impl GpioPin> + 'd, | 127 | sda: impl Peripheral<P = impl GpioPin> + 'd, |
| 128 | scl: impl Peripheral<P = impl GpioPin> + 'd, | 128 | scl: impl Peripheral<P = impl GpioPin> + 'd, |
| 129 | config: Config, | 129 | config: Config, |
| @@ -174,8 +174,8 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 174 | // Disable all events interrupts | 174 | // Disable all events interrupts |
| 175 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | 175 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); |
| 176 | 176 | ||
| 177 | unsafe { T::Interrupt::steal() }.unpend(); | 177 | T::Interrupt::unpend(); |
| 178 | unsafe { T::Interrupt::steal() }.enable(); | 178 | unsafe { T::Interrupt::enable() }; |
| 179 | 179 | ||
| 180 | Self { _p: twim } | 180 | Self { _p: twim } |
| 181 | } | 181 | } |
| @@ -750,7 +750,7 @@ pub(crate) mod sealed { | |||
| 750 | /// TWIM peripheral instance. | 750 | /// TWIM peripheral instance. |
| 751 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 751 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { |
| 752 | /// Interrupt for this peripheral. | 752 | /// Interrupt for this peripheral. |
| 753 | type Interrupt: Interrupt; | 753 | type Interrupt: interrupt::typelevel::Interrupt; |
| 754 | } | 754 | } |
| 755 | 755 | ||
| 756 | macro_rules! impl_twim { | 756 | macro_rules! impl_twim { |
| @@ -765,7 +765,7 @@ macro_rules! impl_twim { | |||
| 765 | } | 765 | } |
| 766 | } | 766 | } |
| 767 | impl crate::twim::Instance for peripherals::$type { | 767 | impl crate::twim::Instance for peripherals::$type { |
| 768 | type Interrupt = crate::interrupt::$irq; | 768 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 769 | } | 769 | } |
| 770 | }; | 770 | }; |
| 771 | } | 771 | } |
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index f68a9940a..a115d5616 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs | |||
| @@ -15,9 +15,9 @@ use embassy_time::{Duration, Instant}; | |||
| 15 | 15 | ||
| 16 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 16 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 17 | use crate::gpio::Pin as GpioPin; | 17 | use crate::gpio::Pin as GpioPin; |
| 18 | use crate::interrupt::{self, Interrupt, InterruptExt}; | 18 | use crate::interrupt::typelevel::Interrupt; |
| 19 | use crate::util::slice_in_ram_or; | 19 | use crate::util::slice_in_ram_or; |
| 20 | use crate::{gpio, pac, Peripheral}; | 20 | use crate::{gpio, interrupt, pac, Peripheral}; |
| 21 | 21 | ||
| 22 | /// TWIS config. | 22 | /// TWIS config. |
| 23 | #[non_exhaustive] | 23 | #[non_exhaustive] |
| @@ -114,7 +114,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 114 | _phantom: PhantomData<T>, | 114 | _phantom: PhantomData<T>, |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 117 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 118 | unsafe fn on_interrupt() { | 118 | unsafe fn on_interrupt() { |
| 119 | let r = T::regs(); | 119 | let r = T::regs(); |
| 120 | let s = T::state(); | 120 | let s = T::state(); |
| @@ -143,7 +143,7 @@ impl<'d, T: Instance> Twis<'d, T> { | |||
| 143 | /// Create a new TWIS driver. | 143 | /// Create a new TWIS driver. |
| 144 | pub fn new( | 144 | pub fn new( |
| 145 | twis: impl Peripheral<P = T> + 'd, | 145 | twis: impl Peripheral<P = T> + 'd, |
| 146 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 146 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 147 | sda: impl Peripheral<P = impl GpioPin> + 'd, | 147 | sda: impl Peripheral<P = impl GpioPin> + 'd, |
| 148 | scl: impl Peripheral<P = impl GpioPin> + 'd, | 148 | scl: impl Peripheral<P = impl GpioPin> + 'd, |
| 149 | config: Config, | 149 | config: Config, |
| @@ -204,8 +204,8 @@ impl<'d, T: Instance> Twis<'d, T> { | |||
| 204 | // Generate suspend on read event | 204 | // Generate suspend on read event |
| 205 | r.shorts.write(|w| w.read_suspend().enabled()); | 205 | r.shorts.write(|w| w.read_suspend().enabled()); |
| 206 | 206 | ||
| 207 | unsafe { T::Interrupt::steal() }.unpend(); | 207 | T::Interrupt::unpend(); |
| 208 | unsafe { T::Interrupt::steal() }.enable(); | 208 | unsafe { T::Interrupt::enable() }; |
| 209 | 209 | ||
| 210 | Self { _p: twis } | 210 | Self { _p: twis } |
| 211 | } | 211 | } |
| @@ -778,7 +778,7 @@ pub(crate) mod sealed { | |||
| 778 | /// TWIS peripheral instance. | 778 | /// TWIS peripheral instance. |
| 779 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 779 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { |
| 780 | /// Interrupt for this peripheral. | 780 | /// Interrupt for this peripheral. |
| 781 | type Interrupt: Interrupt; | 781 | type Interrupt: interrupt::typelevel::Interrupt; |
| 782 | } | 782 | } |
| 783 | 783 | ||
| 784 | macro_rules! impl_twis { | 784 | macro_rules! impl_twis { |
| @@ -793,7 +793,7 @@ macro_rules! impl_twis { | |||
| 793 | } | 793 | } |
| 794 | } | 794 | } |
| 795 | impl crate::twis::Instance for peripherals::$type { | 795 | impl crate::twis::Instance for peripherals::$type { |
| 796 | type Interrupt = crate::interrupt::$irq; | 796 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 797 | } | 797 | } |
| 798 | }; | 798 | }; |
| 799 | } | 799 | } |
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 032089635..48d57fea4 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -27,11 +27,11 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari | |||
| 27 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 27 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 28 | use crate::gpio::sealed::Pin as _; | 28 | use crate::gpio::sealed::Pin as _; |
| 29 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | 29 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; |
| 30 | use crate::interrupt::{self, Interrupt, InterruptExt}; | 30 | use crate::interrupt::typelevel::Interrupt; |
| 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; |
| 32 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 32 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; |
| 33 | use crate::util::slice_in_ram_or; | 33 | use crate::util::slice_in_ram_or; |
| 34 | use crate::{pac, Peripheral}; | 34 | use crate::{interrupt, pac, Peripheral}; |
| 35 | 35 | ||
| 36 | /// UARTE config. | 36 | /// UARTE config. |
| 37 | #[derive(Clone)] | 37 | #[derive(Clone)] |
| @@ -68,7 +68,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 68 | _phantom: PhantomData<T>, | 68 | _phantom: PhantomData<T>, |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 71 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 72 | unsafe fn on_interrupt() { | 72 | unsafe fn on_interrupt() { |
| 73 | let r = T::regs(); | 73 | let r = T::regs(); |
| 74 | let s = T::state(); | 74 | let s = T::state(); |
| @@ -108,7 +108,7 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 108 | /// Create a new UARTE without hardware flow control | 108 | /// Create a new UARTE without hardware flow control |
| 109 | pub fn new( | 109 | pub fn new( |
| 110 | uarte: impl Peripheral<P = T> + 'd, | 110 | uarte: impl Peripheral<P = T> + 'd, |
| 111 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 111 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 112 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 112 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 113 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 113 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 114 | config: Config, | 114 | config: Config, |
| @@ -120,7 +120,7 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 120 | /// Create a new UARTE with hardware flow control (RTS/CTS) | 120 | /// Create a new UARTE with hardware flow control (RTS/CTS) |
| 121 | pub fn new_with_rtscts( | 121 | pub fn new_with_rtscts( |
| 122 | uarte: impl Peripheral<P = T> + 'd, | 122 | uarte: impl Peripheral<P = T> + 'd, |
| 123 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 123 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 124 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 124 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 125 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 125 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 126 | cts: impl Peripheral<P = impl GpioPin> + 'd, | 126 | cts: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -168,8 +168,8 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 168 | } | 168 | } |
| 169 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | 169 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); |
| 170 | 170 | ||
| 171 | unsafe { T::Interrupt::steal() }.unpend(); | 171 | T::Interrupt::unpend(); |
| 172 | unsafe { T::Interrupt::steal() }.enable(); | 172 | unsafe { T::Interrupt::enable() }; |
| 173 | 173 | ||
| 174 | let hardware_flow_control = match (rts.is_some(), cts.is_some()) { | 174 | let hardware_flow_control = match (rts.is_some(), cts.is_some()) { |
| 175 | (false, false) => false, | 175 | (false, false) => false, |
| @@ -205,50 +205,7 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 205 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | 205 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, |
| 206 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | 206 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, |
| 207 | ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { | 207 | ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { |
| 208 | let timer = Timer::new(timer); | 208 | (self.tx, self.rx.with_idle(timer, ppi_ch1, ppi_ch2)) |
| 209 | |||
| 210 | into_ref!(ppi_ch1, ppi_ch2); | ||
| 211 | |||
| 212 | let r = T::regs(); | ||
| 213 | |||
| 214 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | ||
| 215 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | ||
| 216 | // | ||
| 217 | // We want to stop RX if line is idle for 2 bytes worth of time | ||
| 218 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | ||
| 219 | // This gives us the amount of 16M ticks for 20 bits. | ||
| 220 | let baudrate = r.baudrate.read().baudrate().variant().unwrap(); | ||
| 221 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | ||
| 222 | |||
| 223 | timer.set_frequency(Frequency::F16MHz); | ||
| 224 | timer.cc(0).write(timeout); | ||
| 225 | timer.cc(0).short_compare_clear(); | ||
| 226 | timer.cc(0).short_compare_stop(); | ||
| 227 | |||
| 228 | let mut ppi_ch1 = Ppi::new_one_to_two( | ||
| 229 | ppi_ch1.map_into(), | ||
| 230 | Event::from_reg(&r.events_rxdrdy), | ||
| 231 | timer.task_clear(), | ||
| 232 | timer.task_start(), | ||
| 233 | ); | ||
| 234 | ppi_ch1.enable(); | ||
| 235 | |||
| 236 | let mut ppi_ch2 = Ppi::new_one_to_one( | ||
| 237 | ppi_ch2.map_into(), | ||
| 238 | timer.cc(0).event_compare(), | ||
| 239 | Task::from_reg(&r.tasks_stoprx), | ||
| 240 | ); | ||
| 241 | ppi_ch2.enable(); | ||
| 242 | |||
| 243 | ( | ||
| 244 | self.tx, | ||
| 245 | UarteRxWithIdle { | ||
| 246 | rx: self.rx, | ||
| 247 | timer, | ||
| 248 | ppi_ch1: ppi_ch1, | ||
| 249 | _ppi_ch2: ppi_ch2, | ||
| 250 | }, | ||
| 251 | ) | ||
| 252 | } | 209 | } |
| 253 | 210 | ||
| 254 | /// Return the endtx event for use with PPI | 211 | /// Return the endtx event for use with PPI |
| @@ -313,7 +270,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { | |||
| 313 | /// Create a new tx-only UARTE without hardware flow control | 270 | /// Create a new tx-only UARTE without hardware flow control |
| 314 | pub fn new( | 271 | pub fn new( |
| 315 | uarte: impl Peripheral<P = T> + 'd, | 272 | uarte: impl Peripheral<P = T> + 'd, |
| 316 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 273 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 317 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 274 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 318 | config: Config, | 275 | config: Config, |
| 319 | ) -> Self { | 276 | ) -> Self { |
| @@ -324,7 +281,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { | |||
| 324 | /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) | 281 | /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) |
| 325 | pub fn new_with_rtscts( | 282 | pub fn new_with_rtscts( |
| 326 | uarte: impl Peripheral<P = T> + 'd, | 283 | uarte: impl Peripheral<P = T> + 'd, |
| 327 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 284 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 328 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 285 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 329 | cts: impl Peripheral<P = impl GpioPin> + 'd, | 286 | cts: impl Peripheral<P = impl GpioPin> + 'd, |
| 330 | config: Config, | 287 | config: Config, |
| @@ -358,8 +315,8 @@ impl<'d, T: Instance> UarteTx<'d, T> { | |||
| 358 | let hardware_flow_control = cts.is_some(); | 315 | let hardware_flow_control = cts.is_some(); |
| 359 | configure(r, config, hardware_flow_control); | 316 | configure(r, config, hardware_flow_control); |
| 360 | 317 | ||
| 361 | unsafe { T::Interrupt::steal() }.unpend(); | 318 | T::Interrupt::unpend(); |
| 362 | unsafe { T::Interrupt::steal() }.enable(); | 319 | unsafe { T::Interrupt::enable() }; |
| 363 | 320 | ||
| 364 | let s = T::state(); | 321 | let s = T::state(); |
| 365 | s.tx_rx_refcount.store(1, Ordering::Relaxed); | 322 | s.tx_rx_refcount.store(1, Ordering::Relaxed); |
| @@ -509,7 +466,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { | |||
| 509 | /// Create a new rx-only UARTE without hardware flow control | 466 | /// Create a new rx-only UARTE without hardware flow control |
| 510 | pub fn new( | 467 | pub fn new( |
| 511 | uarte: impl Peripheral<P = T> + 'd, | 468 | uarte: impl Peripheral<P = T> + 'd, |
| 512 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 469 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 513 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 470 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 514 | config: Config, | 471 | config: Config, |
| 515 | ) -> Self { | 472 | ) -> Self { |
| @@ -520,7 +477,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { | |||
| 520 | /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) | 477 | /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) |
| 521 | pub fn new_with_rtscts( | 478 | pub fn new_with_rtscts( |
| 522 | uarte: impl Peripheral<P = T> + 'd, | 479 | uarte: impl Peripheral<P = T> + 'd, |
| 523 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 480 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 524 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 481 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 525 | rts: impl Peripheral<P = impl GpioPin> + 'd, | 482 | rts: impl Peripheral<P = impl GpioPin> + 'd, |
| 526 | config: Config, | 483 | config: Config, |
| @@ -551,8 +508,8 @@ impl<'d, T: Instance> UarteRx<'d, T> { | |||
| 551 | r.psel.txd.write(|w| w.connect().disconnected()); | 508 | r.psel.txd.write(|w| w.connect().disconnected()); |
| 552 | r.psel.cts.write(|w| w.connect().disconnected()); | 509 | r.psel.cts.write(|w| w.connect().disconnected()); |
| 553 | 510 | ||
| 554 | unsafe { T::Interrupt::steal() }.unpend(); | 511 | T::Interrupt::unpend(); |
| 555 | unsafe { T::Interrupt::steal() }.enable(); | 512 | unsafe { T::Interrupt::enable() }; |
| 556 | 513 | ||
| 557 | let hardware_flow_control = rts.is_some(); | 514 | let hardware_flow_control = rts.is_some(); |
| 558 | configure(r, config, hardware_flow_control); | 515 | configure(r, config, hardware_flow_control); |
| @@ -563,6 +520,56 @@ impl<'d, T: Instance> UarteRx<'d, T> { | |||
| 563 | Self { _p: uarte } | 520 | Self { _p: uarte } |
| 564 | } | 521 | } |
| 565 | 522 | ||
| 523 | /// Upgrade to an instance that supports idle line detection. | ||
| 524 | pub fn with_idle<U: TimerInstance>( | ||
| 525 | self, | ||
| 526 | timer: impl Peripheral<P = U> + 'd, | ||
| 527 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 528 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 529 | ) -> UarteRxWithIdle<'d, T, U> { | ||
| 530 | let timer = Timer::new(timer); | ||
| 531 | |||
| 532 | into_ref!(ppi_ch1, ppi_ch2); | ||
| 533 | |||
| 534 | let r = T::regs(); | ||
| 535 | |||
| 536 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | ||
| 537 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | ||
| 538 | // | ||
| 539 | // We want to stop RX if line is idle for 2 bytes worth of time | ||
| 540 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | ||
| 541 | // This gives us the amount of 16M ticks for 20 bits. | ||
| 542 | let baudrate = r.baudrate.read().baudrate().variant().unwrap(); | ||
| 543 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | ||
| 544 | |||
| 545 | timer.set_frequency(Frequency::F16MHz); | ||
| 546 | timer.cc(0).write(timeout); | ||
| 547 | timer.cc(0).short_compare_clear(); | ||
| 548 | timer.cc(0).short_compare_stop(); | ||
| 549 | |||
| 550 | let mut ppi_ch1 = Ppi::new_one_to_two( | ||
| 551 | ppi_ch1.map_into(), | ||
| 552 | Event::from_reg(&r.events_rxdrdy), | ||
| 553 | timer.task_clear(), | ||
| 554 | timer.task_start(), | ||
| 555 | ); | ||
| 556 | ppi_ch1.enable(); | ||
| 557 | |||
| 558 | let mut ppi_ch2 = Ppi::new_one_to_one( | ||
| 559 | ppi_ch2.map_into(), | ||
| 560 | timer.cc(0).event_compare(), | ||
| 561 | Task::from_reg(&r.tasks_stoprx), | ||
| 562 | ); | ||
| 563 | ppi_ch2.enable(); | ||
| 564 | |||
| 565 | UarteRxWithIdle { | ||
| 566 | rx: self, | ||
| 567 | timer, | ||
| 568 | ppi_ch1: ppi_ch1, | ||
| 569 | _ppi_ch2: ppi_ch2, | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 566 | /// Read bytes until the buffer is filled. | 573 | /// Read bytes until the buffer is filled. |
| 567 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 574 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 568 | if buffer.len() == 0 { | 575 | if buffer.len() == 0 { |
| @@ -889,7 +896,7 @@ pub(crate) mod sealed { | |||
| 889 | /// UARTE peripheral instance. | 896 | /// UARTE peripheral instance. |
| 890 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 897 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 891 | /// Interrupt for this peripheral. | 898 | /// Interrupt for this peripheral. |
| 892 | type Interrupt: Interrupt; | 899 | type Interrupt: interrupt::typelevel::Interrupt; |
| 893 | } | 900 | } |
| 894 | 901 | ||
| 895 | macro_rules! impl_uarte { | 902 | macro_rules! impl_uarte { |
| @@ -908,7 +915,7 @@ macro_rules! impl_uarte { | |||
| 908 | } | 915 | } |
| 909 | } | 916 | } |
| 910 | impl crate::uarte::Instance for peripherals::$type { | 917 | impl crate::uarte::Instance for peripherals::$type { |
| 911 | type Interrupt = crate::interrupt::$irq; | 918 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 912 | } | 919 | } |
| 913 | }; | 920 | }; |
| 914 | } | 921 | } |
diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs index c1f3f48cb..76cf40ac7 100644 --- a/embassy-nrf/src/usb/mod.rs +++ b/embassy-nrf/src/usb/mod.rs | |||
| @@ -18,9 +18,9 @@ use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo | |||
| 18 | use pac::usbd::RegisterBlock; | 18 | use pac::usbd::RegisterBlock; |
| 19 | 19 | ||
| 20 | use self::vbus_detect::VbusDetect; | 20 | use self::vbus_detect::VbusDetect; |
| 21 | use crate::interrupt::{self, Interrupt, InterruptExt}; | 21 | use crate::interrupt::typelevel::Interrupt; |
| 22 | use crate::util::slice_in_ram; | 22 | use crate::util::slice_in_ram; |
| 23 | use crate::{pac, Peripheral}; | 23 | use crate::{interrupt, pac, Peripheral}; |
| 24 | 24 | ||
| 25 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 25 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 26 | static BUS_WAKER: AtomicWaker = NEW_AW; | 26 | static BUS_WAKER: AtomicWaker = NEW_AW; |
| @@ -34,7 +34,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 34 | _phantom: PhantomData<T>, | 34 | _phantom: PhantomData<T>, |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 37 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 38 | unsafe fn on_interrupt() { | 38 | unsafe fn on_interrupt() { |
| 39 | let regs = T::regs(); | 39 | let regs = T::regs(); |
| 40 | 40 | ||
| @@ -98,13 +98,13 @@ impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> { | |||
| 98 | /// Create a new USB driver. | 98 | /// Create a new USB driver. |
| 99 | pub fn new( | 99 | pub fn new( |
| 100 | usb: impl Peripheral<P = T> + 'd, | 100 | usb: impl Peripheral<P = T> + 'd, |
| 101 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 101 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 102 | vbus_detect: V, | 102 | vbus_detect: V, |
| 103 | ) -> Self { | 103 | ) -> Self { |
| 104 | into_ref!(usb); | 104 | into_ref!(usb); |
| 105 | 105 | ||
| 106 | unsafe { T::Interrupt::steal() }.unpend(); | 106 | T::Interrupt::unpend(); |
| 107 | unsafe { T::Interrupt::steal() }.enable(); | 107 | unsafe { T::Interrupt::enable() }; |
| 108 | 108 | ||
| 109 | Self { | 109 | Self { |
| 110 | _p: usb, | 110 | _p: usb, |
| @@ -804,7 +804,7 @@ pub(crate) mod sealed { | |||
| 804 | /// USB peripheral instance. | 804 | /// USB peripheral instance. |
| 805 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 805 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 806 | /// Interrupt for this peripheral. | 806 | /// Interrupt for this peripheral. |
| 807 | type Interrupt: Interrupt; | 807 | type Interrupt: interrupt::typelevel::Interrupt; |
| 808 | } | 808 | } |
| 809 | 809 | ||
| 810 | macro_rules! impl_usb { | 810 | macro_rules! impl_usb { |
| @@ -815,7 +815,7 @@ macro_rules! impl_usb { | |||
| 815 | } | 815 | } |
| 816 | } | 816 | } |
| 817 | impl crate::usb::Instance for peripherals::$type { | 817 | impl crate::usb::Instance for peripherals::$type { |
| 818 | type Interrupt = crate::interrupt::$irq; | 818 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 819 | } | 819 | } |
| 820 | }; | 820 | }; |
| 821 | } | 821 | } |
diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs index cecd4c595..a05e5aa52 100644 --- a/embassy-nrf/src/usb/vbus_detect.rs +++ b/embassy-nrf/src/usb/vbus_detect.rs | |||
| @@ -7,8 +7,8 @@ use core::task::Poll; | |||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | 8 | ||
| 9 | use super::BUS_WAKER; | 9 | use super::BUS_WAKER; |
| 10 | use crate::interrupt::{self, Interrupt, InterruptExt}; | 10 | use crate::interrupt::typelevel::Interrupt; |
| 11 | use crate::pac; | 11 | use crate::{interrupt, pac}; |
| 12 | 12 | ||
| 13 | /// Trait for detecting USB VBUS power. | 13 | /// Trait for detecting USB VBUS power. |
| 14 | /// | 14 | /// |
| @@ -29,9 +29,9 @@ pub trait VbusDetect { | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | #[cfg(not(feature = "_nrf5340"))] | 31 | #[cfg(not(feature = "_nrf5340"))] |
| 32 | type UsbRegIrq = interrupt::POWER_CLOCK; | 32 | type UsbRegIrq = interrupt::typelevel::POWER_CLOCK; |
| 33 | #[cfg(feature = "_nrf5340")] | 33 | #[cfg(feature = "_nrf5340")] |
| 34 | type UsbRegIrq = interrupt::USBREGULATOR; | 34 | type UsbRegIrq = interrupt::typelevel::USBREGULATOR; |
| 35 | 35 | ||
| 36 | #[cfg(not(feature = "_nrf5340"))] | 36 | #[cfg(not(feature = "_nrf5340"))] |
| 37 | type UsbRegPeri = pac::POWER; | 37 | type UsbRegPeri = pac::POWER; |
| @@ -43,7 +43,7 @@ pub struct InterruptHandler { | |||
| 43 | _private: (), | 43 | _private: (), |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | impl interrupt::Handler<UsbRegIrq> for InterruptHandler { | 46 | impl interrupt::typelevel::Handler<UsbRegIrq> for InterruptHandler { |
| 47 | unsafe fn on_interrupt() { | 47 | unsafe fn on_interrupt() { |
| 48 | let regs = unsafe { &*UsbRegPeri::ptr() }; | 48 | let regs = unsafe { &*UsbRegPeri::ptr() }; |
| 49 | 49 | ||
| @@ -77,11 +77,11 @@ static POWER_WAKER: AtomicWaker = AtomicWaker::new(); | |||
| 77 | 77 | ||
| 78 | impl HardwareVbusDetect { | 78 | impl HardwareVbusDetect { |
| 79 | /// Create a new `VbusDetectNative`. | 79 | /// Create a new `VbusDetectNative`. |
| 80 | pub fn new(_irq: impl interrupt::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self { | 80 | pub fn new(_irq: impl interrupt::typelevel::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self { |
| 81 | let regs = unsafe { &*UsbRegPeri::ptr() }; | 81 | let regs = unsafe { &*UsbRegPeri::ptr() }; |
| 82 | 82 | ||
| 83 | unsafe { UsbRegIrq::steal() }.unpend(); | 83 | UsbRegIrq::unpend(); |
| 84 | unsafe { UsbRegIrq::steal() }.enable(); | 84 | unsafe { UsbRegIrq::enable() }; |
| 85 | 85 | ||
| 86 | regs.intenset | 86 | regs.intenset |
| 87 | .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); | 87 | .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); |
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index e032dfdae..49aa6a4d5 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml | |||
| @@ -13,7 +13,8 @@ flavors = [ | |||
| 13 | ] | 13 | ] |
| 14 | 14 | ||
| 15 | [features] | 15 | [features] |
| 16 | default = [ "rp-pac/rt" ] | 16 | default = [ "rt" ] |
| 17 | rt = [ "rp-pac/rt" ] | ||
| 17 | 18 | ||
| 18 | defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"] | 19 | defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"] |
| 19 | 20 | ||
| @@ -41,8 +42,13 @@ boot2-ram-memcpy = [] | |||
| 41 | boot2-w25q080 = [] | 42 | boot2-w25q080 = [] |
| 42 | boot2-w25x10cl = [] | 43 | boot2-w25x10cl = [] |
| 43 | 44 | ||
| 45 | # Indicate code is running from RAM. | ||
| 46 | # Set this if all code is in RAM, and the cores never access memory-mapped flash memory through XIP. | ||
| 47 | # This allows the flash driver to not force pausing execution on both cores when doing flash operations. | ||
| 48 | run-from-ram = [] | ||
| 49 | |||
| 44 | # Enable nightly-only features | 50 | # Enable nightly-only features |
| 45 | nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"] | 51 | nightly = ["embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"] |
| 46 | 52 | ||
| 47 | # Implement embedded-hal 1.0 alpha traits. | 53 | # Implement embedded-hal 1.0 alpha traits. |
| 48 | # Implement embedded-hal-async traits if `nightly` is set as well. | 54 | # Implement embedded-hal-async traits if `nightly` is set as well. |
| @@ -50,11 +56,9 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"] | |||
| 50 | 56 | ||
| 51 | [dependencies] | 57 | [dependencies] |
| 52 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } | 58 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } |
| 53 | embassy-executor = { version = "0.2.0", path = "../embassy-executor" } | ||
| 54 | embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } | 59 | embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } |
| 55 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | 60 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } |
| 56 | embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]} | 61 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-2"] } |
| 57 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } | ||
| 58 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } | 62 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } |
| 59 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } | 63 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } |
| 60 | atomic-polyfill = "1.0.1" | 64 | atomic-polyfill = "1.0.1" |
| @@ -72,7 +76,7 @@ embedded-storage = { version = "0.3" } | |||
| 72 | rand_core = "0.6.4" | 76 | rand_core = "0.6.4" |
| 73 | fixed = "1.23.1" | 77 | fixed = "1.23.1" |
| 74 | 78 | ||
| 75 | rp-pac = { version = "4" } | 79 | rp-pac = { version = "5" } |
| 76 | 80 | ||
| 77 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 81 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 78 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} | 82 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} |
| @@ -85,5 +89,5 @@ pio = {version= "0.2.1" } | |||
| 85 | rp2040-boot2 = "0.3" | 89 | rp2040-boot2 = "0.3" |
| 86 | 90 | ||
| 87 | [dev-dependencies] | 91 | [dev-dependencies] |
| 88 | embassy-executor = { version = "0.2.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } | 92 | embassy-executor = { version = "0.2.0", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] } |
| 89 | static_cell = "1.0" | 93 | static_cell = "1.1" |
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 59c7a47ce..b96d5a4a8 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs | |||
| @@ -3,14 +3,14 @@ use core::marker::PhantomData; | |||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | 3 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use embassy_cortex_m::interrupt::{Binding, Interrupt}; | ||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 6 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use embedded_hal_02::adc::{Channel, OneShot}; | 7 | use embedded_hal_02::adc::{Channel, OneShot}; |
| 9 | 8 | ||
| 10 | use crate::gpio::Pin; | 9 | use crate::gpio::Pin; |
| 11 | use crate::interrupt::{self, InterruptExt, ADC_IRQ_FIFO}; | 10 | use crate::interrupt::typelevel::Binding; |
| 11 | use crate::interrupt::InterruptExt; | ||
| 12 | use crate::peripherals::ADC; | 12 | use crate::peripherals::ADC; |
| 13 | use crate::{pac, peripherals, Peripheral}; | 13 | use crate::{interrupt, pac, peripherals, Peripheral}; |
| 14 | static WAKER: AtomicWaker = AtomicWaker::new(); | 14 | static WAKER: AtomicWaker = AtomicWaker::new(); |
| 15 | 15 | ||
| 16 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 16 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| @@ -47,105 +47,91 @@ impl<'d> Adc<'d> { | |||
| 47 | 47 | ||
| 48 | pub fn new( | 48 | pub fn new( |
| 49 | _inner: impl Peripheral<P = ADC> + 'd, | 49 | _inner: impl Peripheral<P = ADC> + 'd, |
| 50 | _irq: impl Binding<ADC_IRQ_FIFO, InterruptHandler>, | 50 | _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>, |
| 51 | _config: Config, | 51 | _config: Config, |
| 52 | ) -> Self { | 52 | ) -> Self { |
| 53 | unsafe { | 53 | let reset = Self::reset(); |
| 54 | let reset = Self::reset(); | 54 | crate::reset::reset(reset); |
| 55 | crate::reset::reset(reset); | 55 | crate::reset::unreset_wait(reset); |
| 56 | crate::reset::unreset_wait(reset); | 56 | let r = Self::regs(); |
| 57 | let r = Self::regs(); | 57 | // Enable ADC |
| 58 | // Enable ADC | 58 | r.cs().write(|w| w.set_en(true)); |
| 59 | r.cs().write(|w| w.set_en(true)); | 59 | // Wait for ADC ready |
| 60 | // Wait for ADC ready | 60 | while !r.cs().read().ready() {} |
| 61 | while !r.cs().read().ready() {} | ||
| 62 | } | ||
| 63 | 61 | ||
| 64 | // Setup IRQ | 62 | // Setup IRQ |
| 65 | unsafe { | 63 | interrupt::ADC_IRQ_FIFO.unpend(); |
| 66 | ADC_IRQ_FIFO::steal().unpend(); | 64 | unsafe { interrupt::ADC_IRQ_FIFO.enable() }; |
| 67 | ADC_IRQ_FIFO::steal().enable(); | ||
| 68 | }; | ||
| 69 | 65 | ||
| 70 | Self { phantom: PhantomData } | 66 | Self { phantom: PhantomData } |
| 71 | } | 67 | } |
| 72 | 68 | ||
| 73 | async fn wait_for_ready() { | 69 | async fn wait_for_ready() { |
| 74 | let r = Self::regs(); | 70 | let r = Self::regs(); |
| 75 | unsafe { | 71 | r.inte().write(|w| w.set_fifo(true)); |
| 76 | r.inte().write(|w| w.set_fifo(true)); | 72 | compiler_fence(Ordering::SeqCst); |
| 77 | compiler_fence(Ordering::SeqCst); | 73 | poll_fn(|cx| { |
| 78 | poll_fn(|cx| { | 74 | WAKER.register(cx.waker()); |
| 79 | WAKER.register(cx.waker()); | 75 | if r.cs().read().ready() { |
| 80 | if r.cs().read().ready() { | 76 | return Poll::Ready(()); |
| 81 | return Poll::Ready(()); | 77 | } |
| 82 | } | 78 | Poll::Pending |
| 83 | Poll::Pending | 79 | }) |
| 84 | }) | 80 | .await; |
| 85 | .await; | ||
| 86 | } | ||
| 87 | } | 81 | } |
| 88 | 82 | ||
| 89 | pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { | 83 | pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { |
| 90 | let r = Self::regs(); | 84 | let r = Self::regs(); |
| 91 | unsafe { | 85 | // disable pull-down and pull-up resistors |
| 92 | // disable pull-down and pull-up resistors | 86 | // pull-down resistors are enabled by default |
| 93 | // pull-down resistors are enabled by default | 87 | pin.pad_ctrl().modify(|w| { |
| 94 | pin.pad_ctrl().modify(|w| { | 88 | w.set_ie(true); |
| 95 | w.set_ie(true); | 89 | let (pu, pd) = (false, false); |
| 96 | let (pu, pd) = (false, false); | 90 | w.set_pue(pu); |
| 97 | w.set_pue(pu); | 91 | w.set_pde(pd); |
| 98 | w.set_pde(pd); | 92 | }); |
| 99 | }); | 93 | r.cs().modify(|w| { |
| 100 | r.cs().modify(|w| { | 94 | w.set_ainsel(PIN::channel()); |
| 101 | w.set_ainsel(PIN::channel()); | 95 | w.set_start_once(true) |
| 102 | w.set_start_once(true) | 96 | }); |
| 103 | }); | 97 | Self::wait_for_ready().await; |
| 104 | Self::wait_for_ready().await; | 98 | r.result().read().result().into() |
| 105 | r.result().read().result().into() | ||
| 106 | } | ||
| 107 | } | 99 | } |
| 108 | 100 | ||
| 109 | pub async fn read_temperature(&mut self) -> u16 { | 101 | pub async fn read_temperature(&mut self) -> u16 { |
| 110 | let r = Self::regs(); | 102 | let r = Self::regs(); |
| 111 | unsafe { | 103 | r.cs().modify(|w| w.set_ts_en(true)); |
| 112 | r.cs().modify(|w| w.set_ts_en(true)); | 104 | if !r.cs().read().ready() { |
| 113 | if !r.cs().read().ready() { | ||
| 114 | Self::wait_for_ready().await; | ||
| 115 | } | ||
| 116 | r.cs().modify(|w| { | ||
| 117 | w.set_ainsel(4); | ||
| 118 | w.set_start_once(true) | ||
| 119 | }); | ||
| 120 | Self::wait_for_ready().await; | 105 | Self::wait_for_ready().await; |
| 121 | r.result().read().result().into() | ||
| 122 | } | 106 | } |
| 107 | r.cs().modify(|w| { | ||
| 108 | w.set_ainsel(4); | ||
| 109 | w.set_start_once(true) | ||
| 110 | }); | ||
| 111 | Self::wait_for_ready().await; | ||
| 112 | r.result().read().result().into() | ||
| 123 | } | 113 | } |
| 124 | 114 | ||
| 125 | pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { | 115 | pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { |
| 126 | let r = Self::regs(); | 116 | let r = Self::regs(); |
| 127 | unsafe { | 117 | r.cs().modify(|w| { |
| 128 | r.cs().modify(|w| { | 118 | w.set_ainsel(PIN::channel()); |
| 129 | w.set_ainsel(PIN::channel()); | 119 | w.set_start_once(true) |
| 130 | w.set_start_once(true) | 120 | }); |
| 131 | }); | 121 | while !r.cs().read().ready() {} |
| 132 | while !r.cs().read().ready() {} | 122 | r.result().read().result().into() |
| 133 | r.result().read().result().into() | ||
| 134 | } | ||
| 135 | } | 123 | } |
| 136 | 124 | ||
| 137 | pub fn blocking_read_temperature(&mut self) -> u16 { | 125 | pub fn blocking_read_temperature(&mut self) -> u16 { |
| 138 | let r = Self::regs(); | 126 | let r = Self::regs(); |
| 139 | unsafe { | 127 | r.cs().modify(|w| w.set_ts_en(true)); |
| 140 | r.cs().modify(|w| w.set_ts_en(true)); | 128 | while !r.cs().read().ready() {} |
| 141 | while !r.cs().read().ready() {} | 129 | r.cs().modify(|w| { |
| 142 | r.cs().modify(|w| { | 130 | w.set_ainsel(4); |
| 143 | w.set_ainsel(4); | 131 | w.set_start_once(true) |
| 144 | w.set_start_once(true) | 132 | }); |
| 145 | }); | 133 | while !r.cs().read().ready() {} |
| 146 | while !r.cs().read().ready() {} | 134 | r.result().read().result().into() |
| 147 | r.result().read().result().into() | ||
| 148 | } | ||
| 149 | } | 135 | } |
| 150 | } | 136 | } |
| 151 | 137 | ||
| @@ -164,7 +150,7 @@ pub struct InterruptHandler { | |||
| 164 | _empty: (), | 150 | _empty: (), |
| 165 | } | 151 | } |
| 166 | 152 | ||
| 167 | impl interrupt::Handler<ADC_IRQ_FIFO> for InterruptHandler { | 153 | impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler { |
| 168 | unsafe fn on_interrupt() { | 154 | unsafe fn on_interrupt() { |
| 169 | let r = Adc::regs(); | 155 | let r = Adc::regs(); |
| 170 | r.inte().write(|w| w.set_fifo(false)); | 156 | r.inte().write(|w| w.set_fifo(false)); |
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 67439fda3..4c6223107 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs | |||
| @@ -542,7 +542,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { | |||
| 542 | reset::unreset_wait(peris); | 542 | reset::unreset_wait(peris); |
| 543 | } | 543 | } |
| 544 | 544 | ||
| 545 | unsafe fn configure_rosc(config: RoscConfig) -> u32 { | 545 | fn configure_rosc(config: RoscConfig) -> u32 { |
| 546 | let p = pac::ROSC; | 546 | let p = pac::ROSC; |
| 547 | 547 | ||
| 548 | p.freqa().write(|w| { | 548 | p.freqa().write(|w| { |
| @@ -620,7 +620,7 @@ pub fn clk_rtc_freq() -> u16 { | |||
| 620 | CLOCKS.rtc.load(Ordering::Relaxed) | 620 | CLOCKS.rtc.load(Ordering::Relaxed) |
| 621 | } | 621 | } |
| 622 | 622 | ||
| 623 | unsafe fn start_xosc(crystal_hz: u32) { | 623 | fn start_xosc(crystal_hz: u32) { |
| 624 | pac::XOSC | 624 | pac::XOSC |
| 625 | .ctrl() | 625 | .ctrl() |
| 626 | .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); | 626 | .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); |
| @@ -635,7 +635,7 @@ unsafe fn start_xosc(crystal_hz: u32) { | |||
| 635 | } | 635 | } |
| 636 | 636 | ||
| 637 | #[inline(always)] | 637 | #[inline(always)] |
| 638 | unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { | 638 | fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { |
| 639 | let ref_freq = input_freq / config.refdiv as u32; | 639 | let ref_freq = input_freq / config.refdiv as u32; |
| 640 | assert!(config.fbdiv >= 16 && config.fbdiv <= 320); | 640 | assert!(config.fbdiv >= 16 && config.fbdiv <= 320); |
| 641 | assert!(config.post_div1 >= 1 && config.post_div1 <= 7); | 641 | assert!(config.post_div1 >= 1 && config.post_div1 <= 7); |
| @@ -700,9 +700,7 @@ impl<'d, T: Pin> Gpin<'d, T> { | |||
| 700 | pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { | 700 | pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { |
| 701 | into_ref!(gpin); | 701 | into_ref!(gpin); |
| 702 | 702 | ||
| 703 | unsafe { | 703 | gpin.io().ctrl().write(|w| w.set_funcsel(0x08)); |
| 704 | gpin.io().ctrl().write(|w| w.set_funcsel(0x08)); | ||
| 705 | } | ||
| 706 | 704 | ||
| 707 | Gpin { | 705 | Gpin { |
| 708 | gpin: gpin.map_into(), | 706 | gpin: gpin.map_into(), |
| @@ -717,12 +715,10 @@ impl<'d, T: Pin> Gpin<'d, T> { | |||
| 717 | 715 | ||
| 718 | impl<'d, T: Pin> Drop for Gpin<'d, T> { | 716 | impl<'d, T: Pin> Drop for Gpin<'d, T> { |
| 719 | fn drop(&mut self) { | 717 | fn drop(&mut self) { |
| 720 | unsafe { | 718 | self.gpin |
| 721 | self.gpin | 719 | .io() |
| 722 | .io() | 720 | .ctrl() |
| 723 | .ctrl() | 721 | .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); |
| 724 | .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); | ||
| 725 | } | ||
| 726 | } | 722 | } |
| 727 | } | 723 | } |
| 728 | 724 | ||
| @@ -768,53 +764,43 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||
| 768 | pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { | 764 | pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { |
| 769 | into_ref!(gpout); | 765 | into_ref!(gpout); |
| 770 | 766 | ||
| 771 | unsafe { | 767 | gpout.io().ctrl().write(|w| w.set_funcsel(0x08)); |
| 772 | gpout.io().ctrl().write(|w| w.set_funcsel(0x08)); | ||
| 773 | } | ||
| 774 | 768 | ||
| 775 | Self { gpout } | 769 | Self { gpout } |
| 776 | } | 770 | } |
| 777 | 771 | ||
| 778 | pub fn set_div(&self, int: u32, frac: u8) { | 772 | pub fn set_div(&self, int: u32, frac: u8) { |
| 779 | unsafe { | 773 | let c = pac::CLOCKS; |
| 780 | let c = pac::CLOCKS; | 774 | c.clk_gpout_div(self.gpout.number()).write(|w| { |
| 781 | c.clk_gpout_div(self.gpout.number()).write(|w| { | 775 | w.set_int(int); |
| 782 | w.set_int(int); | 776 | w.set_frac(frac); |
| 783 | w.set_frac(frac); | 777 | }); |
| 784 | }); | ||
| 785 | } | ||
| 786 | } | 778 | } |
| 787 | 779 | ||
| 788 | pub fn set_src(&self, src: GpoutSrc) { | 780 | pub fn set_src(&self, src: GpoutSrc) { |
| 789 | unsafe { | 781 | let c = pac::CLOCKS; |
| 790 | let c = pac::CLOCKS; | 782 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { |
| 791 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { | 783 | w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _)); |
| 792 | w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _)); | 784 | }); |
| 793 | }); | ||
| 794 | } | ||
| 795 | } | 785 | } |
| 796 | 786 | ||
| 797 | pub fn enable(&self) { | 787 | pub fn enable(&self) { |
| 798 | unsafe { | 788 | let c = pac::CLOCKS; |
| 799 | let c = pac::CLOCKS; | 789 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { |
| 800 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { | 790 | w.set_enable(true); |
| 801 | w.set_enable(true); | 791 | }); |
| 802 | }); | ||
| 803 | } | ||
| 804 | } | 792 | } |
| 805 | 793 | ||
| 806 | pub fn disable(&self) { | 794 | pub fn disable(&self) { |
| 807 | unsafe { | 795 | let c = pac::CLOCKS; |
| 808 | let c = pac::CLOCKS; | 796 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { |
| 809 | c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { | 797 | w.set_enable(false); |
| 810 | w.set_enable(false); | 798 | }); |
| 811 | }); | ||
| 812 | } | ||
| 813 | } | 799 | } |
| 814 | 800 | ||
| 815 | pub fn get_freq(&self) -> u32 { | 801 | pub fn get_freq(&self) -> u32 { |
| 816 | let c = pac::CLOCKS; | 802 | let c = pac::CLOCKS; |
| 817 | let src = unsafe { c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc() }; | 803 | let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc(); |
| 818 | 804 | ||
| 819 | let base = match src { | 805 | let base = match src { |
| 820 | ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), | 806 | ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), |
| @@ -831,7 +817,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||
| 831 | _ => unreachable!(), | 817 | _ => unreachable!(), |
| 832 | }; | 818 | }; |
| 833 | 819 | ||
| 834 | let div = unsafe { c.clk_gpout_div(self.gpout.number()).read() }; | 820 | let div = c.clk_gpout_div(self.gpout.number()).read(); |
| 835 | let int = if div.int() == 0 { 65536 } else { div.int() } as u64; | 821 | let int = if div.int() == 0 { 65536 } else { div.int() } as u64; |
| 836 | let frac = div.frac() as u64; | 822 | let frac = div.frac() as u64; |
| 837 | 823 | ||
| @@ -842,12 +828,10 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||
| 842 | impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { | 828 | impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { |
| 843 | fn drop(&mut self) { | 829 | fn drop(&mut self) { |
| 844 | self.disable(); | 830 | self.disable(); |
| 845 | unsafe { | 831 | self.gpout |
| 846 | self.gpout | 832 | .io() |
| 847 | .io() | 833 | .ctrl() |
| 848 | .ctrl() | 834 | .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); |
| 849 | .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); | ||
| 850 | } | ||
| 851 | } | 835 | } |
| 852 | } | 836 | } |
| 853 | 837 | ||
| @@ -864,7 +848,7 @@ impl RoscRng { | |||
| 864 | let mut acc = 0; | 848 | let mut acc = 0; |
| 865 | for _ in 0..u8::BITS { | 849 | for _ in 0..u8::BITS { |
| 866 | acc <<= 1; | 850 | acc <<= 1; |
| 867 | acc |= unsafe { random_reg.read().randombit() as u8 }; | 851 | acc |= random_reg.read().randombit() as u8; |
| 868 | } | 852 | } |
| 869 | acc | 853 | acc |
| 870 | } | 854 | } |
diff --git a/embassy-rp/src/critical_section_impl.rs b/embassy-rp/src/critical_section_impl.rs index ce284c856..d233e6fab 100644 --- a/embassy-rp/src/critical_section_impl.rs +++ b/embassy-rp/src/critical_section_impl.rs | |||
| @@ -103,14 +103,11 @@ where | |||
| 103 | /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is | 103 | /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is |
| 104 | /// already in use somewhere else. | 104 | /// already in use somewhere else. |
| 105 | pub fn try_claim() -> Option<Self> { | 105 | pub fn try_claim() -> Option<Self> { |
| 106 | // Safety: We're only reading from this register | 106 | let lock = pac::SIO.spinlock(N).read(); |
| 107 | unsafe { | 107 | if lock > 0 { |
| 108 | let lock = pac::SIO.spinlock(N).read(); | 108 | Some(Self(core::marker::PhantomData)) |
| 109 | if lock > 0 { | 109 | } else { |
| 110 | Some(Self(core::marker::PhantomData)) | 110 | None |
| 111 | } else { | ||
| 112 | None | ||
| 113 | } | ||
| 114 | } | 111 | } |
| 115 | } | 112 | } |
| 116 | 113 | ||
| @@ -120,10 +117,8 @@ where | |||
| 120 | /// | 117 | /// |
| 121 | /// Only call this function if you hold the spin-lock. | 118 | /// Only call this function if you hold the spin-lock. |
| 122 | pub unsafe fn release() { | 119 | pub unsafe fn release() { |
| 123 | unsafe { | 120 | // Write (any value): release the lock |
| 124 | // Write (any value): release the lock | 121 | pac::SIO.spinlock(N).write_value(1); |
| 125 | pac::SIO.spinlock(N).write_value(1); | ||
| 126 | } | ||
| 127 | } | 122 | } |
| 128 | } | 123 | } |
| 129 | 124 | ||
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index ba07a88df..1a458778c 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs | |||
| @@ -4,16 +4,17 @@ use core::pin::Pin; | |||
| 4 | use core::sync::atomic::{compiler_fence, Ordering}; | 4 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 5 | use core::task::{Context, Poll}; | 5 | use core::task::{Context, Poll}; |
| 6 | 6 | ||
| 7 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 8 | use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; | 7 | use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use embassy_sync::waitqueue::AtomicWaker; |
| 10 | use pac::dma::vals::DataSize; | 9 | use pac::dma::vals::DataSize; |
| 11 | 10 | ||
| 11 | use crate::interrupt::InterruptExt; | ||
| 12 | use crate::pac::dma::vals; | 12 | use crate::pac::dma::vals; |
| 13 | use crate::{interrupt, pac, peripherals}; | 13 | use crate::{interrupt, pac, peripherals}; |
| 14 | 14 | ||
| 15 | #[cfg(feature = "rt")] | ||
| 15 | #[interrupt] | 16 | #[interrupt] |
| 16 | unsafe fn DMA_IRQ_0() { | 17 | fn DMA_IRQ_0() { |
| 17 | let ints0 = pac::DMA.ints0().read().ints0(); | 18 | let ints0 = pac::DMA.ints0().read().ints0(); |
| 18 | for channel in 0..CHANNEL_COUNT { | 19 | for channel in 0..CHANNEL_COUNT { |
| 19 | let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read(); | 20 | let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read(); |
| @@ -29,13 +30,12 @@ unsafe fn DMA_IRQ_0() { | |||
| 29 | } | 30 | } |
| 30 | 31 | ||
| 31 | pub(crate) unsafe fn init() { | 32 | pub(crate) unsafe fn init() { |
| 32 | let irq = interrupt::DMA_IRQ_0::steal(); | 33 | interrupt::DMA_IRQ_0.disable(); |
| 33 | irq.disable(); | 34 | interrupt::DMA_IRQ_0.set_priority(interrupt::Priority::P3); |
| 34 | irq.set_priority(interrupt::Priority::P3); | ||
| 35 | 35 | ||
| 36 | pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF)); | 36 | pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF)); |
| 37 | 37 | ||
| 38 | irq.enable(); | 38 | interrupt::DMA_IRQ_0.enable(); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | pub unsafe fn read<'a, C: Channel, W: Word>( | 41 | pub unsafe fn read<'a, C: Channel, W: Word>( |
| @@ -76,16 +76,17 @@ pub unsafe fn write<'a, C: Channel, W: Word>( | |||
| 76 | ) | 76 | ) |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | static DUMMY: u32 = 0; | ||
| 80 | |||
| 79 | pub unsafe fn write_repeated<'a, C: Channel, W: Word>( | 81 | pub unsafe fn write_repeated<'a, C: Channel, W: Word>( |
| 80 | ch: impl Peripheral<P = C> + 'a, | 82 | ch: impl Peripheral<P = C> + 'a, |
| 81 | to: *mut W, | 83 | to: *mut W, |
| 82 | len: usize, | 84 | len: usize, |
| 83 | dreq: u8, | 85 | dreq: u8, |
| 84 | ) -> Transfer<'a, C> { | 86 | ) -> Transfer<'a, C> { |
| 85 | let dummy: u32 = 0; | ||
| 86 | copy_inner( | 87 | copy_inner( |
| 87 | ch, | 88 | ch, |
| 88 | &dummy as *const u32, | 89 | &DUMMY as *const u32, |
| 89 | to as *mut u32, | 90 | to as *mut u32, |
| 90 | len, | 91 | len, |
| 91 | W::size(), | 92 | W::size(), |
| @@ -127,28 +128,26 @@ fn copy_inner<'a, C: Channel>( | |||
| 127 | ) -> Transfer<'a, C> { | 128 | ) -> Transfer<'a, C> { |
| 128 | into_ref!(ch); | 129 | into_ref!(ch); |
| 129 | 130 | ||
| 130 | unsafe { | 131 | let p = ch.regs(); |
| 131 | let p = ch.regs(); | ||
| 132 | 132 | ||
| 133 | p.read_addr().write_value(from as u32); | 133 | p.read_addr().write_value(from as u32); |
| 134 | p.write_addr().write_value(to as u32); | 134 | p.write_addr().write_value(to as u32); |
| 135 | p.trans_count().write_value(len as u32); | 135 | p.trans_count().write_value(len as u32); |
| 136 | 136 | ||
| 137 | compiler_fence(Ordering::SeqCst); | 137 | compiler_fence(Ordering::SeqCst); |
| 138 | 138 | ||
| 139 | p.ctrl_trig().write(|w| { | 139 | p.ctrl_trig().write(|w| { |
| 140 | // TODO: Add all DREQ options to pac vals::TreqSel, and use | 140 | // TODO: Add all DREQ options to pac vals::TreqSel, and use |
| 141 | // `set_treq:sel` | 141 | // `set_treq:sel` |
| 142 | w.0 = ((dreq as u32) & 0x3f) << 15usize; | 142 | w.0 = ((dreq as u32) & 0x3f) << 15usize; |
| 143 | w.set_data_size(data_size); | 143 | w.set_data_size(data_size); |
| 144 | w.set_incr_read(incr_read); | 144 | w.set_incr_read(incr_read); |
| 145 | w.set_incr_write(incr_write); | 145 | w.set_incr_write(incr_write); |
| 146 | w.set_chain_to(ch.number()); | 146 | w.set_chain_to(ch.number()); |
| 147 | w.set_en(true); | 147 | w.set_en(true); |
| 148 | }); | 148 | }); |
| 149 | 149 | ||
| 150 | compiler_fence(Ordering::SeqCst); | 150 | compiler_fence(Ordering::SeqCst); |
| 151 | } | ||
| 152 | Transfer::new(ch) | 151 | Transfer::new(ch) |
| 153 | } | 152 | } |
| 154 | 153 | ||
| @@ -168,12 +167,10 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 168 | impl<'a, C: Channel> Drop for Transfer<'a, C> { | 167 | impl<'a, C: Channel> Drop for Transfer<'a, C> { |
| 169 | fn drop(&mut self) { | 168 | fn drop(&mut self) { |
| 170 | let p = self.channel.regs(); | 169 | let p = self.channel.regs(); |
| 171 | unsafe { | 170 | pac::DMA |
| 172 | pac::DMA | 171 | .chan_abort() |
| 173 | .chan_abort() | 172 | .modify(|m| m.set_chan_abort(1 << self.channel.number())); |
| 174 | .modify(|m| m.set_chan_abort(1 << self.channel.number())); | 173 | while p.ctrl_trig().read().busy() {} |
| 175 | while p.ctrl_trig().read().busy() {} | ||
| 176 | } | ||
| 177 | } | 174 | } |
| 178 | } | 175 | } |
| 179 | 176 | ||
| @@ -185,7 +182,7 @@ impl<'a, C: Channel> Future for Transfer<'a, C> { | |||
| 185 | // calls to wake will deregister the waker. | 182 | // calls to wake will deregister the waker. |
| 186 | CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker()); | 183 | CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker()); |
| 187 | 184 | ||
| 188 | if unsafe { self.channel.regs().ctrl_trig().read().busy() } { | 185 | if self.channel.regs().ctrl_trig().read().busy() { |
| 189 | Poll::Pending | 186 | Poll::Pending |
| 190 | } else { | 187 | } else { |
| 191 | Poll::Ready(()) | 188 | Poll::Ready(()) |
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 0410429e0..96d2d4541 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs | |||
| @@ -9,7 +9,11 @@ use embedded_storage::nor_flash::{ | |||
| 9 | use crate::pac; | 9 | use crate::pac; |
| 10 | use crate::peripherals::FLASH; | 10 | use crate::peripherals::FLASH; |
| 11 | 11 | ||
| 12 | pub const FLASH_BASE: usize = 0x10000000; | 12 | pub const FLASH_BASE: *const u32 = 0x10000000 as _; |
| 13 | |||
| 14 | // If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. | ||
| 15 | // TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance. | ||
| 16 | pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); | ||
| 13 | 17 | ||
| 14 | // **NOTE**: | 18 | // **NOTE**: |
| 15 | // | 19 | // |
| @@ -63,8 +67,8 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { | |||
| 63 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | 67 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |
| 64 | trace!( | 68 | trace!( |
| 65 | "Reading from 0x{:x} to 0x{:x}", | 69 | "Reading from 0x{:x} to 0x{:x}", |
| 66 | FLASH_BASE + offset as usize, | 70 | FLASH_BASE as u32 + offset, |
| 67 | FLASH_BASE + offset as usize + bytes.len() | 71 | FLASH_BASE as u32 + offset + bytes.len() as u32 |
| 68 | ); | 72 | ); |
| 69 | check_read(self, offset, bytes.len())?; | 73 | check_read(self, offset, bytes.len())?; |
| 70 | 74 | ||
| @@ -89,7 +93,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { | |||
| 89 | 93 | ||
| 90 | let len = to - from; | 94 | let len = to - from; |
| 91 | 95 | ||
| 92 | unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len, true))? }; | 96 | unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len))? }; |
| 93 | 97 | ||
| 94 | Ok(()) | 98 | Ok(()) |
| 95 | } | 99 | } |
| @@ -114,7 +118,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { | |||
| 114 | 118 | ||
| 115 | let unaligned_offset = offset as usize - start; | 119 | let unaligned_offset = offset as usize - start; |
| 116 | 120 | ||
| 117 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? } | 121 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? } |
| 118 | } | 122 | } |
| 119 | 123 | ||
| 120 | let remaining_len = bytes.len() - start_padding; | 124 | let remaining_len = bytes.len() - start_padding; |
| @@ -132,12 +136,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { | |||
| 132 | if bytes.as_ptr() as usize >= 0x2000_0000 { | 136 | if bytes.as_ptr() as usize >= 0x2000_0000 { |
| 133 | let aligned_data = &bytes[start_padding..end_padding]; | 137 | let aligned_data = &bytes[start_padding..end_padding]; |
| 134 | 138 | ||
| 135 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data, true))? } | 139 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? } |
| 136 | } else { | 140 | } else { |
| 137 | for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) { | 141 | for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) { |
| 138 | let mut ram_buf = [0xFF_u8; PAGE_SIZE]; | 142 | let mut ram_buf = [0xFF_u8; PAGE_SIZE]; |
| 139 | ram_buf.copy_from_slice(chunk); | 143 | ram_buf.copy_from_slice(chunk); |
| 140 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf, true))? } | 144 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? } |
| 141 | aligned_offset += PAGE_SIZE; | 145 | aligned_offset += PAGE_SIZE; |
| 142 | } | 146 | } |
| 143 | } | 147 | } |
| @@ -152,7 +156,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { | |||
| 152 | 156 | ||
| 153 | let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset); | 157 | let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset); |
| 154 | 158 | ||
| 155 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? } | 159 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? } |
| 156 | } | 160 | } |
| 157 | 161 | ||
| 158 | Ok(()) | 162 | Ok(()) |
| @@ -163,7 +167,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { | |||
| 163 | /// - DMA must not access flash memory | 167 | /// - DMA must not access flash memory |
| 164 | unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> { | 168 | unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> { |
| 165 | // Make sure we're running on CORE0 | 169 | // Make sure we're running on CORE0 |
| 166 | let core_id: u32 = unsafe { pac::SIO.cpuid().read() }; | 170 | let core_id: u32 = pac::SIO.cpuid().read(); |
| 167 | if core_id != 0 { | 171 | if core_id != 0 { |
| 168 | return Err(Error::InvalidCore); | 172 | return Err(Error::InvalidCore); |
| 169 | } | 173 | } |
| @@ -190,7 +194,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { | |||
| 190 | 194 | ||
| 191 | /// Read SPI flash unique ID | 195 | /// Read SPI flash unique ID |
| 192 | pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { | 196 | pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { |
| 193 | unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid, true))? }; | 197 | unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? }; |
| 194 | Ok(()) | 198 | Ok(()) |
| 195 | } | 199 | } |
| 196 | 200 | ||
| @@ -199,7 +203,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { | |||
| 199 | let mut jedec = None; | 203 | let mut jedec = None; |
| 200 | unsafe { | 204 | unsafe { |
| 201 | self.in_ram(|| { | 205 | self.in_ram(|| { |
| 202 | jedec.replace(ram_helpers::flash_jedec_id(true)); | 206 | jedec.replace(ram_helpers::flash_jedec_id()); |
| 203 | })?; | 207 | })?; |
| 204 | }; | 208 | }; |
| 205 | Ok(jedec.unwrap()) | 209 | Ok(jedec.unwrap()) |
| @@ -242,6 +246,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_S | |||
| 242 | mod ram_helpers { | 246 | mod ram_helpers { |
| 243 | use core::marker::PhantomData; | 247 | use core::marker::PhantomData; |
| 244 | 248 | ||
| 249 | use super::*; | ||
| 245 | use crate::rom_data; | 250 | use crate::rom_data; |
| 246 | 251 | ||
| 247 | #[repr(C)] | 252 | #[repr(C)] |
| @@ -306,7 +311,7 @@ mod ram_helpers { | |||
| 306 | /// | 311 | /// |
| 307 | /// `addr` and `len` must be multiples of 4096 | 312 | /// `addr` and `len` must be multiples of 4096 |
| 308 | /// | 313 | /// |
| 309 | /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader | 314 | /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader |
| 310 | /// is used to re-initialize the XIP engine after flashing. | 315 | /// is used to re-initialize the XIP engine after flashing. |
| 311 | /// | 316 | /// |
| 312 | /// # Safety | 317 | /// # Safety |
| @@ -318,10 +323,10 @@ mod ram_helpers { | |||
| 318 | /// - DMA must not access flash memory | 323 | /// - DMA must not access flash memory |
| 319 | /// | 324 | /// |
| 320 | /// `addr` and `len` parameters must be valid and are not checked. | 325 | /// `addr` and `len` parameters must be valid and are not checked. |
| 321 | pub unsafe fn flash_range_erase(addr: u32, len: u32, use_boot2: bool) { | 326 | pub unsafe fn flash_range_erase(addr: u32, len: u32) { |
| 322 | let mut boot2 = [0u32; 256 / 4]; | 327 | let mut boot2 = [0u32; 256 / 4]; |
| 323 | let ptrs = if use_boot2 { | 328 | let ptrs = if USE_BOOT2 { |
| 324 | rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); | 329 | rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); |
| 325 | flash_function_pointers_with_boot2(true, false, &boot2) | 330 | flash_function_pointers_with_boot2(true, false, &boot2) |
| 326 | } else { | 331 | } else { |
| 327 | flash_function_pointers(true, false) | 332 | flash_function_pointers(true, false) |
| @@ -336,7 +341,7 @@ mod ram_helpers { | |||
| 336 | /// | 341 | /// |
| 337 | /// `addr` and `data.len()` must be multiples of 4096 | 342 | /// `addr` and `data.len()` must be multiples of 4096 |
| 338 | /// | 343 | /// |
| 339 | /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader | 344 | /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader |
| 340 | /// is used to re-initialize the XIP engine after flashing. | 345 | /// is used to re-initialize the XIP engine after flashing. |
| 341 | /// | 346 | /// |
| 342 | /// # Safety | 347 | /// # Safety |
| @@ -348,10 +353,10 @@ mod ram_helpers { | |||
| 348 | /// - DMA must not access flash memory | 353 | /// - DMA must not access flash memory |
| 349 | /// | 354 | /// |
| 350 | /// `addr` and `len` parameters must be valid and are not checked. | 355 | /// `addr` and `len` parameters must be valid and are not checked. |
| 351 | pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8], use_boot2: bool) { | 356 | pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) { |
| 352 | let mut boot2 = [0u32; 256 / 4]; | 357 | let mut boot2 = [0u32; 256 / 4]; |
| 353 | let ptrs = if use_boot2 { | 358 | let ptrs = if USE_BOOT2 { |
| 354 | rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); | 359 | rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); |
| 355 | flash_function_pointers_with_boot2(true, true, &boot2) | 360 | flash_function_pointers_with_boot2(true, true, &boot2) |
| 356 | } else { | 361 | } else { |
| 357 | flash_function_pointers(true, true) | 362 | flash_function_pointers(true, true) |
| @@ -371,7 +376,7 @@ mod ram_helpers { | |||
| 371 | /// | 376 | /// |
| 372 | /// `addr` and `data.len()` must be multiples of 256 | 377 | /// `addr` and `data.len()` must be multiples of 256 |
| 373 | /// | 378 | /// |
| 374 | /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader | 379 | /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader |
| 375 | /// is used to re-initialize the XIP engine after flashing. | 380 | /// is used to re-initialize the XIP engine after flashing. |
| 376 | /// | 381 | /// |
| 377 | /// # Safety | 382 | /// # Safety |
| @@ -383,10 +388,10 @@ mod ram_helpers { | |||
| 383 | /// - DMA must not access flash memory | 388 | /// - DMA must not access flash memory |
| 384 | /// | 389 | /// |
| 385 | /// `addr` and `len` parameters must be valid and are not checked. | 390 | /// `addr` and `len` parameters must be valid and are not checked. |
| 386 | pub unsafe fn flash_range_program(addr: u32, data: &[u8], use_boot2: bool) { | 391 | pub unsafe fn flash_range_program(addr: u32, data: &[u8]) { |
| 387 | let mut boot2 = [0u32; 256 / 4]; | 392 | let mut boot2 = [0u32; 256 / 4]; |
| 388 | let ptrs = if use_boot2 { | 393 | let ptrs = if USE_BOOT2 { |
| 389 | rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); | 394 | rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); |
| 390 | flash_function_pointers_with_boot2(false, true, &boot2) | 395 | flash_function_pointers_with_boot2(false, true, &boot2) |
| 391 | } else { | 396 | } else { |
| 392 | flash_function_pointers(false, true) | 397 | flash_function_pointers(false, true) |
| @@ -508,10 +513,10 @@ mod ram_helpers { | |||
| 508 | /// - DMA must not access flash memory | 513 | /// - DMA must not access flash memory |
| 509 | /// | 514 | /// |
| 510 | /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) | 515 | /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) |
| 511 | pub unsafe fn flash_unique_id(out: &mut [u8], use_boot2: bool) { | 516 | pub unsafe fn flash_unique_id(out: &mut [u8]) { |
| 512 | let mut boot2 = [0u32; 256 / 4]; | 517 | let mut boot2 = [0u32; 256 / 4]; |
| 513 | let ptrs = if use_boot2 { | 518 | let ptrs = if USE_BOOT2 { |
| 514 | rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256); | 519 | rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); |
| 515 | flash_function_pointers_with_boot2(false, false, &boot2) | 520 | flash_function_pointers_with_boot2(false, false, &boot2) |
| 516 | } else { | 521 | } else { |
| 517 | flash_function_pointers(false, false) | 522 | flash_function_pointers(false, false) |
| @@ -536,10 +541,10 @@ mod ram_helpers { | |||
| 536 | /// - DMA must not access flash memory | 541 | /// - DMA must not access flash memory |
| 537 | /// | 542 | /// |
| 538 | /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) | 543 | /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) |
| 539 | pub unsafe fn flash_jedec_id(use_boot2: bool) -> u32 { | 544 | pub unsafe fn flash_jedec_id() -> u32 { |
| 540 | let mut boot2 = [0u32; 256 / 4]; | 545 | let mut boot2 = [0u32; 256 / 4]; |
| 541 | let ptrs = if use_boot2 { | 546 | let ptrs = if USE_BOOT2 { |
| 542 | rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256); | 547 | rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); |
| 543 | flash_function_pointers_with_boot2(false, false, &boot2) | 548 | flash_function_pointers_with_boot2(false, false, &boot2) |
| 544 | } else { | 549 | } else { |
| 545 | flash_function_pointers(false, false) | 550 | flash_function_pointers(false, false) |
| @@ -586,7 +591,6 @@ mod ram_helpers { | |||
| 586 | "ldr r4, [r5, #4]", | 591 | "ldr r4, [r5, #4]", |
| 587 | "blx r4", // flash_exit_xip() | 592 | "blx r4", // flash_exit_xip() |
| 588 | 593 | ||
| 589 | "mov r7, r10", // cmd | ||
| 590 | 594 | ||
| 591 | "movs r4, #0x18", | 595 | "movs r4, #0x18", |
| 592 | "lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13 | 596 | "lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13 |
| @@ -603,8 +607,9 @@ mod ram_helpers { | |||
| 603 | "str r1, [r4, #0]", | 607 | "str r1, [r4, #0]", |
| 604 | 608 | ||
| 605 | // Write ctrlr1 with len-1 | 609 | // Write ctrlr1 with len-1 |
| 606 | "ldr r0, [r7, #8]", // dummy_len | 610 | "mov r3, r10", // cmd |
| 607 | "ldr r1, [r7, #16]", // data_len | 611 | "ldr r0, [r3, #8]", // dummy_len |
| 612 | "ldr r1, [r3, #16]", // data_len | ||
| 608 | "add r0, r1", | 613 | "add r0, r1", |
| 609 | "subs r0, #1", | 614 | "subs r0, #1", |
| 610 | "str r0, [r4, #0x04]", // CTRLR1 | 615 | "str r0, [r4, #0x04]", // CTRLR1 |
| @@ -616,8 +621,8 @@ mod ram_helpers { | |||
| 616 | // Write cmd/addr phase to DR | 621 | // Write cmd/addr phase to DR |
| 617 | "mov r2, r4", | 622 | "mov r2, r4", |
| 618 | "adds r2, 0x60", // &DR | 623 | "adds r2, 0x60", // &DR |
| 619 | "ldr r0, [r7, #0]", // cmd_addr | 624 | "ldr r0, [r3, #0]", // cmd_addr |
| 620 | "ldr r1, [r7, #4]", // cmd_addr_len | 625 | "ldr r1, [r3, #4]", // cmd_addr_len |
| 621 | "10:", | 626 | "10:", |
| 622 | "ldrb r3, [r0]", | 627 | "ldrb r3, [r0]", |
| 623 | "strb r3, [r2]", // DR | 628 | "strb r3, [r2]", // DR |
| @@ -626,7 +631,8 @@ mod ram_helpers { | |||
| 626 | "bne 10b", | 631 | "bne 10b", |
| 627 | 632 | ||
| 628 | // Skip any dummy cycles | 633 | // Skip any dummy cycles |
| 629 | "ldr r1, [r7, #8]", // dummy_len | 634 | "mov r3, r10", // cmd |
| 635 | "ldr r1, [r3, #8]", // dummy_len | ||
| 630 | "cmp r1, #0", | 636 | "cmp r1, #0", |
| 631 | "beq 9f", | 637 | "beq 9f", |
| 632 | "4:", | 638 | "4:", |
| @@ -643,8 +649,9 @@ mod ram_helpers { | |||
| 643 | 649 | ||
| 644 | // Read RX fifo | 650 | // Read RX fifo |
| 645 | "9:", | 651 | "9:", |
| 646 | "ldr r0, [r7, #12]", // data | 652 | "mov r2, r10", // cmd |
| 647 | "ldr r1, [r7, #16]", // data_len | 653 | "ldr r0, [r2, #12]", // data |
| 654 | "ldr r1, [r2, #16]", // data_len | ||
| 648 | 655 | ||
| 649 | "2:", | 656 | "2:", |
| 650 | "ldr r3, [r4, #0x28]", // SR | 657 | "ldr r3, [r4, #0x28]", // SR |
| @@ -678,13 +685,12 @@ mod ram_helpers { | |||
| 678 | out("r2") _, | 685 | out("r2") _, |
| 679 | out("r3") _, | 686 | out("r3") _, |
| 680 | out("r4") _, | 687 | out("r4") _, |
| 688 | out("r5") _, | ||
| 681 | // Registers r8-r10 are used to store values | 689 | // Registers r8-r10 are used to store values |
| 682 | // from r0-r2 in registers not clobbered by | 690 | // from r0-r2 in registers not clobbered by |
| 683 | // function calls. | 691 | // function calls. |
| 684 | // The values can't be passed in using r8-r10 directly | 692 | // The values can't be passed in using r8-r10 directly |
| 685 | // due to https://github.com/rust-lang/rust/issues/99071 | 693 | // due to https://github.com/rust-lang/rust/issues/99071 |
| 686 | out("r8") _, | ||
| 687 | out("r9") _, | ||
| 688 | out("r10") _, | 694 | out("r10") _, |
| 689 | clobber_abi("C"), | 695 | clobber_abi("C"), |
| 690 | ); | 696 | ); |
diff --git a/embassy-rp/src/float/div.rs b/embassy-rp/src/float/div.rs index 094dec446..aff0dcb07 100644 --- a/embassy-rp/src/float/div.rs +++ b/embassy-rp/src/float/div.rs | |||
| @@ -17,45 +17,43 @@ where | |||
| 17 | { | 17 | { |
| 18 | let sio = rp_pac::SIO; | 18 | let sio = rp_pac::SIO; |
| 19 | 19 | ||
| 20 | unsafe { | 20 | // Since we can't save the signed-ness of the calculation, we have to make |
| 21 | // Since we can't save the signed-ness of the calculation, we have to make | 21 | // sure that there's at least an 8 cycle delay before we read the result. |
| 22 | // sure that there's at least an 8 cycle delay before we read the result. | 22 | // The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads. |
| 23 | // The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads. | 23 | // Since we can't be sure the Rust implementation will optimize to the same, |
| 24 | // Since we can't be sure the Rust implementation will optimize to the same, | 24 | // just use an explicit wait. |
| 25 | // just use an explicit wait. | 25 | while !sio.div().csr().read().ready() {} |
| 26 | while !sio.div().csr().read().ready() {} | 26 | |
| 27 | 27 | // Read the quotient last, since that's what clears the dirty flag | |
| 28 | // Read the quotient last, since that's what clears the dirty flag | 28 | let dividend = sio.div().udividend().read(); |
| 29 | let dividend = sio.div().udividend().read(); | 29 | let divisor = sio.div().udivisor().read(); |
| 30 | let divisor = sio.div().udivisor().read(); | 30 | let remainder = sio.div().remainder().read(); |
| 31 | let remainder = sio.div().remainder().read(); | 31 | let quotient = sio.div().quotient().read(); |
| 32 | let quotient = sio.div().quotient().read(); | 32 | |
| 33 | 33 | // If we get interrupted here (before a write sets the DIRTY flag) its fine, since | |
| 34 | // If we get interrupted here (before a write sets the DIRTY flag) its fine, since | 34 | // we have the full state, so the interruptor doesn't have to restore it. Once the |
| 35 | // we have the full state, so the interruptor doesn't have to restore it. Once the | 35 | // write happens and the DIRTY flag is set, the interruptor becomes responsible for |
| 36 | // write happens and the DIRTY flag is set, the interruptor becomes responsible for | 36 | // restoring our state. |
| 37 | // restoring our state. | 37 | let result = f(); |
| 38 | let result = f(); | 38 | |
| 39 | 39 | // If we are interrupted here, then the interruptor will start an incorrect calculation | |
| 40 | // If we are interrupted here, then the interruptor will start an incorrect calculation | 40 | // using a wrong divisor, but we'll restore the divisor and result ourselves correctly. |
| 41 | // using a wrong divisor, but we'll restore the divisor and result ourselves correctly. | 41 | // This sets DIRTY, so any interruptor will save the state. |
| 42 | // This sets DIRTY, so any interruptor will save the state. | 42 | sio.div().udividend().write_value(dividend); |
| 43 | sio.div().udividend().write_value(dividend); | 43 | // If we are interrupted here, the the interruptor may start the calculation using |
| 44 | // If we are interrupted here, the the interruptor may start the calculation using | 44 | // incorrectly signed inputs, but we'll restore the result ourselves. |
| 45 | // incorrectly signed inputs, but we'll restore the result ourselves. | 45 | // This sets DIRTY, so any interruptor will save the state. |
| 46 | // This sets DIRTY, so any interruptor will save the state. | 46 | sio.div().udivisor().write_value(divisor); |
| 47 | sio.div().udivisor().write_value(divisor); | 47 | // If we are interrupted here, the interruptor will have restored everything but the |
| 48 | // If we are interrupted here, the interruptor will have restored everything but the | 48 | // quotient may be wrongly signed. If the calculation started by the above writes is |
| 49 | // quotient may be wrongly signed. If the calculation started by the above writes is | 49 | // still ongoing it is stopped, so it won't replace the result we're restoring. |
| 50 | // still ongoing it is stopped, so it won't replace the result we're restoring. | 50 | // DIRTY and READY set, but only DIRTY matters to make the interruptor save the state. |
| 51 | // DIRTY and READY set, but only DIRTY matters to make the interruptor save the state. | 51 | sio.div().remainder().write_value(remainder); |
| 52 | sio.div().remainder().write_value(remainder); | 52 | // State fully restored after the quotient write. This sets both DIRTY and READY, so |
| 53 | // State fully restored after the quotient write. This sets both DIRTY and READY, so | 53 | // whatever we may have interrupted can read the result. |
| 54 | // whatever we may have interrupted can read the result. | 54 | sio.div().quotient().write_value(quotient); |
| 55 | sio.div().quotient().write_value(quotient); | 55 | |
| 56 | 56 | result | |
| 57 | result | ||
| 58 | } | ||
| 59 | } | 57 | } |
| 60 | 58 | ||
| 61 | fn save_divider<F, R>(f: F) -> R | 59 | fn save_divider<F, R>(f: F) -> R |
| @@ -63,7 +61,7 @@ where | |||
| 63 | F: FnOnce() -> R, | 61 | F: FnOnce() -> R, |
| 64 | { | 62 | { |
| 65 | let sio = rp_pac::SIO; | 63 | let sio = rp_pac::SIO; |
| 66 | if unsafe { !sio.div().csr().read().dirty() } { | 64 | if !sio.div().csr().read().dirty() { |
| 67 | // Not dirty, so nothing is waiting for the calculation. So we can just | 65 | // Not dirty, so nothing is waiting for the calculation. So we can just |
| 68 | // issue it directly without a save/restore. | 66 | // issue it directly without a save/restore. |
| 69 | f() | 67 | f() |
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index da8efba91..ce0d02557 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs | |||
| @@ -3,10 +3,10 @@ use core::future::Future; | |||
| 3 | use core::pin::Pin as FuturePin; | 3 | use core::pin::Pin as FuturePin; |
| 4 | use core::task::{Context, Poll}; | 4 | use core::task::{Context, Poll}; |
| 5 | 5 | ||
| 6 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 7 | use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; | 6 | use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 9 | 8 | ||
| 9 | use crate::interrupt::InterruptExt; | ||
| 10 | use crate::pac::common::{Reg, RW}; | 10 | use crate::pac::common::{Reg, RW}; |
| 11 | use crate::pac::SIO; | 11 | use crate::pac::SIO; |
| 12 | use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; | 12 | use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; |
| @@ -31,9 +31,9 @@ impl From<bool> for Level { | |||
| 31 | } | 31 | } |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | impl Into<bool> for Level { | 34 | impl From<Level> for bool { |
| 35 | fn into(self) -> bool { | 35 | fn from(level: Level) -> bool { |
| 36 | match self { | 36 | match level { |
| 37 | Level::Low => false, | 37 | Level::Low => false, |
| 38 | Level::High => true, | 38 | Level::High => true, |
| 39 | } | 39 | } |
| @@ -137,14 +137,14 @@ pub enum InterruptTrigger { | |||
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | pub(crate) unsafe fn init() { | 139 | pub(crate) unsafe fn init() { |
| 140 | let irq = interrupt::IO_IRQ_BANK0::steal(); | 140 | interrupt::IO_IRQ_BANK0.disable(); |
| 141 | irq.disable(); | 141 | interrupt::IO_IRQ_BANK0.set_priority(interrupt::Priority::P3); |
| 142 | irq.set_priority(interrupt::Priority::P3); | 142 | interrupt::IO_IRQ_BANK0.enable(); |
| 143 | irq.enable(); | ||
| 144 | } | 143 | } |
| 145 | 144 | ||
| 145 | #[cfg(feature = "rt")] | ||
| 146 | #[interrupt] | 146 | #[interrupt] |
| 147 | unsafe fn IO_IRQ_BANK0() { | 147 | fn IO_IRQ_BANK0() { |
| 148 | let cpu = SIO.cpuid().read() as usize; | 148 | let cpu = SIO.cpuid().read() as usize; |
| 149 | // There are two sets of interrupt registers, one for cpu0 and one for cpu1 | 149 | // There are two sets of interrupt registers, one for cpu0 and one for cpu1 |
| 150 | // and here we are selecting the set that belongs to the currently executing | 150 | // and here we are selecting the set that belongs to the currently executing |
| @@ -185,47 +185,45 @@ struct InputFuture<'a, T: Pin> { | |||
| 185 | impl<'d, T: Pin> InputFuture<'d, T> { | 185 | impl<'d, T: Pin> InputFuture<'d, T> { |
| 186 | pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { | 186 | pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { |
| 187 | into_ref!(pin); | 187 | into_ref!(pin); |
| 188 | unsafe { | 188 | let pin_group = (pin.pin() % 8) as usize; |
| 189 | let pin_group = (pin.pin() % 8) as usize; | 189 | // first, clear the INTR register bits. without this INTR will still |
| 190 | // first, clear the INTR register bits. without this INTR will still | 190 | // contain reports of previous edges, causing the IRQ to fire early |
| 191 | // contain reports of previous edges, causing the IRQ to fire early | 191 | // on stale state. clearing these means that we can only detect edges |
| 192 | // on stale state. clearing these means that we can only detect edges | 192 | // that occur *after* the clear happened, but since both this and the |
| 193 | // that occur *after* the clear happened, but since both this and the | 193 | // alternative are fundamentally racy it's probably fine. |
| 194 | // alternative are fundamentally racy it's probably fine. | 194 | // (the alternative being checking the current level and waiting for |
| 195 | // (the alternative being checking the current level and waiting for | 195 | // its inverse, but that requires reading the current level and thus |
| 196 | // its inverse, but that requires reading the current level and thus | 196 | // missing anything that happened before the level was read.) |
| 197 | // missing anything that happened before the level was read.) | 197 | pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| { |
| 198 | pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| { | 198 | w.set_edge_high(pin_group, true); |
| 199 | w.set_edge_high(pin_group, true); | 199 | w.set_edge_low(pin_group, true); |
| 200 | w.set_edge_low(pin_group, true); | 200 | }); |
| 201 | |||
| 202 | // Each INTR register is divided into 8 groups, one group for each | ||
| 203 | // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, | ||
| 204 | // and EGDE_HIGH. | ||
| 205 | pin.int_proc() | ||
| 206 | .inte((pin.pin() / 8) as usize) | ||
| 207 | .write_set(|w| match level { | ||
| 208 | InterruptTrigger::LevelHigh => { | ||
| 209 | trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin()); | ||
| 210 | w.set_level_high(pin_group, true); | ||
| 211 | } | ||
| 212 | InterruptTrigger::LevelLow => { | ||
| 213 | w.set_level_low(pin_group, true); | ||
| 214 | } | ||
| 215 | InterruptTrigger::EdgeHigh => { | ||
| 216 | w.set_edge_high(pin_group, true); | ||
| 217 | } | ||
| 218 | InterruptTrigger::EdgeLow => { | ||
| 219 | w.set_edge_low(pin_group, true); | ||
| 220 | } | ||
| 221 | InterruptTrigger::AnyEdge => { | ||
| 222 | w.set_edge_high(pin_group, true); | ||
| 223 | w.set_edge_low(pin_group, true); | ||
| 224 | } | ||
| 201 | }); | 225 | }); |
| 202 | 226 | ||
| 203 | // Each INTR register is divided into 8 groups, one group for each | ||
| 204 | // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, | ||
| 205 | // and EGDE_HIGH. | ||
| 206 | pin.int_proc() | ||
| 207 | .inte((pin.pin() / 8) as usize) | ||
| 208 | .write_set(|w| match level { | ||
| 209 | InterruptTrigger::LevelHigh => { | ||
| 210 | trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin()); | ||
| 211 | w.set_level_high(pin_group, true); | ||
| 212 | } | ||
| 213 | InterruptTrigger::LevelLow => { | ||
| 214 | w.set_level_low(pin_group, true); | ||
| 215 | } | ||
| 216 | InterruptTrigger::EdgeHigh => { | ||
| 217 | w.set_edge_high(pin_group, true); | ||
| 218 | } | ||
| 219 | InterruptTrigger::EdgeLow => { | ||
| 220 | w.set_edge_low(pin_group, true); | ||
| 221 | } | ||
| 222 | InterruptTrigger::AnyEdge => { | ||
| 223 | w.set_edge_high(pin_group, true); | ||
| 224 | w.set_edge_low(pin_group, true); | ||
| 225 | } | ||
| 226 | }); | ||
| 227 | } | ||
| 228 | |||
| 229 | Self { pin, level } | 227 | Self { pin, level } |
| 230 | } | 228 | } |
| 231 | } | 229 | } |
| @@ -242,7 +240,7 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> { | |||
| 242 | // then we want to access the interrupt enable register for our | 240 | // then we want to access the interrupt enable register for our |
| 243 | // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and | 241 | // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and |
| 244 | // PROC0_INTE3 per cpu). | 242 | // PROC0_INTE3 per cpu). |
| 245 | let inte: pac::io::regs::Int = unsafe { self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read() }; | 243 | let inte: pac::io::regs::Int = self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read(); |
| 246 | // The register is divided into groups of four, one group for | 244 | // The register is divided into groups of four, one group for |
| 247 | // each pin. Each group consists of four trigger levels LEVEL_LOW, | 245 | // each pin. Each group consists of four trigger levels LEVEL_LOW, |
| 248 | // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. | 246 | // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. |
| @@ -449,15 +447,13 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 449 | pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { | 447 | pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { |
| 450 | into_ref!(pin); | 448 | into_ref!(pin); |
| 451 | 449 | ||
| 452 | unsafe { | 450 | pin.pad_ctrl().write(|w| { |
| 453 | pin.pad_ctrl().write(|w| { | 451 | w.set_ie(true); |
| 454 | w.set_ie(true); | 452 | }); |
| 455 | }); | ||
| 456 | 453 | ||
| 457 | pin.io().ctrl().write(|w| { | 454 | pin.io().ctrl().write(|w| { |
| 458 | w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0); | 455 | w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0); |
| 459 | }); | 456 | }); |
| 460 | } | ||
| 461 | 457 | ||
| 462 | Self { pin } | 458 | Self { pin } |
| 463 | } | 459 | } |
| @@ -470,43 +466,37 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 470 | /// Set the pin's pull. | 466 | /// Set the pin's pull. |
| 471 | #[inline] | 467 | #[inline] |
| 472 | pub fn set_pull(&mut self, pull: Pull) { | 468 | pub fn set_pull(&mut self, pull: Pull) { |
| 473 | unsafe { | 469 | self.pin.pad_ctrl().modify(|w| { |
| 474 | self.pin.pad_ctrl().modify(|w| { | 470 | w.set_ie(true); |
| 475 | w.set_ie(true); | 471 | let (pu, pd) = match pull { |
| 476 | let (pu, pd) = match pull { | 472 | Pull::Up => (true, false), |
| 477 | Pull::Up => (true, false), | 473 | Pull::Down => (false, true), |
| 478 | Pull::Down => (false, true), | 474 | Pull::None => (false, false), |
| 479 | Pull::None => (false, false), | 475 | }; |
| 480 | }; | 476 | w.set_pue(pu); |
| 481 | w.set_pue(pu); | 477 | w.set_pde(pd); |
| 482 | w.set_pde(pd); | 478 | }); |
| 483 | }); | ||
| 484 | } | ||
| 485 | } | 479 | } |
| 486 | 480 | ||
| 487 | /// Set the pin's drive strength. | 481 | /// Set the pin's drive strength. |
| 488 | #[inline] | 482 | #[inline] |
| 489 | pub fn set_drive_strength(&mut self, strength: Drive) { | 483 | pub fn set_drive_strength(&mut self, strength: Drive) { |
| 490 | unsafe { | 484 | self.pin.pad_ctrl().modify(|w| { |
| 491 | self.pin.pad_ctrl().modify(|w| { | 485 | w.set_drive(match strength { |
| 492 | w.set_drive(match strength { | 486 | Drive::_2mA => pac::pads::vals::Drive::_2MA, |
| 493 | Drive::_2mA => pac::pads::vals::Drive::_2MA, | 487 | Drive::_4mA => pac::pads::vals::Drive::_4MA, |
| 494 | Drive::_4mA => pac::pads::vals::Drive::_4MA, | 488 | Drive::_8mA => pac::pads::vals::Drive::_8MA, |
| 495 | Drive::_8mA => pac::pads::vals::Drive::_8MA, | 489 | Drive::_12mA => pac::pads::vals::Drive::_12MA, |
| 496 | Drive::_12mA => pac::pads::vals::Drive::_12MA, | ||
| 497 | }); | ||
| 498 | }); | 490 | }); |
| 499 | } | 491 | }); |
| 500 | } | 492 | } |
| 501 | 493 | ||
| 502 | // Set the pin's slew rate. | 494 | // Set the pin's slew rate. |
| 503 | #[inline] | 495 | #[inline] |
| 504 | pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { | 496 | pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { |
| 505 | unsafe { | 497 | self.pin.pad_ctrl().modify(|w| { |
| 506 | self.pin.pad_ctrl().modify(|w| { | 498 | w.set_slewfast(slew_rate == SlewRate::Fast); |
| 507 | w.set_slewfast(slew_rate == SlewRate::Fast); | 499 | }); |
| 508 | }); | ||
| 509 | } | ||
| 510 | } | 500 | } |
| 511 | 501 | ||
| 512 | /// Put the pin into input mode. | 502 | /// Put the pin into input mode. |
| @@ -514,7 +504,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 514 | /// The pull setting is left unchanged. | 504 | /// The pull setting is left unchanged. |
| 515 | #[inline] | 505 | #[inline] |
| 516 | pub fn set_as_input(&mut self) { | 506 | pub fn set_as_input(&mut self) { |
| 517 | unsafe { self.pin.sio_oe().value_clr().write_value(self.bit()) } | 507 | self.pin.sio_oe().value_clr().write_value(self.bit()) |
| 518 | } | 508 | } |
| 519 | 509 | ||
| 520 | /// Put the pin into output mode. | 510 | /// Put the pin into output mode. |
| @@ -523,17 +513,17 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 523 | /// at a specific level, call `set_high`/`set_low` on the pin first. | 513 | /// at a specific level, call `set_high`/`set_low` on the pin first. |
| 524 | #[inline] | 514 | #[inline] |
| 525 | pub fn set_as_output(&mut self) { | 515 | pub fn set_as_output(&mut self) { |
| 526 | unsafe { self.pin.sio_oe().value_set().write_value(self.bit()) } | 516 | self.pin.sio_oe().value_set().write_value(self.bit()) |
| 527 | } | 517 | } |
| 528 | 518 | ||
| 529 | #[inline] | 519 | #[inline] |
| 530 | fn is_set_as_output(&self) -> bool { | 520 | fn is_set_as_output(&self) -> bool { |
| 531 | unsafe { (self.pin.sio_oe().value().read() & self.bit()) != 0 } | 521 | (self.pin.sio_oe().value().read() & self.bit()) != 0 |
| 532 | } | 522 | } |
| 533 | 523 | ||
| 534 | #[inline] | 524 | #[inline] |
| 535 | pub fn toggle_set_as_output(&mut self) { | 525 | pub fn toggle_set_as_output(&mut self) { |
| 536 | unsafe { self.pin.sio_oe().value_xor().write_value(self.bit()) } | 526 | self.pin.sio_oe().value_xor().write_value(self.bit()) |
| 537 | } | 527 | } |
| 538 | 528 | ||
| 539 | #[inline] | 529 | #[inline] |
| @@ -543,7 +533,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 543 | 533 | ||
| 544 | #[inline] | 534 | #[inline] |
| 545 | pub fn is_low(&self) -> bool { | 535 | pub fn is_low(&self) -> bool { |
| 546 | unsafe { self.pin.sio_in().read() & self.bit() == 0 } | 536 | self.pin.sio_in().read() & self.bit() == 0 |
| 547 | } | 537 | } |
| 548 | 538 | ||
| 549 | /// Returns current pin level | 539 | /// Returns current pin level |
| @@ -555,13 +545,13 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 555 | /// Set the output as high. | 545 | /// Set the output as high. |
| 556 | #[inline] | 546 | #[inline] |
| 557 | pub fn set_high(&mut self) { | 547 | pub fn set_high(&mut self) { |
| 558 | unsafe { self.pin.sio_out().value_set().write_value(self.bit()) } | 548 | self.pin.sio_out().value_set().write_value(self.bit()) |
| 559 | } | 549 | } |
| 560 | 550 | ||
| 561 | /// Set the output as low. | 551 | /// Set the output as low. |
| 562 | #[inline] | 552 | #[inline] |
| 563 | pub fn set_low(&mut self) { | 553 | pub fn set_low(&mut self) { |
| 564 | unsafe { self.pin.sio_out().value_clr().write_value(self.bit()) } | 554 | self.pin.sio_out().value_clr().write_value(self.bit()) |
| 565 | } | 555 | } |
| 566 | 556 | ||
| 567 | /// Set the output level. | 557 | /// Set the output level. |
| @@ -576,7 +566,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 576 | /// Is the output level high? | 566 | /// Is the output level high? |
| 577 | #[inline] | 567 | #[inline] |
| 578 | pub fn is_set_high(&self) -> bool { | 568 | pub fn is_set_high(&self) -> bool { |
| 579 | unsafe { (self.pin.sio_out().value().read() & self.bit()) == 0 } | 569 | (self.pin.sio_out().value().read() & self.bit()) == 0 |
| 580 | } | 570 | } |
| 581 | 571 | ||
| 582 | /// Is the output level low? | 572 | /// Is the output level low? |
| @@ -594,7 +584,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 594 | /// Toggle pin output | 584 | /// Toggle pin output |
| 595 | #[inline] | 585 | #[inline] |
| 596 | pub fn toggle(&mut self) { | 586 | pub fn toggle(&mut self) { |
| 597 | unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) } | 587 | self.pin.sio_out().value_xor().write_value(self.bit()) |
| 598 | } | 588 | } |
| 599 | 589 | ||
| 600 | #[inline] | 590 | #[inline] |
| @@ -626,12 +616,10 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 626 | impl<'d, T: Pin> Drop for Flex<'d, T> { | 616 | impl<'d, T: Pin> Drop for Flex<'d, T> { |
| 627 | #[inline] | 617 | #[inline] |
| 628 | fn drop(&mut self) { | 618 | fn drop(&mut self) { |
| 629 | unsafe { | 619 | self.pin.pad_ctrl().write(|_| {}); |
| 630 | self.pin.pad_ctrl().write(|_| {}); | 620 | self.pin.io().ctrl().write(|w| { |
| 631 | self.pin.io().ctrl().write(|w| { | 621 | w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0); |
| 632 | w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0); | 622 | }); |
| 633 | }); | ||
| 634 | } | ||
| 635 | } | 623 | } |
| 636 | } | 624 | } |
| 637 | 625 | ||
| @@ -688,7 +676,7 @@ pub(crate) mod sealed { | |||
| 688 | Bank::Bank0 => crate::pac::IO_BANK0, | 676 | Bank::Bank0 => crate::pac::IO_BANK0, |
| 689 | Bank::Qspi => crate::pac::IO_QSPI, | 677 | Bank::Qspi => crate::pac::IO_QSPI, |
| 690 | }; | 678 | }; |
| 691 | let proc = unsafe { SIO.cpuid().read() }; | 679 | let proc = SIO.cpuid().read(); |
| 692 | io_block.int_proc(proc as _) | 680 | io_block.int_proc(proc as _) |
| 693 | } | 681 | } |
| 694 | } | 682 | } |
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index 6ce77f073..791c64554 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs | |||
| @@ -2,14 +2,14 @@ use core::future; | |||
| 2 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt}; | ||
| 6 | use embassy_hal_common::{into_ref, PeripheralRef}; | 5 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 6 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use pac::i2c; | 7 | use pac::i2c; |
| 9 | 8 | ||
| 10 | use crate::gpio::sealed::Pin; | 9 | use crate::gpio::sealed::Pin; |
| 11 | use crate::gpio::AnyPin; | 10 | use crate::gpio::AnyPin; |
| 12 | use crate::{pac, peripherals, Peripheral}; | 11 | use crate::interrupt::typelevel::{Binding, Interrupt}; |
| 12 | use crate::{interrupt, pac, peripherals, Peripheral}; | ||
| 13 | 13 | ||
| 14 | /// I2C error abort reason | 14 | /// I2C error abort reason |
| 15 | #[derive(Debug)] | 15 | #[derive(Debug)] |
| @@ -82,14 +82,12 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 82 | 82 | ||
| 83 | let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config); | 83 | let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config); |
| 84 | 84 | ||
| 85 | unsafe { | 85 | let r = T::regs(); |
| 86 | let i2c = T::regs(); | ||
| 87 | 86 | ||
| 88 | // mask everything initially | 87 | // mask everything initially |
| 89 | i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); | 88 | r.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); |
| 90 | T::Interrupt::steal().unpend(); | 89 | T::Interrupt::unpend(); |
| 91 | T::Interrupt::steal().enable(); | 90 | unsafe { T::Interrupt::enable() }; |
| 92 | } | ||
| 93 | 91 | ||
| 94 | i2c | 92 | i2c |
| 95 | } | 93 | } |
| @@ -137,13 +135,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 137 | let last = remaining_queue == 0; | 135 | let last = remaining_queue == 0; |
| 138 | batch += 1; | 136 | batch += 1; |
| 139 | 137 | ||
| 140 | unsafe { | 138 | p.ic_data_cmd().write(|w| { |
| 141 | p.ic_data_cmd().write(|w| { | 139 | w.set_restart(restart && remaining_queue == buffer.len() - 1); |
| 142 | w.set_restart(restart && remaining_queue == buffer.len() - 1); | 140 | w.set_stop(last && send_stop); |
| 143 | w.set_stop(last && send_stop); | 141 | w.set_cmd(true); |
| 144 | w.set_cmd(true); | 142 | }); |
| 145 | }); | ||
| 146 | } | ||
| 147 | } | 143 | } |
| 148 | 144 | ||
| 149 | // We've either run out of txfifo or just plain finished setting up | 145 | // We've either run out of txfifo or just plain finished setting up |
| @@ -163,7 +159,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 163 | Poll::Pending | 159 | Poll::Pending |
| 164 | } | 160 | } |
| 165 | }, | 161 | }, |
| 166 | |_me| unsafe { | 162 | |_me| { |
| 167 | // Set the read threshold to the number of bytes we're | 163 | // Set the read threshold to the number of bytes we're |
| 168 | // expecting so we don't get spurious interrupts. | 164 | // expecting so we don't get spurious interrupts. |
| 169 | p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1)); | 165 | p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1)); |
| @@ -187,7 +183,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 187 | let rxbytes = (rxfifo as usize).min(remaining); | 183 | let rxbytes = (rxfifo as usize).min(remaining); |
| 188 | let received = buffer.len() - remaining; | 184 | let received = buffer.len() - remaining; |
| 189 | for b in &mut buffer[received..received + rxbytes] { | 185 | for b in &mut buffer[received..received + rxbytes] { |
| 190 | *b = unsafe { p.ic_data_cmd().read().dat() }; | 186 | *b = p.ic_data_cmd().read().dat(); |
| 191 | } | 187 | } |
| 192 | remaining -= rxbytes; | 188 | remaining -= rxbytes; |
| 193 | } | 189 | } |
| @@ -213,13 +209,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 213 | if let Some(byte) = bytes.next() { | 209 | if let Some(byte) = bytes.next() { |
| 214 | let last = bytes.peek().is_none(); | 210 | let last = bytes.peek().is_none(); |
| 215 | 211 | ||
| 216 | unsafe { | 212 | p.ic_data_cmd().write(|w| { |
| 217 | p.ic_data_cmd().write(|w| { | 213 | w.set_stop(last && send_stop); |
| 218 | w.set_stop(last && send_stop); | 214 | w.set_cmd(false); |
| 219 | w.set_cmd(false); | 215 | w.set_dat(byte); |
| 220 | w.set_dat(byte); | 216 | }); |
| 221 | }); | ||
| 222 | } | ||
| 223 | } else { | 217 | } else { |
| 224 | break 'xmit Ok(()); | 218 | break 'xmit Ok(()); |
| 225 | } | 219 | } |
| @@ -237,7 +231,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 237 | Poll::Pending | 231 | Poll::Pending |
| 238 | } | 232 | } |
| 239 | }, | 233 | }, |
| 240 | |_me| unsafe { | 234 | |_me| { |
| 241 | // Set tx "free" threshold a little high so that we get | 235 | // Set tx "free" threshold a little high so that we get |
| 242 | // woken before the fifo completely drains to minimize | 236 | // woken before the fifo completely drains to minimize |
| 243 | // transfer stalls. | 237 | // transfer stalls. |
| @@ -269,7 +263,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 269 | 263 | ||
| 270 | let had_abort2 = self | 264 | let had_abort2 = self |
| 271 | .wait_on( | 265 | .wait_on( |
| 272 | |me| unsafe { | 266 | |me| { |
| 273 | // We could see an abort while processing fifo backlog, | 267 | // We could see an abort while processing fifo backlog, |
| 274 | // so handle it here. | 268 | // so handle it here. |
| 275 | let abort = me.read_and_clear_abort_reason(); | 269 | let abort = me.read_and_clear_abort_reason(); |
| @@ -281,7 +275,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 281 | Poll::Pending | 275 | Poll::Pending |
| 282 | } | 276 | } |
| 283 | }, | 277 | }, |
| 284 | |_me| unsafe { | 278 | |_me| { |
| 285 | p.ic_intr_mask().modify(|w| { | 279 | p.ic_intr_mask().modify(|w| { |
| 286 | w.set_m_stop_det(true); | 280 | w.set_m_stop_det(true); |
| 287 | w.set_m_tx_abrt(true); | 281 | w.set_m_tx_abrt(true); |
| @@ -289,9 +283,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||
| 289 | }, | 283 | }, |
| 290 | ) | 284 | ) |
| 291 | .await; | 285 | .await; |
| 292 | unsafe { | 286 | p.ic_clr_stop_det().read(); |
| 293 | p.ic_clr_stop_det().read(); | ||
| 294 | } | ||
| 295 | 287 | ||
| 296 | had_abort.and(had_abort2) | 288 | had_abort.and(had_abort2) |
| 297 | } else { | 289 | } else { |
| @@ -314,7 +306,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 314 | _uart: PhantomData<T>, | 306 | _uart: PhantomData<T>, |
| 315 | } | 307 | } |
| 316 | 308 | ||
| 317 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 309 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 318 | // Mask interrupts and wake any task waiting for this interrupt | 310 | // Mask interrupts and wake any task waiting for this interrupt |
| 319 | unsafe fn on_interrupt() { | 311 | unsafe fn on_interrupt() { |
| 320 | let i2c = T::regs(); | 312 | let i2c = T::regs(); |
| @@ -338,95 +330,93 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 338 | 330 | ||
| 339 | let p = T::regs(); | 331 | let p = T::regs(); |
| 340 | 332 | ||
| 341 | unsafe { | 333 | let reset = T::reset(); |
| 342 | let reset = T::reset(); | 334 | crate::reset::reset(reset); |
| 343 | crate::reset::reset(reset); | 335 | crate::reset::unreset_wait(reset); |
| 344 | crate::reset::unreset_wait(reset); | 336 | |
| 345 | 337 | p.ic_enable().write(|w| w.set_enable(false)); | |
| 346 | p.ic_enable().write(|w| w.set_enable(false)); | 338 | |
| 347 | 339 | // Select controller mode & speed | |
| 348 | // Select controller mode & speed | 340 | p.ic_con().modify(|w| { |
| 349 | p.ic_con().modify(|w| { | 341 | // Always use "fast" mode (<= 400 kHz, works fine for standard |
| 350 | // Always use "fast" mode (<= 400 kHz, works fine for standard | 342 | // mode too) |
| 351 | // mode too) | 343 | w.set_speed(i2c::vals::Speed::FAST); |
| 352 | w.set_speed(i2c::vals::Speed::FAST); | 344 | w.set_master_mode(true); |
| 353 | w.set_master_mode(true); | 345 | w.set_ic_slave_disable(true); |
| 354 | w.set_ic_slave_disable(true); | 346 | w.set_ic_restart_en(true); |
| 355 | w.set_ic_restart_en(true); | 347 | w.set_tx_empty_ctrl(true); |
| 356 | w.set_tx_empty_ctrl(true); | 348 | }); |
| 357 | }); | 349 | |
| 358 | 350 | // Set FIFO watermarks to 1 to make things simpler. This is encoded | |
| 359 | // Set FIFO watermarks to 1 to make things simpler. This is encoded | 351 | // by a register value of 0. |
| 360 | // by a register value of 0. | 352 | p.ic_tx_tl().write(|w| w.set_tx_tl(0)); |
| 361 | p.ic_tx_tl().write(|w| w.set_tx_tl(0)); | 353 | p.ic_rx_tl().write(|w| w.set_rx_tl(0)); |
| 362 | p.ic_rx_tl().write(|w| w.set_rx_tl(0)); | 354 | |
| 363 | 355 | // Configure SCL & SDA pins | |
| 364 | // Configure SCL & SDA pins | 356 | scl.io().ctrl().write(|w| w.set_funcsel(3)); |
| 365 | scl.io().ctrl().write(|w| w.set_funcsel(3)); | 357 | sda.io().ctrl().write(|w| w.set_funcsel(3)); |
| 366 | sda.io().ctrl().write(|w| w.set_funcsel(3)); | 358 | |
| 367 | 359 | scl.pad_ctrl().write(|w| { | |
| 368 | scl.pad_ctrl().write(|w| { | 360 | w.set_schmitt(true); |
| 369 | w.set_schmitt(true); | 361 | w.set_ie(true); |
| 370 | w.set_ie(true); | 362 | w.set_od(false); |
| 371 | w.set_od(false); | 363 | w.set_pue(true); |
| 372 | w.set_pue(true); | 364 | w.set_pde(false); |
| 373 | w.set_pde(false); | 365 | }); |
| 374 | }); | 366 | sda.pad_ctrl().write(|w| { |
| 375 | sda.pad_ctrl().write(|w| { | 367 | w.set_schmitt(true); |
| 376 | w.set_schmitt(true); | 368 | w.set_ie(true); |
| 377 | w.set_ie(true); | 369 | w.set_od(false); |
| 378 | w.set_od(false); | 370 | w.set_pue(true); |
| 379 | w.set_pue(true); | 371 | w.set_pde(false); |
| 380 | w.set_pde(false); | 372 | }); |
| 381 | }); | 373 | |
| 374 | // Configure baudrate | ||
| 375 | |||
| 376 | // There are some subtleties to I2C timing which we are completely | ||
| 377 | // ignoring here See: | ||
| 378 | // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 | ||
| 379 | let clk_base = crate::clocks::clk_peri_freq(); | ||
| 380 | |||
| 381 | let period = (clk_base + config.frequency / 2) / config.frequency; | ||
| 382 | let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low | ||
| 383 | let hcnt = period - lcnt; // and 2/5 (40%) of the period high | ||
| 384 | |||
| 385 | // Check for out-of-range divisors: | ||
| 386 | assert!(hcnt <= 0xffff); | ||
| 387 | assert!(lcnt <= 0xffff); | ||
| 388 | assert!(hcnt >= 8); | ||
| 389 | assert!(lcnt >= 8); | ||
| 390 | |||
| 391 | // Per I2C-bus specification a device in standard or fast mode must | ||
| 392 | // internally provide a hold time of at least 300ns for the SDA | ||
| 393 | // signal to bridge the undefined region of the falling edge of SCL. | ||
| 394 | // A smaller hold time of 120ns is used for fast mode plus. | ||
| 395 | let sda_tx_hold_count = if config.frequency < 1_000_000 { | ||
| 396 | // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s / | ||
| 397 | // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't | ||
| 398 | // fit in uint. Add 1 to avoid division truncation. | ||
| 399 | ((clk_base * 3) / 10_000_000) + 1 | ||
| 400 | } else { | ||
| 401 | // fast mode plus requires a clk_base > 32MHz | ||
| 402 | assert!(clk_base >= 32_000_000); | ||
| 382 | 403 | ||
| 383 | // Configure baudrate | 404 | // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / |
| 384 | 405 | // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't | |
| 385 | // There are some subtleties to I2C timing which we are completely | 406 | // fit in uint. Add 1 to avoid division truncation. |
| 386 | // ignoring here See: | 407 | ((clk_base * 3) / 25_000_000) + 1 |
| 387 | // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 | 408 | }; |
| 388 | let clk_base = crate::clocks::clk_peri_freq(); | 409 | assert!(sda_tx_hold_count <= lcnt - 2); |
| 389 | |||
| 390 | let period = (clk_base + config.frequency / 2) / config.frequency; | ||
| 391 | let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low | ||
| 392 | let hcnt = period - lcnt; // and 2/5 (40%) of the period high | ||
| 393 | |||
| 394 | // Check for out-of-range divisors: | ||
| 395 | assert!(hcnt <= 0xffff); | ||
| 396 | assert!(lcnt <= 0xffff); | ||
| 397 | assert!(hcnt >= 8); | ||
| 398 | assert!(lcnt >= 8); | ||
| 399 | |||
| 400 | // Per I2C-bus specification a device in standard or fast mode must | ||
| 401 | // internally provide a hold time of at least 300ns for the SDA | ||
| 402 | // signal to bridge the undefined region of the falling edge of SCL. | ||
| 403 | // A smaller hold time of 120ns is used for fast mode plus. | ||
| 404 | let sda_tx_hold_count = if config.frequency < 1_000_000 { | ||
| 405 | // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s / | ||
| 406 | // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't | ||
| 407 | // fit in uint. Add 1 to avoid division truncation. | ||
| 408 | ((clk_base * 3) / 10_000_000) + 1 | ||
| 409 | } else { | ||
| 410 | // fast mode plus requires a clk_base > 32MHz | ||
| 411 | assert!(clk_base >= 32_000_000); | ||
| 412 | 410 | ||
| 413 | // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / | 411 | p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); |
| 414 | // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't | 412 | p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); |
| 415 | // fit in uint. Add 1 to avoid division truncation. | 413 | p.ic_fs_spklen() |
| 416 | ((clk_base * 3) / 25_000_000) + 1 | 414 | .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 })); |
| 417 | }; | 415 | p.ic_sda_hold() |
| 418 | assert!(sda_tx_hold_count <= lcnt - 2); | 416 | .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); |
| 419 | 417 | ||
| 420 | p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); | 418 | // Enable I2C block |
| 421 | p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); | 419 | p.ic_enable().write(|w| w.set_enable(true)); |
| 422 | p.ic_fs_spklen() | ||
| 423 | .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 })); | ||
| 424 | p.ic_sda_hold() | ||
| 425 | .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); | ||
| 426 | |||
| 427 | // Enable I2C block | ||
| 428 | p.ic_enable().write(|w| w.set_enable(true)); | ||
| 429 | } | ||
| 430 | 420 | ||
| 431 | Self { phantom: PhantomData } | 421 | Self { phantom: PhantomData } |
| 432 | } | 422 | } |
| @@ -441,11 +431,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 441 | } | 431 | } |
| 442 | 432 | ||
| 443 | let p = T::regs(); | 433 | let p = T::regs(); |
| 444 | unsafe { | 434 | p.ic_enable().write(|w| w.set_enable(false)); |
| 445 | p.ic_enable().write(|w| w.set_enable(false)); | 435 | p.ic_tar().write(|w| w.set_ic_tar(addr)); |
| 446 | p.ic_tar().write(|w| w.set_ic_tar(addr)); | 436 | p.ic_enable().write(|w| w.set_enable(true)); |
| 447 | p.ic_enable().write(|w| w.set_enable(true)); | ||
| 448 | } | ||
| 449 | Ok(()) | 437 | Ok(()) |
| 450 | } | 438 | } |
| 451 | 439 | ||
| @@ -457,40 +445,38 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 457 | #[inline] | 445 | #[inline] |
| 458 | fn tx_fifo_capacity() -> u8 { | 446 | fn tx_fifo_capacity() -> u8 { |
| 459 | let p = T::regs(); | 447 | let p = T::regs(); |
| 460 | unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() } | 448 | FIFO_SIZE - p.ic_txflr().read().txflr() |
| 461 | } | 449 | } |
| 462 | 450 | ||
| 463 | #[inline] | 451 | #[inline] |
| 464 | fn rx_fifo_len() -> u8 { | 452 | fn rx_fifo_len() -> u8 { |
| 465 | let p = T::regs(); | 453 | let p = T::regs(); |
| 466 | unsafe { p.ic_rxflr().read().rxflr() } | 454 | p.ic_rxflr().read().rxflr() |
| 467 | } | 455 | } |
| 468 | 456 | ||
| 469 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { | 457 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { |
| 470 | let p = T::regs(); | 458 | let p = T::regs(); |
| 471 | unsafe { | 459 | let abort_reason = p.ic_tx_abrt_source().read(); |
| 472 | let abort_reason = p.ic_tx_abrt_source().read(); | 460 | if abort_reason.0 != 0 { |
| 473 | if abort_reason.0 != 0 { | 461 | // Note clearing the abort flag also clears the reason, and this |
| 474 | // Note clearing the abort flag also clears the reason, and this | 462 | // instance of flag is clear-on-read! Note also the |
| 475 | // instance of flag is clear-on-read! Note also the | 463 | // IC_CLR_TX_ABRT register always reads as 0. |
| 476 | // IC_CLR_TX_ABRT register always reads as 0. | 464 | p.ic_clr_tx_abrt().read(); |
| 477 | p.ic_clr_tx_abrt().read(); | 465 | |
| 478 | 466 | let reason = if abort_reason.abrt_7b_addr_noack() | |
| 479 | let reason = if abort_reason.abrt_7b_addr_noack() | 467 | | abort_reason.abrt_10addr1_noack() |
| 480 | | abort_reason.abrt_10addr1_noack() | 468 | | abort_reason.abrt_10addr2_noack() |
| 481 | | abort_reason.abrt_10addr2_noack() | 469 | { |
| 482 | { | 470 | AbortReason::NoAcknowledge |
| 483 | AbortReason::NoAcknowledge | 471 | } else if abort_reason.arb_lost() { |
| 484 | } else if abort_reason.arb_lost() { | 472 | AbortReason::ArbitrationLoss |
| 485 | AbortReason::ArbitrationLoss | ||
| 486 | } else { | ||
| 487 | AbortReason::Other(abort_reason.0) | ||
| 488 | }; | ||
| 489 | |||
| 490 | Err(Error::Abort(reason)) | ||
| 491 | } else { | 473 | } else { |
| 492 | Ok(()) | 474 | AbortReason::Other(abort_reason.0) |
| 493 | } | 475 | }; |
| 476 | |||
| 477 | Err(Error::Abort(reason)) | ||
| 478 | } else { | ||
| 479 | Ok(()) | ||
| 494 | } | 480 | } |
| 495 | } | 481 | } |
| 496 | 482 | ||
| @@ -505,24 +491,21 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 505 | let first = i == 0; | 491 | let first = i == 0; |
| 506 | let last = i == lastindex; | 492 | let last = i == lastindex; |
| 507 | 493 | ||
| 508 | // NOTE(unsafe) We have &mut self | 494 | // wait until there is space in the FIFO to write the next byte |
| 509 | unsafe { | 495 | while Self::tx_fifo_full() {} |
| 510 | // wait until there is space in the FIFO to write the next byte | ||
| 511 | while Self::tx_fifo_full() {} | ||
| 512 | 496 | ||
| 513 | p.ic_data_cmd().write(|w| { | 497 | p.ic_data_cmd().write(|w| { |
| 514 | w.set_restart(restart && first); | 498 | w.set_restart(restart && first); |
| 515 | w.set_stop(send_stop && last); | 499 | w.set_stop(send_stop && last); |
| 516 | 500 | ||
| 517 | w.set_cmd(true); | 501 | w.set_cmd(true); |
| 518 | }); | 502 | }); |
| 519 | |||
| 520 | while Self::rx_fifo_len() == 0 { | ||
| 521 | self.read_and_clear_abort_reason()?; | ||
| 522 | } | ||
| 523 | 503 | ||
| 524 | *byte = p.ic_data_cmd().read().dat(); | 504 | while Self::rx_fifo_len() == 0 { |
| 505 | self.read_and_clear_abort_reason()?; | ||
| 525 | } | 506 | } |
| 507 | |||
| 508 | *byte = p.ic_data_cmd().read().dat(); | ||
| 526 | } | 509 | } |
| 527 | 510 | ||
| 528 | Ok(()) | 511 | Ok(()) |
| @@ -538,36 +521,33 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||
| 538 | for (i, byte) in write.iter().enumerate() { | 521 | for (i, byte) in write.iter().enumerate() { |
| 539 | let last = i == write.len() - 1; | 522 | let last = i == write.len() - 1; |
| 540 | 523 | ||
| 541 | // NOTE(unsafe) We have &mut self | 524 | p.ic_data_cmd().write(|w| { |
| 542 | unsafe { | 525 | w.set_stop(send_stop && last); |
| 543 | p.ic_data_cmd().write(|w| { | 526 | w.set_dat(*byte); |
| 544 | w.set_stop(send_stop && last); | 527 | }); |
| 545 | w.set_dat(*byte); | ||
| 546 | }); | ||
| 547 | |||
| 548 | // Wait until the transmission of the address/data from the | ||
| 549 | // internal shift register has completed. For this to function | ||
| 550 | // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The | ||
| 551 | // TX_EMPTY_CTRL flag was set in i2c_init. | ||
| 552 | while !p.ic_raw_intr_stat().read().tx_empty() {} | ||
| 553 | 528 | ||
| 554 | let abort_reason = self.read_and_clear_abort_reason(); | 529 | // Wait until the transmission of the address/data from the |
| 530 | // internal shift register has completed. For this to function | ||
| 531 | // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The | ||
| 532 | // TX_EMPTY_CTRL flag was set in i2c_init. | ||
| 533 | while !p.ic_raw_intr_stat().read().tx_empty() {} | ||
| 555 | 534 | ||
| 556 | if abort_reason.is_err() || (send_stop && last) { | 535 | let abort_reason = self.read_and_clear_abort_reason(); |
| 557 | // If the transaction was aborted or if it completed | ||
| 558 | // successfully wait until the STOP condition has occurred. | ||
| 559 | 536 | ||
| 560 | while !p.ic_raw_intr_stat().read().stop_det() {} | 537 | if abort_reason.is_err() || (send_stop && last) { |
| 538 | // If the transaction was aborted or if it completed | ||
| 539 | // successfully wait until the STOP condition has occurred. | ||
| 561 | 540 | ||
| 562 | p.ic_clr_stop_det().read().clr_stop_det(); | 541 | while !p.ic_raw_intr_stat().read().stop_det() {} |
| 563 | } | ||
| 564 | 542 | ||
| 565 | // Note the hardware issues a STOP automatically on an abort | 543 | p.ic_clr_stop_det().read().clr_stop_det(); |
| 566 | // condition. Note also the hardware clears RX FIFO as well as | ||
| 567 | // TX on abort, ecause we set hwparam | ||
| 568 | // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. | ||
| 569 | abort_reason?; | ||
| 570 | } | 544 | } |
| 545 | |||
| 546 | // Note the hardware issues a STOP automatically on an abort | ||
| 547 | // condition. Note also the hardware clears RX FIFO as well as | ||
| 548 | // TX on abort, ecause we set hwparam | ||
| 549 | // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. | ||
| 550 | abort_reason?; | ||
| 571 | } | 551 | } |
| 572 | Ok(()) | 552 | Ok(()) |
| 573 | } | 553 | } |
| @@ -762,14 +742,15 @@ fn i2c_reserved_addr(addr: u16) -> bool { | |||
| 762 | } | 742 | } |
| 763 | 743 | ||
| 764 | mod sealed { | 744 | mod sealed { |
| 765 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 766 | use embassy_sync::waitqueue::AtomicWaker; | 745 | use embassy_sync::waitqueue::AtomicWaker; |
| 767 | 746 | ||
| 747 | use crate::interrupt; | ||
| 748 | |||
| 768 | pub trait Instance { | 749 | pub trait Instance { |
| 769 | const TX_DREQ: u8; | 750 | const TX_DREQ: u8; |
| 770 | const RX_DREQ: u8; | 751 | const RX_DREQ: u8; |
| 771 | 752 | ||
| 772 | type Interrupt: Interrupt; | 753 | type Interrupt: interrupt::typelevel::Interrupt; |
| 773 | 754 | ||
| 774 | fn regs() -> crate::pac::i2c::I2c; | 755 | fn regs() -> crate::pac::i2c::I2c; |
| 775 | fn reset() -> crate::pac::resets::regs::Peripherals; | 756 | fn reset() -> crate::pac::resets::regs::Peripherals; |
| @@ -805,7 +786,7 @@ macro_rules! impl_instance { | |||
| 805 | const TX_DREQ: u8 = $tx_dreq; | 786 | const TX_DREQ: u8 = $tx_dreq; |
| 806 | const RX_DREQ: u8 = $rx_dreq; | 787 | const RX_DREQ: u8 = $rx_dreq; |
| 807 | 788 | ||
| 808 | type Interrupt = crate::interrupt::$irq; | 789 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 809 | 790 | ||
| 810 | #[inline] | 791 | #[inline] |
| 811 | fn regs() -> pac::i2c::I2c { | 792 | fn regs() -> pac::i2c::I2c { |
diff --git a/embassy-rp/src/interrupt.rs b/embassy-rp/src/interrupt.rs deleted file mode 100644 index 1db13deef..000000000 --- a/embassy-rp/src/interrupt.rs +++ /dev/null | |||
| @@ -1,65 +0,0 @@ | |||
| 1 | //! Interrupt definitions and macros to bind them. | ||
| 2 | pub use cortex_m::interrupt::{CriticalSection, Mutex}; | ||
| 3 | use embassy_cortex_m::interrupt::_export::declare; | ||
| 4 | pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority}; | ||
| 5 | |||
| 6 | use crate::pac::Interrupt as InterruptEnum; | ||
| 7 | declare!(TIMER_IRQ_0); | ||
| 8 | declare!(TIMER_IRQ_1); | ||
| 9 | declare!(TIMER_IRQ_2); | ||
| 10 | declare!(TIMER_IRQ_3); | ||
| 11 | declare!(PWM_IRQ_WRAP); | ||
| 12 | declare!(USBCTRL_IRQ); | ||
| 13 | declare!(XIP_IRQ); | ||
| 14 | declare!(PIO0_IRQ_0); | ||
| 15 | declare!(PIO0_IRQ_1); | ||
| 16 | declare!(PIO1_IRQ_0); | ||
| 17 | declare!(PIO1_IRQ_1); | ||
| 18 | declare!(DMA_IRQ_0); | ||
| 19 | declare!(DMA_IRQ_1); | ||
| 20 | declare!(IO_IRQ_BANK0); | ||
| 21 | declare!(IO_IRQ_QSPI); | ||
| 22 | declare!(SIO_IRQ_PROC0); | ||
| 23 | declare!(SIO_IRQ_PROC1); | ||
| 24 | declare!(CLOCKS_IRQ); | ||
| 25 | declare!(SPI0_IRQ); | ||
| 26 | declare!(SPI1_IRQ); | ||
| 27 | declare!(UART0_IRQ); | ||
| 28 | declare!(UART1_IRQ); | ||
| 29 | declare!(ADC_IRQ_FIFO); | ||
| 30 | declare!(I2C0_IRQ); | ||
| 31 | declare!(I2C1_IRQ); | ||
| 32 | declare!(RTC_IRQ); | ||
| 33 | declare!(SWI_IRQ_0); | ||
| 34 | declare!(SWI_IRQ_1); | ||
| 35 | declare!(SWI_IRQ_2); | ||
| 36 | declare!(SWI_IRQ_3); | ||
| 37 | declare!(SWI_IRQ_4); | ||
| 38 | declare!(SWI_IRQ_5); | ||
| 39 | |||
| 40 | /// Macro to bind interrupts to handlers. | ||
| 41 | /// | ||
| 42 | /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) | ||
| 43 | /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to | ||
| 44 | /// prove at compile-time that the right interrupts have been bound. | ||
| 45 | // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`. | ||
| 46 | #[macro_export] | ||
| 47 | macro_rules! bind_interrupts { | ||
| 48 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { | ||
| 49 | $vis struct $name; | ||
| 50 | |||
| 51 | $( | ||
| 52 | #[allow(non_snake_case)] | ||
| 53 | #[no_mangle] | ||
| 54 | unsafe extern "C" fn $irq() { | ||
| 55 | $( | ||
| 56 | <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt(); | ||
| 57 | )* | ||
| 58 | } | ||
| 59 | |||
| 60 | $( | ||
| 61 | unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {} | ||
| 62 | )* | ||
| 63 | )* | ||
| 64 | }; | ||
| 65 | } | ||
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 4e4542d70..4fd3cb46a 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -16,7 +16,6 @@ pub mod flash; | |||
| 16 | mod float; | 16 | mod float; |
| 17 | pub mod gpio; | 17 | pub mod gpio; |
| 18 | pub mod i2c; | 18 | pub mod i2c; |
| 19 | pub mod interrupt; | ||
| 20 | pub mod multicore; | 19 | pub mod multicore; |
| 21 | pub mod pwm; | 20 | pub mod pwm; |
| 22 | mod reset; | 21 | mod reset; |
| @@ -37,14 +36,77 @@ pub mod pio_instr_util; | |||
| 37 | pub mod relocate; | 36 | pub mod relocate; |
| 38 | 37 | ||
| 39 | // Reexports | 38 | // Reexports |
| 40 | pub use embassy_cortex_m::executor; | ||
| 41 | pub use embassy_cortex_m::interrupt::_export::interrupt; | ||
| 42 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 39 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
| 43 | #[cfg(feature = "unstable-pac")] | 40 | #[cfg(feature = "unstable-pac")] |
| 44 | pub use rp_pac as pac; | 41 | pub use rp_pac as pac; |
| 45 | #[cfg(not(feature = "unstable-pac"))] | 42 | #[cfg(not(feature = "unstable-pac"))] |
| 46 | pub(crate) use rp_pac as pac; | 43 | pub(crate) use rp_pac as pac; |
| 47 | 44 | ||
| 45 | #[cfg(feature = "rt")] | ||
| 46 | pub use crate::pac::NVIC_PRIO_BITS; | ||
| 47 | |||
| 48 | embassy_hal_common::interrupt_mod!( | ||
| 49 | TIMER_IRQ_0, | ||
| 50 | TIMER_IRQ_1, | ||
| 51 | TIMER_IRQ_2, | ||
| 52 | TIMER_IRQ_3, | ||
| 53 | PWM_IRQ_WRAP, | ||
| 54 | USBCTRL_IRQ, | ||
| 55 | XIP_IRQ, | ||
| 56 | PIO0_IRQ_0, | ||
| 57 | PIO0_IRQ_1, | ||
| 58 | PIO1_IRQ_0, | ||
| 59 | PIO1_IRQ_1, | ||
| 60 | DMA_IRQ_0, | ||
| 61 | DMA_IRQ_1, | ||
| 62 | IO_IRQ_BANK0, | ||
| 63 | IO_IRQ_QSPI, | ||
| 64 | SIO_IRQ_PROC0, | ||
| 65 | SIO_IRQ_PROC1, | ||
| 66 | CLOCKS_IRQ, | ||
| 67 | SPI0_IRQ, | ||
| 68 | SPI1_IRQ, | ||
| 69 | UART0_IRQ, | ||
| 70 | UART1_IRQ, | ||
| 71 | ADC_IRQ_FIFO, | ||
| 72 | I2C0_IRQ, | ||
| 73 | I2C1_IRQ, | ||
| 74 | RTC_IRQ, | ||
| 75 | SWI_IRQ_0, | ||
| 76 | SWI_IRQ_1, | ||
| 77 | SWI_IRQ_2, | ||
| 78 | SWI_IRQ_3, | ||
| 79 | SWI_IRQ_4, | ||
| 80 | SWI_IRQ_5, | ||
| 81 | ); | ||
| 82 | |||
| 83 | /// Macro to bind interrupts to handlers. | ||
| 84 | /// | ||
| 85 | /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) | ||
| 86 | /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to | ||
| 87 | /// prove at compile-time that the right interrupts have been bound. | ||
| 88 | // developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`. | ||
| 89 | #[macro_export] | ||
| 90 | macro_rules! bind_interrupts { | ||
| 91 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { | ||
| 92 | $vis struct $name; | ||
| 93 | |||
| 94 | $( | ||
| 95 | #[allow(non_snake_case)] | ||
| 96 | #[no_mangle] | ||
| 97 | unsafe extern "C" fn $irq() { | ||
| 98 | $( | ||
| 99 | <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); | ||
| 100 | )* | ||
| 101 | } | ||
| 102 | |||
| 103 | $( | ||
| 104 | unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} | ||
| 105 | )* | ||
| 106 | )* | ||
| 107 | }; | ||
| 108 | } | ||
| 109 | |||
| 48 | embassy_hal_common::peripherals! { | 110 | embassy_hal_common::peripherals! { |
| 49 | PIN_0, | 111 | PIN_0, |
| 50 | PIN_1, | 112 | PIN_1, |
| @@ -199,33 +261,39 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 199 | 261 | ||
| 200 | /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. | 262 | /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. |
| 201 | trait RegExt<T: Copy> { | 263 | trait RegExt<T: Copy> { |
| 202 | unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; | 264 | fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; |
| 203 | unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; | 265 | fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; |
| 204 | unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; | 266 | fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; |
| 205 | } | 267 | } |
| 206 | 268 | ||
| 207 | impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> { | 269 | impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> { |
| 208 | unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { | 270 | fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { |
| 209 | let mut val = Default::default(); | 271 | let mut val = Default::default(); |
| 210 | let res = f(&mut val); | 272 | let res = f(&mut val); |
| 211 | let ptr = (self.ptr() as *mut u8).add(0x1000) as *mut T; | 273 | unsafe { |
| 212 | ptr.write_volatile(val); | 274 | let ptr = (self.as_ptr() as *mut u8).add(0x1000) as *mut T; |
| 275 | ptr.write_volatile(val); | ||
| 276 | } | ||
| 213 | res | 277 | res |
| 214 | } | 278 | } |
| 215 | 279 | ||
| 216 | unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { | 280 | fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { |
| 217 | let mut val = Default::default(); | 281 | let mut val = Default::default(); |
| 218 | let res = f(&mut val); | 282 | let res = f(&mut val); |
| 219 | let ptr = (self.ptr() as *mut u8).add(0x2000) as *mut T; | 283 | unsafe { |
| 220 | ptr.write_volatile(val); | 284 | let ptr = (self.as_ptr() as *mut u8).add(0x2000) as *mut T; |
| 285 | ptr.write_volatile(val); | ||
| 286 | } | ||
| 221 | res | 287 | res |
| 222 | } | 288 | } |
| 223 | 289 | ||
| 224 | unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { | 290 | fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { |
| 225 | let mut val = Default::default(); | 291 | let mut val = Default::default(); |
| 226 | let res = f(&mut val); | 292 | let res = f(&mut val); |
| 227 | let ptr = (self.ptr() as *mut u8).add(0x3000) as *mut T; | 293 | unsafe { |
| 228 | ptr.write_volatile(val); | 294 | let ptr = (self.as_ptr() as *mut u8).add(0x3000) as *mut T; |
| 295 | ptr.write_volatile(val); | ||
| 296 | } | ||
| 229 | res | 297 | res |
| 230 | } | 298 | } |
| 231 | } | 299 | } |
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index a13209f74..468e8470a 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs | |||
| @@ -50,7 +50,7 @@ | |||
| 50 | use core::mem::ManuallyDrop; | 50 | use core::mem::ManuallyDrop; |
| 51 | use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; | 51 | use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; |
| 52 | 52 | ||
| 53 | use crate::interrupt::{Interrupt, InterruptExt}; | 53 | use crate::interrupt::InterruptExt; |
| 54 | use crate::peripherals::CORE1; | 54 | use crate::peripherals::CORE1; |
| 55 | use crate::{gpio, interrupt, pac}; | 55 | use crate::{gpio, interrupt, pac}; |
| 56 | 56 | ||
| @@ -106,6 +106,7 @@ impl<const SIZE: usize> Stack<SIZE> { | |||
| 106 | } | 106 | } |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | #[cfg(feature = "rt")] | ||
| 109 | #[interrupt] | 110 | #[interrupt] |
| 110 | #[link_section = ".data.ram_func"] | 111 | #[link_section = ".data.ram_func"] |
| 111 | unsafe fn SIO_IRQ_PROC1() { | 112 | unsafe fn SIO_IRQ_PROC1() { |
| @@ -156,21 +157,18 @@ where | |||
| 156 | 157 | ||
| 157 | IS_CORE1_INIT.store(true, Ordering::Release); | 158 | IS_CORE1_INIT.store(true, Ordering::Release); |
| 158 | // Enable fifo interrupt on CORE1 for `pause` functionality. | 159 | // Enable fifo interrupt on CORE1 for `pause` functionality. |
| 159 | let irq = unsafe { interrupt::SIO_IRQ_PROC1::steal() }; | 160 | unsafe { interrupt::SIO_IRQ_PROC1.enable() }; |
| 160 | irq.enable(); | ||
| 161 | 161 | ||
| 162 | entry() | 162 | entry() |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | // Reset the core | 165 | // Reset the core |
| 166 | unsafe { | 166 | let psm = pac::PSM; |
| 167 | let psm = pac::PSM; | 167 | psm.frce_off().modify(|w| w.set_proc1(true)); |
| 168 | psm.frce_off().modify(|w| w.set_proc1(true)); | 168 | while !psm.frce_off().read().proc1() { |
| 169 | while !psm.frce_off().read().proc1() { | 169 | cortex_m::asm::nop(); |
| 170 | cortex_m::asm::nop(); | ||
| 171 | } | ||
| 172 | psm.frce_off().modify(|w| w.set_proc1(false)); | ||
| 173 | } | 170 | } |
| 171 | psm.frce_off().modify(|w| w.set_proc1(false)); | ||
| 174 | 172 | ||
| 175 | // The ARM AAPCS ABI requires 8-byte stack alignment. | 173 | // The ARM AAPCS ABI requires 8-byte stack alignment. |
| 176 | // #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be | 174 | // #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be |
| @@ -270,14 +268,12 @@ pub fn resume_core1() { | |||
| 270 | // Push a value to the inter-core FIFO, block until space is available | 268 | // Push a value to the inter-core FIFO, block until space is available |
| 271 | #[inline(always)] | 269 | #[inline(always)] |
| 272 | fn fifo_write(value: u32) { | 270 | fn fifo_write(value: u32) { |
| 273 | unsafe { | 271 | let sio = pac::SIO; |
| 274 | let sio = pac::SIO; | 272 | // Wait for the FIFO to have enough space |
| 275 | // Wait for the FIFO to have enough space | 273 | while !sio.fifo().st().read().rdy() { |
| 276 | while !sio.fifo().st().read().rdy() { | 274 | cortex_m::asm::nop(); |
| 277 | cortex_m::asm::nop(); | ||
| 278 | } | ||
| 279 | sio.fifo().wr().write_value(value); | ||
| 280 | } | 275 | } |
| 276 | sio.fifo().wr().write_value(value); | ||
| 281 | // Fire off an event to the other core. | 277 | // Fire off an event to the other core. |
| 282 | // This is required as the other core may be `wfe` (waiting for event) | 278 | // This is required as the other core may be `wfe` (waiting for event) |
| 283 | cortex_m::asm::sev(); | 279 | cortex_m::asm::sev(); |
| @@ -286,37 +282,32 @@ fn fifo_write(value: u32) { | |||
| 286 | // Pop a value from inter-core FIFO, block until available | 282 | // Pop a value from inter-core FIFO, block until available |
| 287 | #[inline(always)] | 283 | #[inline(always)] |
| 288 | fn fifo_read() -> u32 { | 284 | fn fifo_read() -> u32 { |
| 289 | unsafe { | 285 | let sio = pac::SIO; |
| 290 | let sio = pac::SIO; | 286 | // Wait until FIFO has data |
| 291 | // Wait until FIFO has data | 287 | while !sio.fifo().st().read().vld() { |
| 292 | while !sio.fifo().st().read().vld() { | 288 | cortex_m::asm::nop(); |
| 293 | cortex_m::asm::nop(); | ||
| 294 | } | ||
| 295 | sio.fifo().rd().read() | ||
| 296 | } | 289 | } |
| 290 | sio.fifo().rd().read() | ||
| 297 | } | 291 | } |
| 298 | 292 | ||
| 299 | // Pop a value from inter-core FIFO, `wfe` until available | 293 | // Pop a value from inter-core FIFO, `wfe` until available |
| 300 | #[inline(always)] | 294 | #[inline(always)] |
| 295 | #[allow(unused)] | ||
| 301 | fn fifo_read_wfe() -> u32 { | 296 | fn fifo_read_wfe() -> u32 { |
| 302 | unsafe { | 297 | let sio = pac::SIO; |
| 303 | let sio = pac::SIO; | 298 | // Wait until FIFO has data |
| 304 | // Wait until FIFO has data | 299 | while !sio.fifo().st().read().vld() { |
| 305 | while !sio.fifo().st().read().vld() { | 300 | cortex_m::asm::wfe(); |
| 306 | cortex_m::asm::wfe(); | ||
| 307 | } | ||
| 308 | sio.fifo().rd().read() | ||
| 309 | } | 301 | } |
| 302 | sio.fifo().rd().read() | ||
| 310 | } | 303 | } |
| 311 | 304 | ||
| 312 | // Drain inter-core FIFO | 305 | // Drain inter-core FIFO |
| 313 | #[inline(always)] | 306 | #[inline(always)] |
| 314 | fn fifo_drain() { | 307 | fn fifo_drain() { |
| 315 | unsafe { | 308 | let sio = pac::SIO; |
| 316 | let sio = pac::SIO; | 309 | while sio.fifo().st().read().vld() { |
| 317 | while sio.fifo().st().read().vld() { | 310 | let _ = sio.fifo().rd().read(); |
| 318 | let _ = sio.fifo().rd().read(); | ||
| 319 | } | ||
| 320 | } | 311 | } |
| 321 | } | 312 | } |
| 322 | 313 | ||
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index cbe45334a..1b36e0a54 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs | |||
| @@ -5,7 +5,6 @@ use core::sync::atomic::{compiler_fence, Ordering}; | |||
| 5 | use core::task::{Context, Poll}; | 5 | use core::task::{Context, Poll}; |
| 6 | 6 | ||
| 7 | use atomic_polyfill::{AtomicU32, AtomicU8}; | 7 | use atomic_polyfill::{AtomicU32, AtomicU8}; |
| 8 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 9 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 8 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 11 | use fixed::types::extra::U8; | 10 | use fixed::types::extra::U8; |
| @@ -17,6 +16,7 @@ use pio::{SideSet, Wrap}; | |||
| 17 | use crate::dma::{Channel, Transfer, Word}; | 16 | use crate::dma::{Channel, Transfer, Word}; |
| 18 | use crate::gpio::sealed::Pin as SealedPin; | 17 | use crate::gpio::sealed::Pin as SealedPin; |
| 19 | use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate}; | 18 | use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate}; |
| 19 | use crate::interrupt::InterruptExt; | ||
| 20 | use crate::pac::dma::vals::TreqSel; | 20 | use crate::pac::dma::vals::TreqSel; |
| 21 | use crate::relocate::RelocatedProgram; | 21 | use crate::relocate::RelocatedProgram; |
| 22 | use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt}; | 22 | use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt}; |
| @@ -85,8 +85,9 @@ const RXNEMPTY_MASK: u32 = 1 << 0; | |||
| 85 | const TXNFULL_MASK: u32 = 1 << 4; | 85 | const TXNFULL_MASK: u32 = 1 << 4; |
| 86 | const SMIRQ_MASK: u32 = 1 << 8; | 86 | const SMIRQ_MASK: u32 = 1 << 8; |
| 87 | 87 | ||
| 88 | #[cfg(feature = "rt")] | ||
| 88 | #[interrupt] | 89 | #[interrupt] |
| 89 | unsafe fn PIO0_IRQ_0() { | 90 | fn PIO0_IRQ_0() { |
| 90 | use crate::pac; | 91 | use crate::pac; |
| 91 | let ints = pac::PIO0.irqs(0).ints().read().0; | 92 | let ints = pac::PIO0.irqs(0).ints().read().0; |
| 92 | for bit in 0..12 { | 93 | for bit in 0..12 { |
| @@ -97,8 +98,9 @@ unsafe fn PIO0_IRQ_0() { | |||
| 97 | pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints); | 98 | pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints); |
| 98 | } | 99 | } |
| 99 | 100 | ||
| 101 | #[cfg(feature = "rt")] | ||
| 100 | #[interrupt] | 102 | #[interrupt] |
| 101 | unsafe fn PIO1_IRQ_0() { | 103 | fn PIO1_IRQ_0() { |
| 102 | use crate::pac; | 104 | use crate::pac; |
| 103 | let ints = pac::PIO1.irqs(0).ints().read().0; | 105 | let ints = pac::PIO1.irqs(0).ints().read().0; |
| 104 | for bit in 0..12 { | 106 | for bit in 0..12 { |
| @@ -110,17 +112,15 @@ unsafe fn PIO1_IRQ_0() { | |||
| 110 | } | 112 | } |
| 111 | 113 | ||
| 112 | pub(crate) unsafe fn init() { | 114 | pub(crate) unsafe fn init() { |
| 113 | let irq = interrupt::PIO0_IRQ_0::steal(); | 115 | interrupt::PIO0_IRQ_0.disable(); |
| 114 | irq.disable(); | 116 | interrupt::PIO0_IRQ_0.set_priority(interrupt::Priority::P3); |
| 115 | irq.set_priority(interrupt::Priority::P3); | ||
| 116 | pac::PIO0.irqs(0).inte().write(|m| m.0 = 0); | 117 | pac::PIO0.irqs(0).inte().write(|m| m.0 = 0); |
| 117 | irq.enable(); | 118 | interrupt::PIO0_IRQ_0.enable(); |
| 118 | 119 | ||
| 119 | let irq = interrupt::PIO1_IRQ_0::steal(); | 120 | interrupt::PIO1_IRQ_0.disable(); |
| 120 | irq.disable(); | 121 | interrupt::PIO1_IRQ_0.set_priority(interrupt::Priority::P3); |
| 121 | irq.set_priority(interrupt::Priority::P3); | ||
| 122 | pac::PIO1.irqs(0).inte().write(|m| m.0 = 0); | 122 | pac::PIO1.irqs(0).inte().write(|m| m.0 = 0); |
| 123 | irq.enable(); | 123 | interrupt::PIO1_IRQ_0.enable(); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | /// Future that waits for TX-FIFO to become writable | 126 | /// Future that waits for TX-FIFO to become writable |
| @@ -145,11 +145,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI | |||
| 145 | Poll::Ready(()) | 145 | Poll::Ready(()) |
| 146 | } else { | 146 | } else { |
| 147 | WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker()); | 147 | WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker()); |
| 148 | unsafe { | 148 | PIO::PIO.irqs(0).inte().write_set(|m| { |
| 149 | PIO::PIO.irqs(0).inte().write_set(|m| { | 149 | m.0 = TXNFULL_MASK << SM; |
| 150 | m.0 = TXNFULL_MASK << SM; | 150 | }); |
| 151 | }); | ||
| 152 | } | ||
| 153 | // debug!("Pending"); | 151 | // debug!("Pending"); |
| 154 | Poll::Pending | 152 | Poll::Pending |
| 155 | } | 153 | } |
| @@ -158,11 +156,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI | |||
| 158 | 156 | ||
| 159 | impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> { | 157 | impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> { |
| 160 | fn drop(&mut self) { | 158 | fn drop(&mut self) { |
| 161 | unsafe { | 159 | PIO::PIO.irqs(0).inte().write_clear(|m| { |
| 162 | PIO::PIO.irqs(0).inte().write_clear(|m| { | 160 | m.0 = TXNFULL_MASK << SM; |
| 163 | m.0 = TXNFULL_MASK << SM; | 161 | }); |
| 164 | }); | ||
| 165 | } | ||
| 166 | } | 162 | } |
| 167 | } | 163 | } |
| 168 | 164 | ||
| @@ -186,11 +182,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO | |||
| 186 | Poll::Ready(v) | 182 | Poll::Ready(v) |
| 187 | } else { | 183 | } else { |
| 188 | WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker()); | 184 | WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker()); |
| 189 | unsafe { | 185 | PIO::PIO.irqs(0).inte().write_set(|m| { |
| 190 | PIO::PIO.irqs(0).inte().write_set(|m| { | 186 | m.0 = RXNEMPTY_MASK << SM; |
| 191 | m.0 = RXNEMPTY_MASK << SM; | 187 | }); |
| 192 | }); | ||
| 193 | } | ||
| 194 | //debug!("Pending"); | 188 | //debug!("Pending"); |
| 195 | Poll::Pending | 189 | Poll::Pending |
| 196 | } | 190 | } |
| @@ -199,11 +193,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO | |||
| 199 | 193 | ||
| 200 | impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> { | 194 | impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> { |
| 201 | fn drop(&mut self) { | 195 | fn drop(&mut self) { |
| 202 | unsafe { | 196 | PIO::PIO.irqs(0).inte().write_clear(|m| { |
| 203 | PIO::PIO.irqs(0).inte().write_clear(|m| { | 197 | m.0 = RXNEMPTY_MASK << SM; |
| 204 | m.0 = RXNEMPTY_MASK << SM; | 198 | }); |
| 205 | }); | ||
| 206 | } | ||
| 207 | } | 199 | } |
| 208 | } | 200 | } |
| 209 | 201 | ||
| @@ -220,30 +212,24 @@ impl<'a, 'd, PIO: Instance> Future for IrqFuture<'a, 'd, PIO> { | |||
| 220 | //debug!("Poll {},{}", PIO::PIO_NO, SM); | 212 | //debug!("Poll {},{}", PIO::PIO_NO, SM); |
| 221 | 213 | ||
| 222 | // Check if IRQ flag is already set | 214 | // Check if IRQ flag is already set |
| 223 | if unsafe { PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 } { | 215 | if PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 { |
| 224 | unsafe { | 216 | PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no); |
| 225 | PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no); | ||
| 226 | } | ||
| 227 | return Poll::Ready(()); | 217 | return Poll::Ready(()); |
| 228 | } | 218 | } |
| 229 | 219 | ||
| 230 | WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); | 220 | WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); |
| 231 | unsafe { | 221 | PIO::PIO.irqs(0).inte().write_set(|m| { |
| 232 | PIO::PIO.irqs(0).inte().write_set(|m| { | 222 | m.0 = SMIRQ_MASK << self.irq_no; |
| 233 | m.0 = SMIRQ_MASK << self.irq_no; | 223 | }); |
| 234 | }); | ||
| 235 | } | ||
| 236 | Poll::Pending | 224 | Poll::Pending |
| 237 | } | 225 | } |
| 238 | } | 226 | } |
| 239 | 227 | ||
| 240 | impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> { | 228 | impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> { |
| 241 | fn drop(&mut self) { | 229 | fn drop(&mut self) { |
| 242 | unsafe { | 230 | PIO::PIO.irqs(0).inte().write_clear(|m| { |
| 243 | PIO::PIO.irqs(0).inte().write_clear(|m| { | 231 | m.0 = SMIRQ_MASK << self.irq_no; |
| 244 | m.0 = SMIRQ_MASK << self.irq_no; | 232 | }); |
| 245 | }); | ||
| 246 | } | ||
| 247 | } | 233 | } |
| 248 | } | 234 | } |
| 249 | 235 | ||
| @@ -256,57 +242,47 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { | |||
| 256 | /// Set the pin's drive strength. | 242 | /// Set the pin's drive strength. |
| 257 | #[inline] | 243 | #[inline] |
| 258 | pub fn set_drive_strength(&mut self, strength: Drive) { | 244 | pub fn set_drive_strength(&mut self, strength: Drive) { |
| 259 | unsafe { | 245 | self.pin.pad_ctrl().modify(|w| { |
| 260 | self.pin.pad_ctrl().modify(|w| { | 246 | w.set_drive(match strength { |
| 261 | w.set_drive(match strength { | 247 | Drive::_2mA => pac::pads::vals::Drive::_2MA, |
| 262 | Drive::_2mA => pac::pads::vals::Drive::_2MA, | 248 | Drive::_4mA => pac::pads::vals::Drive::_4MA, |
| 263 | Drive::_4mA => pac::pads::vals::Drive::_4MA, | 249 | Drive::_8mA => pac::pads::vals::Drive::_8MA, |
| 264 | Drive::_8mA => pac::pads::vals::Drive::_8MA, | 250 | Drive::_12mA => pac::pads::vals::Drive::_12MA, |
| 265 | Drive::_12mA => pac::pads::vals::Drive::_12MA, | ||
| 266 | }); | ||
| 267 | }); | 251 | }); |
| 268 | } | 252 | }); |
| 269 | } | 253 | } |
| 270 | 254 | ||
| 271 | // Set the pin's slew rate. | 255 | // Set the pin's slew rate. |
| 272 | #[inline] | 256 | #[inline] |
| 273 | pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { | 257 | pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { |
| 274 | unsafe { | 258 | self.pin.pad_ctrl().modify(|w| { |
| 275 | self.pin.pad_ctrl().modify(|w| { | 259 | w.set_slewfast(slew_rate == SlewRate::Fast); |
| 276 | w.set_slewfast(slew_rate == SlewRate::Fast); | 260 | }); |
| 277 | }); | ||
| 278 | } | ||
| 279 | } | 261 | } |
| 280 | 262 | ||
| 281 | /// Set the pin's pull. | 263 | /// Set the pin's pull. |
| 282 | #[inline] | 264 | #[inline] |
| 283 | pub fn set_pull(&mut self, pull: Pull) { | 265 | pub fn set_pull(&mut self, pull: Pull) { |
| 284 | unsafe { | 266 | self.pin.pad_ctrl().modify(|w| { |
| 285 | self.pin.pad_ctrl().modify(|w| { | 267 | w.set_pue(pull == Pull::Up); |
| 286 | w.set_pue(pull == Pull::Up); | 268 | w.set_pde(pull == Pull::Down); |
| 287 | w.set_pde(pull == Pull::Down); | 269 | }); |
| 288 | }); | ||
| 289 | } | ||
| 290 | } | 270 | } |
| 291 | 271 | ||
| 292 | /// Set the pin's schmitt trigger. | 272 | /// Set the pin's schmitt trigger. |
| 293 | #[inline] | 273 | #[inline] |
| 294 | pub fn set_schmitt(&mut self, enable: bool) { | 274 | pub fn set_schmitt(&mut self, enable: bool) { |
| 295 | unsafe { | 275 | self.pin.pad_ctrl().modify(|w| { |
| 296 | self.pin.pad_ctrl().modify(|w| { | 276 | w.set_schmitt(enable); |
| 297 | w.set_schmitt(enable); | 277 | }); |
| 298 | }); | ||
| 299 | } | ||
| 300 | } | 278 | } |
| 301 | 279 | ||
| 302 | pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { | 280 | pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { |
| 303 | let mask = 1 << self.pin(); | 281 | let mask = 1 << self.pin(); |
| 304 | unsafe { | 282 | if bypass { |
| 305 | if bypass { | 283 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); |
| 306 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); | 284 | } else { |
| 307 | } else { | 285 | PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask); |
| 308 | PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask); | ||
| 309 | } | ||
| 310 | } | 286 | } |
| 311 | } | 287 | } |
| 312 | 288 | ||
| @@ -321,41 +297,37 @@ pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> { | |||
| 321 | 297 | ||
| 322 | impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | 298 | impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { |
| 323 | pub fn empty(&self) -> bool { | 299 | pub fn empty(&self) -> bool { |
| 324 | unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 } | 300 | PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 |
| 325 | } | 301 | } |
| 326 | 302 | ||
| 327 | pub fn full(&self) -> bool { | 303 | pub fn full(&self) -> bool { |
| 328 | unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 } | 304 | PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 |
| 329 | } | 305 | } |
| 330 | 306 | ||
| 331 | pub fn level(&self) -> u8 { | 307 | pub fn level(&self) -> u8 { |
| 332 | unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f } | 308 | (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f |
| 333 | } | 309 | } |
| 334 | 310 | ||
| 335 | pub fn stalled(&self) -> bool { | 311 | pub fn stalled(&self) -> bool { |
| 336 | unsafe { | 312 | let fdebug = PIO::PIO.fdebug(); |
| 337 | let fdebug = PIO::PIO.fdebug(); | 313 | let ret = fdebug.read().rxstall() & (1 << SM) != 0; |
| 338 | let ret = fdebug.read().rxstall() & (1 << SM) != 0; | 314 | if ret { |
| 339 | if ret { | 315 | fdebug.write(|w| w.set_rxstall(1 << SM)); |
| 340 | fdebug.write(|w| w.set_rxstall(1 << SM)); | ||
| 341 | } | ||
| 342 | ret | ||
| 343 | } | 316 | } |
| 317 | ret | ||
| 344 | } | 318 | } |
| 345 | 319 | ||
| 346 | pub fn underflowed(&self) -> bool { | 320 | pub fn underflowed(&self) -> bool { |
| 347 | unsafe { | 321 | let fdebug = PIO::PIO.fdebug(); |
| 348 | let fdebug = PIO::PIO.fdebug(); | 322 | let ret = fdebug.read().rxunder() & (1 << SM) != 0; |
| 349 | let ret = fdebug.read().rxunder() & (1 << SM) != 0; | 323 | if ret { |
| 350 | if ret { | 324 | fdebug.write(|w| w.set_rxunder(1 << SM)); |
| 351 | fdebug.write(|w| w.set_rxunder(1 << SM)); | ||
| 352 | } | ||
| 353 | ret | ||
| 354 | } | 325 | } |
| 326 | ret | ||
| 355 | } | 327 | } |
| 356 | 328 | ||
| 357 | pub fn pull(&mut self) -> u32 { | 329 | pub fn pull(&mut self) -> u32 { |
| 358 | unsafe { PIO::PIO.rxf(SM).read() } | 330 | PIO::PIO.rxf(SM).read() |
| 359 | } | 331 | } |
| 360 | 332 | ||
| 361 | pub fn try_pull(&mut self) -> Option<u32> { | 333 | pub fn try_pull(&mut self) -> Option<u32> { |
| @@ -374,24 +346,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | |||
| 374 | ch: PeripheralRef<'a, C>, | 346 | ch: PeripheralRef<'a, C>, |
| 375 | data: &'a mut [W], | 347 | data: &'a mut [W], |
| 376 | ) -> Transfer<'a, C> { | 348 | ) -> Transfer<'a, C> { |
| 377 | unsafe { | 349 | let pio_no = PIO::PIO_NO; |
| 378 | let pio_no = PIO::PIO_NO; | 350 | let p = ch.regs(); |
| 379 | let p = ch.regs(); | 351 | p.write_addr().write_value(data.as_ptr() as u32); |
| 380 | p.write_addr().write_value(data.as_ptr() as u32); | 352 | p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32); |
| 381 | p.read_addr().write_value(PIO::PIO.rxf(SM).ptr() as u32); | 353 | p.trans_count().write_value(data.len() as u32); |
| 382 | p.trans_count().write_value(data.len() as u32); | 354 | compiler_fence(Ordering::SeqCst); |
| 383 | compiler_fence(Ordering::SeqCst); | 355 | p.ctrl_trig().write(|w| { |
| 384 | p.ctrl_trig().write(|w| { | 356 | // Set RX DREQ for this statemachine |
| 385 | // Set RX DREQ for this statemachine | 357 | w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); |
| 386 | w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); | 358 | w.set_data_size(W::size()); |
| 387 | w.set_data_size(W::size()); | 359 | w.set_chain_to(ch.number()); |
| 388 | w.set_chain_to(ch.number()); | 360 | w.set_incr_read(false); |
| 389 | w.set_incr_read(false); | 361 | w.set_incr_write(true); |
| 390 | w.set_incr_write(true); | 362 | w.set_en(true); |
| 391 | w.set_en(true); | 363 | }); |
| 392 | }); | 364 | compiler_fence(Ordering::SeqCst); |
| 393 | compiler_fence(Ordering::SeqCst); | ||
| 394 | } | ||
| 395 | Transfer::new(ch) | 365 | Transfer::new(ch) |
| 396 | } | 366 | } |
| 397 | } | 367 | } |
| @@ -402,42 +372,36 @@ pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> { | |||
| 402 | 372 | ||
| 403 | impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | 373 | impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { |
| 404 | pub fn empty(&self) -> bool { | 374 | pub fn empty(&self) -> bool { |
| 405 | unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 } | 375 | PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 |
| 406 | } | 376 | } |
| 407 | pub fn full(&self) -> bool { | 377 | pub fn full(&self) -> bool { |
| 408 | unsafe { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 } | 378 | PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 |
| 409 | } | 379 | } |
| 410 | 380 | ||
| 411 | pub fn level(&self) -> u8 { | 381 | pub fn level(&self) -> u8 { |
| 412 | unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f } | 382 | (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f |
| 413 | } | 383 | } |
| 414 | 384 | ||
| 415 | pub fn stalled(&self) -> bool { | 385 | pub fn stalled(&self) -> bool { |
| 416 | unsafe { | 386 | let fdebug = PIO::PIO.fdebug(); |
| 417 | let fdebug = PIO::PIO.fdebug(); | 387 | let ret = fdebug.read().txstall() & (1 << SM) != 0; |
| 418 | let ret = fdebug.read().txstall() & (1 << SM) != 0; | 388 | if ret { |
| 419 | if ret { | 389 | fdebug.write(|w| w.set_txstall(1 << SM)); |
| 420 | fdebug.write(|w| w.set_txstall(1 << SM)); | ||
| 421 | } | ||
| 422 | ret | ||
| 423 | } | 390 | } |
| 391 | ret | ||
| 424 | } | 392 | } |
| 425 | 393 | ||
| 426 | pub fn overflowed(&self) -> bool { | 394 | pub fn overflowed(&self) -> bool { |
| 427 | unsafe { | 395 | let fdebug = PIO::PIO.fdebug(); |
| 428 | let fdebug = PIO::PIO.fdebug(); | 396 | let ret = fdebug.read().txover() & (1 << SM) != 0; |
| 429 | let ret = fdebug.read().txover() & (1 << SM) != 0; | 397 | if ret { |
| 430 | if ret { | 398 | fdebug.write(|w| w.set_txover(1 << SM)); |
| 431 | fdebug.write(|w| w.set_txover(1 << SM)); | ||
| 432 | } | ||
| 433 | ret | ||
| 434 | } | 399 | } |
| 400 | ret | ||
| 435 | } | 401 | } |
| 436 | 402 | ||
| 437 | pub fn push(&mut self, v: u32) { | 403 | pub fn push(&mut self, v: u32) { |
| 438 | unsafe { | 404 | PIO::PIO.txf(SM).write_value(v); |
| 439 | PIO::PIO.txf(SM).write_value(v); | ||
| 440 | } | ||
| 441 | } | 405 | } |
| 442 | 406 | ||
| 443 | pub fn try_push(&mut self, v: u32) -> bool { | 407 | pub fn try_push(&mut self, v: u32) -> bool { |
| @@ -453,24 +417,22 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 453 | } | 417 | } |
| 454 | 418 | ||
| 455 | pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { | 419 | pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { |
| 456 | unsafe { | 420 | let pio_no = PIO::PIO_NO; |
| 457 | let pio_no = PIO::PIO_NO; | 421 | let p = ch.regs(); |
| 458 | let p = ch.regs(); | 422 | p.read_addr().write_value(data.as_ptr() as u32); |
| 459 | p.read_addr().write_value(data.as_ptr() as u32); | 423 | p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32); |
| 460 | p.write_addr().write_value(PIO::PIO.txf(SM).ptr() as u32); | 424 | p.trans_count().write_value(data.len() as u32); |
| 461 | p.trans_count().write_value(data.len() as u32); | 425 | compiler_fence(Ordering::SeqCst); |
| 462 | compiler_fence(Ordering::SeqCst); | 426 | p.ctrl_trig().write(|w| { |
| 463 | p.ctrl_trig().write(|w| { | 427 | // Set TX DREQ for this statemachine |
| 464 | // Set TX DREQ for this statemachine | 428 | w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); |
| 465 | w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); | 429 | w.set_data_size(W::size()); |
| 466 | w.set_data_size(W::size()); | 430 | w.set_chain_to(ch.number()); |
| 467 | w.set_chain_to(ch.number()); | 431 | w.set_incr_read(true); |
| 468 | w.set_incr_read(true); | 432 | w.set_incr_write(false); |
| 469 | w.set_incr_write(false); | 433 | w.set_en(true); |
| 470 | w.set_en(true); | 434 | }); |
| 471 | }); | 435 | compiler_fence(Ordering::SeqCst); |
| 472 | compiler_fence(Ordering::SeqCst); | ||
| 473 | } | ||
| 474 | Transfer::new(ch) | 436 | Transfer::new(ch) |
| 475 | } | 437 | } |
| 476 | } | 438 | } |
| @@ -482,9 +444,7 @@ pub struct StateMachine<'d, PIO: Instance, const SM: usize> { | |||
| 482 | 444 | ||
| 483 | impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> { | 445 | impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> { |
| 484 | fn drop(&mut self) { | 446 | fn drop(&mut self) { |
| 485 | unsafe { | 447 | PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM)); |
| 486 | PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM)); | ||
| 487 | } | ||
| 488 | on_pio_drop::<PIO>(); | 448 | on_pio_drop::<PIO>(); |
| 489 | } | 449 | } |
| 490 | } | 450 | } |
| @@ -647,45 +607,43 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 647 | assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); | 607 | assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); |
| 648 | assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); | 608 | assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); |
| 649 | let sm = Self::this_sm(); | 609 | let sm = Self::this_sm(); |
| 650 | unsafe { | 610 | sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8); |
| 651 | sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8); | 611 | sm.execctrl().write(|w| { |
| 652 | sm.execctrl().write(|w| { | 612 | w.set_side_en(config.exec.side_en); |
| 653 | w.set_side_en(config.exec.side_en); | 613 | w.set_side_pindir(config.exec.side_pindir); |
| 654 | w.set_side_pindir(config.exec.side_pindir); | 614 | w.set_jmp_pin(config.exec.jmp_pin); |
| 655 | w.set_jmp_pin(config.exec.jmp_pin); | 615 | w.set_out_en_sel(config.out_en_sel); |
| 656 | w.set_out_en_sel(config.out_en_sel); | 616 | w.set_inline_out_en(config.inline_out_en); |
| 657 | w.set_inline_out_en(config.inline_out_en); | 617 | w.set_out_sticky(config.out_sticky); |
| 658 | w.set_out_sticky(config.out_sticky); | 618 | w.set_wrap_top(config.exec.wrap_top); |
| 659 | w.set_wrap_top(config.exec.wrap_top); | 619 | w.set_wrap_bottom(config.exec.wrap_bottom); |
| 660 | w.set_wrap_bottom(config.exec.wrap_bottom); | 620 | w.set_status_sel(match config.status_sel { |
| 661 | w.set_status_sel(match config.status_sel { | 621 | StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, |
| 662 | StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, | 622 | StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL, |
| 663 | StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL, | ||
| 664 | }); | ||
| 665 | w.set_status_n(config.status_n); | ||
| 666 | }); | ||
| 667 | sm.shiftctrl().write(|w| { | ||
| 668 | w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly); | ||
| 669 | w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly); | ||
| 670 | w.set_pull_thresh(config.shift_out.threshold); | ||
| 671 | w.set_push_thresh(config.shift_in.threshold); | ||
| 672 | w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right); | ||
| 673 | w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right); | ||
| 674 | w.set_autopull(config.shift_out.auto_fill); | ||
| 675 | w.set_autopush(config.shift_in.auto_fill); | ||
| 676 | }); | ||
| 677 | sm.pinctrl().write(|w| { | ||
| 678 | w.set_sideset_count(config.pins.sideset_count); | ||
| 679 | w.set_set_count(config.pins.set_count); | ||
| 680 | w.set_out_count(config.pins.out_count); | ||
| 681 | w.set_in_base(config.pins.in_base); | ||
| 682 | w.set_sideset_base(config.pins.sideset_base); | ||
| 683 | w.set_set_base(config.pins.set_base); | ||
| 684 | w.set_out_base(config.pins.out_base); | ||
| 685 | }); | 623 | }); |
| 686 | if let Some(origin) = config.origin { | 624 | w.set_status_n(config.status_n); |
| 687 | pio_instr_util::exec_jmp(self, origin); | 625 | }); |
| 688 | } | 626 | sm.shiftctrl().write(|w| { |
| 627 | w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly); | ||
| 628 | w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly); | ||
| 629 | w.set_pull_thresh(config.shift_out.threshold); | ||
| 630 | w.set_push_thresh(config.shift_in.threshold); | ||
| 631 | w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right); | ||
| 632 | w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right); | ||
| 633 | w.set_autopull(config.shift_out.auto_fill); | ||
| 634 | w.set_autopush(config.shift_in.auto_fill); | ||
| 635 | }); | ||
| 636 | sm.pinctrl().write(|w| { | ||
| 637 | w.set_sideset_count(config.pins.sideset_count); | ||
| 638 | w.set_set_count(config.pins.set_count); | ||
| 639 | w.set_out_count(config.pins.out_count); | ||
| 640 | w.set_in_base(config.pins.in_base); | ||
| 641 | w.set_sideset_base(config.pins.sideset_base); | ||
| 642 | w.set_set_base(config.pins.set_base); | ||
| 643 | w.set_out_base(config.pins.out_base); | ||
| 644 | }); | ||
| 645 | if let Some(origin) = config.origin { | ||
| 646 | unsafe { pio_instr_util::exec_jmp(self, origin) } | ||
| 689 | } | 647 | } |
| 690 | } | 648 | } |
| 691 | 649 | ||
| @@ -696,45 +654,35 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 696 | 654 | ||
| 697 | pub fn restart(&mut self) { | 655 | pub fn restart(&mut self) { |
| 698 | let mask = 1u8 << SM; | 656 | let mask = 1u8 << SM; |
| 699 | unsafe { | 657 | PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); |
| 700 | PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); | ||
| 701 | } | ||
| 702 | } | 658 | } |
| 703 | pub fn set_enable(&mut self, enable: bool) { | 659 | pub fn set_enable(&mut self, enable: bool) { |
| 704 | let mask = 1u8 << SM; | 660 | let mask = 1u8 << SM; |
| 705 | unsafe { | 661 | if enable { |
| 706 | if enable { | 662 | PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); |
| 707 | PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); | 663 | } else { |
| 708 | } else { | 664 | PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask)); |
| 709 | PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask)); | ||
| 710 | } | ||
| 711 | } | 665 | } |
| 712 | } | 666 | } |
| 713 | 667 | ||
| 714 | pub fn is_enabled(&self) -> bool { | 668 | pub fn is_enabled(&self) -> bool { |
| 715 | unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } | 669 | PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 |
| 716 | } | 670 | } |
| 717 | 671 | ||
| 718 | pub fn clkdiv_restart(&mut self) { | 672 | pub fn clkdiv_restart(&mut self) { |
| 719 | let mask = 1u8 << SM; | 673 | let mask = 1u8 << SM; |
| 720 | unsafe { | 674 | PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); |
| 721 | PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); | ||
| 722 | } | ||
| 723 | } | 675 | } |
| 724 | 676 | ||
| 725 | fn with_paused(&mut self, f: impl FnOnce(&mut Self)) { | 677 | fn with_paused(&mut self, f: impl FnOnce(&mut Self)) { |
| 726 | let enabled = self.is_enabled(); | 678 | let enabled = self.is_enabled(); |
| 727 | self.set_enable(false); | 679 | self.set_enable(false); |
| 728 | let pincfg = unsafe { Self::this_sm().pinctrl().read() }; | 680 | let pincfg = Self::this_sm().pinctrl().read(); |
| 729 | let execcfg = unsafe { Self::this_sm().execctrl().read() }; | 681 | let execcfg = Self::this_sm().execctrl().read(); |
| 730 | unsafe { | 682 | Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true)); |
| 731 | Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true)); | ||
| 732 | } | ||
| 733 | f(self); | 683 | f(self); |
| 734 | unsafe { | 684 | Self::this_sm().pinctrl().write_value(pincfg); |
| 735 | Self::this_sm().pinctrl().write_value(pincfg); | 685 | Self::this_sm().execctrl().write_value(execcfg); |
| 736 | Self::this_sm().execctrl().write_value(execcfg); | ||
| 737 | } | ||
| 738 | self.set_enable(enabled); | 686 | self.set_enable(enabled); |
| 739 | } | 687 | } |
| 740 | 688 | ||
| @@ -743,14 +691,12 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 743 | pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) { | 691 | pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) { |
| 744 | self.with_paused(|sm| { | 692 | self.with_paused(|sm| { |
| 745 | for pin in pins { | 693 | for pin in pins { |
| 746 | unsafe { | 694 | Self::this_sm().pinctrl().write(|w| { |
| 747 | Self::this_sm().pinctrl().write(|w| { | 695 | w.set_set_base(pin.pin()); |
| 748 | w.set_set_base(pin.pin()); | 696 | w.set_set_count(1); |
| 749 | w.set_set_count(1); | 697 | }); |
| 750 | }); | 698 | // SET PINDIRS, (dir) |
| 751 | // SET PINDIRS, (dir) | 699 | unsafe { sm.exec_instr(0b111_00000_100_00000 | dir as u16) }; |
| 752 | sm.exec_instr(0b111_00000_100_00000 | dir as u16); | ||
| 753 | } | ||
| 754 | } | 700 | } |
| 755 | }); | 701 | }); |
| 756 | } | 702 | } |
| @@ -760,29 +706,25 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 760 | pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) { | 706 | pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) { |
| 761 | self.with_paused(|sm| { | 707 | self.with_paused(|sm| { |
| 762 | for pin in pins { | 708 | for pin in pins { |
| 763 | unsafe { | 709 | Self::this_sm().pinctrl().write(|w| { |
| 764 | Self::this_sm().pinctrl().write(|w| { | 710 | w.set_set_base(pin.pin()); |
| 765 | w.set_set_base(pin.pin()); | 711 | w.set_set_count(1); |
| 766 | w.set_set_count(1); | 712 | }); |
| 767 | }); | 713 | // SET PINS, (dir) |
| 768 | // SET PINS, (dir) | 714 | unsafe { sm.exec_instr(0b111_00000_000_00000 | level as u16) }; |
| 769 | sm.exec_instr(0b111_00000_000_00000 | level as u16); | ||
| 770 | } | ||
| 771 | } | 715 | } |
| 772 | }); | 716 | }); |
| 773 | } | 717 | } |
| 774 | 718 | ||
| 775 | pub fn clear_fifos(&mut self) { | 719 | pub fn clear_fifos(&mut self) { |
| 776 | // Toggle FJOIN_RX to flush FIFOs | 720 | // Toggle FJOIN_RX to flush FIFOs |
| 777 | unsafe { | 721 | let shiftctrl = Self::this_sm().shiftctrl(); |
| 778 | let shiftctrl = Self::this_sm().shiftctrl(); | 722 | shiftctrl.modify(|w| { |
| 779 | shiftctrl.modify(|w| { | 723 | w.set_fjoin_rx(!w.fjoin_rx()); |
| 780 | w.set_fjoin_rx(!w.fjoin_rx()); | 724 | }); |
| 781 | }); | 725 | shiftctrl.modify(|w| { |
| 782 | shiftctrl.modify(|w| { | 726 | w.set_fjoin_rx(!w.fjoin_rx()); |
| 783 | w.set_fjoin_rx(!w.fjoin_rx()); | 727 | }); |
| 784 | }); | ||
| 785 | } | ||
| 786 | } | 728 | } |
| 787 | 729 | ||
| 788 | pub unsafe fn exec_instr(&mut self, instr: u16) { | 730 | pub unsafe fn exec_instr(&mut self, instr: u16) { |
| @@ -856,11 +798,9 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 856 | if (self.instructions_used | used_mask) & mask != 0 { | 798 | if (self.instructions_used | used_mask) & mask != 0 { |
| 857 | return Err(addr); | 799 | return Err(addr); |
| 858 | } | 800 | } |
| 859 | unsafe { | 801 | PIO::PIO.instr_mem(addr).write(|w| { |
| 860 | PIO::PIO.instr_mem(addr).write(|w| { | 802 | w.set_instr_mem(instr); |
| 861 | w.set_instr_mem(instr); | 803 | }); |
| 862 | }); | ||
| 863 | } | ||
| 864 | used_mask |= mask; | 804 | used_mask |= mask; |
| 865 | } | 805 | } |
| 866 | self.instructions_used |= used_mask; | 806 | self.instructions_used |= used_mask; |
| @@ -877,17 +817,15 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 877 | } | 817 | } |
| 878 | 818 | ||
| 879 | pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { | 819 | pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { |
| 880 | unsafe { | 820 | // this can interfere with per-pin bypass functions. splitting the |
| 881 | // this can interfere with per-pin bypass functions. splitting the | 821 | // modification is going to be fine since nothing that relies on |
| 882 | // modification is going to be fine since nothing that relies on | 822 | // it can reasonably run before we finish. |
| 883 | // it can reasonably run before we finish. | 823 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); |
| 884 | PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); | 824 | PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); |
| 885 | PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); | ||
| 886 | } | ||
| 887 | } | 825 | } |
| 888 | 826 | ||
| 889 | pub fn get_input_sync_bypass(&self) -> u32 { | 827 | pub fn get_input_sync_bypass(&self) -> u32 { |
| 890 | unsafe { PIO::PIO.input_sync_bypass().read() } | 828 | PIO::PIO.input_sync_bypass().read() |
| 891 | } | 829 | } |
| 892 | 830 | ||
| 893 | /// Register a pin for PIO usage. Pins will be released from the PIO block | 831 | /// Register a pin for PIO usage. Pins will be released from the PIO block |
| @@ -896,9 +834,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 896 | /// of [`Pio`] do not keep pin registrations alive.** | 834 | /// of [`Pio`] do not keep pin registrations alive.** |
| 897 | pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> { | 835 | pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> { |
| 898 | into_ref!(pin); | 836 | into_ref!(pin); |
| 899 | unsafe { | 837 | pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); |
| 900 | pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); | ||
| 901 | } | ||
| 902 | // we can be relaxed about this because we're &mut here and nothing is cached | 838 | // we can be relaxed about this because we're &mut here and nothing is cached |
| 903 | PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); | 839 | PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); |
| 904 | Pin { | 840 | Pin { |
| @@ -916,13 +852,11 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 916 | _pio: PhantomData, | 852 | _pio: PhantomData, |
| 917 | }; | 853 | }; |
| 918 | f(&mut batch); | 854 | f(&mut batch); |
| 919 | unsafe { | 855 | PIO::PIO.ctrl().modify(|w| { |
| 920 | PIO::PIO.ctrl().modify(|w| { | 856 | w.set_clkdiv_restart(batch.clkdiv_restart); |
| 921 | w.set_clkdiv_restart(batch.clkdiv_restart); | 857 | w.set_sm_restart(batch.sm_restart); |
| 922 | w.set_sm_restart(batch.sm_restart); | 858 | w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable); |
| 923 | w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable); | 859 | }); |
| 924 | }); | ||
| 925 | } | ||
| 926 | } | 860 | } |
| 927 | } | 861 | } |
| 928 | 862 | ||
| @@ -974,11 +908,11 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> { | |||
| 974 | } | 908 | } |
| 975 | 909 | ||
| 976 | pub fn check_any(&self, irqs: u8) -> bool { | 910 | pub fn check_any(&self, irqs: u8) -> bool { |
| 977 | unsafe { PIO::PIO.irq().read().irq() & irqs != 0 } | 911 | PIO::PIO.irq().read().irq() & irqs != 0 |
| 978 | } | 912 | } |
| 979 | 913 | ||
| 980 | pub fn check_all(&self, irqs: u8) -> bool { | 914 | pub fn check_all(&self, irqs: u8) -> bool { |
| 981 | unsafe { PIO::PIO.irq().read().irq() & irqs == irqs } | 915 | PIO::PIO.irq().read().irq() & irqs == irqs |
| 982 | } | 916 | } |
| 983 | 917 | ||
| 984 | pub fn clear(&self, irq_no: usize) { | 918 | pub fn clear(&self, irq_no: usize) { |
| @@ -987,7 +921,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> { | |||
| 987 | } | 921 | } |
| 988 | 922 | ||
| 989 | pub fn clear_all(&self, irqs: u8) { | 923 | pub fn clear_all(&self, irqs: u8) { |
| 990 | unsafe { PIO::PIO.irq().write(|w| w.set_irq(irqs)) } | 924 | PIO::PIO.irq().write(|w| w.set_irq(irqs)) |
| 991 | } | 925 | } |
| 992 | 926 | ||
| 993 | pub fn set(&self, irq_no: usize) { | 927 | pub fn set(&self, irq_no: usize) { |
| @@ -996,7 +930,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> { | |||
| 996 | } | 930 | } |
| 997 | 931 | ||
| 998 | pub fn set_all(&self, irqs: u8) { | 932 | pub fn set_all(&self, irqs: u8) { |
| 999 | unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) } | 933 | PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) |
| 1000 | } | 934 | } |
| 1001 | } | 935 | } |
| 1002 | 936 | ||
| @@ -1068,9 +1002,7 @@ fn on_pio_drop<PIO: Instance>() { | |||
| 1068 | // we only have 30 pins. don't test the other two since gpio() asserts. | 1002 | // we only have 30 pins. don't test the other two since gpio() asserts. |
| 1069 | for i in 0..30 { | 1003 | for i in 0..30 { |
| 1070 | if used_pins & (1 << i) != 0 { | 1004 | if used_pins & (1 << i) != 0 { |
| 1071 | unsafe { | 1005 | pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null)); |
| 1072 | pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null)); | ||
| 1073 | } | ||
| 1074 | } | 1006 | } |
| 1075 | } | 1007 | } |
| 1076 | } | 1008 | } |
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 0f9dcf479..20bb88446 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs | |||
| @@ -71,20 +71,18 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 71 | into_ref!(inner); | 71 | into_ref!(inner); |
| 72 | 72 | ||
| 73 | let p = inner.regs(); | 73 | let p = inner.regs(); |
| 74 | unsafe { | 74 | p.csr().modify(|w| { |
| 75 | p.csr().modify(|w| { | 75 | w.set_divmode(divmode); |
| 76 | w.set_divmode(divmode); | 76 | w.set_en(false); |
| 77 | w.set_en(false); | 77 | }); |
| 78 | }); | 78 | p.ctr().write(|w| w.0 = 0); |
| 79 | p.ctr().write(|w| w.0 = 0); | 79 | Self::configure(p, &config); |
| 80 | Self::configure(p, &config); | 80 | |
| 81 | 81 | if let Some(pin) = &a { | |
| 82 | if let Some(pin) = &a { | 82 | pin.io().ctrl().write(|w| w.set_funcsel(4)); |
| 83 | pin.io().ctrl().write(|w| w.set_funcsel(4)); | 83 | } |
| 84 | } | 84 | if let Some(pin) = &b { |
| 85 | if let Some(pin) = &b { | 85 | pin.io().ctrl().write(|w| w.set_funcsel(4)); |
| 86 | pin.io().ctrl().write(|w| w.set_funcsel(4)); | ||
| 87 | } | ||
| 88 | } | 86 | } |
| 89 | Self { | 87 | Self { |
| 90 | inner, | 88 | inner, |
| @@ -161,31 +159,29 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 161 | panic!("Requested divider is too large"); | 159 | panic!("Requested divider is too large"); |
| 162 | } | 160 | } |
| 163 | 161 | ||
| 164 | unsafe { | 162 | p.div().write_value(ChDiv(config.divider.to_bits() as u32)); |
| 165 | p.div().write_value(ChDiv(config.divider.to_bits() as u32)); | 163 | p.cc().write(|w| { |
| 166 | p.cc().write(|w| { | 164 | w.set_a(config.compare_a); |
| 167 | w.set_a(config.compare_a); | 165 | w.set_b(config.compare_b); |
| 168 | w.set_b(config.compare_b); | 166 | }); |
| 169 | }); | 167 | p.top().write(|w| w.set_top(config.top)); |
| 170 | p.top().write(|w| w.set_top(config.top)); | 168 | p.csr().modify(|w| { |
| 171 | p.csr().modify(|w| { | 169 | w.set_a_inv(config.invert_a); |
| 172 | w.set_a_inv(config.invert_a); | 170 | w.set_b_inv(config.invert_b); |
| 173 | w.set_b_inv(config.invert_b); | 171 | w.set_ph_correct(config.phase_correct); |
| 174 | w.set_ph_correct(config.phase_correct); | 172 | w.set_en(config.enable); |
| 175 | w.set_en(config.enable); | 173 | }); |
| 176 | }); | ||
| 177 | } | ||
| 178 | } | 174 | } |
| 179 | 175 | ||
| 180 | #[inline] | 176 | #[inline] |
| 181 | pub unsafe fn phase_advance(&mut self) { | 177 | pub fn phase_advance(&mut self) { |
| 182 | let p = self.inner.regs(); | 178 | let p = self.inner.regs(); |
| 183 | p.csr().write_set(|w| w.set_ph_adv(true)); | 179 | p.csr().write_set(|w| w.set_ph_adv(true)); |
| 184 | while p.csr().read().ph_adv() {} | 180 | while p.csr().read().ph_adv() {} |
| 185 | } | 181 | } |
| 186 | 182 | ||
| 187 | #[inline] | 183 | #[inline] |
| 188 | pub unsafe fn phase_retard(&mut self) { | 184 | pub fn phase_retard(&mut self) { |
| 189 | let p = self.inner.regs(); | 185 | let p = self.inner.regs(); |
| 190 | p.csr().write_set(|w| w.set_ph_ret(true)); | 186 | p.csr().write_set(|w| w.set_ph_ret(true)); |
| 191 | while p.csr().read().ph_ret() {} | 187 | while p.csr().read().ph_ret() {} |
| @@ -193,12 +189,12 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 193 | 189 | ||
| 194 | #[inline] | 190 | #[inline] |
| 195 | pub fn counter(&self) -> u16 { | 191 | pub fn counter(&self) -> u16 { |
| 196 | unsafe { self.inner.regs().ctr().read().ctr() } | 192 | self.inner.regs().ctr().read().ctr() |
| 197 | } | 193 | } |
| 198 | 194 | ||
| 199 | #[inline] | 195 | #[inline] |
| 200 | pub fn set_counter(&self, ctr: u16) { | 196 | pub fn set_counter(&self, ctr: u16) { |
| 201 | unsafe { self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) } | 197 | self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) |
| 202 | } | 198 | } |
| 203 | 199 | ||
| 204 | #[inline] | 200 | #[inline] |
| @@ -209,14 +205,12 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||
| 209 | 205 | ||
| 210 | #[inline] | 206 | #[inline] |
| 211 | pub fn wrapped(&mut self) -> bool { | 207 | pub fn wrapped(&mut self) -> bool { |
| 212 | unsafe { pac::PWM.intr().read().0 & self.bit() != 0 } | 208 | pac::PWM.intr().read().0 & self.bit() != 0 |
| 213 | } | 209 | } |
| 214 | 210 | ||
| 215 | #[inline] | 211 | #[inline] |
| 216 | pub fn clear_wrapped(&mut self) { | 212 | pub fn clear_wrapped(&mut self) { |
| 217 | unsafe { | 213 | pac::PWM.intr().write_value(Intr(self.bit() as _)); |
| 218 | pac::PWM.intr().write_value(Intr(self.bit() as _)); | ||
| 219 | } | ||
| 220 | } | 214 | } |
| 221 | 215 | ||
| 222 | #[inline] | 216 | #[inline] |
| @@ -237,26 +231,22 @@ impl PwmBatch { | |||
| 237 | pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { | 231 | pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { |
| 238 | let mut en = PwmBatch(0); | 232 | let mut en = PwmBatch(0); |
| 239 | batch(&mut en); | 233 | batch(&mut en); |
| 240 | unsafe { | 234 | if enabled { |
| 241 | if enabled { | 235 | pac::PWM.en().write_set(|w| w.0 = en.0); |
| 242 | pac::PWM.en().write_set(|w| w.0 = en.0); | 236 | } else { |
| 243 | } else { | 237 | pac::PWM.en().write_clear(|w| w.0 = en.0); |
| 244 | pac::PWM.en().write_clear(|w| w.0 = en.0); | ||
| 245 | } | ||
| 246 | } | 238 | } |
| 247 | } | 239 | } |
| 248 | } | 240 | } |
| 249 | 241 | ||
| 250 | impl<'d, T: Channel> Drop for Pwm<'d, T> { | 242 | impl<'d, T: Channel> Drop for Pwm<'d, T> { |
| 251 | fn drop(&mut self) { | 243 | fn drop(&mut self) { |
| 252 | unsafe { | 244 | self.inner.regs().csr().write_clear(|w| w.set_en(false)); |
| 253 | self.inner.regs().csr().write_clear(|w| w.set_en(false)); | 245 | if let Some(pin) = &self.pin_a { |
| 254 | if let Some(pin) = &self.pin_a { | 246 | pin.io().ctrl().write(|w| w.set_funcsel(31)); |
| 255 | pin.io().ctrl().write(|w| w.set_funcsel(31)); | 247 | } |
| 256 | } | 248 | if let Some(pin) = &self.pin_b { |
| 257 | if let Some(pin) = &self.pin_b { | 249 | pin.io().ctrl().write(|w| w.set_funcsel(31)); |
| 258 | pin.io().ctrl().write(|w| w.set_funcsel(31)); | ||
| 259 | } | ||
| 260 | } | 250 | } |
| 261 | } | 251 | } |
| 262 | } | 252 | } |
diff --git a/embassy-rp/src/reset.rs b/embassy-rp/src/reset.rs index edd47c223..70512fa14 100644 --- a/embassy-rp/src/reset.rs +++ b/embassy-rp/src/reset.rs | |||
| @@ -4,11 +4,11 @@ use crate::pac; | |||
| 4 | 4 | ||
| 5 | pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); | 5 | pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); |
| 6 | 6 | ||
| 7 | pub unsafe fn reset(peris: Peripherals) { | 7 | pub(crate) fn reset(peris: Peripherals) { |
| 8 | pac::RESETS.reset().write_value(peris); | 8 | pac::RESETS.reset().write_value(peris); |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | pub unsafe fn unreset_wait(peris: Peripherals) { | 11 | pub(crate) fn unreset_wait(peris: Peripherals) { |
| 12 | // TODO use the "atomic clear" register version | 12 | // TODO use the "atomic clear" register version |
| 13 | pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0)); | 13 | pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0)); |
| 14 | while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {} | 14 | while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {} |
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index e1d886d4a..b18f12fc4 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs | |||
| @@ -26,7 +26,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 26 | into_ref!(inner); | 26 | into_ref!(inner); |
| 27 | 27 | ||
| 28 | // Set the RTC divider | 28 | // Set the RTC divider |
| 29 | unsafe { inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)) }; | 29 | inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)); |
| 30 | 30 | ||
| 31 | let mut result = Self { inner }; | 31 | let mut result = Self { inner }; |
| 32 | result.set_leap_year_check(true); // should be on by default, make sure this is the case. | 32 | result.set_leap_year_check(true); // should be on by default, make sure this is the case. |
| @@ -38,17 +38,14 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 38 | /// | 38 | /// |
| 39 | /// Leap year checking is enabled by default. | 39 | /// Leap year checking is enabled by default. |
| 40 | pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { | 40 | pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { |
| 41 | unsafe { | 41 | self.inner.regs().ctrl().modify(|w| { |
| 42 | self.inner | 42 | w.set_force_notleapyear(!leap_year_check_enabled); |
| 43 | .regs() | 43 | }); |
| 44 | .ctrl() | ||
| 45 | .modify(|w| w.set_force_notleapyear(!leap_year_check_enabled)) | ||
| 46 | }; | ||
| 47 | } | 44 | } |
| 48 | 45 | ||
| 49 | /// Checks to see if this RealTimeClock is running | 46 | /// Checks to see if this RealTimeClock is running |
| 50 | pub fn is_running(&self) -> bool { | 47 | pub fn is_running(&self) -> bool { |
| 51 | unsafe { self.inner.regs().ctrl().read().rtc_active() } | 48 | self.inner.regs().ctrl().read().rtc_active() |
| 52 | } | 49 | } |
| 53 | 50 | ||
| 54 | /// Set the datetime to a new value. | 51 | /// Set the datetime to a new value. |
| @@ -60,25 +57,23 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 60 | self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?; | 57 | self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?; |
| 61 | 58 | ||
| 62 | // disable RTC while we configure it | 59 | // disable RTC while we configure it |
| 63 | unsafe { | 60 | self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false)); |
| 64 | self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false)); | 61 | while self.inner.regs().ctrl().read().rtc_active() { |
| 65 | while self.inner.regs().ctrl().read().rtc_active() { | 62 | core::hint::spin_loop(); |
| 66 | core::hint::spin_loop(); | 63 | } |
| 67 | } | 64 | |
| 68 | 65 | self.inner.regs().setup_0().write(|w| { | |
| 69 | self.inner.regs().setup_0().write(|w| { | 66 | self::datetime::write_setup_0(&t, w); |
| 70 | self::datetime::write_setup_0(&t, w); | 67 | }); |
| 71 | }); | 68 | self.inner.regs().setup_1().write(|w| { |
| 72 | self.inner.regs().setup_1().write(|w| { | 69 | self::datetime::write_setup_1(&t, w); |
| 73 | self::datetime::write_setup_1(&t, w); | 70 | }); |
| 74 | }); | 71 | |
| 75 | 72 | // Load the new datetime and re-enable RTC | |
| 76 | // Load the new datetime and re-enable RTC | 73 | self.inner.regs().ctrl().write(|w| w.set_load(true)); |
| 77 | self.inner.regs().ctrl().write(|w| w.set_load(true)); | 74 | self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true)); |
| 78 | self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true)); | 75 | while !self.inner.regs().ctrl().read().rtc_active() { |
| 79 | while !self.inner.regs().ctrl().read().rtc_active() { | 76 | core::hint::spin_loop(); |
| 80 | core::hint::spin_loop(); | ||
| 81 | } | ||
| 82 | } | 77 | } |
| 83 | Ok(()) | 78 | Ok(()) |
| 84 | } | 79 | } |
| @@ -93,8 +88,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 93 | return Err(RtcError::NotRunning); | 88 | return Err(RtcError::NotRunning); |
| 94 | } | 89 | } |
| 95 | 90 | ||
| 96 | let rtc_0 = unsafe { self.inner.regs().rtc_0().read() }; | 91 | let rtc_0 = self.inner.regs().rtc_0().read(); |
| 97 | let rtc_1 = unsafe { self.inner.regs().rtc_1().read() }; | 92 | let rtc_1 = self.inner.regs().rtc_1().read(); |
| 98 | 93 | ||
| 99 | self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime) | 94 | self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime) |
| 100 | } | 95 | } |
| @@ -103,12 +98,10 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 103 | /// | 98 | /// |
| 104 | /// [`schedule_alarm`]: #method.schedule_alarm | 99 | /// [`schedule_alarm`]: #method.schedule_alarm |
| 105 | pub fn disable_alarm(&mut self) { | 100 | pub fn disable_alarm(&mut self) { |
| 106 | unsafe { | 101 | self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false)); |
| 107 | self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false)); | ||
| 108 | 102 | ||
| 109 | while self.inner.regs().irq_setup_0().read().match_active() { | 103 | while self.inner.regs().irq_setup_0().read().match_active() { |
| 110 | core::hint::spin_loop(); | 104 | core::hint::spin_loop(); |
| 111 | } | ||
| 112 | } | 105 | } |
| 113 | } | 106 | } |
| 114 | 107 | ||
| @@ -132,21 +125,19 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { | |||
| 132 | pub fn schedule_alarm(&mut self, filter: DateTimeFilter) { | 125 | pub fn schedule_alarm(&mut self, filter: DateTimeFilter) { |
| 133 | self.disable_alarm(); | 126 | self.disable_alarm(); |
| 134 | 127 | ||
| 135 | unsafe { | 128 | self.inner.regs().irq_setup_0().write(|w| { |
| 136 | self.inner.regs().irq_setup_0().write(|w| { | 129 | filter.write_setup_0(w); |
| 137 | filter.write_setup_0(w); | 130 | }); |
| 138 | }); | 131 | self.inner.regs().irq_setup_1().write(|w| { |
| 139 | self.inner.regs().irq_setup_1().write(|w| { | 132 | filter.write_setup_1(w); |
| 140 | filter.write_setup_1(w); | 133 | }); |
| 141 | }); | 134 | |
| 142 | 135 | self.inner.regs().inte().modify(|w| w.set_rtc(true)); | |
| 143 | self.inner.regs().inte().modify(|w| w.set_rtc(true)); | 136 | |
| 144 | 137 | // Set the enable bit and check if it is set | |
| 145 | // Set the enable bit and check if it is set | 138 | self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true)); |
| 146 | self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true)); | 139 | while !self.inner.regs().irq_setup_0().read().match_active() { |
| 147 | while !self.inner.regs().irq_setup_0().read().match_active() { | 140 | core::hint::spin_loop(); |
| 148 | core::hint::spin_loop(); | ||
| 149 | } | ||
| 150 | } | 141 | } |
| 151 | } | 142 | } |
| 152 | 143 | ||
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 742a35d49..e817d074e 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs | |||
| @@ -79,33 +79,37 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { | |||
| 79 | ) -> Self { | 79 | ) -> Self { |
| 80 | into_ref!(inner); | 80 | into_ref!(inner); |
| 81 | 81 | ||
| 82 | unsafe { | 82 | let p = inner.regs(); |
| 83 | let p = inner.regs(); | 83 | let (presc, postdiv) = calc_prescs(config.frequency); |
| 84 | let (presc, postdiv) = calc_prescs(config.frequency); | 84 | |
| 85 | 85 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); | |
| 86 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); | 86 | p.cr0().write(|w| { |
| 87 | p.cr0().write(|w| { | 87 | w.set_dss(0b0111); // 8bit |
| 88 | w.set_dss(0b0111); // 8bit | 88 | w.set_spo(config.polarity == Polarity::IdleHigh); |
| 89 | w.set_spo(config.polarity == Polarity::IdleHigh); | 89 | w.set_sph(config.phase == Phase::CaptureOnSecondTransition); |
| 90 | w.set_sph(config.phase == Phase::CaptureOnSecondTransition); | 90 | w.set_scr(postdiv); |
| 91 | w.set_scr(postdiv); | 91 | }); |
| 92 | }); | 92 | |
| 93 | p.cr1().write(|w| { | 93 | // Always enable DREQ signals -- harmless if DMA is not listening |
| 94 | w.set_sse(true); // enable | 94 | p.dmacr().write(|reg| { |
| 95 | }); | 95 | reg.set_rxdmae(true); |
| 96 | 96 | reg.set_txdmae(true); | |
| 97 | if let Some(pin) = &clk { | 97 | }); |
| 98 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | 98 | |
| 99 | } | 99 | // finally, enable. |
| 100 | if let Some(pin) = &mosi { | 100 | p.cr1().write(|w| w.set_sse(true)); |
| 101 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | 101 | |
| 102 | } | 102 | if let Some(pin) = &clk { |
| 103 | if let Some(pin) = &miso { | 103 | pin.io().ctrl().write(|w| w.set_funcsel(1)); |
| 104 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | 104 | } |
| 105 | } | 105 | if let Some(pin) = &mosi { |
| 106 | if let Some(pin) = &cs { | 106 | pin.io().ctrl().write(|w| w.set_funcsel(1)); |
| 107 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | 107 | } |
| 108 | } | 108 | if let Some(pin) = &miso { |
| 109 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | ||
| 110 | } | ||
| 111 | if let Some(pin) = &cs { | ||
| 112 | pin.io().ctrl().write(|w| w.set_funcsel(1)); | ||
| 109 | } | 113 | } |
| 110 | Self { | 114 | Self { |
| 111 | inner, | 115 | inner, |
| @@ -116,60 +120,52 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { | |||
| 116 | } | 120 | } |
| 117 | 121 | ||
| 118 | pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { | 122 | pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { |
| 119 | unsafe { | 123 | let p = self.inner.regs(); |
| 120 | let p = self.inner.regs(); | 124 | for &b in data { |
| 121 | for &b in data { | 125 | while !p.sr().read().tnf() {} |
| 122 | while !p.sr().read().tnf() {} | 126 | p.dr().write(|w| w.set_data(b as _)); |
| 123 | p.dr().write(|w| w.set_data(b as _)); | 127 | while !p.sr().read().rne() {} |
| 124 | while !p.sr().read().rne() {} | 128 | let _ = p.dr().read(); |
| 125 | let _ = p.dr().read(); | ||
| 126 | } | ||
| 127 | } | 129 | } |
| 128 | self.flush()?; | 130 | self.flush()?; |
| 129 | Ok(()) | 131 | Ok(()) |
| 130 | } | 132 | } |
| 131 | 133 | ||
| 132 | pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { | 134 | pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { |
| 133 | unsafe { | 135 | let p = self.inner.regs(); |
| 134 | let p = self.inner.regs(); | 136 | for b in data { |
| 135 | for b in data { | 137 | while !p.sr().read().tnf() {} |
| 136 | while !p.sr().read().tnf() {} | 138 | p.dr().write(|w| w.set_data(*b as _)); |
| 137 | p.dr().write(|w| w.set_data(*b as _)); | 139 | while !p.sr().read().rne() {} |
| 138 | while !p.sr().read().rne() {} | 140 | *b = p.dr().read().data() as u8; |
| 139 | *b = p.dr().read().data() as u8; | ||
| 140 | } | ||
| 141 | } | 141 | } |
| 142 | self.flush()?; | 142 | self.flush()?; |
| 143 | Ok(()) | 143 | Ok(()) |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { | 146 | pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { |
| 147 | unsafe { | 147 | let p = self.inner.regs(); |
| 148 | let p = self.inner.regs(); | 148 | for b in data { |
| 149 | for b in data { | 149 | while !p.sr().read().tnf() {} |
| 150 | while !p.sr().read().tnf() {} | 150 | p.dr().write(|w| w.set_data(0)); |
| 151 | p.dr().write(|w| w.set_data(0)); | 151 | while !p.sr().read().rne() {} |
| 152 | while !p.sr().read().rne() {} | 152 | *b = p.dr().read().data() as u8; |
| 153 | *b = p.dr().read().data() as u8; | ||
| 154 | } | ||
| 155 | } | 153 | } |
| 156 | self.flush()?; | 154 | self.flush()?; |
| 157 | Ok(()) | 155 | Ok(()) |
| 158 | } | 156 | } |
| 159 | 157 | ||
| 160 | pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { | 158 | pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { |
| 161 | unsafe { | 159 | let p = self.inner.regs(); |
| 162 | let p = self.inner.regs(); | 160 | let len = read.len().max(write.len()); |
| 163 | let len = read.len().max(write.len()); | 161 | for i in 0..len { |
| 164 | for i in 0..len { | 162 | let wb = write.get(i).copied().unwrap_or(0); |
| 165 | let wb = write.get(i).copied().unwrap_or(0); | 163 | while !p.sr().read().tnf() {} |
| 166 | while !p.sr().read().tnf() {} | 164 | p.dr().write(|w| w.set_data(wb as _)); |
| 167 | p.dr().write(|w| w.set_data(wb as _)); | 165 | while !p.sr().read().rne() {} |
| 168 | while !p.sr().read().rne() {} | 166 | let rb = p.dr().read().data() as u8; |
| 169 | let rb = p.dr().read().data() as u8; | 167 | if let Some(r) = read.get_mut(i) { |
| 170 | if let Some(r) = read.get_mut(i) { | 168 | *r = rb; |
| 171 | *r = rb; | ||
| 172 | } | ||
| 173 | } | 169 | } |
| 174 | } | 170 | } |
| 175 | self.flush()?; | 171 | self.flush()?; |
| @@ -177,29 +173,25 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { | |||
| 177 | } | 173 | } |
| 178 | 174 | ||
| 179 | pub fn flush(&mut self) -> Result<(), Error> { | 175 | pub fn flush(&mut self) -> Result<(), Error> { |
| 180 | unsafe { | 176 | let p = self.inner.regs(); |
| 181 | let p = self.inner.regs(); | 177 | while p.sr().read().bsy() {} |
| 182 | while p.sr().read().bsy() {} | ||
| 183 | } | ||
| 184 | Ok(()) | 178 | Ok(()) |
| 185 | } | 179 | } |
| 186 | 180 | ||
| 187 | pub fn set_frequency(&mut self, freq: u32) { | 181 | pub fn set_frequency(&mut self, freq: u32) { |
| 188 | let (presc, postdiv) = calc_prescs(freq); | 182 | let (presc, postdiv) = calc_prescs(freq); |
| 189 | let p = self.inner.regs(); | 183 | let p = self.inner.regs(); |
| 190 | unsafe { | 184 | // disable |
| 191 | // disable | 185 | p.cr1().write(|w| w.set_sse(false)); |
| 192 | p.cr1().write(|w| w.set_sse(false)); | 186 | |
| 193 | 187 | // change stuff | |
| 194 | // change stuff | 188 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); |
| 195 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); | 189 | p.cr0().modify(|w| { |
| 196 | p.cr0().modify(|w| { | 190 | w.set_scr(postdiv); |
| 197 | w.set_scr(postdiv); | 191 | }); |
| 198 | }); | 192 | |
| 199 | 193 | // enable | |
| 200 | // enable | 194 | p.cr1().write(|w| w.set_sse(true)); |
| 201 | p.cr1().write(|w| w.set_sse(true)); | ||
| 202 | } | ||
| 203 | } | 195 | } |
| 204 | } | 196 | } |
| 205 | 197 | ||
| @@ -329,48 +321,45 @@ impl<'d, T: Instance> Spi<'d, T, Async> { | |||
| 329 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 321 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 330 | let tx_ch = self.tx_dma.as_mut().unwrap(); | 322 | let tx_ch = self.tx_dma.as_mut().unwrap(); |
| 331 | let tx_transfer = unsafe { | 323 | let tx_transfer = unsafe { |
| 332 | self.inner.regs().dmacr().modify(|reg| { | ||
| 333 | reg.set_txdmae(true); | ||
| 334 | }); | ||
| 335 | // If we don't assign future to a variable, the data register pointer | 324 | // If we don't assign future to a variable, the data register pointer |
| 336 | // is held across an await and makes the future non-Send. | 325 | // is held across an await and makes the future non-Send. |
| 337 | crate::dma::write(tx_ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) | 326 | crate::dma::write(tx_ch, buffer, self.inner.regs().dr().as_ptr() as *mut _, T::TX_DREQ) |
| 338 | }; | 327 | }; |
| 339 | tx_transfer.await; | 328 | tx_transfer.await; |
| 340 | 329 | ||
| 341 | let p = self.inner.regs(); | 330 | let p = self.inner.regs(); |
| 342 | unsafe { | 331 | while p.sr().read().bsy() {} |
| 343 | while p.sr().read().bsy() {} | ||
| 344 | 332 | ||
| 345 | // clear RX FIFO contents to prevent stale reads | 333 | // clear RX FIFO contents to prevent stale reads |
| 346 | while p.sr().read().rne() { | 334 | while p.sr().read().rne() { |
| 347 | let _: u16 = p.dr().read().data(); | 335 | let _: u16 = p.dr().read().data(); |
| 348 | } | ||
| 349 | // clear RX overrun interrupt | ||
| 350 | p.icr().write(|w| w.set_roric(true)); | ||
| 351 | } | 336 | } |
| 337 | // clear RX overrun interrupt | ||
| 338 | p.icr().write(|w| w.set_roric(true)); | ||
| 352 | 339 | ||
| 353 | Ok(()) | 340 | Ok(()) |
| 354 | } | 341 | } |
| 355 | 342 | ||
| 356 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 343 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 357 | unsafe { | 344 | // Start RX first. Transfer starts when TX starts, if RX |
| 358 | self.inner.regs().dmacr().write(|reg| { | 345 | // is not started yet we might lose bytes. |
| 359 | reg.set_rxdmae(true); | 346 | let rx_ch = self.rx_dma.as_mut().unwrap(); |
| 360 | reg.set_txdmae(true); | 347 | let rx_transfer = unsafe { |
| 361 | }) | ||
| 362 | }; | ||
| 363 | let tx_ch = self.tx_dma.as_mut().unwrap(); | ||
| 364 | let tx_transfer = unsafe { | ||
| 365 | // If we don't assign future to a variable, the data register pointer | 348 | // If we don't assign future to a variable, the data register pointer |
| 366 | // is held across an await and makes the future non-Send. | 349 | // is held across an await and makes the future non-Send. |
| 367 | crate::dma::write_repeated(tx_ch, self.inner.regs().dr().ptr() as *mut u8, buffer.len(), T::TX_DREQ) | 350 | crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, buffer, T::RX_DREQ) |
| 368 | }; | 351 | }; |
| 369 | let rx_ch = self.rx_dma.as_mut().unwrap(); | 352 | |
| 370 | let rx_transfer = unsafe { | 353 | let tx_ch = self.tx_dma.as_mut().unwrap(); |
| 354 | let tx_transfer = unsafe { | ||
| 371 | // If we don't assign future to a variable, the data register pointer | 355 | // If we don't assign future to a variable, the data register pointer |
| 372 | // is held across an await and makes the future non-Send. | 356 | // is held across an await and makes the future non-Send. |
| 373 | crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ) | 357 | crate::dma::write_repeated( |
| 358 | tx_ch, | ||
| 359 | self.inner.regs().dr().as_ptr() as *mut u8, | ||
| 360 | buffer.len(), | ||
| 361 | T::TX_DREQ, | ||
| 362 | ) | ||
| 374 | }; | 363 | }; |
| 375 | join(tx_transfer, rx_transfer).await; | 364 | join(tx_transfer, rx_transfer).await; |
| 376 | Ok(()) | 365 | Ok(()) |
| @@ -388,11 +377,13 @@ impl<'d, T: Instance> Spi<'d, T, Async> { | |||
| 388 | let (_, tx_len) = crate::dma::slice_ptr_parts(tx_ptr); | 377 | let (_, tx_len) = crate::dma::slice_ptr_parts(tx_ptr); |
| 389 | let (_, rx_len) = crate::dma::slice_ptr_parts_mut(rx_ptr); | 378 | let (_, rx_len) = crate::dma::slice_ptr_parts_mut(rx_ptr); |
| 390 | 379 | ||
| 391 | unsafe { | 380 | // Start RX first. Transfer starts when TX starts, if RX |
| 392 | self.inner.regs().dmacr().write(|reg| { | 381 | // is not started yet we might lose bytes. |
| 393 | reg.set_rxdmae(true); | 382 | let rx_ch = self.rx_dma.as_mut().unwrap(); |
| 394 | reg.set_txdmae(true); | 383 | let rx_transfer = unsafe { |
| 395 | }) | 384 | // If we don't assign future to a variable, the data register pointer |
| 385 | // is held across an await and makes the future non-Send. | ||
| 386 | crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, rx_ptr, T::RX_DREQ) | ||
| 396 | }; | 387 | }; |
| 397 | 388 | ||
| 398 | let mut tx_ch = self.tx_dma.as_mut().unwrap(); | 389 | let mut tx_ch = self.tx_dma.as_mut().unwrap(); |
| @@ -401,38 +392,29 @@ impl<'d, T: Instance> Spi<'d, T, Async> { | |||
| 401 | let tx_transfer = async { | 392 | let tx_transfer = async { |
| 402 | let p = self.inner.regs(); | 393 | let p = self.inner.regs(); |
| 403 | unsafe { | 394 | unsafe { |
| 404 | crate::dma::write(&mut tx_ch, tx_ptr, p.dr().ptr() as *mut _, T::TX_DREQ).await; | 395 | crate::dma::write(&mut tx_ch, tx_ptr, p.dr().as_ptr() as *mut _, T::TX_DREQ).await; |
| 405 | 396 | ||
| 406 | if rx_len > tx_len { | 397 | if rx_len > tx_len { |
| 407 | let write_bytes_len = rx_len - tx_len; | 398 | let write_bytes_len = rx_len - tx_len; |
| 408 | // write dummy data | 399 | // write dummy data |
| 409 | // this will disable incrementation of the buffers | 400 | // this will disable incrementation of the buffers |
| 410 | crate::dma::write_repeated(tx_ch, p.dr().ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await | 401 | crate::dma::write_repeated(tx_ch, p.dr().as_ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await |
| 411 | } | 402 | } |
| 412 | } | 403 | } |
| 413 | }; | 404 | }; |
| 414 | |||
| 415 | let rx_ch = self.rx_dma.as_mut().unwrap(); | ||
| 416 | let rx_transfer = unsafe { | ||
| 417 | // If we don't assign future to a variable, the data register pointer | ||
| 418 | // is held across an await and makes the future non-Send. | ||
| 419 | crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ) | ||
| 420 | }; | ||
| 421 | join(tx_transfer, rx_transfer).await; | 405 | join(tx_transfer, rx_transfer).await; |
| 422 | 406 | ||
| 423 | // if tx > rx we should clear any overflow of the FIFO SPI buffer | 407 | // if tx > rx we should clear any overflow of the FIFO SPI buffer |
| 424 | if tx_len > rx_len { | 408 | if tx_len > rx_len { |
| 425 | let p = self.inner.regs(); | 409 | let p = self.inner.regs(); |
| 426 | unsafe { | 410 | while p.sr().read().bsy() {} |
| 427 | while p.sr().read().bsy() {} | ||
| 428 | 411 | ||
| 429 | // clear RX FIFO contents to prevent stale reads | 412 | // clear RX FIFO contents to prevent stale reads |
| 430 | while p.sr().read().rne() { | 413 | while p.sr().read().rne() { |
| 431 | let _: u16 = p.dr().read().data(); | 414 | let _: u16 = p.dr().read().data(); |
| 432 | } | ||
| 433 | // clear RX overrun interrupt | ||
| 434 | p.icr().write(|w| w.set_roric(true)); | ||
| 435 | } | 415 | } |
| 416 | // clear RX overrun interrupt | ||
| 417 | p.icr().write(|w| w.set_roric(true)); | ||
| 436 | } | 418 | } |
| 437 | 419 | ||
| 438 | Ok(()) | 420 | Ok(()) |
| @@ -630,14 +612,12 @@ impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> { | |||
| 630 | fn set_config(&mut self, config: &Self::Config) { | 612 | fn set_config(&mut self, config: &Self::Config) { |
| 631 | let p = self.inner.regs(); | 613 | let p = self.inner.regs(); |
| 632 | let (presc, postdiv) = calc_prescs(config.frequency); | 614 | let (presc, postdiv) = calc_prescs(config.frequency); |
| 633 | unsafe { | 615 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); |
| 634 | p.cpsr().write(|w| w.set_cpsdvsr(presc)); | 616 | p.cr0().write(|w| { |
| 635 | p.cr0().write(|w| { | 617 | w.set_dss(0b0111); // 8bit |
| 636 | w.set_dss(0b0111); // 8bit | 618 | w.set_spo(config.polarity == Polarity::IdleHigh); |
| 637 | w.set_spo(config.polarity == Polarity::IdleHigh); | 619 | w.set_sph(config.phase == Phase::CaptureOnSecondTransition); |
| 638 | w.set_sph(config.phase == Phase::CaptureOnSecondTransition); | 620 | w.set_scr(postdiv); |
| 639 | w.set_scr(postdiv); | 621 | }); |
| 640 | }); | ||
| 641 | } | ||
| 642 | } | 622 | } |
| 643 | } | 623 | } |
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs index 80efd779f..faa8df037 100644 --- a/embassy-rp/src/timer.rs +++ b/embassy-rp/src/timer.rs | |||
| @@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | |||
| 6 | use embassy_sync::blocking_mutex::Mutex; | 6 | use embassy_sync::blocking_mutex::Mutex; |
| 7 | use embassy_time::driver::{AlarmHandle, Driver}; | 7 | use embassy_time::driver::{AlarmHandle, Driver}; |
| 8 | 8 | ||
| 9 | use crate::interrupt::{Interrupt, InterruptExt}; | 9 | use crate::interrupt::InterruptExt; |
| 10 | use crate::{interrupt, pac}; | 10 | use crate::{interrupt, pac}; |
| 11 | 11 | ||
| 12 | struct AlarmState { | 12 | struct AlarmState { |
| @@ -34,13 +34,11 @@ embassy_time::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ | |||
| 34 | impl Driver for TimerDriver { | 34 | impl Driver for TimerDriver { |
| 35 | fn now(&self) -> u64 { | 35 | fn now(&self) -> u64 { |
| 36 | loop { | 36 | loop { |
| 37 | unsafe { | 37 | let hi = pac::TIMER.timerawh().read(); |
| 38 | let hi = pac::TIMER.timerawh().read(); | 38 | let lo = pac::TIMER.timerawl().read(); |
| 39 | let lo = pac::TIMER.timerawl().read(); | 39 | let hi2 = pac::TIMER.timerawh().read(); |
| 40 | let hi2 = pac::TIMER.timerawh().read(); | 40 | if hi == hi2 { |
| 41 | if hi == hi2 { | 41 | return (hi as u64) << 32 | (lo as u64); |
| 42 | return (hi as u64) << 32 | (lo as u64); | ||
| 43 | } | ||
| 44 | } | 42 | } |
| 45 | } | 43 | } |
| 46 | } | 44 | } |
| @@ -78,13 +76,13 @@ impl Driver for TimerDriver { | |||
| 78 | // Note that we're not checking the high bits at all. This means the irq may fire early | 76 | // Note that we're not checking the high bits at all. This means the irq may fire early |
| 79 | // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire | 77 | // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire |
| 80 | // it is checked if the alarm time has passed. | 78 | // it is checked if the alarm time has passed. |
| 81 | unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; | 79 | pac::TIMER.alarm(n).write_value(timestamp as u32); |
| 82 | 80 | ||
| 83 | let now = self.now(); | 81 | let now = self.now(); |
| 84 | if timestamp <= now { | 82 | if timestamp <= now { |
| 85 | // If alarm timestamp has passed the alarm will not fire. | 83 | // If alarm timestamp has passed the alarm will not fire. |
| 86 | // Disarm the alarm and return `false` to indicate that. | 84 | // Disarm the alarm and return `false` to indicate that. |
| 87 | unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } | 85 | pac::TIMER.armed().write(|w| w.set_armed(1 << n)); |
| 88 | 86 | ||
| 89 | alarm.timestamp.set(u64::MAX); | 87 | alarm.timestamp.set(u64::MAX); |
| 90 | 88 | ||
| @@ -106,17 +104,17 @@ impl TimerDriver { | |||
| 106 | } else { | 104 | } else { |
| 107 | // Not elapsed, arm it again. | 105 | // Not elapsed, arm it again. |
| 108 | // This can happen if it was set more than 2^32 us in the future. | 106 | // This can happen if it was set more than 2^32 us in the future. |
| 109 | unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) }; | 107 | pac::TIMER.alarm(n).write_value(timestamp as u32); |
| 110 | } | 108 | } |
| 111 | }); | 109 | }); |
| 112 | 110 | ||
| 113 | // clear the irq | 111 | // clear the irq |
| 114 | unsafe { pac::TIMER.intr().write(|w| w.set_alarm(n, true)) } | 112 | pac::TIMER.intr().write(|w| w.set_alarm(n, true)); |
| 115 | } | 113 | } |
| 116 | 114 | ||
| 117 | fn trigger_alarm(&self, n: usize, cs: CriticalSection) { | 115 | fn trigger_alarm(&self, n: usize, cs: CriticalSection) { |
| 118 | // disarm | 116 | // disarm |
| 119 | unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } | 117 | pac::TIMER.armed().write(|w| w.set_armed(1 << n)); |
| 120 | 118 | ||
| 121 | let alarm = &self.alarms.borrow(cs)[n]; | 119 | let alarm = &self.alarms.borrow(cs)[n]; |
| 122 | alarm.timestamp.set(u64::MAX); | 120 | alarm.timestamp.set(u64::MAX); |
| @@ -145,28 +143,32 @@ pub unsafe fn init() { | |||
| 145 | w.set_alarm(2, true); | 143 | w.set_alarm(2, true); |
| 146 | w.set_alarm(3, true); | 144 | w.set_alarm(3, true); |
| 147 | }); | 145 | }); |
| 148 | interrupt::TIMER_IRQ_0::steal().enable(); | 146 | interrupt::TIMER_IRQ_0.enable(); |
| 149 | interrupt::TIMER_IRQ_1::steal().enable(); | 147 | interrupt::TIMER_IRQ_1.enable(); |
| 150 | interrupt::TIMER_IRQ_2::steal().enable(); | 148 | interrupt::TIMER_IRQ_2.enable(); |
| 151 | interrupt::TIMER_IRQ_3::steal().enable(); | 149 | interrupt::TIMER_IRQ_3.enable(); |
| 152 | } | 150 | } |
| 153 | 151 | ||
| 152 | #[cfg(feature = "rt")] | ||
| 154 | #[interrupt] | 153 | #[interrupt] |
| 155 | unsafe fn TIMER_IRQ_0() { | 154 | fn TIMER_IRQ_0() { |
| 156 | DRIVER.check_alarm(0) | 155 | DRIVER.check_alarm(0) |
| 157 | } | 156 | } |
| 158 | 157 | ||
| 158 | #[cfg(feature = "rt")] | ||
| 159 | #[interrupt] | 159 | #[interrupt] |
| 160 | unsafe fn TIMER_IRQ_1() { | 160 | fn TIMER_IRQ_1() { |
| 161 | DRIVER.check_alarm(1) | 161 | DRIVER.check_alarm(1) |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | #[cfg(feature = "rt")] | ||
| 164 | #[interrupt] | 165 | #[interrupt] |
| 165 | unsafe fn TIMER_IRQ_2() { | 166 | fn TIMER_IRQ_2() { |
| 166 | DRIVER.check_alarm(2) | 167 | DRIVER.check_alarm(2) |
| 167 | } | 168 | } |
| 168 | 169 | ||
| 170 | #[cfg(feature = "rt")] | ||
| 169 | #[interrupt] | 171 | #[interrupt] |
| 170 | unsafe fn TIMER_IRQ_3() { | 172 | fn TIMER_IRQ_3() { |
| 171 | DRIVER.check_alarm(3) | 173 | DRIVER.check_alarm(3) |
| 172 | } | 174 | } |
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 12d6b8d91..30eeb5476 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -3,14 +3,14 @@ use core::slice; | |||
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use atomic_polyfill::{AtomicU8, Ordering}; | 5 | use atomic_polyfill::{AtomicU8, Ordering}; |
| 6 | use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt}; | ||
| 7 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; | 6 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 9 | use embassy_time::{Duration, Timer}; | 8 | use embassy_time::{Duration, Timer}; |
| 10 | 9 | ||
| 11 | use super::*; | 10 | use super::*; |
| 12 | use crate::clocks::clk_peri_freq; | 11 | use crate::clocks::clk_peri_freq; |
| 13 | use crate::RegExt; | 12 | use crate::interrupt::typelevel::{Binding, Interrupt}; |
| 13 | use crate::{interrupt, RegExt}; | ||
| 14 | 14 | ||
| 15 | pub struct State { | 15 | pub struct State { |
| 16 | tx_waker: AtomicWaker, | 16 | tx_waker: AtomicWaker, |
| @@ -73,16 +73,14 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>( | |||
| 73 | // we clear it after it happens. The downside is that the we manually have | 73 | // we clear it after it happens. The downside is that the we manually have |
| 74 | // to pend the ISR when we want data transmission to start. | 74 | // to pend the ISR when we want data transmission to start. |
| 75 | let regs = T::regs(); | 75 | let regs = T::regs(); |
| 76 | unsafe { | 76 | regs.uartimsc().write(|w| { |
| 77 | regs.uartimsc().write(|w| { | 77 | w.set_rxim(true); |
| 78 | w.set_rxim(true); | 78 | w.set_rtim(true); |
| 79 | w.set_rtim(true); | 79 | w.set_txim(true); |
| 80 | w.set_txim(true); | 80 | }); |
| 81 | }); | 81 | |
| 82 | 82 | T::Interrupt::unpend(); | |
| 83 | T::Interrupt::steal().unpend(); | 83 | unsafe { T::Interrupt::enable() }; |
| 84 | T::Interrupt::steal().enable(); | ||
| 85 | }; | ||
| 86 | } | 84 | } |
| 87 | 85 | ||
| 88 | impl<'d, T: Instance> BufferedUart<'d, T> { | 86 | impl<'d, T: Instance> BufferedUart<'d, T> { |
| @@ -247,12 +245,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { | |||
| 247 | // (Re-)Enable the interrupt to receive more data in case it was | 245 | // (Re-)Enable the interrupt to receive more data in case it was |
| 248 | // disabled because the buffer was full or errors were detected. | 246 | // disabled because the buffer was full or errors were detected. |
| 249 | let regs = T::regs(); | 247 | let regs = T::regs(); |
| 250 | unsafe { | 248 | regs.uartimsc().write_set(|w| { |
| 251 | regs.uartimsc().write_set(|w| { | 249 | w.set_rxim(true); |
| 252 | w.set_rxim(true); | 250 | w.set_rtim(true); |
| 253 | w.set_rtim(true); | 251 | }); |
| 254 | }); | ||
| 255 | } | ||
| 256 | 252 | ||
| 257 | Poll::Ready(result) | 253 | Poll::Ready(result) |
| 258 | } | 254 | } |
| @@ -299,12 +295,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { | |||
| 299 | // (Re-)Enable the interrupt to receive more data in case it was | 295 | // (Re-)Enable the interrupt to receive more data in case it was |
| 300 | // disabled because the buffer was full or errors were detected. | 296 | // disabled because the buffer was full or errors were detected. |
| 301 | let regs = T::regs(); | 297 | let regs = T::regs(); |
| 302 | unsafe { | 298 | regs.uartimsc().write_set(|w| { |
| 303 | regs.uartimsc().write_set(|w| { | 299 | w.set_rxim(true); |
| 304 | w.set_rxim(true); | 300 | w.set_rtim(true); |
| 305 | w.set_rtim(true); | 301 | }); |
| 306 | }); | ||
| 307 | } | ||
| 308 | } | 302 | } |
| 309 | } | 303 | } |
| 310 | 304 | ||
| @@ -362,7 +356,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { | |||
| 362 | // FIFO and the number of bytes drops below a threshold. When the | 356 | // FIFO and the number of bytes drops below a threshold. When the |
| 363 | // FIFO was empty we have to manually pend the interrupt to shovel | 357 | // FIFO was empty we have to manually pend the interrupt to shovel |
| 364 | // TX data from the buffer into the FIFO. | 358 | // TX data from the buffer into the FIFO. |
| 365 | unsafe { T::Interrupt::steal() }.pend(); | 359 | T::Interrupt::pend(); |
| 366 | Poll::Ready(Ok(n)) | 360 | Poll::Ready(Ok(n)) |
| 367 | }) | 361 | }) |
| 368 | } | 362 | } |
| @@ -398,7 +392,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { | |||
| 398 | // FIFO and the number of bytes drops below a threshold. When the | 392 | // FIFO and the number of bytes drops below a threshold. When the |
| 399 | // FIFO was empty we have to manually pend the interrupt to shovel | 393 | // FIFO was empty we have to manually pend the interrupt to shovel |
| 400 | // TX data from the buffer into the FIFO. | 394 | // TX data from the buffer into the FIFO. |
| 401 | unsafe { T::Interrupt::steal() }.pend(); | 395 | T::Interrupt::pend(); |
| 402 | return Ok(n); | 396 | return Ok(n); |
| 403 | } | 397 | } |
| 404 | } | 398 | } |
| @@ -414,7 +408,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { | |||
| 414 | } | 408 | } |
| 415 | 409 | ||
| 416 | pub fn busy(&self) -> bool { | 410 | pub fn busy(&self) -> bool { |
| 417 | unsafe { T::regs().uartfr().read().busy() } | 411 | T::regs().uartfr().read().busy() |
| 418 | } | 412 | } |
| 419 | 413 | ||
| 420 | /// Assert a break condition after waiting for the transmit buffers to empty, | 414 | /// Assert a break condition after waiting for the transmit buffers to empty, |
| @@ -426,42 +420,35 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { | |||
| 426 | /// for the transmit fifo to empty, which may take a while on slow links. | 420 | /// for the transmit fifo to empty, which may take a while on slow links. |
| 427 | pub async fn send_break(&mut self, bits: u32) { | 421 | pub async fn send_break(&mut self, bits: u32) { |
| 428 | let regs = T::regs(); | 422 | let regs = T::regs(); |
| 429 | let bits = bits.max(unsafe { | 423 | let bits = bits.max({ |
| 430 | let lcr = regs.uartlcr_h().read(); | 424 | let lcr = regs.uartlcr_h().read(); |
| 431 | let width = lcr.wlen() as u32 + 5; | 425 | let width = lcr.wlen() as u32 + 5; |
| 432 | let parity = lcr.pen() as u32; | 426 | let parity = lcr.pen() as u32; |
| 433 | let stops = 1 + lcr.stp2() as u32; | 427 | let stops = 1 + lcr.stp2() as u32; |
| 434 | 2 * (1 + width + parity + stops) | 428 | 2 * (1 + width + parity + stops) |
| 435 | }); | 429 | }); |
| 436 | let divx64 = unsafe { | 430 | let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6) |
| 437 | ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 | 431 | + regs.uartfbrd().read().baud_divfrac() as u32) as u64; |
| 438 | } as u64; | ||
| 439 | let div_clk = clk_peri_freq() as u64 * 64; | 432 | let div_clk = clk_peri_freq() as u64 * 64; |
| 440 | let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; | 433 | let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; |
| 441 | 434 | ||
| 442 | Self::flush().await.unwrap(); | 435 | Self::flush().await.unwrap(); |
| 443 | while self.busy() {} | 436 | while self.busy() {} |
| 444 | unsafe { | 437 | regs.uartlcr_h().write_set(|w| w.set_brk(true)); |
| 445 | regs.uartlcr_h().write_set(|w| w.set_brk(true)); | ||
| 446 | } | ||
| 447 | Timer::after(Duration::from_micros(wait_usecs)).await; | 438 | Timer::after(Duration::from_micros(wait_usecs)).await; |
| 448 | unsafe { | 439 | regs.uartlcr_h().write_clear(|w| w.set_brk(true)); |
| 449 | regs.uartlcr_h().write_clear(|w| w.set_brk(true)); | ||
| 450 | } | ||
| 451 | } | 440 | } |
| 452 | } | 441 | } |
| 453 | 442 | ||
| 454 | impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { | 443 | impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { |
| 455 | fn drop(&mut self) { | 444 | fn drop(&mut self) { |
| 456 | let state = T::buffered_state(); | 445 | let state = T::buffered_state(); |
| 457 | unsafe { | 446 | unsafe { state.rx_buf.deinit() } |
| 458 | state.rx_buf.deinit(); | ||
| 459 | 447 | ||
| 460 | // TX is inactive if the the buffer is not available. | 448 | // TX is inactive if the the buffer is not available. |
| 461 | // We can now unregister the interrupt handler | 449 | // We can now unregister the interrupt handler |
| 462 | if state.tx_buf.len() == 0 { | 450 | if state.tx_buf.len() == 0 { |
| 463 | T::Interrupt::steal().disable(); | 451 | T::Interrupt::disable(); |
| 464 | } | ||
| 465 | } | 452 | } |
| 466 | } | 453 | } |
| 467 | } | 454 | } |
| @@ -469,14 +456,12 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { | |||
| 469 | impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { | 456 | impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { |
| 470 | fn drop(&mut self) { | 457 | fn drop(&mut self) { |
| 471 | let state = T::buffered_state(); | 458 | let state = T::buffered_state(); |
| 472 | unsafe { | 459 | unsafe { state.tx_buf.deinit() } |
| 473 | state.tx_buf.deinit(); | ||
| 474 | 460 | ||
| 475 | // RX is inactive if the the buffer is not available. | 461 | // RX is inactive if the the buffer is not available. |
| 476 | // We can now unregister the interrupt handler | 462 | // We can now unregister the interrupt handler |
| 477 | if state.rx_buf.len() == 0 { | 463 | if state.rx_buf.len() == 0 { |
| 478 | T::Interrupt::steal().disable(); | 464 | T::Interrupt::disable(); |
| 479 | } | ||
| 480 | } | 465 | } |
| 481 | } | 466 | } |
| 482 | } | 467 | } |
| @@ -485,7 +470,7 @@ pub struct BufferedInterruptHandler<T: Instance> { | |||
| 485 | _uart: PhantomData<T>, | 470 | _uart: PhantomData<T>, |
| 486 | } | 471 | } |
| 487 | 472 | ||
| 488 | impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<T> { | 473 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> { |
| 489 | unsafe fn on_interrupt() { | 474 | unsafe fn on_interrupt() { |
| 490 | let r = T::regs(); | 475 | let r = T::regs(); |
| 491 | if r.uartdmacr().read().rxdmae() { | 476 | if r.uartdmacr().read().rxdmae() { |
| @@ -494,94 +479,92 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler< | |||
| 494 | 479 | ||
| 495 | let s = T::buffered_state(); | 480 | let s = T::buffered_state(); |
| 496 | 481 | ||
| 497 | unsafe { | 482 | // Clear TX and error interrupt flags |
| 498 | // Clear TX and error interrupt flags | 483 | // RX interrupt flags are cleared by reading from the FIFO. |
| 499 | // RX interrupt flags are cleared by reading from the FIFO. | 484 | let ris = r.uartris().read(); |
| 500 | let ris = r.uartris().read(); | 485 | r.uarticr().write(|w| { |
| 501 | r.uarticr().write(|w| { | 486 | w.set_txic(ris.txris()); |
| 502 | w.set_txic(ris.txris()); | 487 | w.set_feic(ris.feris()); |
| 503 | w.set_feic(ris.feris()); | 488 | w.set_peic(ris.peris()); |
| 504 | w.set_peic(ris.peris()); | 489 | w.set_beic(ris.beris()); |
| 505 | w.set_beic(ris.beris()); | 490 | w.set_oeic(ris.oeris()); |
| 506 | w.set_oeic(ris.oeris()); | 491 | }); |
| 507 | }); | ||
| 508 | 492 | ||
| 509 | trace!("on_interrupt ris={:#X}", ris.0); | 493 | trace!("on_interrupt ris={:#X}", ris.0); |
| 510 | 494 | ||
| 511 | // Errors | 495 | // Errors |
| 512 | if ris.feris() { | 496 | if ris.feris() { |
| 513 | warn!("Framing error"); | 497 | warn!("Framing error"); |
| 514 | } | 498 | } |
| 515 | if ris.peris() { | 499 | if ris.peris() { |
| 516 | warn!("Parity error"); | 500 | warn!("Parity error"); |
| 517 | } | 501 | } |
| 518 | if ris.beris() { | 502 | if ris.beris() { |
| 519 | warn!("Break error"); | 503 | warn!("Break error"); |
| 520 | } | 504 | } |
| 521 | if ris.oeris() { | 505 | if ris.oeris() { |
| 522 | warn!("Overrun error"); | 506 | warn!("Overrun error"); |
| 523 | } | 507 | } |
| 524 | 508 | ||
| 525 | // RX | 509 | // RX |
| 526 | let mut rx_writer = s.rx_buf.writer(); | 510 | let mut rx_writer = unsafe { s.rx_buf.writer() }; |
| 527 | let rx_buf = rx_writer.push_slice(); | 511 | let rx_buf = rx_writer.push_slice(); |
| 528 | let mut n_read = 0; | 512 | let mut n_read = 0; |
| 529 | let mut error = false; | 513 | let mut error = false; |
| 530 | for rx_byte in rx_buf { | 514 | for rx_byte in rx_buf { |
| 531 | if r.uartfr().read().rxfe() { | 515 | if r.uartfr().read().rxfe() { |
| 532 | break; | 516 | break; |
| 533 | } | ||
| 534 | let dr = r.uartdr().read(); | ||
| 535 | if (dr.0 >> 8) != 0 { | ||
| 536 | s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); | ||
| 537 | error = true; | ||
| 538 | // only fill the buffer with valid characters. the current character is fine | ||
| 539 | // if the error is an overrun, but if we add it to the buffer we'll report | ||
| 540 | // the overrun one character too late. drop it instead and pretend we were | ||
| 541 | // a bit slower at draining the rx fifo than we actually were. | ||
| 542 | // this is consistent with blocking uart error reporting. | ||
| 543 | break; | ||
| 544 | } | ||
| 545 | *rx_byte = dr.data(); | ||
| 546 | n_read += 1; | ||
| 547 | } | ||
| 548 | if n_read > 0 { | ||
| 549 | rx_writer.push_done(n_read); | ||
| 550 | s.rx_waker.wake(); | ||
| 551 | } else if error { | ||
| 552 | s.rx_waker.wake(); | ||
| 553 | } | 517 | } |
| 554 | // Disable any further RX interrupts when the buffer becomes full or | 518 | let dr = r.uartdr().read(); |
| 555 | // errors have occurred. This lets us buffer additional errors in the | 519 | if (dr.0 >> 8) != 0 { |
| 556 | // fifo without needing more error storage locations, and most applications | 520 | s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); |
| 557 | // will want to do a full reset of their uart state anyway once an error | 521 | error = true; |
| 558 | // has happened. | 522 | // only fill the buffer with valid characters. the current character is fine |
| 559 | if s.rx_buf.is_full() || error { | 523 | // if the error is an overrun, but if we add it to the buffer we'll report |
| 560 | r.uartimsc().write_clear(|w| { | 524 | // the overrun one character too late. drop it instead and pretend we were |
| 561 | w.set_rxim(true); | 525 | // a bit slower at draining the rx fifo than we actually were. |
| 562 | w.set_rtim(true); | 526 | // this is consistent with blocking uart error reporting. |
| 563 | }); | 527 | break; |
| 564 | } | 528 | } |
| 529 | *rx_byte = dr.data(); | ||
| 530 | n_read += 1; | ||
| 531 | } | ||
| 532 | if n_read > 0 { | ||
| 533 | rx_writer.push_done(n_read); | ||
| 534 | s.rx_waker.wake(); | ||
| 535 | } else if error { | ||
| 536 | s.rx_waker.wake(); | ||
| 537 | } | ||
| 538 | // Disable any further RX interrupts when the buffer becomes full or | ||
| 539 | // errors have occurred. This lets us buffer additional errors in the | ||
| 540 | // fifo without needing more error storage locations, and most applications | ||
| 541 | // will want to do a full reset of their uart state anyway once an error | ||
| 542 | // has happened. | ||
| 543 | if s.rx_buf.is_full() || error { | ||
| 544 | r.uartimsc().write_clear(|w| { | ||
| 545 | w.set_rxim(true); | ||
| 546 | w.set_rtim(true); | ||
| 547 | }); | ||
| 548 | } | ||
| 565 | 549 | ||
| 566 | // TX | 550 | // TX |
| 567 | let mut tx_reader = s.tx_buf.reader(); | 551 | let mut tx_reader = unsafe { s.tx_buf.reader() }; |
| 568 | let tx_buf = tx_reader.pop_slice(); | 552 | let tx_buf = tx_reader.pop_slice(); |
| 569 | let mut n_written = 0; | 553 | let mut n_written = 0; |
| 570 | for tx_byte in tx_buf.iter_mut() { | 554 | for tx_byte in tx_buf.iter_mut() { |
| 571 | if r.uartfr().read().txff() { | 555 | if r.uartfr().read().txff() { |
| 572 | break; | 556 | break; |
| 573 | } | ||
| 574 | r.uartdr().write(|w| w.set_data(*tx_byte)); | ||
| 575 | n_written += 1; | ||
| 576 | } | ||
| 577 | if n_written > 0 { | ||
| 578 | tx_reader.pop_done(n_written); | ||
| 579 | s.tx_waker.wake(); | ||
| 580 | } | 557 | } |
| 581 | // The TX interrupt only triggers once when the FIFO threshold is | 558 | r.uartdr().write(|w| w.set_data(*tx_byte)); |
| 582 | // crossed. No need to disable it when the buffer becomes empty | 559 | n_written += 1; |
| 583 | // as it does re-trigger anymore once we have cleared it. | 560 | } |
| 561 | if n_written > 0 { | ||
| 562 | tx_reader.pop_done(n_written); | ||
| 563 | s.tx_waker.wake(); | ||
| 584 | } | 564 | } |
| 565 | // The TX interrupt only triggers once when the FIFO threshold is | ||
| 566 | // crossed. No need to disable it when the buffer becomes empty | ||
| 567 | // as it does re-trigger anymore once we have cleared it. | ||
| 585 | } | 568 | } |
| 586 | } | 569 | } |
| 587 | 570 | ||
| @@ -695,24 +678,22 @@ mod eh02 { | |||
| 695 | 678 | ||
| 696 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | 679 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { |
| 697 | let r = T::regs(); | 680 | let r = T::regs(); |
| 698 | unsafe { | 681 | if r.uartfr().read().rxfe() { |
| 699 | if r.uartfr().read().rxfe() { | 682 | return Err(nb::Error::WouldBlock); |
| 700 | return Err(nb::Error::WouldBlock); | 683 | } |
| 701 | } | ||
| 702 | 684 | ||
| 703 | let dr = r.uartdr().read(); | 685 | let dr = r.uartdr().read(); |
| 704 | 686 | ||
| 705 | if dr.oe() { | 687 | if dr.oe() { |
| 706 | Err(nb::Error::Other(Error::Overrun)) | 688 | Err(nb::Error::Other(Error::Overrun)) |
| 707 | } else if dr.be() { | 689 | } else if dr.be() { |
| 708 | Err(nb::Error::Other(Error::Break)) | 690 | Err(nb::Error::Other(Error::Break)) |
| 709 | } else if dr.pe() { | 691 | } else if dr.pe() { |
| 710 | Err(nb::Error::Other(Error::Parity)) | 692 | Err(nb::Error::Other(Error::Parity)) |
| 711 | } else if dr.fe() { | 693 | } else if dr.fe() { |
| 712 | Err(nb::Error::Other(Error::Framing)) | 694 | Err(nb::Error::Other(Error::Framing)) |
| 713 | } else { | 695 | } else { |
| 714 | Ok(dr.data()) | 696 | Ok(dr.data()) |
| 715 | } | ||
| 716 | } | 697 | } |
| 717 | } | 698 | } |
| 718 | } | 699 | } |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 44e0ca0f6..7b94bce5e 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -3,7 +3,6 @@ use core::marker::PhantomData; | |||
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use atomic_polyfill::{AtomicU16, Ordering}; | 5 | use atomic_polyfill::{AtomicU16, Ordering}; |
| 6 | use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt}; | ||
| 7 | use embassy_futures::select::{select, Either}; | 6 | use embassy_futures::select::{select, Either}; |
| 8 | use embassy_hal_common::{into_ref, PeripheralRef}; | 7 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -14,8 +13,9 @@ use crate::clocks::clk_peri_freq; | |||
| 14 | use crate::dma::{AnyChannel, Channel}; | 13 | use crate::dma::{AnyChannel, Channel}; |
| 15 | use crate::gpio::sealed::Pin; | 14 | use crate::gpio::sealed::Pin; |
| 16 | use crate::gpio::AnyPin; | 15 | use crate::gpio::AnyPin; |
| 16 | use crate::interrupt::typelevel::{Binding, Interrupt}; | ||
| 17 | use crate::pac::io::vals::{Inover, Outover}; | 17 | use crate::pac::io::vals::{Inover, Outover}; |
| 18 | use crate::{pac, peripherals, Peripheral, RegExt}; | 18 | use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; |
| 19 | 19 | ||
| 20 | #[cfg(feature = "nightly")] | 20 | #[cfg(feature = "nightly")] |
| 21 | mod buffered; | 21 | mod buffered; |
| @@ -146,23 +146,21 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { | |||
| 146 | 146 | ||
| 147 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 147 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 148 | let r = T::regs(); | 148 | let r = T::regs(); |
| 149 | unsafe { | 149 | for &b in buffer { |
| 150 | for &b in buffer { | 150 | while r.uartfr().read().txff() {} |
| 151 | while r.uartfr().read().txff() {} | 151 | r.uartdr().write(|w| w.set_data(b)); |
| 152 | r.uartdr().write(|w| w.set_data(b)); | ||
| 153 | } | ||
| 154 | } | 152 | } |
| 155 | Ok(()) | 153 | Ok(()) |
| 156 | } | 154 | } |
| 157 | 155 | ||
| 158 | pub fn blocking_flush(&mut self) -> Result<(), Error> { | 156 | pub fn blocking_flush(&mut self) -> Result<(), Error> { |
| 159 | let r = T::regs(); | 157 | let r = T::regs(); |
| 160 | unsafe { while !r.uartfr().read().txfe() {} } | 158 | while !r.uartfr().read().txfe() {} |
| 161 | Ok(()) | 159 | Ok(()) |
| 162 | } | 160 | } |
| 163 | 161 | ||
| 164 | pub fn busy(&self) -> bool { | 162 | pub fn busy(&self) -> bool { |
| 165 | unsafe { T::regs().uartfr().read().busy() } | 163 | T::regs().uartfr().read().busy() |
| 166 | } | 164 | } |
| 167 | 165 | ||
| 168 | /// Assert a break condition after waiting for the transmit buffers to empty, | 166 | /// Assert a break condition after waiting for the transmit buffers to empty, |
| @@ -174,28 +172,23 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { | |||
| 174 | /// for the transmit fifo to empty, which may take a while on slow links. | 172 | /// for the transmit fifo to empty, which may take a while on slow links. |
| 175 | pub async fn send_break(&mut self, bits: u32) { | 173 | pub async fn send_break(&mut self, bits: u32) { |
| 176 | let regs = T::regs(); | 174 | let regs = T::regs(); |
| 177 | let bits = bits.max(unsafe { | 175 | let bits = bits.max({ |
| 178 | let lcr = regs.uartlcr_h().read(); | 176 | let lcr = regs.uartlcr_h().read(); |
| 179 | let width = lcr.wlen() as u32 + 5; | 177 | let width = lcr.wlen() as u32 + 5; |
| 180 | let parity = lcr.pen() as u32; | 178 | let parity = lcr.pen() as u32; |
| 181 | let stops = 1 + lcr.stp2() as u32; | 179 | let stops = 1 + lcr.stp2() as u32; |
| 182 | 2 * (1 + width + parity + stops) | 180 | 2 * (1 + width + parity + stops) |
| 183 | }); | 181 | }); |
| 184 | let divx64 = unsafe { | 182 | let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6) |
| 185 | ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 | 183 | + regs.uartfbrd().read().baud_divfrac() as u32) as u64; |
| 186 | } as u64; | ||
| 187 | let div_clk = clk_peri_freq() as u64 * 64; | 184 | let div_clk = clk_peri_freq() as u64 * 64; |
| 188 | let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; | 185 | let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; |
| 189 | 186 | ||
| 190 | self.blocking_flush().unwrap(); | 187 | self.blocking_flush().unwrap(); |
| 191 | while self.busy() {} | 188 | while self.busy() {} |
| 192 | unsafe { | 189 | regs.uartlcr_h().write_set(|w| w.set_brk(true)); |
| 193 | regs.uartlcr_h().write_set(|w| w.set_brk(true)); | ||
| 194 | } | ||
| 195 | Timer::after(Duration::from_micros(wait_usecs)).await; | 190 | Timer::after(Duration::from_micros(wait_usecs)).await; |
| 196 | unsafe { | 191 | regs.uartlcr_h().write_clear(|w| w.set_brk(true)); |
| 197 | regs.uartlcr_h().write_clear(|w| w.set_brk(true)); | ||
| 198 | } | ||
| 199 | } | 192 | } |
| 200 | } | 193 | } |
| 201 | 194 | ||
| @@ -221,7 +214,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> { | |||
| 221 | }); | 214 | }); |
| 222 | // If we don't assign future to a variable, the data register pointer | 215 | // If we don't assign future to a variable, the data register pointer |
| 223 | // is held across an await and makes the future non-Send. | 216 | // is held across an await and makes the future non-Send. |
| 224 | crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ) | 217 | crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ) |
| 225 | }; | 218 | }; |
| 226 | transfer.await; | 219 | transfer.await; |
| 227 | Ok(()) | 220 | Ok(()) |
| @@ -245,12 +238,10 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||
| 245 | fn new_inner(has_irq: bool, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self { | 238 | fn new_inner(has_irq: bool, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self { |
| 246 | debug_assert_eq!(has_irq, rx_dma.is_some()); | 239 | debug_assert_eq!(has_irq, rx_dma.is_some()); |
| 247 | if has_irq { | 240 | if has_irq { |
| 248 | unsafe { | 241 | // disable all error interrupts initially |
| 249 | // disable all error interrupts initially | 242 | T::regs().uartimsc().write(|w| w.0 = 0); |
| 250 | T::regs().uartimsc().write(|w| w.0 = 0); | 243 | T::Interrupt::unpend(); |
| 251 | T::Interrupt::steal().unpend(); | 244 | unsafe { T::Interrupt::enable() }; |
| 252 | T::Interrupt::steal().enable(); | ||
| 253 | } | ||
| 254 | } | 245 | } |
| 255 | Self { | 246 | Self { |
| 256 | rx_dma, | 247 | rx_dma, |
| @@ -269,11 +260,11 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||
| 269 | fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 260 | fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 270 | let r = T::regs(); | 261 | let r = T::regs(); |
| 271 | for (i, b) in buffer.iter_mut().enumerate() { | 262 | for (i, b) in buffer.iter_mut().enumerate() { |
| 272 | if unsafe { r.uartfr().read().rxfe() } { | 263 | if r.uartfr().read().rxfe() { |
| 273 | return Ok(i); | 264 | return Ok(i); |
| 274 | } | 265 | } |
| 275 | 266 | ||
| 276 | let dr = unsafe { r.uartdr().read() }; | 267 | let dr = r.uartdr().read(); |
| 277 | 268 | ||
| 278 | if dr.oe() { | 269 | if dr.oe() { |
| 279 | return Err(Error::Overrun); | 270 | return Err(Error::Overrun); |
| @@ -294,15 +285,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | |||
| 294 | impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { | 285 | impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { |
| 295 | fn drop(&mut self) { | 286 | fn drop(&mut self) { |
| 296 | if let Some(_) = self.rx_dma { | 287 | if let Some(_) = self.rx_dma { |
| 297 | unsafe { | 288 | T::Interrupt::disable(); |
| 298 | T::Interrupt::steal().disable(); | 289 | // clear dma flags. irq handlers use these to disambiguate among themselves. |
| 299 | // clear dma flags. irq handlers use these to disambiguate among themselves. | 290 | T::regs().uartdmacr().write_clear(|reg| { |
| 300 | T::regs().uartdmacr().write_clear(|reg| { | 291 | reg.set_rxdmae(true); |
| 301 | reg.set_rxdmae(true); | 292 | reg.set_txdmae(true); |
| 302 | reg.set_txdmae(true); | 293 | reg.set_dmaonerr(true); |
| 303 | reg.set_dmaonerr(true); | 294 | }); |
| 304 | }); | ||
| 305 | } | ||
| 306 | } | 295 | } |
| 307 | } | 296 | } |
| 308 | } | 297 | } |
| @@ -334,7 +323,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 334 | _uart: PhantomData<T>, | 323 | _uart: PhantomData<T>, |
| 335 | } | 324 | } |
| 336 | 325 | ||
| 337 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 326 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 338 | unsafe fn on_interrupt() { | 327 | unsafe fn on_interrupt() { |
| 339 | let uart = T::regs(); | 328 | let uart = T::regs(); |
| 340 | if !uart.uartdmacr().read().rxdmae() { | 329 | if !uart.uartdmacr().read().rxdmae() { |
| @@ -357,14 +346,12 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 357 | // clear error flags before we drain the fifo. errors that have accumulated | 346 | // clear error flags before we drain the fifo. errors that have accumulated |
| 358 | // in the flags will also be present in the fifo. | 347 | // in the flags will also be present in the fifo. |
| 359 | T::dma_state().rx_errs.store(0, Ordering::Relaxed); | 348 | T::dma_state().rx_errs.store(0, Ordering::Relaxed); |
| 360 | unsafe { | 349 | T::regs().uarticr().write(|w| { |
| 361 | T::regs().uarticr().write(|w| { | 350 | w.set_oeic(true); |
| 362 | w.set_oeic(true); | 351 | w.set_beic(true); |
| 363 | w.set_beic(true); | 352 | w.set_peic(true); |
| 364 | w.set_peic(true); | 353 | w.set_feic(true); |
| 365 | w.set_feic(true); | 354 | }); |
| 366 | }); | ||
| 367 | } | ||
| 368 | 355 | ||
| 369 | // then drain the fifo. we need to read at most 32 bytes. errors that apply | 356 | // then drain the fifo. we need to read at most 32 bytes. errors that apply |
| 370 | // to fifo bytes will be reported directly. | 357 | // to fifo bytes will be reported directly. |
| @@ -381,20 +368,20 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 381 | // interrupt flags will have been raised, and those will be picked up immediately | 368 | // interrupt flags will have been raised, and those will be picked up immediately |
| 382 | // by the interrupt handler. | 369 | // by the interrupt handler. |
| 383 | let ch = self.rx_dma.as_mut().unwrap(); | 370 | let ch = self.rx_dma.as_mut().unwrap(); |
| 371 | T::regs().uartimsc().write_set(|w| { | ||
| 372 | w.set_oeim(true); | ||
| 373 | w.set_beim(true); | ||
| 374 | w.set_peim(true); | ||
| 375 | w.set_feim(true); | ||
| 376 | }); | ||
| 377 | T::regs().uartdmacr().write_set(|reg| { | ||
| 378 | reg.set_rxdmae(true); | ||
| 379 | reg.set_dmaonerr(true); | ||
| 380 | }); | ||
| 384 | let transfer = unsafe { | 381 | let transfer = unsafe { |
| 385 | T::regs().uartimsc().write_set(|w| { | ||
| 386 | w.set_oeim(true); | ||
| 387 | w.set_beim(true); | ||
| 388 | w.set_peim(true); | ||
| 389 | w.set_feim(true); | ||
| 390 | }); | ||
| 391 | T::regs().uartdmacr().write_set(|reg| { | ||
| 392 | reg.set_rxdmae(true); | ||
| 393 | reg.set_dmaonerr(true); | ||
| 394 | }); | ||
| 395 | // If we don't assign future to a variable, the data register pointer | 382 | // If we don't assign future to a variable, the data register pointer |
| 396 | // is held across an await and makes the future non-Send. | 383 | // is held across an await and makes the future non-Send. |
| 397 | crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ) | 384 | crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ) |
| 398 | }; | 385 | }; |
| 399 | 386 | ||
| 400 | // wait for either the transfer to complete or an error to happen. | 387 | // wait for either the transfer to complete or an error to happen. |
| @@ -577,81 +564,79 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { | |||
| 577 | config: Config, | 564 | config: Config, |
| 578 | ) { | 565 | ) { |
| 579 | let r = T::regs(); | 566 | let r = T::regs(); |
| 580 | unsafe { | 567 | if let Some(pin) = &tx { |
| 581 | if let Some(pin) = &tx { | 568 | pin.io().ctrl().write(|w| { |
| 582 | pin.io().ctrl().write(|w| { | 569 | w.set_funcsel(2); |
| 583 | w.set_funcsel(2); | 570 | w.set_outover(if config.invert_tx { |
| 584 | w.set_outover(if config.invert_tx { | 571 | Outover::INVERT |
| 585 | Outover::INVERT | 572 | } else { |
| 586 | } else { | 573 | Outover::NORMAL |
| 587 | Outover::NORMAL | ||
| 588 | }); | ||
| 589 | }); | 574 | }); |
| 590 | pin.pad_ctrl().write(|w| w.set_ie(true)); | 575 | }); |
| 591 | } | 576 | pin.pad_ctrl().write(|w| w.set_ie(true)); |
| 592 | if let Some(pin) = &rx { | 577 | } |
| 593 | pin.io().ctrl().write(|w| { | 578 | if let Some(pin) = &rx { |
| 594 | w.set_funcsel(2); | 579 | pin.io().ctrl().write(|w| { |
| 595 | w.set_inover(if config.invert_rx { | 580 | w.set_funcsel(2); |
| 596 | Inover::INVERT | 581 | w.set_inover(if config.invert_rx { |
| 597 | } else { | 582 | Inover::INVERT |
| 598 | Inover::NORMAL | 583 | } else { |
| 599 | }); | 584 | Inover::NORMAL |
| 600 | }); | 585 | }); |
| 601 | pin.pad_ctrl().write(|w| w.set_ie(true)); | 586 | }); |
| 602 | } | 587 | pin.pad_ctrl().write(|w| w.set_ie(true)); |
| 603 | if let Some(pin) = &cts { | 588 | } |
| 604 | pin.io().ctrl().write(|w| { | 589 | if let Some(pin) = &cts { |
| 605 | w.set_funcsel(2); | 590 | pin.io().ctrl().write(|w| { |
| 606 | w.set_inover(if config.invert_cts { | 591 | w.set_funcsel(2); |
| 607 | Inover::INVERT | 592 | w.set_inover(if config.invert_cts { |
| 608 | } else { | 593 | Inover::INVERT |
| 609 | Inover::NORMAL | 594 | } else { |
| 610 | }); | 595 | Inover::NORMAL |
| 611 | }); | 596 | }); |
| 612 | pin.pad_ctrl().write(|w| w.set_ie(true)); | 597 | }); |
| 613 | } | 598 | pin.pad_ctrl().write(|w| w.set_ie(true)); |
| 614 | if let Some(pin) = &rts { | 599 | } |
| 615 | pin.io().ctrl().write(|w| { | 600 | if let Some(pin) = &rts { |
| 616 | w.set_funcsel(2); | 601 | pin.io().ctrl().write(|w| { |
| 617 | w.set_outover(if config.invert_rts { | 602 | w.set_funcsel(2); |
| 618 | Outover::INVERT | 603 | w.set_outover(if config.invert_rts { |
| 619 | } else { | 604 | Outover::INVERT |
| 620 | Outover::NORMAL | 605 | } else { |
| 621 | }); | 606 | Outover::NORMAL |
| 622 | }); | 607 | }); |
| 623 | pin.pad_ctrl().write(|w| w.set_ie(true)); | 608 | }); |
| 624 | } | 609 | pin.pad_ctrl().write(|w| w.set_ie(true)); |
| 610 | } | ||
| 625 | 611 | ||
| 626 | Self::set_baudrate_inner(config.baudrate); | 612 | Self::set_baudrate_inner(config.baudrate); |
| 627 | 613 | ||
| 628 | let (pen, eps) = match config.parity { | 614 | let (pen, eps) = match config.parity { |
| 629 | Parity::ParityNone => (false, false), | 615 | Parity::ParityNone => (false, false), |
| 630 | Parity::ParityOdd => (true, false), | 616 | Parity::ParityOdd => (true, false), |
| 631 | Parity::ParityEven => (true, true), | 617 | Parity::ParityEven => (true, true), |
| 632 | }; | 618 | }; |
| 633 | 619 | ||
| 634 | r.uartlcr_h().write(|w| { | 620 | r.uartlcr_h().write(|w| { |
| 635 | w.set_wlen(config.data_bits.bits()); | 621 | w.set_wlen(config.data_bits.bits()); |
| 636 | w.set_stp2(config.stop_bits == StopBits::STOP2); | 622 | w.set_stp2(config.stop_bits == StopBits::STOP2); |
| 637 | w.set_pen(pen); | 623 | w.set_pen(pen); |
| 638 | w.set_eps(eps); | 624 | w.set_eps(eps); |
| 639 | w.set_fen(true); | 625 | w.set_fen(true); |
| 640 | }); | 626 | }); |
| 641 | 627 | ||
| 642 | r.uartifls().write(|w| { | 628 | r.uartifls().write(|w| { |
| 643 | w.set_rxiflsel(0b000); | 629 | w.set_rxiflsel(0b000); |
| 644 | w.set_txiflsel(0b000); | 630 | w.set_txiflsel(0b000); |
| 645 | }); | 631 | }); |
| 646 | 632 | ||
| 647 | r.uartcr().write(|w| { | 633 | r.uartcr().write(|w| { |
| 648 | w.set_uarten(true); | 634 | w.set_uarten(true); |
| 649 | w.set_rxe(true); | 635 | w.set_rxe(true); |
| 650 | w.set_txe(true); | 636 | w.set_txe(true); |
| 651 | w.set_ctsen(cts.is_some()); | 637 | w.set_ctsen(cts.is_some()); |
| 652 | w.set_rtsen(rts.is_some()); | 638 | w.set_rtsen(rts.is_some()); |
| 653 | }); | 639 | }); |
| 654 | } | ||
| 655 | } | 640 | } |
| 656 | 641 | ||
| 657 | /// sets baudrate on runtime | 642 | /// sets baudrate on runtime |
| @@ -676,15 +661,13 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { | |||
| 676 | baud_fbrd = 0; | 661 | baud_fbrd = 0; |
| 677 | } | 662 | } |
| 678 | 663 | ||
| 679 | unsafe { | 664 | // Load PL011's baud divisor registers |
| 680 | // Load PL011's baud divisor registers | 665 | r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); |
| 681 | r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); | 666 | r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd)); |
| 682 | r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd)); | ||
| 683 | 667 | ||
| 684 | // PL011 needs a (dummy) line control register write to latch in the | 668 | // PL011 needs a (dummy) line control register write to latch in the |
| 685 | // divisors. We don't want to actually change LCR contents here. | 669 | // divisors. We don't want to actually change LCR contents here. |
| 686 | r.uartlcr_h().modify(|_| {}); | 670 | r.uartlcr_h().modify(|_| {}); |
| 687 | } | ||
| 688 | } | 671 | } |
| 689 | } | 672 | } |
| 690 | 673 | ||
| @@ -733,24 +716,22 @@ mod eh02 { | |||
| 733 | type Error = Error; | 716 | type Error = Error; |
| 734 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | 717 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { |
| 735 | let r = T::regs(); | 718 | let r = T::regs(); |
| 736 | unsafe { | 719 | if r.uartfr().read().rxfe() { |
| 737 | if r.uartfr().read().rxfe() { | 720 | return Err(nb::Error::WouldBlock); |
| 738 | return Err(nb::Error::WouldBlock); | 721 | } |
| 739 | } | ||
| 740 | 722 | ||
| 741 | let dr = r.uartdr().read(); | 723 | let dr = r.uartdr().read(); |
| 742 | 724 | ||
| 743 | if dr.oe() { | 725 | if dr.oe() { |
| 744 | Err(nb::Error::Other(Error::Overrun)) | 726 | Err(nb::Error::Other(Error::Overrun)) |
| 745 | } else if dr.be() { | 727 | } else if dr.be() { |
| 746 | Err(nb::Error::Other(Error::Break)) | 728 | Err(nb::Error::Other(Error::Break)) |
| 747 | } else if dr.pe() { | 729 | } else if dr.pe() { |
| 748 | Err(nb::Error::Other(Error::Parity)) | 730 | Err(nb::Error::Other(Error::Parity)) |
| 749 | } else if dr.fe() { | 731 | } else if dr.fe() { |
| 750 | Err(nb::Error::Other(Error::Framing)) | 732 | Err(nb::Error::Other(Error::Framing)) |
| 751 | } else { | 733 | } else { |
| 752 | Ok(dr.data()) | 734 | Ok(dr.data()) |
| 753 | } | ||
| 754 | } | 735 | } |
| 755 | } | 736 | } |
| 756 | } | 737 | } |
| @@ -760,22 +741,18 @@ mod eh02 { | |||
| 760 | 741 | ||
| 761 | fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { | 742 | fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { |
| 762 | let r = T::regs(); | 743 | let r = T::regs(); |
| 763 | unsafe { | 744 | if r.uartfr().read().txff() { |
| 764 | if r.uartfr().read().txff() { | 745 | return Err(nb::Error::WouldBlock); |
| 765 | return Err(nb::Error::WouldBlock); | ||
| 766 | } | ||
| 767 | |||
| 768 | r.uartdr().write(|w| w.set_data(word)); | ||
| 769 | } | 746 | } |
| 747 | |||
| 748 | r.uartdr().write(|w| w.set_data(word)); | ||
| 770 | Ok(()) | 749 | Ok(()) |
| 771 | } | 750 | } |
| 772 | 751 | ||
| 773 | fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> { | 752 | fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> { |
| 774 | let r = T::regs(); | 753 | let r = T::regs(); |
| 775 | unsafe { | 754 | if !r.uartfr().read().txfe() { |
| 776 | if !r.uartfr().read().txfe() { | 755 | return Err(nb::Error::WouldBlock); |
| 777 | return Err(nb::Error::WouldBlock); | ||
| 778 | } | ||
| 779 | } | 756 | } |
| 780 | Ok(()) | 757 | Ok(()) |
| 781 | } | 758 | } |
| @@ -856,22 +833,20 @@ mod eh1 { | |||
| 856 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { | 833 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { |
| 857 | fn read(&mut self) -> nb::Result<u8, Self::Error> { | 834 | fn read(&mut self) -> nb::Result<u8, Self::Error> { |
| 858 | let r = T::regs(); | 835 | let r = T::regs(); |
| 859 | unsafe { | 836 | let dr = r.uartdr().read(); |
| 860 | let dr = r.uartdr().read(); | 837 | |
| 861 | 838 | if dr.oe() { | |
| 862 | if dr.oe() { | 839 | Err(nb::Error::Other(Error::Overrun)) |
| 863 | Err(nb::Error::Other(Error::Overrun)) | 840 | } else if dr.be() { |
| 864 | } else if dr.be() { | 841 | Err(nb::Error::Other(Error::Break)) |
| 865 | Err(nb::Error::Other(Error::Break)) | 842 | } else if dr.pe() { |
| 866 | } else if dr.pe() { | 843 | Err(nb::Error::Other(Error::Parity)) |
| 867 | Err(nb::Error::Other(Error::Parity)) | 844 | } else if dr.fe() { |
| 868 | } else if dr.fe() { | 845 | Err(nb::Error::Other(Error::Framing)) |
| 869 | Err(nb::Error::Other(Error::Framing)) | 846 | } else if dr.fe() { |
| 870 | } else if dr.fe() { | 847 | Ok(dr.data()) |
| 871 | Ok(dr.data()) | 848 | } else { |
| 872 | } else { | 849 | Err(nb::Error::WouldBlock) |
| 873 | Err(nb::Error::WouldBlock) | ||
| 874 | } | ||
| 875 | } | 850 | } |
| 876 | } | 851 | } |
| 877 | } | 852 | } |
| @@ -932,7 +907,7 @@ mod sealed { | |||
| 932 | const TX_DREQ: u8; | 907 | const TX_DREQ: u8; |
| 933 | const RX_DREQ: u8; | 908 | const RX_DREQ: u8; |
| 934 | 909 | ||
| 935 | type Interrupt: crate::interrupt::Interrupt; | 910 | type Interrupt: interrupt::typelevel::Interrupt; |
| 936 | 911 | ||
| 937 | fn regs() -> pac::uart::Uart; | 912 | fn regs() -> pac::uart::Uart; |
| 938 | 913 | ||
| @@ -970,7 +945,7 @@ macro_rules! impl_instance { | |||
| 970 | const TX_DREQ: u8 = $tx_dreq; | 945 | const TX_DREQ: u8 = $tx_dreq; |
| 971 | const RX_DREQ: u8 = $rx_dreq; | 946 | const RX_DREQ: u8 = $rx_dreq; |
| 972 | 947 | ||
| 973 | type Interrupt = crate::interrupt::$irq; | 948 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 974 | 949 | ||
| 975 | fn regs() -> pac::uart::Uart { | 950 | fn regs() -> pac::uart::Uart { |
| 976 | pac::$inst | 951 | pac::$inst |
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index fada2790f..1900ab416 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs | |||
| @@ -4,15 +4,14 @@ use core::slice; | |||
| 4 | use core::sync::atomic::{compiler_fence, Ordering}; | 4 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 5 | use core::task::Poll; | 5 | use core::task::Poll; |
| 6 | 6 | ||
| 7 | use embassy_cortex_m::interrupt::{self, Binding}; | ||
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 9 | use embassy_usb_driver as driver; | 8 | use embassy_usb_driver as driver; |
| 10 | use embassy_usb_driver::{ | 9 | use embassy_usb_driver::{ |
| 11 | Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, | 10 | Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, |
| 12 | }; | 11 | }; |
| 13 | 12 | ||
| 14 | use crate::interrupt::{Interrupt, InterruptExt}; | 13 | use crate::interrupt::typelevel::{Binding, Interrupt}; |
| 15 | use crate::{pac, peripherals, Peripheral, RegExt}; | 14 | use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; |
| 16 | 15 | ||
| 17 | pub(crate) mod sealed { | 16 | pub(crate) mod sealed { |
| 18 | pub trait Instance { | 17 | pub trait Instance { |
| @@ -22,7 +21,7 @@ pub(crate) mod sealed { | |||
| 22 | } | 21 | } |
| 23 | 22 | ||
| 24 | pub trait Instance: sealed::Instance + 'static { | 23 | pub trait Instance: sealed::Instance + 'static { |
| 25 | type Interrupt: Interrupt; | 24 | type Interrupt: interrupt::typelevel::Interrupt; |
| 26 | } | 25 | } |
| 27 | 26 | ||
| 28 | impl crate::usb::sealed::Instance for peripherals::USB { | 27 | impl crate::usb::sealed::Instance for peripherals::USB { |
| @@ -35,12 +34,12 @@ impl crate::usb::sealed::Instance for peripherals::USB { | |||
| 35 | } | 34 | } |
| 36 | 35 | ||
| 37 | impl crate::usb::Instance for peripherals::USB { | 36 | impl crate::usb::Instance for peripherals::USB { |
| 38 | type Interrupt = crate::interrupt::USBCTRL_IRQ; | 37 | type Interrupt = crate::interrupt::typelevel::USBCTRL_IRQ; |
| 39 | } | 38 | } |
| 40 | 39 | ||
| 41 | const EP_COUNT: usize = 16; | 40 | const EP_COUNT: usize = 16; |
| 42 | const EP_MEMORY_SIZE: usize = 4096; | 41 | const EP_MEMORY_SIZE: usize = 4096; |
| 43 | const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.0; | 42 | const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.as_ptr() as *mut u8; |
| 44 | 43 | ||
| 45 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 44 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 46 | static BUS_WAKER: AtomicWaker = NEW_AW; | 45 | static BUS_WAKER: AtomicWaker = NEW_AW; |
| @@ -106,15 +105,13 @@ pub struct Driver<'d, T: Instance> { | |||
| 106 | 105 | ||
| 107 | impl<'d, T: Instance> Driver<'d, T> { | 106 | impl<'d, T: Instance> Driver<'d, T> { |
| 108 | pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self { | 107 | pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self { |
| 109 | unsafe { | 108 | T::Interrupt::unpend(); |
| 110 | T::Interrupt::steal().unpend(); | 109 | unsafe { T::Interrupt::enable() }; |
| 111 | T::Interrupt::steal().enable(); | ||
| 112 | } | ||
| 113 | 110 | ||
| 114 | let regs = T::regs(); | 111 | let regs = T::regs(); |
| 115 | unsafe { | 112 | unsafe { |
| 116 | // zero fill regs | 113 | // zero fill regs |
| 117 | let p = regs.0 as *mut u32; | 114 | let p = regs.as_ptr() as *mut u32; |
| 118 | for i in 0..0x9c / 4 { | 115 | for i in 0..0x9c / 4 { |
| 119 | p.add(i).write_volatile(0) | 116 | p.add(i).write_volatile(0) |
| 120 | } | 117 | } |
| @@ -124,20 +121,20 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 124 | for i in 0..0x100 / 4 { | 121 | for i in 0..0x100 / 4 { |
| 125 | p.add(i).write_volatile(0) | 122 | p.add(i).write_volatile(0) |
| 126 | } | 123 | } |
| 127 | |||
| 128 | regs.usb_muxing().write(|w| { | ||
| 129 | w.set_to_phy(true); | ||
| 130 | w.set_softcon(true); | ||
| 131 | }); | ||
| 132 | regs.usb_pwr().write(|w| { | ||
| 133 | w.set_vbus_detect(true); | ||
| 134 | w.set_vbus_detect_override_en(true); | ||
| 135 | }); | ||
| 136 | regs.main_ctrl().write(|w| { | ||
| 137 | w.set_controller_en(true); | ||
| 138 | }); | ||
| 139 | } | 124 | } |
| 140 | 125 | ||
| 126 | regs.usb_muxing().write(|w| { | ||
| 127 | w.set_to_phy(true); | ||
| 128 | w.set_softcon(true); | ||
| 129 | }); | ||
| 130 | regs.usb_pwr().write(|w| { | ||
| 131 | w.set_vbus_detect(true); | ||
| 132 | w.set_vbus_detect_override_en(true); | ||
| 133 | }); | ||
| 134 | regs.main_ctrl().write(|w| { | ||
| 135 | w.set_controller_en(true); | ||
| 136 | }); | ||
| 137 | |||
| 141 | // Initialize the bus so that it signals that power is available | 138 | // Initialize the bus so that it signals that power is available |
| 142 | BUS_WAKER.wake(); | 139 | BUS_WAKER.wake(); |
| 143 | 140 | ||
| @@ -216,22 +213,18 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 216 | }; | 213 | }; |
| 217 | 214 | ||
| 218 | match D::dir() { | 215 | match D::dir() { |
| 219 | Direction::Out => unsafe { | 216 | Direction::Out => T::dpram().ep_out_control(index - 1).write(|w| { |
| 220 | T::dpram().ep_out_control(index - 1).write(|w| { | 217 | w.set_enable(false); |
| 221 | w.set_enable(false); | 218 | w.set_buffer_address(addr); |
| 222 | w.set_buffer_address(addr); | 219 | w.set_interrupt_per_buff(true); |
| 223 | w.set_interrupt_per_buff(true); | 220 | w.set_endpoint_type(ep_type_reg); |
| 224 | w.set_endpoint_type(ep_type_reg); | 221 | }), |
| 225 | }) | 222 | Direction::In => T::dpram().ep_in_control(index - 1).write(|w| { |
| 226 | }, | 223 | w.set_enable(false); |
| 227 | Direction::In => unsafe { | 224 | w.set_buffer_address(addr); |
| 228 | T::dpram().ep_in_control(index - 1).write(|w| { | 225 | w.set_interrupt_per_buff(true); |
| 229 | w.set_enable(false); | 226 | w.set_endpoint_type(ep_type_reg); |
| 230 | w.set_buffer_address(addr); | 227 | }), |
| 231 | w.set_interrupt_per_buff(true); | ||
| 232 | w.set_endpoint_type(ep_type_reg); | ||
| 233 | }) | ||
| 234 | }, | ||
| 235 | } | 228 | } |
| 236 | 229 | ||
| 237 | Ok(Endpoint { | 230 | Ok(Endpoint { |
| @@ -251,7 +244,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 251 | _uart: PhantomData<T>, | 244 | _uart: PhantomData<T>, |
| 252 | } | 245 | } |
| 253 | 246 | ||
| 254 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 247 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 255 | unsafe fn on_interrupt() { | 248 | unsafe fn on_interrupt() { |
| 256 | let regs = T::regs(); | 249 | let regs = T::regs(); |
| 257 | //let x = regs.istr().read().0; | 250 | //let x = regs.istr().read().0; |
| @@ -318,22 +311,21 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 318 | 311 | ||
| 319 | fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { | 312 | fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { |
| 320 | let regs = T::regs(); | 313 | let regs = T::regs(); |
| 321 | unsafe { | 314 | regs.inte().write(|w| { |
| 322 | regs.inte().write(|w| { | 315 | w.set_bus_reset(true); |
| 323 | w.set_bus_reset(true); | 316 | w.set_buff_status(true); |
| 324 | w.set_buff_status(true); | 317 | w.set_dev_resume_from_host(true); |
| 325 | w.set_dev_resume_from_host(true); | 318 | w.set_dev_suspend(true); |
| 326 | w.set_dev_suspend(true); | 319 | w.set_setup_req(true); |
| 327 | w.set_setup_req(true); | 320 | }); |
| 328 | }); | 321 | regs.int_ep_ctrl().write(|w| { |
| 329 | regs.int_ep_ctrl().write(|w| { | 322 | w.set_int_ep_active(0xFFFE); // all EPs |
| 330 | w.set_int_ep_active(0xFFFE); // all EPs | 323 | }); |
| 331 | }); | 324 | regs.sie_ctrl().write(|w| { |
| 332 | regs.sie_ctrl().write(|w| { | 325 | w.set_ep0_int_1buf(true); |
| 333 | w.set_ep0_int_1buf(true); | 326 | w.set_pullup_en(true); |
| 334 | w.set_pullup_en(true); | 327 | }); |
| 335 | }) | 328 | |
| 336 | } | ||
| 337 | trace!("enabled"); | 329 | trace!("enabled"); |
| 338 | 330 | ||
| 339 | ( | 331 | ( |
| @@ -358,7 +350,7 @@ pub struct Bus<'d, T: Instance> { | |||
| 358 | 350 | ||
| 359 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | 351 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { |
| 360 | async fn poll(&mut self) -> Event { | 352 | async fn poll(&mut self) -> Event { |
| 361 | poll_fn(move |cx| unsafe { | 353 | poll_fn(move |cx| { |
| 362 | BUS_WAKER.register(cx.waker()); | 354 | BUS_WAKER.register(cx.waker()); |
| 363 | 355 | ||
| 364 | if !self.inited { | 356 | if !self.inited { |
| @@ -428,14 +420,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 428 | 420 | ||
| 429 | let n = ep_addr.index(); | 421 | let n = ep_addr.index(); |
| 430 | match ep_addr.direction() { | 422 | match ep_addr.direction() { |
| 431 | Direction::In => unsafe { | 423 | Direction::In => { |
| 432 | T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); | 424 | T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); |
| 433 | T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { | 425 | T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { |
| 434 | w.set_pid(0, true); // first packet is DATA0, but PID is flipped before | 426 | w.set_pid(0, true); // first packet is DATA0, but PID is flipped before |
| 435 | }); | 427 | }); |
| 436 | EP_IN_WAKERS[n].wake(); | 428 | EP_IN_WAKERS[n].wake(); |
| 437 | }, | 429 | } |
| 438 | Direction::Out => unsafe { | 430 | Direction::Out => { |
| 439 | T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); | 431 | T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); |
| 440 | 432 | ||
| 441 | T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { | 433 | T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { |
| @@ -449,7 +441,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 449 | w.set_available(0, true); | 441 | w.set_available(0, true); |
| 450 | }); | 442 | }); |
| 451 | EP_OUT_WAKERS[n].wake(); | 443 | EP_OUT_WAKERS[n].wake(); |
| 452 | }, | 444 | } |
| 453 | } | 445 | } |
| 454 | } | 446 | } |
| 455 | 447 | ||
| @@ -507,7 +499,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { | |||
| 507 | let index = self.info.addr.index(); | 499 | let index = self.info.addr.index(); |
| 508 | poll_fn(|cx| { | 500 | poll_fn(|cx| { |
| 509 | EP_IN_WAKERS[index].register(cx.waker()); | 501 | EP_IN_WAKERS[index].register(cx.waker()); |
| 510 | let val = unsafe { T::dpram().ep_in_control(self.info.addr.index() - 1).read() }; | 502 | let val = T::dpram().ep_in_control(self.info.addr.index() - 1).read(); |
| 511 | if val.enable() { | 503 | if val.enable() { |
| 512 | Poll::Ready(()) | 504 | Poll::Ready(()) |
| 513 | } else { | 505 | } else { |
| @@ -529,7 +521,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> { | |||
| 529 | let index = self.info.addr.index(); | 521 | let index = self.info.addr.index(); |
| 530 | poll_fn(|cx| { | 522 | poll_fn(|cx| { |
| 531 | EP_OUT_WAKERS[index].register(cx.waker()); | 523 | EP_OUT_WAKERS[index].register(cx.waker()); |
| 532 | let val = unsafe { T::dpram().ep_out_control(self.info.addr.index() - 1).read() }; | 524 | let val = T::dpram().ep_out_control(self.info.addr.index() - 1).read(); |
| 533 | if val.enable() { | 525 | if val.enable() { |
| 534 | Poll::Ready(()) | 526 | Poll::Ready(()) |
| 535 | } else { | 527 | } else { |
| @@ -545,7 +537,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 545 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { | 537 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { |
| 546 | trace!("READ WAITING, buf.len() = {}", buf.len()); | 538 | trace!("READ WAITING, buf.len() = {}", buf.len()); |
| 547 | let index = self.info.addr.index(); | 539 | let index = self.info.addr.index(); |
| 548 | let val = poll_fn(|cx| unsafe { | 540 | let val = poll_fn(|cx| { |
| 549 | EP_OUT_WAKERS[index].register(cx.waker()); | 541 | EP_OUT_WAKERS[index].register(cx.waker()); |
| 550 | let val = T::dpram().ep_out_buffer_control(index).read(); | 542 | let val = T::dpram().ep_out_buffer_control(index).read(); |
| 551 | if val.available(0) { | 543 | if val.available(0) { |
| @@ -564,19 +556,17 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 564 | 556 | ||
| 565 | trace!("READ OK, rx_len = {}", rx_len); | 557 | trace!("READ OK, rx_len = {}", rx_len); |
| 566 | 558 | ||
| 567 | unsafe { | 559 | let pid = !val.pid(0); |
| 568 | let pid = !val.pid(0); | 560 | T::dpram().ep_out_buffer_control(index).write(|w| { |
| 569 | T::dpram().ep_out_buffer_control(index).write(|w| { | 561 | w.set_pid(0, pid); |
| 570 | w.set_pid(0, pid); | 562 | w.set_length(0, self.info.max_packet_size); |
| 571 | w.set_length(0, self.info.max_packet_size); | 563 | }); |
| 572 | }); | 564 | cortex_m::asm::delay(12); |
| 573 | cortex_m::asm::delay(12); | 565 | T::dpram().ep_out_buffer_control(index).write(|w| { |
| 574 | T::dpram().ep_out_buffer_control(index).write(|w| { | 566 | w.set_pid(0, pid); |
| 575 | w.set_pid(0, pid); | 567 | w.set_length(0, self.info.max_packet_size); |
| 576 | w.set_length(0, self.info.max_packet_size); | 568 | w.set_available(0, true); |
| 577 | w.set_available(0, true); | 569 | }); |
| 578 | }); | ||
| 579 | } | ||
| 580 | 570 | ||
| 581 | Ok(rx_len) | 571 | Ok(rx_len) |
| 582 | } | 572 | } |
| @@ -591,7 +581,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 591 | trace!("WRITE WAITING"); | 581 | trace!("WRITE WAITING"); |
| 592 | 582 | ||
| 593 | let index = self.info.addr.index(); | 583 | let index = self.info.addr.index(); |
| 594 | let val = poll_fn(|cx| unsafe { | 584 | let val = poll_fn(|cx| { |
| 595 | EP_IN_WAKERS[index].register(cx.waker()); | 585 | EP_IN_WAKERS[index].register(cx.waker()); |
| 596 | let val = T::dpram().ep_in_buffer_control(index).read(); | 586 | let val = T::dpram().ep_in_buffer_control(index).read(); |
| 597 | if val.available(0) { | 587 | if val.available(0) { |
| @@ -604,21 +594,19 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 604 | 594 | ||
| 605 | self.buf.write(buf); | 595 | self.buf.write(buf); |
| 606 | 596 | ||
| 607 | unsafe { | 597 | let pid = !val.pid(0); |
| 608 | let pid = !val.pid(0); | 598 | T::dpram().ep_in_buffer_control(index).write(|w| { |
| 609 | T::dpram().ep_in_buffer_control(index).write(|w| { | 599 | w.set_pid(0, pid); |
| 610 | w.set_pid(0, pid); | 600 | w.set_length(0, buf.len() as _); |
| 611 | w.set_length(0, buf.len() as _); | 601 | w.set_full(0, true); |
| 612 | w.set_full(0, true); | 602 | }); |
| 613 | }); | 603 | cortex_m::asm::delay(12); |
| 614 | cortex_m::asm::delay(12); | 604 | T::dpram().ep_in_buffer_control(index).write(|w| { |
| 615 | T::dpram().ep_in_buffer_control(index).write(|w| { | 605 | w.set_pid(0, pid); |
| 616 | w.set_pid(0, pid); | 606 | w.set_length(0, buf.len() as _); |
| 617 | w.set_length(0, buf.len() as _); | 607 | w.set_full(0, true); |
| 618 | w.set_full(0, true); | 608 | w.set_available(0, true); |
| 619 | w.set_available(0, true); | 609 | }); |
| 620 | }); | ||
| 621 | } | ||
| 622 | 610 | ||
| 623 | trace!("WRITE OK"); | 611 | trace!("WRITE OK"); |
| 624 | 612 | ||
| @@ -640,9 +628,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 640 | loop { | 628 | loop { |
| 641 | trace!("SETUP read waiting"); | 629 | trace!("SETUP read waiting"); |
| 642 | let regs = T::regs(); | 630 | let regs = T::regs(); |
| 643 | unsafe { regs.inte().write_set(|w| w.set_setup_req(true)) }; | 631 | regs.inte().write_set(|w| w.set_setup_req(true)); |
| 644 | 632 | ||
| 645 | poll_fn(|cx| unsafe { | 633 | poll_fn(|cx| { |
| 646 | EP_OUT_WAKERS[0].register(cx.waker()); | 634 | EP_OUT_WAKERS[0].register(cx.waker()); |
| 647 | let regs = T::regs(); | 635 | let regs = T::regs(); |
| 648 | if regs.sie_status().read().setup_rec() { | 636 | if regs.sie_status().read().setup_rec() { |
| @@ -657,13 +645,11 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 657 | EndpointBuffer::<T>::new(0, 8).read(&mut buf); | 645 | EndpointBuffer::<T>::new(0, 8).read(&mut buf); |
| 658 | 646 | ||
| 659 | let regs = T::regs(); | 647 | let regs = T::regs(); |
| 660 | unsafe { | 648 | regs.sie_status().write(|w| w.set_setup_rec(true)); |
| 661 | regs.sie_status().write(|w| w.set_setup_rec(true)); | ||
| 662 | 649 | ||
| 663 | // set PID to 0, so (after toggling) first DATA is PID 1 | 650 | // set PID to 0, so (after toggling) first DATA is PID 1 |
| 664 | T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false)); | 651 | T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false)); |
| 665 | T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false)); | 652 | T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false)); |
| 666 | } | ||
| 667 | 653 | ||
| 668 | trace!("SETUP read ok"); | 654 | trace!("SETUP read ok"); |
| 669 | return buf; | 655 | return buf; |
| @@ -671,23 +657,21 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 671 | } | 657 | } |
| 672 | 658 | ||
| 673 | async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> { | 659 | async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> { |
| 674 | unsafe { | 660 | let bufcontrol = T::dpram().ep_out_buffer_control(0); |
| 675 | let bufcontrol = T::dpram().ep_out_buffer_control(0); | 661 | let pid = !bufcontrol.read().pid(0); |
| 676 | let pid = !bufcontrol.read().pid(0); | 662 | bufcontrol.write(|w| { |
| 677 | bufcontrol.write(|w| { | 663 | w.set_length(0, self.max_packet_size); |
| 678 | w.set_length(0, self.max_packet_size); | 664 | w.set_pid(0, pid); |
| 679 | w.set_pid(0, pid); | 665 | }); |
| 680 | }); | 666 | cortex_m::asm::delay(12); |
| 681 | cortex_m::asm::delay(12); | 667 | bufcontrol.write(|w| { |
| 682 | bufcontrol.write(|w| { | 668 | w.set_length(0, self.max_packet_size); |
| 683 | w.set_length(0, self.max_packet_size); | 669 | w.set_pid(0, pid); |
| 684 | w.set_pid(0, pid); | 670 | w.set_available(0, true); |
| 685 | w.set_available(0, true); | 671 | }); |
| 686 | }); | ||
| 687 | } | ||
| 688 | 672 | ||
| 689 | trace!("control: data_out len={} first={} last={}", buf.len(), first, last); | 673 | trace!("control: data_out len={} first={} last={}", buf.len(), first, last); |
| 690 | let val = poll_fn(|cx| unsafe { | 674 | let val = poll_fn(|cx| { |
| 691 | EP_OUT_WAKERS[0].register(cx.waker()); | 675 | EP_OUT_WAKERS[0].register(cx.waker()); |
| 692 | let val = T::dpram().ep_out_buffer_control(0).read(); | 676 | let val = T::dpram().ep_out_buffer_control(0).read(); |
| 693 | if val.available(0) { | 677 | if val.available(0) { |
| @@ -717,24 +701,22 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 717 | } | 701 | } |
| 718 | EndpointBuffer::<T>::new(0x100, 64).write(data); | 702 | EndpointBuffer::<T>::new(0x100, 64).write(data); |
| 719 | 703 | ||
| 720 | unsafe { | 704 | let bufcontrol = T::dpram().ep_in_buffer_control(0); |
| 721 | let bufcontrol = T::dpram().ep_in_buffer_control(0); | 705 | let pid = !bufcontrol.read().pid(0); |
| 722 | let pid = !bufcontrol.read().pid(0); | 706 | bufcontrol.write(|w| { |
| 723 | bufcontrol.write(|w| { | 707 | w.set_length(0, data.len() as _); |
| 724 | w.set_length(0, data.len() as _); | 708 | w.set_pid(0, pid); |
| 725 | w.set_pid(0, pid); | 709 | w.set_full(0, true); |
| 726 | w.set_full(0, true); | 710 | }); |
| 727 | }); | 711 | cortex_m::asm::delay(12); |
| 728 | cortex_m::asm::delay(12); | 712 | bufcontrol.write(|w| { |
| 729 | bufcontrol.write(|w| { | 713 | w.set_length(0, data.len() as _); |
| 730 | w.set_length(0, data.len() as _); | 714 | w.set_pid(0, pid); |
| 731 | w.set_pid(0, pid); | 715 | w.set_full(0, true); |
| 732 | w.set_full(0, true); | 716 | w.set_available(0, true); |
| 733 | w.set_available(0, true); | 717 | }); |
| 734 | }); | ||
| 735 | } | ||
| 736 | 718 | ||
| 737 | poll_fn(|cx| unsafe { | 719 | poll_fn(|cx| { |
| 738 | EP_IN_WAKERS[0].register(cx.waker()); | 720 | EP_IN_WAKERS[0].register(cx.waker()); |
| 739 | let bufcontrol = T::dpram().ep_in_buffer_control(0); | 721 | let bufcontrol = T::dpram().ep_in_buffer_control(0); |
| 740 | if bufcontrol.read().available(0) { | 722 | if bufcontrol.read().available(0) { |
| @@ -748,48 +730,44 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 748 | 730 | ||
| 749 | if last { | 731 | if last { |
| 750 | // prepare status phase right away. | 732 | // prepare status phase right away. |
| 751 | unsafe { | 733 | let bufcontrol = T::dpram().ep_out_buffer_control(0); |
| 752 | let bufcontrol = T::dpram().ep_out_buffer_control(0); | ||
| 753 | bufcontrol.write(|w| { | ||
| 754 | w.set_length(0, 0); | ||
| 755 | w.set_pid(0, true); | ||
| 756 | }); | ||
| 757 | cortex_m::asm::delay(12); | ||
| 758 | bufcontrol.write(|w| { | ||
| 759 | w.set_length(0, 0); | ||
| 760 | w.set_pid(0, true); | ||
| 761 | w.set_available(0, true); | ||
| 762 | }); | ||
| 763 | } | ||
| 764 | } | ||
| 765 | |||
| 766 | Ok(()) | ||
| 767 | } | ||
| 768 | |||
| 769 | async fn accept(&mut self) { | ||
| 770 | trace!("control: accept"); | ||
| 771 | |||
| 772 | let bufcontrol = T::dpram().ep_in_buffer_control(0); | ||
| 773 | unsafe { | ||
| 774 | bufcontrol.write(|w| { | 734 | bufcontrol.write(|w| { |
| 775 | w.set_length(0, 0); | 735 | w.set_length(0, 0); |
| 776 | w.set_pid(0, true); | 736 | w.set_pid(0, true); |
| 777 | w.set_full(0, true); | ||
| 778 | }); | 737 | }); |
| 779 | cortex_m::asm::delay(12); | 738 | cortex_m::asm::delay(12); |
| 780 | bufcontrol.write(|w| { | 739 | bufcontrol.write(|w| { |
| 781 | w.set_length(0, 0); | 740 | w.set_length(0, 0); |
| 782 | w.set_pid(0, true); | 741 | w.set_pid(0, true); |
| 783 | w.set_full(0, true); | ||
| 784 | w.set_available(0, true); | 742 | w.set_available(0, true); |
| 785 | }); | 743 | }); |
| 786 | } | 744 | } |
| 787 | 745 | ||
| 746 | Ok(()) | ||
| 747 | } | ||
| 748 | |||
| 749 | async fn accept(&mut self) { | ||
| 750 | trace!("control: accept"); | ||
| 751 | |||
| 752 | let bufcontrol = T::dpram().ep_in_buffer_control(0); | ||
| 753 | bufcontrol.write(|w| { | ||
| 754 | w.set_length(0, 0); | ||
| 755 | w.set_pid(0, true); | ||
| 756 | w.set_full(0, true); | ||
| 757 | }); | ||
| 758 | cortex_m::asm::delay(12); | ||
| 759 | bufcontrol.write(|w| { | ||
| 760 | w.set_length(0, 0); | ||
| 761 | w.set_pid(0, true); | ||
| 762 | w.set_full(0, true); | ||
| 763 | w.set_available(0, true); | ||
| 764 | }); | ||
| 765 | |||
| 788 | // wait for completion before returning, needed so | 766 | // wait for completion before returning, needed so |
| 789 | // set_address() doesn't happen early. | 767 | // set_address() doesn't happen early. |
| 790 | poll_fn(|cx| { | 768 | poll_fn(|cx| { |
| 791 | EP_IN_WAKERS[0].register(cx.waker()); | 769 | EP_IN_WAKERS[0].register(cx.waker()); |
| 792 | if unsafe { bufcontrol.read().available(0) } { | 770 | if bufcontrol.read().available(0) { |
| 793 | Poll::Pending | 771 | Poll::Pending |
| 794 | } else { | 772 | } else { |
| 795 | Poll::Ready(()) | 773 | Poll::Ready(()) |
| @@ -802,14 +780,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 802 | trace!("control: reject"); | 780 | trace!("control: reject"); |
| 803 | 781 | ||
| 804 | let regs = T::regs(); | 782 | let regs = T::regs(); |
| 805 | unsafe { | 783 | regs.ep_stall_arm().write_set(|w| { |
| 806 | regs.ep_stall_arm().write_set(|w| { | 784 | w.set_ep0_in(true); |
| 807 | w.set_ep0_in(true); | 785 | w.set_ep0_out(true); |
| 808 | w.set_ep0_out(true); | 786 | }); |
| 809 | }); | 787 | T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true)); |
| 810 | T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true)); | 788 | T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true)); |
| 811 | T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true)); | ||
| 812 | } | ||
| 813 | } | 789 | } |
| 814 | 790 | ||
| 815 | async fn accept_set_address(&mut self, addr: u8) { | 791 | async fn accept_set_address(&mut self, addr: u8) { |
| @@ -817,6 +793,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 817 | 793 | ||
| 818 | let regs = T::regs(); | 794 | let regs = T::regs(); |
| 819 | trace!("setting addr: {}", addr); | 795 | trace!("setting addr: {}", addr); |
| 820 | unsafe { regs.addr_endp().write(|w| w.set_address(addr)) } | 796 | regs.addr_endp().write(|w| w.set_address(addr)) |
| 821 | } | 797 | } |
| 822 | } | 798 | } |
diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs index 78a295ae7..d37795cc9 100644 --- a/embassy-rp/src/watchdog.rs +++ b/embassy-rp/src/watchdog.rs | |||
| @@ -35,45 +35,37 @@ impl Watchdog { | |||
| 35 | /// * `cycles` - Total number of tick cycles before the next tick is generated. | 35 | /// * `cycles` - Total number of tick cycles before the next tick is generated. |
| 36 | /// It is expected to be the frequency in MHz of clk_ref. | 36 | /// It is expected to be the frequency in MHz of clk_ref. |
| 37 | pub fn enable_tick_generation(&mut self, cycles: u8) { | 37 | pub fn enable_tick_generation(&mut self, cycles: u8) { |
| 38 | unsafe { | 38 | let watchdog = pac::WATCHDOG; |
| 39 | let watchdog = pac::WATCHDOG; | 39 | watchdog.tick().write(|w| { |
| 40 | watchdog.tick().write(|w| { | 40 | w.set_enable(true); |
| 41 | w.set_enable(true); | 41 | w.set_cycles(cycles.into()) |
| 42 | w.set_cycles(cycles.into()) | 42 | }); |
| 43 | }); | ||
| 44 | } | ||
| 45 | } | 43 | } |
| 46 | 44 | ||
| 47 | /// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode | 45 | /// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode |
| 48 | /// or when JTAG is accessing bus fabric | 46 | /// or when JTAG is accessing bus fabric |
| 49 | pub fn pause_on_debug(&mut self, pause: bool) { | 47 | pub fn pause_on_debug(&mut self, pause: bool) { |
| 50 | unsafe { | 48 | let watchdog = pac::WATCHDOG; |
| 51 | let watchdog = pac::WATCHDOG; | 49 | watchdog.ctrl().write(|w| { |
| 52 | watchdog.ctrl().write(|w| { | 50 | w.set_pause_dbg0(pause); |
| 53 | w.set_pause_dbg0(pause); | 51 | w.set_pause_dbg1(pause); |
| 54 | w.set_pause_dbg1(pause); | 52 | w.set_pause_jtag(pause); |
| 55 | w.set_pause_jtag(pause); | 53 | }) |
| 56 | }) | ||
| 57 | } | ||
| 58 | } | 54 | } |
| 59 | 55 | ||
| 60 | fn load_counter(&self, counter: u32) { | 56 | fn load_counter(&self, counter: u32) { |
| 61 | unsafe { | 57 | let watchdog = pac::WATCHDOG; |
| 62 | let watchdog = pac::WATCHDOG; | 58 | watchdog.load().write_value(pac::watchdog::regs::Load(counter)); |
| 63 | watchdog.load().write_value(pac::watchdog::regs::Load(counter)); | ||
| 64 | } | ||
| 65 | } | 59 | } |
| 66 | 60 | ||
| 67 | fn enable(&self, bit: bool) { | 61 | fn enable(&self, bit: bool) { |
| 68 | unsafe { | 62 | let watchdog = pac::WATCHDOG; |
| 69 | let watchdog = pac::WATCHDOG; | 63 | watchdog.ctrl().write(|w| w.set_enable(bit)) |
| 70 | watchdog.ctrl().write(|w| w.set_enable(bit)) | ||
| 71 | } | ||
| 72 | } | 64 | } |
| 73 | 65 | ||
| 74 | // Configure which hardware will be reset by the watchdog | 66 | // Configure which hardware will be reset by the watchdog |
| 75 | // (everything except ROSC, XOSC) | 67 | // (everything except ROSC, XOSC) |
| 76 | unsafe fn configure_wdog_reset_triggers(&self) { | 68 | fn configure_wdog_reset_triggers(&self) { |
| 77 | let psm = pac::PSM; | 69 | let psm = pac::PSM; |
| 78 | psm.wdsel().write_value(pac::psm::regs::Wdsel( | 70 | psm.wdsel().write_value(pac::psm::regs::Wdsel( |
| 79 | 0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize), | 71 | 0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize), |
| @@ -100,23 +92,19 @@ impl Watchdog { | |||
| 100 | self.load_value = delay_us * 2; | 92 | self.load_value = delay_us * 2; |
| 101 | 93 | ||
| 102 | self.enable(false); | 94 | self.enable(false); |
| 103 | unsafe { | 95 | self.configure_wdog_reset_triggers(); |
| 104 | self.configure_wdog_reset_triggers(); | ||
| 105 | } | ||
| 106 | self.load_counter(self.load_value); | 96 | self.load_counter(self.load_value); |
| 107 | self.enable(true); | 97 | self.enable(true); |
| 108 | } | 98 | } |
| 109 | 99 | ||
| 110 | /// Trigger a system reset | 100 | /// Trigger a system reset |
| 111 | pub fn trigger_reset(&mut self) { | 101 | pub fn trigger_reset(&mut self) { |
| 112 | unsafe { | 102 | self.configure_wdog_reset_triggers(); |
| 113 | self.configure_wdog_reset_triggers(); | 103 | self.pause_on_debug(false); |
| 114 | self.pause_on_debug(false); | 104 | self.enable(true); |
| 115 | self.enable(true); | 105 | let watchdog = pac::WATCHDOG; |
| 116 | let watchdog = pac::WATCHDOG; | 106 | watchdog.ctrl().write(|w| { |
| 117 | watchdog.ctrl().write(|w| { | 107 | w.set_trigger(true); |
| 118 | w.set_trigger(true); | 108 | }) |
| 119 | }) | ||
| 120 | } | ||
| 121 | } | 109 | } |
| 122 | } | 110 | } |
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml new file mode 100644 index 000000000..1c1b57b36 --- /dev/null +++ b/embassy-stm32-wpan/Cargo.toml | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-stm32-wpan" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [package.metadata.embassy_docs] | ||
| 8 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src" | ||
| 9 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32-wpan/src" | ||
| 10 | target = "thumbv7em-none-eabihf" | ||
| 11 | features = ["stm32wb55rg"] | ||
| 12 | |||
| 13 | [dependencies] | ||
| 14 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } | ||
| 15 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } | ||
| 16 | embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } | ||
| 17 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | ||
| 18 | embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" } | ||
| 19 | embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } | ||
| 20 | |||
| 21 | defmt = { version = "0.3", optional = true } | ||
| 22 | cortex-m = "0.7.6" | ||
| 23 | heapless = "0.7.16" | ||
| 24 | |||
| 25 | bit_field = "0.10.2" | ||
| 26 | |||
| 27 | [features] | ||
| 28 | defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"] | ||
| 29 | |||
| 30 | stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] | ||
| 31 | stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ] | ||
| 32 | stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ] | ||
| 33 | stm32wb35cc = [ "embassy-stm32/stm32wb35cc" ] | ||
| 34 | stm32wb35ce = [ "embassy-stm32/stm32wb35ce" ] | ||
| 35 | stm32wb50cg = [ "embassy-stm32/stm32wb50cg" ] | ||
| 36 | stm32wb55cc = [ "embassy-stm32/stm32wb55cc" ] | ||
| 37 | stm32wb55ce = [ "embassy-stm32/stm32wb55ce" ] | ||
| 38 | stm32wb55cg = [ "embassy-stm32/stm32wb55cg" ] | ||
| 39 | stm32wb55rc = [ "embassy-stm32/stm32wb55rc" ] | ||
| 40 | stm32wb55re = [ "embassy-stm32/stm32wb55re" ] | ||
| 41 | stm32wb55rg = [ "embassy-stm32/stm32wb55rg" ] | ||
| 42 | stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ] | ||
| 43 | stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ] | ||
| 44 | stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ] | ||
| 45 | stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ] \ No newline at end of file | ||
diff --git a/embassy-stm32-wpan/build.rs b/embassy-stm32-wpan/build.rs new file mode 100644 index 000000000..4edf73d59 --- /dev/null +++ b/embassy-stm32-wpan/build.rs | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | use std::env; | ||
| 2 | |||
| 3 | fn main() { | ||
| 4 | match env::vars() | ||
| 5 | .map(|(a, _)| a) | ||
| 6 | .filter(|x| x.starts_with("CARGO_FEATURE_STM32")) | ||
| 7 | .get_one() | ||
| 8 | { | ||
| 9 | Ok(_) => {} | ||
| 10 | Err(GetOneError::None) => panic!("No stm32xx Cargo feature enabled"), | ||
| 11 | Err(GetOneError::Multiple) => panic!("Multiple stm32xx Cargo features enabled"), | ||
| 12 | } | ||
| 13 | } | ||
| 14 | |||
| 15 | enum GetOneError { | ||
| 16 | None, | ||
| 17 | Multiple, | ||
| 18 | } | ||
| 19 | |||
| 20 | trait IteratorExt: Iterator { | ||
| 21 | fn get_one(self) -> Result<Self::Item, GetOneError>; | ||
| 22 | } | ||
| 23 | |||
| 24 | impl<T: Iterator> IteratorExt for T { | ||
| 25 | fn get_one(mut self) -> Result<Self::Item, GetOneError> { | ||
| 26 | match self.next() { | ||
| 27 | None => Err(GetOneError::None), | ||
| 28 | Some(res) => match self.next() { | ||
| 29 | Some(_) => Err(GetOneError::Multiple), | ||
| 30 | None => Ok(res), | ||
| 31 | }, | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | ||
diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs new file mode 100644 index 000000000..f0bd6f48c --- /dev/null +++ b/embassy-stm32-wpan/src/ble.rs | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_stm32::ipcc::Ipcc; | ||
| 4 | |||
| 5 | use crate::cmd::CmdPacket; | ||
| 6 | use crate::consts::TlPacketType; | ||
| 7 | use crate::evt::EvtBox; | ||
| 8 | use crate::tables::BleTable; | ||
| 9 | use crate::unsafe_linked_list::LinkedListNode; | ||
| 10 | use crate::{channels, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; | ||
| 11 | |||
| 12 | pub struct Ble { | ||
| 13 | phantom: PhantomData<Ble>, | ||
| 14 | } | ||
| 15 | |||
| 16 | impl Ble { | ||
| 17 | pub(crate) fn new() -> Self { | ||
| 18 | unsafe { | ||
| 19 | LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); | ||
| 20 | |||
| 21 | TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable { | ||
| 22 | pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(), | ||
| 23 | pcs_buffer: CS_BUFFER.as_ptr().cast(), | ||
| 24 | pevt_queue: EVT_QUEUE.as_ptr().cast(), | ||
| 25 | phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(), | ||
| 26 | }); | ||
| 27 | } | ||
| 28 | |||
| 29 | Self { phantom: PhantomData } | ||
| 30 | } | ||
| 31 | /// `HW_IPCC_BLE_EvtNot` | ||
| 32 | pub async fn read(&self) -> EvtBox { | ||
| 33 | Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe { | ||
| 34 | if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) { | ||
| 35 | Some(EvtBox::new(node_ptr.cast())) | ||
| 36 | } else { | ||
| 37 | None | ||
| 38 | } | ||
| 39 | }) | ||
| 40 | .await | ||
| 41 | } | ||
| 42 | |||
| 43 | /// `TL_BLE_SendCmd` | ||
| 44 | pub async fn write(&self, opcode: u16, payload: &[u8]) { | ||
| 45 | Ipcc::send(channels::cpu1::IPCC_BLE_CMD_CHANNEL, || unsafe { | ||
| 46 | CmdPacket::write_into(BLE_CMD_BUFFER.as_mut_ptr(), TlPacketType::BleCmd, opcode, payload); | ||
| 47 | }) | ||
| 48 | .await; | ||
| 49 | } | ||
| 50 | |||
| 51 | /// `TL_BLE_SendAclData` | ||
| 52 | pub async fn acl_write(&self, handle: u16, payload: &[u8]) { | ||
| 53 | Ipcc::send(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, || unsafe { | ||
| 54 | CmdPacket::write_into( | ||
| 55 | HCI_ACL_DATA_BUFFER.as_mut_ptr() as *mut _, | ||
| 56 | TlPacketType::AclData, | ||
| 57 | handle, | ||
| 58 | payload, | ||
| 59 | ); | ||
| 60 | }) | ||
| 61 | .await; | ||
| 62 | } | ||
| 63 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/channels.rs b/embassy-stm32-wpan/src/channels.rs index 25a065ba4..9a2be1cfa 100644 --- a/embassy-stm32/src/tl_mbox/channels.rs +++ b/embassy-stm32-wpan/src/channels.rs | |||
| @@ -50,36 +50,30 @@ | |||
| 50 | //! | 50 | //! |
| 51 | 51 | ||
| 52 | pub mod cpu1 { | 52 | pub mod cpu1 { |
| 53 | use crate::tl_mbox::ipcc::IpccChannel; | 53 | use embassy_stm32::ipcc::IpccChannel; |
| 54 | 54 | ||
| 55 | // Not used currently but reserved | ||
| 56 | pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; | 55 | pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1; |
| 57 | // Not used currently but reserved | ||
| 58 | pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; | 56 | pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2; |
| 59 | #[allow(dead_code)] // Not used currently but reserved | ||
| 60 | pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; | 57 | pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| 61 | #[allow(dead_code)] // Not used currently but reserved | 58 | #[allow(dead_code)] // Not used currently but reserved |
| 62 | pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3; | 59 | pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| 63 | #[allow(dead_code)] // Not used currently but reserved | 60 | #[allow(dead_code)] // Not used currently but reserved |
| 64 | pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; | 61 | pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| 65 | // Not used currently but reserved | ||
| 66 | pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4; | ||
| 67 | #[allow(dead_code)] // Not used currently but reserved | 62 | #[allow(dead_code)] // Not used currently but reserved |
| 63 | pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4; | ||
| 68 | pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; | 64 | pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; |
| 69 | #[allow(dead_code)] // Not used currently but reserved | 65 | #[allow(dead_code)] // Not used currently but reserved |
| 70 | pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; | 66 | pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; |
| 71 | #[allow(dead_code)] // Not used currently but reserved | 67 | #[allow(dead_code)] // Not used currently but reserved |
| 72 | pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; | 68 | pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5; |
| 73 | #[allow(dead_code)] // Not used currently but reserved | ||
| 74 | pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6; | 69 | pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6; |
| 75 | } | 70 | } |
| 76 | 71 | ||
| 77 | pub mod cpu2 { | 72 | pub mod cpu2 { |
| 78 | use crate::tl_mbox::ipcc::IpccChannel; | 73 | use embassy_stm32::ipcc::IpccChannel; |
| 79 | 74 | ||
| 80 | pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1; | 75 | pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1; |
| 81 | pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2; | 76 | pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2; |
| 82 | #[allow(dead_code)] // Not used currently but reserved | ||
| 83 | pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; | 77 | pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| 84 | #[allow(dead_code)] // Not used currently but reserved | 78 | #[allow(dead_code)] // Not used currently but reserved |
| 85 | pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; | 79 | pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| @@ -88,10 +82,8 @@ pub mod cpu2 { | |||
| 88 | #[allow(dead_code)] // Not used currently but reserved | 82 | #[allow(dead_code)] // Not used currently but reserved |
| 89 | pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; | 83 | pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| 90 | #[allow(dead_code)] // Not used currently but reserved | 84 | #[allow(dead_code)] // Not used currently but reserved |
| 91 | pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; | 85 | pub const IPCC_BLE_LLDÇM0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3; |
| 92 | #[allow(dead_code)] // Not used currently but reserved | ||
| 93 | pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4; | 86 | pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4; |
| 94 | #[allow(dead_code)] // Not used currently but reserved | ||
| 95 | pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5; | 87 | pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5; |
| 96 | #[allow(dead_code)] // Not used currently but reserved | 88 | #[allow(dead_code)] // Not used currently but reserved |
| 97 | pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; | 89 | pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5; |
diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/cmd.rs new file mode 100644 index 000000000..edca82390 --- /dev/null +++ b/embassy-stm32-wpan/src/cmd.rs | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | use core::ptr; | ||
| 2 | |||
| 3 | use crate::consts::TlPacketType; | ||
| 4 | use crate::PacketHeader; | ||
| 5 | |||
| 6 | #[derive(Copy, Clone)] | ||
| 7 | #[repr(C, packed)] | ||
| 8 | pub struct Cmd { | ||
| 9 | pub cmd_code: u16, | ||
| 10 | pub payload_len: u8, | ||
| 11 | pub payload: [u8; 255], | ||
| 12 | } | ||
| 13 | |||
| 14 | impl Default for Cmd { | ||
| 15 | fn default() -> Self { | ||
| 16 | Self { | ||
| 17 | cmd_code: 0, | ||
| 18 | payload_len: 0, | ||
| 19 | payload: [0u8; 255], | ||
| 20 | } | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | #[derive(Copy, Clone, Default)] | ||
| 25 | #[repr(C, packed)] | ||
| 26 | pub struct CmdSerial { | ||
| 27 | pub ty: u8, | ||
| 28 | pub cmd: Cmd, | ||
| 29 | } | ||
| 30 | |||
| 31 | #[derive(Copy, Clone, Default)] | ||
| 32 | #[repr(C, packed)] | ||
| 33 | pub struct CmdSerialStub { | ||
| 34 | pub ty: u8, | ||
| 35 | pub cmd_code: u16, | ||
| 36 | pub payload_len: u8, | ||
| 37 | } | ||
| 38 | |||
| 39 | #[derive(Copy, Clone, Default)] | ||
| 40 | #[repr(C, packed)] | ||
| 41 | pub struct CmdPacket { | ||
| 42 | pub header: PacketHeader, | ||
| 43 | pub cmdserial: CmdSerial, | ||
| 44 | } | ||
| 45 | |||
| 46 | impl CmdPacket { | ||
| 47 | pub unsafe fn write_into(cmd_buf: *mut CmdPacket, packet_type: TlPacketType, cmd_code: u16, payload: &[u8]) { | ||
| 48 | let p_cmd_serial = &mut (*cmd_buf).cmdserial as *mut _ as *mut CmdSerialStub; | ||
| 49 | let p_payload = &mut (*cmd_buf).cmdserial.cmd.payload as *mut _; | ||
| 50 | |||
| 51 | ptr::write_volatile( | ||
| 52 | p_cmd_serial, | ||
| 53 | CmdSerialStub { | ||
| 54 | ty: packet_type as u8, | ||
| 55 | cmd_code: cmd_code, | ||
| 56 | payload_len: payload.len() as u8, | ||
| 57 | }, | ||
| 58 | ); | ||
| 59 | |||
| 60 | ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len()); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | #[derive(Copy, Clone)] | ||
| 65 | #[repr(C, packed)] | ||
| 66 | pub struct AclDataSerial { | ||
| 67 | pub ty: u8, | ||
| 68 | pub handle: u16, | ||
| 69 | pub length: u16, | ||
| 70 | pub acl_data: [u8; 1], | ||
| 71 | } | ||
| 72 | |||
| 73 | #[derive(Copy, Clone)] | ||
| 74 | #[repr(C, packed)] | ||
| 75 | pub struct AclDataSerialStub { | ||
| 76 | pub ty: u8, | ||
| 77 | pub handle: u16, | ||
| 78 | pub length: u16, | ||
| 79 | } | ||
| 80 | |||
| 81 | #[derive(Copy, Clone)] | ||
| 82 | #[repr(C, packed)] | ||
| 83 | pub struct AclDataPacket { | ||
| 84 | pub header: PacketHeader, | ||
| 85 | pub acl_data_serial: AclDataSerial, | ||
| 86 | } | ||
| 87 | |||
| 88 | impl AclDataPacket { | ||
| 89 | pub unsafe fn write_into(cmd_buf: *mut AclDataPacket, packet_type: TlPacketType, handle: u16, payload: &[u8]) { | ||
| 90 | let p_cmd_serial = &mut (*cmd_buf).acl_data_serial as *mut _ as *mut AclDataSerialStub; | ||
| 91 | let p_payload = &mut (*cmd_buf).acl_data_serial.acl_data as *mut _; | ||
| 92 | |||
| 93 | ptr::write_volatile( | ||
| 94 | p_cmd_serial, | ||
| 95 | AclDataSerialStub { | ||
| 96 | ty: packet_type as u8, | ||
| 97 | handle: handle, | ||
| 98 | length: payload.len() as u16, | ||
| 99 | }, | ||
| 100 | ); | ||
| 101 | |||
| 102 | ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len()); | ||
| 103 | } | ||
| 104 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/consts.rs b/embassy-stm32-wpan/src/consts.rs index e16a26cd0..caf26c06b 100644 --- a/embassy-stm32/src/tl_mbox/consts.rs +++ b/embassy-stm32-wpan/src/consts.rs | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | #[derive(PartialEq)] | 1 | use core::convert::TryFrom; |
| 2 | |||
| 3 | #[derive(Debug)] | ||
| 2 | #[repr(C)] | 4 | #[repr(C)] |
| 3 | pub enum TlPacketType { | 5 | pub enum TlPacketType { |
| 4 | BleCmd = 0x01, | 6 | BleCmd = 0x01, |
diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs new file mode 100644 index 000000000..3a9d03576 --- /dev/null +++ b/embassy-stm32-wpan/src/evt.rs | |||
| @@ -0,0 +1,195 @@ | |||
| 1 | use core::{ptr, slice}; | ||
| 2 | |||
| 3 | use super::PacketHeader; | ||
| 4 | use crate::mm; | ||
| 5 | |||
| 6 | /** | ||
| 7 | * The payload of `Evt` for a command status event | ||
| 8 | */ | ||
| 9 | #[derive(Copy, Clone)] | ||
| 10 | #[repr(C, packed)] | ||
| 11 | pub struct CsEvt { | ||
| 12 | pub status: u8, | ||
| 13 | pub num_cmd: u8, | ||
| 14 | pub cmd_code: u16, | ||
| 15 | } | ||
| 16 | |||
| 17 | /** | ||
| 18 | * The payload of `Evt` for a command complete event | ||
| 19 | */ | ||
| 20 | #[derive(Copy, Clone, Default)] | ||
| 21 | #[repr(C, packed)] | ||
| 22 | pub struct CcEvt { | ||
| 23 | pub num_cmd: u8, | ||
| 24 | pub cmd_code: u16, | ||
| 25 | pub payload: [u8; 1], | ||
| 26 | } | ||
| 27 | |||
| 28 | impl CcEvt { | ||
| 29 | pub fn write(&self, buf: &mut [u8]) { | ||
| 30 | unsafe { | ||
| 31 | let len = core::mem::size_of::<CcEvt>(); | ||
| 32 | assert!(buf.len() >= len); | ||
| 33 | |||
| 34 | let self_ptr: *const CcEvt = self; | ||
| 35 | let self_buf_ptr: *const u8 = self_ptr.cast(); | ||
| 36 | |||
| 37 | core::ptr::copy(self_buf_ptr, buf.as_mut_ptr(), len); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | #[derive(Copy, Clone, Default)] | ||
| 43 | #[repr(C, packed)] | ||
| 44 | pub struct AsynchEvt { | ||
| 45 | sub_evt_code: u16, | ||
| 46 | payload: [u8; 1], | ||
| 47 | } | ||
| 48 | |||
| 49 | #[derive(Copy, Clone, Default)] | ||
| 50 | #[repr(C, packed)] | ||
| 51 | pub struct Evt { | ||
| 52 | pub evt_code: u8, | ||
| 53 | pub payload_len: u8, | ||
| 54 | pub payload: [u8; 1], | ||
| 55 | } | ||
| 56 | |||
| 57 | #[derive(Copy, Clone, Default)] | ||
| 58 | #[repr(C, packed)] | ||
| 59 | pub struct EvtSerial { | ||
| 60 | pub kind: u8, | ||
| 61 | pub evt: Evt, | ||
| 62 | } | ||
| 63 | |||
| 64 | #[derive(Copy, Clone, Default)] | ||
| 65 | pub struct EvtStub { | ||
| 66 | pub kind: u8, | ||
| 67 | pub evt_code: u8, | ||
| 68 | } | ||
| 69 | |||
| 70 | /// This format shall be used for all events (asynchronous and command response) reported | ||
| 71 | /// by the CPU2 except for the command response of a system command where the header is not there | ||
| 72 | /// and the format to be used shall be `EvtSerial`. | ||
| 73 | /// | ||
| 74 | /// ### Note: | ||
| 75 | /// Be careful that the asynchronous events reported by the CPU2 on the system channel do | ||
| 76 | /// include the header and shall use `EvtPacket` format. Only the command response format on the | ||
| 77 | /// system channel is different. | ||
| 78 | #[derive(Copy, Clone, Default)] | ||
| 79 | #[repr(C, packed)] | ||
| 80 | pub struct EvtPacket { | ||
| 81 | pub header: PacketHeader, | ||
| 82 | pub evt_serial: EvtSerial, | ||
| 83 | } | ||
| 84 | |||
| 85 | impl EvtPacket { | ||
| 86 | pub fn kind(&self) -> u8 { | ||
| 87 | self.evt_serial.kind | ||
| 88 | } | ||
| 89 | |||
| 90 | pub fn evt(&self) -> &Evt { | ||
| 91 | &self.evt_serial.evt | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | /// smart pointer to the [`EvtPacket`] that will dispose of [`EvtPacket`] buffer automatically | ||
| 96 | /// on [`Drop`] | ||
| 97 | #[derive(Debug)] | ||
| 98 | pub struct EvtBox { | ||
| 99 | ptr: *mut EvtPacket, | ||
| 100 | } | ||
| 101 | |||
| 102 | unsafe impl Send for EvtBox {} | ||
| 103 | impl EvtBox { | ||
| 104 | pub(super) fn new(ptr: *mut EvtPacket) -> Self { | ||
| 105 | Self { ptr } | ||
| 106 | } | ||
| 107 | |||
| 108 | /// Returns information about the event | ||
| 109 | pub fn stub(&self) -> EvtStub { | ||
| 110 | unsafe { | ||
| 111 | let p_evt_stub = &(*self.ptr).evt_serial as *const _ as *const EvtStub; | ||
| 112 | |||
| 113 | ptr::read_volatile(p_evt_stub) | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | pub fn payload<'a>(&self) -> &'a [u8] { | ||
| 118 | unsafe { | ||
| 119 | let p_payload_len = &(*self.ptr).evt_serial.evt.payload_len as *const u8; | ||
| 120 | let p_payload = &(*self.ptr).evt_serial.evt.payload as *const u8; | ||
| 121 | |||
| 122 | let payload_len = ptr::read_volatile(p_payload_len); | ||
| 123 | |||
| 124 | slice::from_raw_parts(p_payload, payload_len as usize) | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | // TODO: bring back acl | ||
| 129 | |||
| 130 | // /// writes an underlying [`EvtPacket`] into the provided buffer. | ||
| 131 | // /// Returns the number of bytes that were written. | ||
| 132 | // /// Returns an error if event kind is unknown or if provided buffer size is not enough. | ||
| 133 | // #[allow(clippy::result_unit_err)] | ||
| 134 | // pub fn write(&self, buf: &mut [u8]) -> Result<usize, ()> { | ||
| 135 | // unsafe { | ||
| 136 | // let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?; | ||
| 137 | // | ||
| 138 | // let evt_data: *const EvtPacket = self.ptr.cast(); | ||
| 139 | // let evt_serial: *const EvtSerial = &(*evt_data).evt_serial; | ||
| 140 | // let evt_serial_buf: *const u8 = evt_serial.cast(); | ||
| 141 | // | ||
| 142 | // let acl_data: *const AclDataPacket = self.ptr.cast(); | ||
| 143 | // let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial; | ||
| 144 | // let acl_serial_buf: *const u8 = acl_serial.cast(); | ||
| 145 | // | ||
| 146 | // if let TlPacketType::AclData = evt_kind { | ||
| 147 | // let len = (*acl_serial).length as usize + 5; | ||
| 148 | // if len > buf.len() { | ||
| 149 | // return Err(()); | ||
| 150 | // } | ||
| 151 | // | ||
| 152 | // core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len); | ||
| 153 | // | ||
| 154 | // Ok(len) | ||
| 155 | // } else { | ||
| 156 | // let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE; | ||
| 157 | // if len > buf.len() { | ||
| 158 | // return Err(()); | ||
| 159 | // } | ||
| 160 | // | ||
| 161 | // core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len); | ||
| 162 | // | ||
| 163 | // Ok(len) | ||
| 164 | // } | ||
| 165 | // } | ||
| 166 | // } | ||
| 167 | // | ||
| 168 | // /// returns the size of a buffer required to hold this event | ||
| 169 | // #[allow(clippy::result_unit_err)] | ||
| 170 | // pub fn size(&self) -> Result<usize, ()> { | ||
| 171 | // unsafe { | ||
| 172 | // let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?; | ||
| 173 | // | ||
| 174 | // let evt_data: *const EvtPacket = self.ptr.cast(); | ||
| 175 | // let evt_serial: *const EvtSerial = &(*evt_data).evt_serial; | ||
| 176 | // | ||
| 177 | // let acl_data: *const AclDataPacket = self.ptr.cast(); | ||
| 178 | // let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial; | ||
| 179 | // | ||
| 180 | // if let TlPacketType::AclData = evt_kind { | ||
| 181 | // Ok((*acl_serial).length as usize + 5) | ||
| 182 | // } else { | ||
| 183 | // Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE) | ||
| 184 | // } | ||
| 185 | // } | ||
| 186 | // } | ||
| 187 | } | ||
| 188 | |||
| 189 | impl Drop for EvtBox { | ||
| 190 | fn drop(&mut self) { | ||
| 191 | trace!("evt box drop packet"); | ||
| 192 | |||
| 193 | unsafe { mm::MemoryManager::drop_event_packet(self.ptr) }; | ||
| 194 | } | ||
| 195 | } | ||
diff --git a/embassy-cortex-m/src/fmt.rs b/embassy-stm32-wpan/src/fmt.rs index f8bb0a035..066970813 100644 --- a/embassy-cortex-m/src/fmt.rs +++ b/embassy-stm32-wpan/src/fmt.rs | |||
| @@ -195,9 +195,6 @@ macro_rules! unwrap { | |||
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | #[cfg(feature = "defmt-timestamp-uptime")] | ||
| 199 | defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() } | ||
| 200 | |||
| 201 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 202 | pub struct NoneError; | 199 | pub struct NoneError; |
| 203 | 200 | ||
diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs new file mode 100644 index 000000000..833db0df3 --- /dev/null +++ b/embassy-stm32-wpan/src/lib.rs | |||
| @@ -0,0 +1,255 @@ | |||
| 1 | #![no_std] | ||
| 2 | |||
| 3 | // This must go FIRST so that all the other modules see its macros. | ||
| 4 | pub mod fmt; | ||
| 5 | |||
| 6 | use core::mem::MaybeUninit; | ||
| 7 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 8 | |||
| 9 | use ble::Ble; | ||
| 10 | use cmd::CmdPacket; | ||
| 11 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | ||
| 12 | use embassy_stm32::interrupt; | ||
| 13 | use embassy_stm32::interrupt::typelevel::Interrupt; | ||
| 14 | use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler}; | ||
| 15 | use embassy_stm32::peripherals::IPCC; | ||
| 16 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 17 | use embassy_sync::channel::Channel; | ||
| 18 | use embassy_sync::signal::Signal; | ||
| 19 | use evt::{CcEvt, EvtBox}; | ||
| 20 | use mm::MemoryManager; | ||
| 21 | use sys::Sys; | ||
| 22 | use tables::{ | ||
| 23 | BleTable, DeviceInfoTable, Mac802_15_4Table, MemManagerTable, RefTable, SysTable, ThreadTable, TracesTable, | ||
| 24 | }; | ||
| 25 | use unsafe_linked_list::LinkedListNode; | ||
| 26 | |||
| 27 | pub mod ble; | ||
| 28 | pub mod channels; | ||
| 29 | pub mod cmd; | ||
| 30 | pub mod consts; | ||
| 31 | pub mod evt; | ||
| 32 | pub mod mm; | ||
| 33 | pub mod shci; | ||
| 34 | pub mod sys; | ||
| 35 | pub mod tables; | ||
| 36 | pub mod unsafe_linked_list; | ||
| 37 | |||
| 38 | #[link_section = "TL_REF_TABLE"] | ||
| 39 | pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit(); | ||
| 40 | |||
| 41 | #[link_section = "MB_MEM1"] | ||
| 42 | static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit(); | ||
| 43 | |||
| 44 | #[link_section = "MB_MEM1"] | ||
| 45 | static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit(); | ||
| 46 | |||
| 47 | #[link_section = "MB_MEM1"] | ||
| 48 | static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit(); | ||
| 49 | |||
| 50 | #[link_section = "MB_MEM1"] | ||
| 51 | static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit(); | ||
| 52 | |||
| 53 | #[link_section = "MB_MEM1"] | ||
| 54 | static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit(); | ||
| 55 | |||
| 56 | #[link_section = "MB_MEM1"] | ||
| 57 | static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit(); | ||
| 58 | |||
| 59 | #[link_section = "MB_MEM1"] | ||
| 60 | static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit(); | ||
| 61 | |||
| 62 | #[link_section = "MB_MEM2"] | ||
| 63 | static mut FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 64 | |||
| 65 | // Not in shared RAM | ||
| 66 | static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 67 | |||
| 68 | #[allow(dead_code)] // Not used currently but reserved | ||
| 69 | #[link_section = "MB_MEM2"] | ||
| 70 | static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 71 | |||
| 72 | type PacketHeader = LinkedListNode; | ||
| 73 | |||
| 74 | const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>(); | ||
| 75 | const TL_EVT_HEADER_SIZE: usize = 3; | ||
| 76 | const TL_CS_EVT_SIZE: usize = core::mem::size_of::<evt::CsEvt>(); | ||
| 77 | |||
| 78 | #[link_section = "MB_MEM2"] | ||
| 79 | static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> = | ||
| 80 | MaybeUninit::uninit(); | ||
| 81 | |||
| 82 | #[link_section = "MB_MEM2"] | ||
| 83 | static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 84 | |||
| 85 | #[link_section = "MB_MEM2"] | ||
| 86 | static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 87 | |||
| 88 | #[link_section = "MB_MEM2"] | ||
| 89 | pub static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit(); | ||
| 90 | |||
| 91 | /** | ||
| 92 | * Queue length of BLE Event | ||
| 93 | * This parameter defines the number of asynchronous events that can be stored in the HCI layer before | ||
| 94 | * being reported to the application. When a command is sent to the BLE core coprocessor, the HCI layer | ||
| 95 | * is waiting for the event with the Num_HCI_Command_Packets set to 1. The receive queue shall be large | ||
| 96 | * enough to store all asynchronous events received in between. | ||
| 97 | * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events | ||
| 98 | * between the HCI command and its event. | ||
| 99 | * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small, | ||
| 100 | * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting | ||
| 101 | * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate | ||
| 102 | * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout). | ||
| 103 | */ | ||
| 104 | const CFG_TLBLE_EVT_QUEUE_LENGTH: usize = 5; | ||
| 105 | const CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255; | ||
| 106 | const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE; | ||
| 107 | |||
| 108 | const fn divc(x: usize, y: usize) -> usize { | ||
| 109 | ((x) + (y) - 1) / (y) | ||
| 110 | } | ||
| 111 | |||
| 112 | const POOL_SIZE: usize = CFG_TLBLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4); | ||
| 113 | |||
| 114 | #[link_section = "MB_MEM2"] | ||
| 115 | static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); | ||
| 116 | |||
| 117 | #[link_section = "MB_MEM2"] | ||
| 118 | static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = | ||
| 119 | MaybeUninit::uninit(); | ||
| 120 | |||
| 121 | #[link_section = "MB_MEM2"] | ||
| 122 | static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = | ||
| 123 | MaybeUninit::uninit(); | ||
| 124 | |||
| 125 | #[link_section = "MB_MEM2"] | ||
| 126 | static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit(); | ||
| 127 | |||
| 128 | #[link_section = "MB_MEM2"] | ||
| 129 | // fuck these "magic" numbers from ST ---v---v | ||
| 130 | static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit(); | ||
| 131 | |||
| 132 | // TODO: remove these items | ||
| 133 | |||
| 134 | #[allow(dead_code)] | ||
| 135 | /// current event that is produced during IPCC IRQ handler execution | ||
| 136 | /// on SYS channel | ||
| 137 | static EVT_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 32> = Channel::new(); | ||
| 138 | |||
| 139 | #[allow(dead_code)] | ||
| 140 | /// last received Command Complete event | ||
| 141 | static LAST_CC_EVT: Signal<CriticalSectionRawMutex, CcEvt> = Signal::new(); | ||
| 142 | |||
| 143 | static STATE: Signal<CriticalSectionRawMutex, ()> = Signal::new(); | ||
| 144 | |||
| 145 | pub struct TlMbox<'d> { | ||
| 146 | _ipcc: PeripheralRef<'d, IPCC>, | ||
| 147 | |||
| 148 | pub sys_subsystem: Sys, | ||
| 149 | pub mm_subsystem: MemoryManager, | ||
| 150 | pub ble_subsystem: Ble, | ||
| 151 | } | ||
| 152 | |||
| 153 | impl<'d> TlMbox<'d> { | ||
| 154 | pub fn init( | ||
| 155 | ipcc: impl Peripheral<P = IPCC> + 'd, | ||
| 156 | _irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler> | ||
| 157 | + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>, | ||
| 158 | config: Config, | ||
| 159 | ) -> Self { | ||
| 160 | into_ref!(ipcc); | ||
| 161 | |||
| 162 | unsafe { | ||
| 163 | TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable { | ||
| 164 | device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), | ||
| 165 | ble_table: TL_BLE_TABLE.as_ptr(), | ||
| 166 | thread_table: TL_THREAD_TABLE.as_ptr(), | ||
| 167 | sys_table: TL_SYS_TABLE.as_ptr(), | ||
| 168 | mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(), | ||
| 169 | traces_table: TL_TRACES_TABLE.as_ptr(), | ||
| 170 | mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(), | ||
| 171 | // zigbee_table: TL_ZIGBEE_TABLE.as_ptr(), | ||
| 172 | // lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(), | ||
| 173 | // ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(), | ||
| 174 | }); | ||
| 175 | |||
| 176 | TL_SYS_TABLE | ||
| 177 | .as_mut_ptr() | ||
| 178 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 179 | TL_DEVICE_INFO_TABLE | ||
| 180 | .as_mut_ptr() | ||
| 181 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 182 | TL_BLE_TABLE | ||
| 183 | .as_mut_ptr() | ||
| 184 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 185 | TL_THREAD_TABLE | ||
| 186 | .as_mut_ptr() | ||
| 187 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 188 | TL_MEM_MANAGER_TABLE | ||
| 189 | .as_mut_ptr() | ||
| 190 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 191 | |||
| 192 | TL_TRACES_TABLE | ||
| 193 | .as_mut_ptr() | ||
| 194 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 195 | TL_MAC_802_15_4_TABLE | ||
| 196 | .as_mut_ptr() | ||
| 197 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 198 | // TL_ZIGBEE_TABLE | ||
| 199 | // .as_mut_ptr() | ||
| 200 | // .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 201 | // TL_LLD_TESTS_TABLE | ||
| 202 | // .as_mut_ptr() | ||
| 203 | // .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 204 | // TL_BLE_LLD_TABLE | ||
| 205 | // .as_mut_ptr() | ||
| 206 | // .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 207 | |||
| 208 | EVT_POOL | ||
| 209 | .as_mut_ptr() | ||
| 210 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 211 | SYS_SPARE_EVT_BUF | ||
| 212 | .as_mut_ptr() | ||
| 213 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 214 | BLE_SPARE_EVT_BUF | ||
| 215 | .as_mut_ptr() | ||
| 216 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 217 | |||
| 218 | { | ||
| 219 | BLE_CMD_BUFFER | ||
| 220 | .as_mut_ptr() | ||
| 221 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 222 | HCI_ACL_DATA_BUFFER | ||
| 223 | .as_mut_ptr() | ||
| 224 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 225 | CS_BUFFER | ||
| 226 | .as_mut_ptr() | ||
| 227 | .write_volatile(MaybeUninit::zeroed().assume_init()); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | compiler_fence(Ordering::SeqCst); | ||
| 232 | |||
| 233 | Ipcc::enable(config); | ||
| 234 | |||
| 235 | let sys = sys::Sys::new(); | ||
| 236 | let ble = ble::Ble::new(); | ||
| 237 | let mm = mm::MemoryManager::new(); | ||
| 238 | |||
| 239 | // enable interrupts | ||
| 240 | interrupt::typelevel::IPCC_C1_RX::unpend(); | ||
| 241 | interrupt::typelevel::IPCC_C1_TX::unpend(); | ||
| 242 | |||
| 243 | unsafe { interrupt::typelevel::IPCC_C1_RX::enable() }; | ||
| 244 | unsafe { interrupt::typelevel::IPCC_C1_TX::enable() }; | ||
| 245 | |||
| 246 | STATE.reset(); | ||
| 247 | |||
| 248 | Self { | ||
| 249 | _ipcc: ipcc, | ||
| 250 | sys_subsystem: sys, | ||
| 251 | ble_subsystem: ble, | ||
| 252 | mm_subsystem: mm, | ||
| 253 | } | ||
| 254 | } | ||
| 255 | } | ||
diff --git a/embassy-stm32-wpan/src/mm.rs b/embassy-stm32-wpan/src/mm.rs new file mode 100644 index 000000000..21f42409a --- /dev/null +++ b/embassy-stm32-wpan/src/mm.rs | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | //! Memory manager routines | ||
| 2 | |||
| 3 | use core::future::poll_fn; | ||
| 4 | use core::marker::PhantomData; | ||
| 5 | use core::task::Poll; | ||
| 6 | |||
| 7 | use cortex_m::interrupt; | ||
| 8 | use embassy_stm32::ipcc::Ipcc; | ||
| 9 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 10 | |||
| 11 | use crate::evt::EvtPacket; | ||
| 12 | use crate::tables::MemManagerTable; | ||
| 13 | use crate::unsafe_linked_list::LinkedListNode; | ||
| 14 | use crate::{ | ||
| 15 | channels, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF, | ||
| 16 | TL_MEM_MANAGER_TABLE, | ||
| 17 | }; | ||
| 18 | |||
| 19 | static MM_WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 20 | |||
| 21 | pub struct MemoryManager { | ||
| 22 | phantom: PhantomData<MemoryManager>, | ||
| 23 | } | ||
| 24 | |||
| 25 | impl MemoryManager { | ||
| 26 | pub(crate) fn new() -> Self { | ||
| 27 | unsafe { | ||
| 28 | LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr()); | ||
| 29 | LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()); | ||
| 30 | |||
| 31 | TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable { | ||
| 32 | spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(), | ||
| 33 | spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(), | ||
| 34 | blepool: EVT_POOL.as_ptr().cast(), | ||
| 35 | blepoolsize: POOL_SIZE as u32, | ||
| 36 | pevt_free_buffer_queue: FREE_BUF_QUEUE.as_mut_ptr(), | ||
| 37 | traces_evt_pool: core::ptr::null(), | ||
| 38 | tracespoolsize: 0, | ||
| 39 | }); | ||
| 40 | } | ||
| 41 | |||
| 42 | Self { phantom: PhantomData } | ||
| 43 | } | ||
| 44 | |||
| 45 | /// SAFETY: passing a pointer to something other than an event packet is UB | ||
| 46 | pub(crate) unsafe fn drop_event_packet(evt: *mut EvtPacket) { | ||
| 47 | interrupt::free(|_| unsafe { | ||
| 48 | LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _); | ||
| 49 | }); | ||
| 50 | |||
| 51 | MM_WAKER.wake(); | ||
| 52 | } | ||
| 53 | |||
| 54 | pub async fn run_queue(&self) { | ||
| 55 | loop { | ||
| 56 | poll_fn(|cx| unsafe { | ||
| 57 | MM_WAKER.register(cx.waker()); | ||
| 58 | if LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { | ||
| 59 | Poll::Pending | ||
| 60 | } else { | ||
| 61 | Poll::Ready(()) | ||
| 62 | } | ||
| 63 | }) | ||
| 64 | .await; | ||
| 65 | |||
| 66 | Ipcc::send(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, || { | ||
| 67 | interrupt::free(|_| unsafe { | ||
| 68 | // CS required while moving nodes | ||
| 69 | while let Some(node_ptr) = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { | ||
| 70 | LinkedListNode::insert_head(FREE_BUF_QUEUE.as_mut_ptr(), node_ptr); | ||
| 71 | } | ||
| 72 | }) | ||
| 73 | }) | ||
| 74 | .await; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/shci.rs b/embassy-stm32-wpan/src/shci.rs index 6b5b2dd19..cdf027d5e 100644 --- a/embassy-stm32/src/tl_mbox/shci.rs +++ b/embassy-stm32-wpan/src/shci.rs | |||
| @@ -1,16 +1,10 @@ | |||
| 1 | //! HCI commands for system channel | 1 | use core::{mem, slice}; |
| 2 | 2 | ||
| 3 | use super::cmd::CmdPacket; | 3 | use super::{TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE}; |
| 4 | use super::consts::TlPacketType; | ||
| 5 | use super::{channels, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE}; | ||
| 6 | use crate::tl_mbox::ipcc::Ipcc; | ||
| 7 | 4 | ||
| 8 | const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66; | 5 | pub const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66; |
| 9 | pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE; | ||
| 10 | #[allow(dead_code)] | ||
| 11 | const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE; | ||
| 12 | 6 | ||
| 13 | #[derive(Clone, Copy)] | 7 | #[derive(Debug, Clone, Copy)] |
| 14 | #[repr(C, packed)] | 8 | #[repr(C, packed)] |
| 15 | pub struct ShciBleInitCmdParam { | 9 | pub struct ShciBleInitCmdParam { |
| 16 | /// NOT USED CURRENTLY | 10 | /// NOT USED CURRENTLY |
| @@ -38,6 +32,12 @@ pub struct ShciBleInitCmdParam { | |||
| 38 | pub hw_version: u8, | 32 | pub hw_version: u8, |
| 39 | } | 33 | } |
| 40 | 34 | ||
| 35 | impl ShciBleInitCmdParam { | ||
| 36 | pub fn payload<'a>(&self) -> &'a [u8] { | ||
| 37 | unsafe { slice::from_raw_parts(self as *const _ as *const u8, mem::size_of::<Self>()) } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | impl Default for ShciBleInitCmdParam { | 41 | impl Default for ShciBleInitCmdParam { |
| 42 | fn default() -> Self { | 42 | fn default() -> Self { |
| 43 | Self { | 43 | Self { |
| @@ -63,39 +63,19 @@ impl Default for ShciBleInitCmdParam { | |||
| 63 | } | 63 | } |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | #[derive(Clone, Copy, Default)] | 66 | #[derive(Debug, Clone, Copy, Default)] |
| 67 | #[repr(C, packed)] | 67 | #[repr(C, packed)] |
| 68 | pub struct ShciHeader { | 68 | pub struct ShciHeader { |
| 69 | metadata: [u32; 3], | 69 | metadata: [u32; 3], |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | #[derive(Clone, Copy)] | 72 | #[derive(Debug, Clone, Copy)] |
| 73 | #[repr(C, packed)] | 73 | #[repr(C, packed)] |
| 74 | pub struct ShciBleInitCmdPacket { | 74 | pub struct ShciBleInitCmdPacket { |
| 75 | header: ShciHeader, | 75 | pub header: ShciHeader, |
| 76 | param: ShciBleInitCmdParam, | 76 | pub param: ShciBleInitCmdParam, |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | pub fn shci_ble_init(param: ShciBleInitCmdParam) { | 79 | pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE; |
| 80 | let mut packet = ShciBleInitCmdPacket { | 80 | #[allow(dead_code)] // Not used currently but reserved |
| 81 | header: ShciHeader::default(), | 81 | const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE; |
| 82 | param, | ||
| 83 | }; | ||
| 84 | |||
| 85 | let packet_ptr: *mut ShciBleInitCmdPacket = &mut packet; | ||
| 86 | |||
| 87 | unsafe { | ||
| 88 | let cmd_ptr: *mut CmdPacket = packet_ptr.cast(); | ||
| 89 | |||
| 90 | (*cmd_ptr).cmd_serial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT; | ||
| 91 | (*cmd_ptr).cmd_serial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8; | ||
| 92 | |||
| 93 | let cmd_buf = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer; | ||
| 94 | core::ptr::write(cmd_buf, *cmd_ptr); | ||
| 95 | |||
| 96 | cmd_buf.cmd_serial.ty = TlPacketType::SysCmd as u8; | ||
| 97 | |||
| 98 | Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL); | ||
| 99 | Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true); | ||
| 100 | } | ||
| 101 | } | ||
diff --git a/embassy-stm32-wpan/src/sys.rs b/embassy-stm32-wpan/src/sys.rs new file mode 100644 index 000000000..a185cd4f1 --- /dev/null +++ b/embassy-stm32-wpan/src/sys.rs | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use crate::cmd::CmdPacket; | ||
| 4 | use crate::consts::TlPacketType; | ||
| 5 | use crate::evt::EvtBox; | ||
| 6 | use crate::shci::{ShciBleInitCmdParam, SCHI_OPCODE_BLE_INIT}; | ||
| 7 | use crate::tables::{SysTable, WirelessFwInfoTable}; | ||
| 8 | use crate::unsafe_linked_list::LinkedListNode; | ||
| 9 | use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; | ||
| 10 | |||
| 11 | pub struct Sys { | ||
| 12 | phantom: PhantomData<Sys>, | ||
| 13 | } | ||
| 14 | |||
| 15 | impl Sys { | ||
| 16 | /// TL_Sys_Init | ||
| 17 | pub(crate) fn new() -> Self { | ||
| 18 | unsafe { | ||
| 19 | LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); | ||
| 20 | |||
| 21 | TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable { | ||
| 22 | pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(), | ||
| 23 | sys_queue: SYSTEM_EVT_QUEUE.as_ptr(), | ||
| 24 | }); | ||
| 25 | } | ||
| 26 | |||
| 27 | Self { phantom: PhantomData } | ||
| 28 | } | ||
| 29 | |||
| 30 | /// Returns CPU2 wireless firmware information (if present). | ||
| 31 | pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> { | ||
| 32 | let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table }; | ||
| 33 | |||
| 34 | // Zero version indicates that CPU2 wasn't active and didn't fill the information table | ||
| 35 | if info.version != 0 { | ||
| 36 | Some(info) | ||
| 37 | } else { | ||
| 38 | None | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | pub fn write(&self, opcode: u16, payload: &[u8]) { | ||
| 43 | unsafe { | ||
| 44 | CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode, payload); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) { | ||
| 49 | debug!("sending SHCI"); | ||
| 50 | |||
| 51 | Ipcc::send(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, || { | ||
| 52 | self.write(SCHI_OPCODE_BLE_INIT, param.payload()); | ||
| 53 | }) | ||
| 54 | .await; | ||
| 55 | |||
| 56 | Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await; | ||
| 57 | } | ||
| 58 | |||
| 59 | /// `HW_IPCC_SYS_EvtNot` | ||
| 60 | pub async fn read(&self) -> EvtBox { | ||
| 61 | Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe { | ||
| 62 | if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) { | ||
| 63 | Some(EvtBox::new(node_ptr.cast())) | ||
| 64 | } else { | ||
| 65 | None | ||
| 66 | } | ||
| 67 | }) | ||
| 68 | .await | ||
| 69 | } | ||
| 70 | } | ||
diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs new file mode 100644 index 000000000..151216958 --- /dev/null +++ b/embassy-stm32-wpan/src/tables.rs | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | use bit_field::BitField; | ||
| 2 | |||
| 3 | use crate::cmd::{AclDataPacket, CmdPacket}; | ||
| 4 | use crate::unsafe_linked_list::LinkedListNode; | ||
| 5 | |||
| 6 | #[derive(Debug, Copy, Clone)] | ||
| 7 | #[repr(C, packed)] | ||
| 8 | pub struct SafeBootInfoTable { | ||
| 9 | version: u32, | ||
| 10 | } | ||
| 11 | |||
| 12 | #[derive(Debug, Copy, Clone)] | ||
| 13 | #[repr(C, packed)] | ||
| 14 | pub struct RssInfoTable { | ||
| 15 | pub version: u32, | ||
| 16 | pub memory_size: u32, | ||
| 17 | pub rss_info: u32, | ||
| 18 | } | ||
| 19 | |||
| 20 | /** | ||
| 21 | * Version | ||
| 22 | * [0:3] = Build - 0: Untracked - 15:Released - x: Tracked version | ||
| 23 | * [4:7] = branch - 0: Mass Market - x: ... | ||
| 24 | * [8:15] = Subversion | ||
| 25 | * [16:23] = Version minor | ||
| 26 | * [24:31] = Version major | ||
| 27 | * | ||
| 28 | * Memory Size | ||
| 29 | * [0:7] = Flash ( Number of 4k sector) | ||
| 30 | * [8:15] = Reserved ( Shall be set to 0 - may be used as flash extension ) | ||
| 31 | * [16:23] = SRAM2b ( Number of 1k sector) | ||
| 32 | * [24:31] = SRAM2a ( Number of 1k sector) | ||
| 33 | */ | ||
| 34 | #[derive(Debug, Copy, Clone)] | ||
| 35 | #[repr(C, packed)] | ||
| 36 | pub struct WirelessFwInfoTable { | ||
| 37 | pub version: u32, | ||
| 38 | pub memory_size: u32, | ||
| 39 | pub thread_info: u32, | ||
| 40 | pub ble_info: u32, | ||
| 41 | } | ||
| 42 | |||
| 43 | impl WirelessFwInfoTable { | ||
| 44 | pub fn version_major(&self) -> u8 { | ||
| 45 | let version = self.version; | ||
| 46 | (version.get_bits(24..31) & 0xff) as u8 | ||
| 47 | } | ||
| 48 | |||
| 49 | pub fn version_minor(&self) -> u8 { | ||
| 50 | let version = self.version; | ||
| 51 | (version.clone().get_bits(16..23) & 0xff) as u8 | ||
| 52 | } | ||
| 53 | |||
| 54 | pub fn subversion(&self) -> u8 { | ||
| 55 | let version = self.version; | ||
| 56 | (version.clone().get_bits(8..15) & 0xff) as u8 | ||
| 57 | } | ||
| 58 | |||
| 59 | /// Size of FLASH, expressed in number of 4K sectors. | ||
| 60 | pub fn flash_size(&self) -> u8 { | ||
| 61 | let memory_size = self.memory_size; | ||
| 62 | (memory_size.clone().get_bits(0..7) & 0xff) as u8 | ||
| 63 | } | ||
| 64 | |||
| 65 | /// Size of SRAM2a, expressed in number of 1K sectors. | ||
| 66 | pub fn sram2a_size(&self) -> u8 { | ||
| 67 | let memory_size = self.memory_size; | ||
| 68 | (memory_size.clone().get_bits(24..31) & 0xff) as u8 | ||
| 69 | } | ||
| 70 | |||
| 71 | /// Size of SRAM2b, expressed in number of 1K sectors. | ||
| 72 | pub fn sram2b_size(&self) -> u8 { | ||
| 73 | let memory_size = self.memory_size; | ||
| 74 | (memory_size.clone().get_bits(16..23) & 0xff) as u8 | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | #[derive(Debug, Clone)] | ||
| 79 | #[repr(C, align(4))] | ||
| 80 | pub struct DeviceInfoTable { | ||
| 81 | pub safe_boot_info_table: SafeBootInfoTable, | ||
| 82 | pub rss_info_table: RssInfoTable, | ||
| 83 | pub wireless_fw_info_table: WirelessFwInfoTable, | ||
| 84 | } | ||
| 85 | |||
| 86 | #[derive(Debug)] | ||
| 87 | #[repr(C, align(4))] | ||
| 88 | pub struct BleTable { | ||
| 89 | pub pcmd_buffer: *mut CmdPacket, | ||
| 90 | pub pcs_buffer: *const u8, | ||
| 91 | pub pevt_queue: *const u8, | ||
| 92 | pub phci_acl_data_buffer: *mut AclDataPacket, | ||
| 93 | } | ||
| 94 | |||
| 95 | #[derive(Debug)] | ||
| 96 | #[repr(C, align(4))] | ||
| 97 | pub struct ThreadTable { | ||
| 98 | pub nostack_buffer: *const u8, | ||
| 99 | pub clicmdrsp_buffer: *const u8, | ||
| 100 | pub otcmdrsp_buffer: *const u8, | ||
| 101 | } | ||
| 102 | |||
| 103 | // TODO: use later | ||
| 104 | #[derive(Debug)] | ||
| 105 | #[repr(C, align(4))] | ||
| 106 | pub struct LldTestsTable { | ||
| 107 | pub clicmdrsp_buffer: *const u8, | ||
| 108 | pub m0cmd_buffer: *const u8, | ||
| 109 | } | ||
| 110 | |||
| 111 | // TODO: use later | ||
| 112 | #[derive(Debug)] | ||
| 113 | #[repr(C, align(4))] | ||
| 114 | pub struct BleLldTable { | ||
| 115 | pub cmdrsp_buffer: *const u8, | ||
| 116 | pub m0cmd_buffer: *const u8, | ||
| 117 | } | ||
| 118 | |||
| 119 | // TODO: use later | ||
| 120 | #[derive(Debug)] | ||
| 121 | #[repr(C, align(4))] | ||
| 122 | pub struct ZigbeeTable { | ||
| 123 | pub notif_m0_to_m4_buffer: *const u8, | ||
| 124 | pub appli_cmd_m4_to_m0_bufer: *const u8, | ||
| 125 | pub request_m0_to_m4_buffer: *const u8, | ||
| 126 | } | ||
| 127 | |||
| 128 | #[derive(Debug)] | ||
| 129 | #[repr(C, align(4))] | ||
| 130 | pub struct SysTable { | ||
| 131 | pub pcmd_buffer: *mut CmdPacket, | ||
| 132 | pub sys_queue: *const LinkedListNode, | ||
| 133 | } | ||
| 134 | |||
| 135 | #[derive(Debug)] | ||
| 136 | #[repr(C, align(4))] | ||
| 137 | pub struct MemManagerTable { | ||
| 138 | pub spare_ble_buffer: *const u8, | ||
| 139 | pub spare_sys_buffer: *const u8, | ||
| 140 | |||
| 141 | pub blepool: *const u8, | ||
| 142 | pub blepoolsize: u32, | ||
| 143 | |||
| 144 | pub pevt_free_buffer_queue: *mut LinkedListNode, | ||
| 145 | |||
| 146 | pub traces_evt_pool: *const u8, | ||
| 147 | pub tracespoolsize: u32, | ||
| 148 | } | ||
| 149 | |||
| 150 | #[derive(Debug)] | ||
| 151 | #[repr(C, align(4))] | ||
| 152 | pub struct TracesTable { | ||
| 153 | pub traces_queue: *const u8, | ||
| 154 | } | ||
| 155 | |||
| 156 | #[derive(Debug)] | ||
| 157 | #[repr(C, align(4))] | ||
| 158 | pub struct Mac802_15_4Table { | ||
| 159 | pub p_cmdrsp_buffer: *const u8, | ||
| 160 | pub p_notack_buffer: *const u8, | ||
| 161 | pub evt_queue: *const u8, | ||
| 162 | } | ||
| 163 | |||
| 164 | /// Reference table. Contains pointers to all other tables. | ||
| 165 | #[derive(Debug, Copy, Clone)] | ||
| 166 | #[repr(C)] | ||
| 167 | pub struct RefTable { | ||
| 168 | pub device_info_table: *const DeviceInfoTable, | ||
| 169 | pub ble_table: *const BleTable, | ||
| 170 | pub thread_table: *const ThreadTable, | ||
| 171 | pub sys_table: *const SysTable, | ||
| 172 | pub mem_manager_table: *const MemManagerTable, | ||
| 173 | pub traces_table: *const TracesTable, | ||
| 174 | pub mac_802_15_4_table: *const Mac802_15_4Table, | ||
| 175 | } | ||
diff --git a/embassy-stm32-wpan/src/unsafe_linked_list.rs b/embassy-stm32-wpan/src/unsafe_linked_list.rs new file mode 100644 index 000000000..d8bc29763 --- /dev/null +++ b/embassy-stm32-wpan/src/unsafe_linked_list.rs | |||
| @@ -0,0 +1,257 @@ | |||
| 1 | //! Unsafe linked list. | ||
| 2 | //! Translated from ST's C by `c2rust` tool. | ||
| 3 | |||
| 4 | #![allow( | ||
| 5 | dead_code, | ||
| 6 | mutable_transmutes, | ||
| 7 | non_camel_case_types, | ||
| 8 | non_snake_case, | ||
| 9 | non_upper_case_globals, | ||
| 10 | unused_assignments, | ||
| 11 | unused_mut | ||
| 12 | )] | ||
| 13 | |||
| 14 | use core::ptr; | ||
| 15 | |||
| 16 | use cortex_m::interrupt; | ||
| 17 | |||
| 18 | #[derive(Copy, Clone)] | ||
| 19 | #[repr(C, packed(4))] | ||
| 20 | pub struct LinkedListNode { | ||
| 21 | pub next: *mut LinkedListNode, | ||
| 22 | pub prev: *mut LinkedListNode, | ||
| 23 | } | ||
| 24 | |||
| 25 | impl Default for LinkedListNode { | ||
| 26 | fn default() -> Self { | ||
| 27 | LinkedListNode { | ||
| 28 | next: core::ptr::null_mut(), | ||
| 29 | prev: core::ptr::null_mut(), | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | impl LinkedListNode { | ||
| 35 | pub unsafe fn init_head(mut p_list_head: *mut LinkedListNode) { | ||
| 36 | ptr::write_volatile( | ||
| 37 | p_list_head, | ||
| 38 | LinkedListNode { | ||
| 39 | next: p_list_head, | ||
| 40 | prev: p_list_head, | ||
| 41 | }, | ||
| 42 | ); | ||
| 43 | } | ||
| 44 | |||
| 45 | pub unsafe fn is_empty(mut p_list_head: *mut LinkedListNode) -> bool { | ||
| 46 | interrupt::free(|_| ptr::read_volatile(p_list_head).next == p_list_head) | ||
| 47 | } | ||
| 48 | |||
| 49 | /// Insert `node` after `list_head` and before the next node | ||
| 50 | pub unsafe fn insert_head(mut p_list_head: *mut LinkedListNode, mut p_node: *mut LinkedListNode) { | ||
| 51 | interrupt::free(|_| { | ||
| 52 | let mut list_head = ptr::read_volatile(p_list_head); | ||
| 53 | if p_list_head != list_head.next { | ||
| 54 | let mut node_next = ptr::read_volatile(list_head.next); | ||
| 55 | let node = LinkedListNode { | ||
| 56 | next: list_head.next, | ||
| 57 | prev: p_list_head, | ||
| 58 | }; | ||
| 59 | |||
| 60 | list_head.next = p_node; | ||
| 61 | node_next.prev = p_node; | ||
| 62 | |||
| 63 | // All nodes must be written because they will all be seen by another core | ||
| 64 | ptr::write_volatile(p_node, node); | ||
| 65 | ptr::write_volatile(node.next, node_next); | ||
| 66 | ptr::write_volatile(p_list_head, list_head); | ||
| 67 | } else { | ||
| 68 | let node = LinkedListNode { | ||
| 69 | next: list_head.next, | ||
| 70 | prev: p_list_head, | ||
| 71 | }; | ||
| 72 | |||
| 73 | list_head.next = p_node; | ||
| 74 | list_head.prev = p_node; | ||
| 75 | |||
| 76 | // All nodes must be written because they will all be seen by another core | ||
| 77 | ptr::write_volatile(p_node, node); | ||
| 78 | ptr::write_volatile(p_list_head, list_head); | ||
| 79 | } | ||
| 80 | }); | ||
| 81 | } | ||
| 82 | |||
| 83 | /// Insert `node` before `list_tail` and after the second-to-last node | ||
| 84 | pub unsafe fn insert_tail(mut p_list_tail: *mut LinkedListNode, mut p_node: *mut LinkedListNode) { | ||
| 85 | interrupt::free(|_| { | ||
| 86 | let mut list_tail = ptr::read_volatile(p_list_tail); | ||
| 87 | if p_list_tail != list_tail.prev { | ||
| 88 | let mut node_prev = ptr::read_volatile(list_tail.prev); | ||
| 89 | let node = LinkedListNode { | ||
| 90 | next: p_list_tail, | ||
| 91 | prev: list_tail.prev, | ||
| 92 | }; | ||
| 93 | |||
| 94 | list_tail.prev = p_node; | ||
| 95 | node_prev.next = p_node; | ||
| 96 | |||
| 97 | // All nodes must be written because they will all be seen by another core | ||
| 98 | ptr::write_volatile(p_node, node); | ||
| 99 | ptr::write_volatile(node.prev, node_prev); | ||
| 100 | ptr::write_volatile(p_list_tail, list_tail); | ||
| 101 | } else { | ||
| 102 | let node = LinkedListNode { | ||
| 103 | next: p_list_tail, | ||
| 104 | prev: list_tail.prev, | ||
| 105 | }; | ||
| 106 | |||
| 107 | list_tail.prev = p_node; | ||
| 108 | list_tail.next = p_node; | ||
| 109 | |||
| 110 | // All nodes must be written because they will all be seen by another core | ||
| 111 | ptr::write_volatile(p_node, node); | ||
| 112 | ptr::write_volatile(p_list_tail, list_tail); | ||
| 113 | } | ||
| 114 | }); | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Remove `node` from the linked list | ||
| 118 | pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) { | ||
| 119 | interrupt::free(|_| { | ||
| 120 | // trace!("remove node: {:x}", p_node); | ||
| 121 | // apparently linked list nodes are not always aligned. | ||
| 122 | // if more hardfaults occur, more of these may need to be converted to unaligned. | ||
| 123 | let node = ptr::read_unaligned(p_node); | ||
| 124 | // trace!("remove node: prev/next {:x}/{:x}", node.prev, node.next); | ||
| 125 | |||
| 126 | if node.next != node.prev { | ||
| 127 | let mut node_next = ptr::read_volatile(node.next); | ||
| 128 | let mut node_prev = ptr::read_volatile(node.prev); | ||
| 129 | |||
| 130 | node_prev.next = node.next; | ||
| 131 | node_next.prev = node.prev; | ||
| 132 | |||
| 133 | ptr::write_volatile(node.next, node_next); | ||
| 134 | ptr::write_volatile(node.prev, node_prev); | ||
| 135 | } else { | ||
| 136 | let mut node_next = ptr::read_volatile(node.next); | ||
| 137 | |||
| 138 | node_next.next = node.next; | ||
| 139 | node_next.prev = node.prev; | ||
| 140 | |||
| 141 | ptr::write_volatile(node.next, node_next); | ||
| 142 | } | ||
| 143 | }); | ||
| 144 | } | ||
| 145 | |||
| 146 | /// Remove `list_head` and return a pointer to the `node`. | ||
| 147 | pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> Option<*mut LinkedListNode> { | ||
| 148 | interrupt::free(|_| { | ||
| 149 | let list_head = ptr::read_volatile(p_list_head); | ||
| 150 | |||
| 151 | if list_head.next == p_list_head { | ||
| 152 | None | ||
| 153 | } else { | ||
| 154 | // Allowed because a removed node is not seen by another core | ||
| 155 | let p_node = list_head.next; | ||
| 156 | Self::remove_node(p_node); | ||
| 157 | |||
| 158 | Some(p_node) | ||
| 159 | } | ||
| 160 | }) | ||
| 161 | } | ||
| 162 | |||
| 163 | /// Remove `list_tail` and return a pointer to the `node`. | ||
| 164 | pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> Option<*mut LinkedListNode> { | ||
| 165 | interrupt::free(|_| { | ||
| 166 | let list_tail = ptr::read_volatile(p_list_tail); | ||
| 167 | |||
| 168 | if list_tail.prev == p_list_tail { | ||
| 169 | None | ||
| 170 | } else { | ||
| 171 | // Allowed because a removed node is not seen by another core | ||
| 172 | let p_node = list_tail.prev; | ||
| 173 | Self::remove_node(p_node); | ||
| 174 | |||
| 175 | Some(p_node) | ||
| 176 | } | ||
| 177 | }) | ||
| 178 | } | ||
| 179 | |||
| 180 | pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) { | ||
| 181 | interrupt::free(|_| { | ||
| 182 | (*node).next = (*ref_node).next; | ||
| 183 | (*node).prev = ref_node; | ||
| 184 | (*ref_node).next = node; | ||
| 185 | (*(*node).next).prev = node; | ||
| 186 | }); | ||
| 187 | |||
| 188 | todo!("this function has not been converted to volatile semantics"); | ||
| 189 | } | ||
| 190 | |||
| 191 | pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) { | ||
| 192 | interrupt::free(|_| { | ||
| 193 | (*node).next = ref_node; | ||
| 194 | (*node).prev = (*ref_node).prev; | ||
| 195 | (*ref_node).prev = node; | ||
| 196 | (*(*node).prev).next = node; | ||
| 197 | }); | ||
| 198 | |||
| 199 | todo!("this function has not been converted to volatile semantics"); | ||
| 200 | } | ||
| 201 | |||
| 202 | pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize { | ||
| 203 | interrupt::free(|_| { | ||
| 204 | let mut size = 0; | ||
| 205 | let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>(); | ||
| 206 | |||
| 207 | temp = (*list_head).next; | ||
| 208 | while temp != list_head { | ||
| 209 | size += 1; | ||
| 210 | temp = (*temp).next | ||
| 211 | } | ||
| 212 | |||
| 213 | size | ||
| 214 | }); | ||
| 215 | |||
| 216 | todo!("this function has not been converted to volatile semantics"); | ||
| 217 | } | ||
| 218 | |||
| 219 | pub unsafe fn get_next_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode { | ||
| 220 | interrupt::free(|_| { | ||
| 221 | let ref_node = ptr::read_volatile(p_ref_node); | ||
| 222 | |||
| 223 | // Allowed because a removed node is not seen by another core | ||
| 224 | ref_node.next | ||
| 225 | }) | ||
| 226 | } | ||
| 227 | |||
| 228 | pub unsafe fn get_prev_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode { | ||
| 229 | interrupt::free(|_| { | ||
| 230 | let ref_node = ptr::read_volatile(p_ref_node); | ||
| 231 | |||
| 232 | // Allowed because a removed node is not seen by another core | ||
| 233 | ref_node.prev | ||
| 234 | }) | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | #[allow(dead_code)] | ||
| 239 | unsafe fn debug_linked_list(mut p_node: *mut LinkedListNode) { | ||
| 240 | info!("iterating list from node: {:x}", p_node); | ||
| 241 | let mut p_current_node = p_node; | ||
| 242 | let mut i = 0; | ||
| 243 | loop { | ||
| 244 | let current_node = ptr::read_volatile(p_current_node); | ||
| 245 | info!( | ||
| 246 | "node (prev, current, next): {:x}, {:x}, {:x}", | ||
| 247 | current_node.prev, p_current_node, current_node.next | ||
| 248 | ); | ||
| 249 | |||
| 250 | i += 1; | ||
| 251 | if i > 10 || current_node.next == p_node { | ||
| 252 | break; | ||
| 253 | } | ||
| 254 | |||
| 255 | p_current_node = current_node.next; | ||
| 256 | } | ||
| 257 | } | ||
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4e29bb32f..3d9ee8261 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -32,11 +32,9 @@ flavors = [ | |||
| 32 | 32 | ||
| 33 | [dependencies] | 33 | [dependencies] |
| 34 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } | 34 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } |
| 35 | embassy-executor = { version = "0.2.0", path = "../embassy-executor" } | ||
| 36 | embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } | 35 | embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } |
| 37 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | 36 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } |
| 38 | embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]} | 37 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-4"] } |
| 39 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } | ||
| 40 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } | 38 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } |
| 41 | embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } | 39 | embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } |
| 42 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } | 40 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } |
| @@ -59,7 +57,7 @@ sdio-host = "0.5.0" | |||
| 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 57 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 60 | critical-section = "1.1" | 58 | critical-section = "1.1" |
| 61 | atomic-polyfill = "1.0.1" | 59 | atomic-polyfill = "1.0.1" |
| 62 | stm32-metapac = "9" | 60 | stm32-metapac = "10" |
| 63 | vcell = "0.1.3" | 61 | vcell = "0.1.3" |
| 64 | bxcan = "0.7.0" | 62 | bxcan = "0.7.0" |
| 65 | nb = "1.0.0" | 63 | nb = "1.0.0" |
| @@ -76,11 +74,13 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 76 | [build-dependencies] | 74 | [build-dependencies] |
| 77 | proc-macro2 = "1.0.36" | 75 | proc-macro2 = "1.0.36" |
| 78 | quote = "1.0.15" | 76 | quote = "1.0.15" |
| 79 | stm32-metapac = { version = "9", default-features = false, features = ["metadata"]} | 77 | stm32-metapac = { version = "10", default-features = false, features = ["metadata"]} |
| 80 | 78 | ||
| 81 | [features] | 79 | [features] |
| 82 | default = ["stm32-metapac/rt"] | 80 | default = ["rt"] |
| 83 | defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"] | 81 | rt = ["stm32-metapac/rt"] |
| 82 | |||
| 83 | defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"] | ||
| 84 | memory-x = ["stm32-metapac/memory-x"] | 84 | memory-x = ["stm32-metapac/memory-x"] |
| 85 | exti = [] | 85 | exti = [] |
| 86 | 86 | ||
| @@ -99,7 +99,7 @@ time-driver-tim12 = ["_time-driver"] | |||
| 99 | time-driver-tim15 = ["_time-driver"] | 99 | time-driver-tim15 = ["_time-driver"] |
| 100 | 100 | ||
| 101 | # Enable nightly-only features | 101 | # Enable nightly-only features |
| 102 | nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"] | 102 | nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"] |
| 103 | 103 | ||
| 104 | # Reexport stm32-metapac at `embassy_stm32::pac`. | 104 | # Reexport stm32-metapac at `embassy_stm32::pac`. |
| 105 | # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. | 105 | # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 730c78f5e..f71074bcf 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -160,13 +160,11 @@ fn main() { | |||
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | g.extend(quote! { | 162 | g.extend(quote! { |
| 163 | pub mod interrupt { | 163 | embassy_hal_common::interrupt_mod!( |
| 164 | use crate::pac::Interrupt as InterruptEnum; | ||
| 165 | use embassy_cortex_m::interrupt::_export::declare; | ||
| 166 | #( | 164 | #( |
| 167 | declare!(#irqs); | 165 | #irqs, |
| 168 | )* | 166 | )* |
| 169 | } | 167 | ); |
| 170 | }); | 168 | }); |
| 171 | 169 | ||
| 172 | // ======== | 170 | // ======== |
| @@ -297,6 +295,7 @@ fn main() { | |||
| 297 | let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch)); | 295 | let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch)); |
| 298 | 296 | ||
| 299 | g.extend(quote! { | 297 | g.extend(quote! { |
| 298 | #[cfg(feature = "rt")] | ||
| 300 | #[crate::interrupt] | 299 | #[crate::interrupt] |
| 301 | unsafe fn #irq () { | 300 | unsafe fn #irq () { |
| 302 | #( | 301 | #( |
| @@ -323,7 +322,7 @@ fn main() { | |||
| 323 | let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); | 322 | let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); |
| 324 | let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); | 323 | let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); |
| 325 | quote! { | 324 | quote! { |
| 326 | critical_section::with(|_| unsafe { | 325 | critical_section::with(|_| { |
| 327 | crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); | 326 | crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); |
| 328 | crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); | 327 | crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); |
| 329 | }); | 328 | }); |
| @@ -354,13 +353,13 @@ fn main() { | |||
| 354 | }) | 353 | }) |
| 355 | } | 354 | } |
| 356 | fn enable() { | 355 | fn enable() { |
| 357 | critical_section::with(|_| unsafe { | 356 | critical_section::with(|_| { |
| 358 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); | 357 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); |
| 359 | #after_enable | 358 | #after_enable |
| 360 | }) | 359 | }) |
| 361 | } | 360 | } |
| 362 | fn disable() { | 361 | fn disable() { |
| 363 | critical_section::with(|_| unsafe { | 362 | critical_section::with(|_| { |
| 364 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); | 363 | crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); |
| 365 | }) | 364 | }) |
| 366 | } | 365 | } |
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index d30ec001d..2322204d5 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs | |||
| @@ -32,26 +32,22 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 32 | into_ref!(adc); | 32 | into_ref!(adc); |
| 33 | T::enable(); | 33 | T::enable(); |
| 34 | T::reset(); | 34 | T::reset(); |
| 35 | unsafe { | 35 | T::regs().cr2().modify(|reg| reg.set_adon(true)); |
| 36 | T::regs().cr2().modify(|reg| reg.set_adon(true)); | ||
| 37 | } | ||
| 38 | 36 | ||
| 39 | // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) | 37 | // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) |
| 40 | // for at least two ADC clock cycles | 38 | // for at least two ADC clock cycles |
| 41 | delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1); | 39 | delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1); |
| 42 | 40 | ||
| 43 | unsafe { | 41 | // Reset calibration |
| 44 | // Reset calibration | 42 | T::regs().cr2().modify(|reg| reg.set_rstcal(true)); |
| 45 | T::regs().cr2().modify(|reg| reg.set_rstcal(true)); | 43 | while T::regs().cr2().read().rstcal() { |
| 46 | while T::regs().cr2().read().rstcal() { | 44 | // spin |
| 47 | // spin | 45 | } |
| 48 | } | 46 | |
| 49 | 47 | // Calibrate | |
| 50 | // Calibrate | 48 | T::regs().cr2().modify(|reg| reg.set_cal(true)); |
| 51 | T::regs().cr2().modify(|reg| reg.set_cal(true)); | 49 | while T::regs().cr2().read().cal() { |
| 52 | while T::regs().cr2().read().cal() { | 50 | // spin |
| 53 | // spin | ||
| 54 | } | ||
| 55 | } | 51 | } |
| 56 | 52 | ||
| 57 | // One cycle after calibration | 53 | // One cycle after calibration |
| @@ -81,20 +77,16 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 81 | } | 77 | } |
| 82 | 78 | ||
| 83 | pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref { | 79 | pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref { |
| 84 | unsafe { | 80 | T::regs().cr2().modify(|reg| { |
| 85 | T::regs().cr2().modify(|reg| { | 81 | reg.set_tsvrefe(true); |
| 86 | reg.set_tsvrefe(true); | 82 | }); |
| 87 | }) | ||
| 88 | } | ||
| 89 | Vref {} | 83 | Vref {} |
| 90 | } | 84 | } |
| 91 | 85 | ||
| 92 | pub fn enable_temperature(&self) -> Temperature { | 86 | pub fn enable_temperature(&self) -> Temperature { |
| 93 | unsafe { | 87 | T::regs().cr2().modify(|reg| { |
| 94 | T::regs().cr2().modify(|reg| { | 88 | reg.set_tsvrefe(true); |
| 95 | reg.set_tsvrefe(true); | 89 | }); |
| 96 | }) | ||
| 97 | } | ||
| 98 | Temperature {} | 90 | Temperature {} |
| 99 | } | 91 | } |
| 100 | 92 | ||
| @@ -104,41 +96,37 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 104 | 96 | ||
| 105 | /// Perform a single conversion. | 97 | /// Perform a single conversion. |
| 106 | fn convert(&mut self) -> u16 { | 98 | fn convert(&mut self) -> u16 { |
| 107 | unsafe { | 99 | T::regs().cr2().modify(|reg| { |
| 108 | T::regs().cr2().modify(|reg| { | 100 | reg.set_adon(true); |
| 109 | reg.set_adon(true); | 101 | reg.set_swstart(true); |
| 110 | reg.set_swstart(true); | 102 | }); |
| 111 | }); | 103 | while T::regs().cr2().read().swstart() {} |
| 112 | while T::regs().cr2().read().swstart() {} | 104 | while !T::regs().sr().read().eoc() {} |
| 113 | while !T::regs().sr().read().eoc() {} | 105 | |
| 114 | 106 | T::regs().dr().read().0 as u16 | |
| 115 | T::regs().dr().read().0 as u16 | ||
| 116 | } | ||
| 117 | } | 107 | } |
| 118 | 108 | ||
| 119 | pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | 109 | pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { |
| 120 | unsafe { | 110 | Self::set_channel_sample_time(pin.channel(), self.sample_time); |
| 121 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | 111 | T::regs().cr1().modify(|reg| { |
| 122 | T::regs().cr1().modify(|reg| { | 112 | reg.set_scan(false); |
| 123 | reg.set_scan(false); | 113 | reg.set_discen(false); |
| 124 | reg.set_discen(false); | 114 | }); |
| 125 | }); | 115 | T::regs().sqr1().modify(|reg| reg.set_l(0)); |
| 126 | T::regs().sqr1().modify(|reg| reg.set_l(0)); | 116 | |
| 127 | 117 | T::regs().cr2().modify(|reg| { | |
| 128 | T::regs().cr2().modify(|reg| { | 118 | reg.set_cont(false); |
| 129 | reg.set_cont(false); | 119 | reg.set_exttrig(true); |
| 130 | reg.set_exttrig(true); | 120 | reg.set_swstart(false); |
| 131 | reg.set_swstart(false); | 121 | reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART); |
| 132 | reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART); | 122 | }); |
| 133 | }); | ||
| 134 | } | ||
| 135 | 123 | ||
| 136 | // Configure the channel to sample | 124 | // Configure the channel to sample |
| 137 | unsafe { T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())) } | 125 | T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())); |
| 138 | self.convert() | 126 | self.convert() |
| 139 | } | 127 | } |
| 140 | 128 | ||
| 141 | unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 129 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| 142 | let sample_time = sample_time.into(); | 130 | let sample_time = sample_time.into(); |
| 143 | if ch <= 9 { | 131 | if ch <= 9 { |
| 144 | T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); | 132 | T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); |
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 82a8c3efb..d9af0c55e 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs | |||
| @@ -57,18 +57,14 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 57 | // | 57 | // |
| 58 | // 6.3.20 Vbat monitoring characteristics | 58 | // 6.3.20 Vbat monitoring characteristics |
| 59 | // ts_vbat ≥ 4μs | 59 | // ts_vbat ≥ 4μs |
| 60 | unsafe { | 60 | T::regs().ccr().modify(|reg| reg.set_vbaten(true)); |
| 61 | T::regs().ccr().modify(|reg| reg.set_vbaten(true)); | ||
| 62 | } | ||
| 63 | Vbat | 61 | Vbat |
| 64 | } | 62 | } |
| 65 | 63 | ||
| 66 | pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref { | 64 | pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref { |
| 67 | // Table 28. Embedded internal reference voltage | 65 | // Table 28. Embedded internal reference voltage |
| 68 | // tstart = 10μs | 66 | // tstart = 10μs |
| 69 | unsafe { | 67 | T::regs().ccr().modify(|reg| reg.set_vrefen(true)); |
| 70 | T::regs().ccr().modify(|reg| reg.set_vrefen(true)); | ||
| 71 | } | ||
| 72 | delay.delay_us(10); | 68 | delay.delay_us(10); |
| 73 | Vref | 69 | Vref |
| 74 | } | 70 | } |
| @@ -79,27 +75,23 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 79 | // 6.3.19 Temperature sensor characteristics | 75 | // 6.3.19 Temperature sensor characteristics |
| 80 | // tstart ≤ 10μs | 76 | // tstart ≤ 10μs |
| 81 | // ts_temp ≥ 4μs | 77 | // ts_temp ≥ 4μs |
| 82 | unsafe { | 78 | T::regs().ccr().modify(|reg| reg.set_tsen(true)); |
| 83 | T::regs().ccr().modify(|reg| reg.set_tsen(true)); | ||
| 84 | } | ||
| 85 | delay.delay_us(10); | 79 | delay.delay_us(10); |
| 86 | Temperature | 80 | Temperature |
| 87 | } | 81 | } |
| 88 | 82 | ||
| 89 | fn calibrate(&self) { | 83 | fn calibrate(&self) { |
| 90 | unsafe { | 84 | // A.7.1 ADC calibration code example |
| 91 | // A.7.1 ADC calibration code example | 85 | if T::regs().cr().read().aden() { |
| 92 | if T::regs().cr().read().aden() { | 86 | T::regs().cr().modify(|reg| reg.set_addis(true)); |
| 93 | T::regs().cr().modify(|reg| reg.set_addis(true)); | 87 | } |
| 94 | } | 88 | while T::regs().cr().read().aden() { |
| 95 | while T::regs().cr().read().aden() { | 89 | // spin |
| 96 | // spin | 90 | } |
| 97 | } | 91 | T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); |
| 98 | T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); | 92 | T::regs().cr().modify(|reg| reg.set_adcal(true)); |
| 99 | T::regs().cr().modify(|reg| reg.set_adcal(true)); | 93 | while T::regs().cr().read().adcal() { |
| 100 | while T::regs().cr().read().adcal() { | 94 | // spin |
| 101 | // spin | ||
| 102 | } | ||
| 103 | } | 95 | } |
| 104 | } | 96 | } |
| 105 | 97 | ||
| @@ -108,9 +100,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 108 | } | 100 | } |
| 109 | 101 | ||
| 110 | pub fn set_resolution(&mut self, resolution: Resolution) { | 102 | pub fn set_resolution(&mut self, resolution: Resolution) { |
| 111 | unsafe { | 103 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); |
| 112 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||
| 113 | } | ||
| 114 | } | 104 | } |
| 115 | 105 | ||
| 116 | pub fn read<P>(&mut self, pin: &mut P) -> u16 | 106 | pub fn read<P>(&mut self, pin: &mut P) -> u16 |
| @@ -118,18 +108,16 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 118 | P: AdcPin<T> + crate::gpio::sealed::Pin, | 108 | P: AdcPin<T> + crate::gpio::sealed::Pin, |
| 119 | { | 109 | { |
| 120 | let channel = pin.channel(); | 110 | let channel = pin.channel(); |
| 121 | unsafe { | 111 | pin.set_as_analog(); |
| 122 | pin.set_as_analog(); | 112 | self.read_channel(channel) |
| 123 | self.read_channel(channel) | ||
| 124 | } | ||
| 125 | } | 113 | } |
| 126 | 114 | ||
| 127 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { | 115 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { |
| 128 | let channel = channel.channel(); | 116 | let channel = channel.channel(); |
| 129 | unsafe { self.read_channel(channel) } | 117 | self.read_channel(channel) |
| 130 | } | 118 | } |
| 131 | 119 | ||
| 132 | unsafe fn read_channel(&mut self, channel: u8) -> u16 { | 120 | fn read_channel(&mut self, channel: u8) -> u16 { |
| 133 | // A.7.2 ADC enable sequence code example | 121 | // A.7.2 ADC enable sequence code example |
| 134 | if T::regs().isr().read().adrdy() { | 122 | if T::regs().isr().read().adrdy() { |
| 135 | T::regs().isr().modify(|reg| reg.set_adrdy(true)); | 123 | T::regs().isr().modify(|reg| reg.set_adrdy(true)); |
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 11a51f993..091c1d447 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -100,13 +100,10 @@ where | |||
| 100 | T::reset(); | 100 | T::reset(); |
| 101 | 101 | ||
| 102 | let presc = Prescaler::from_pclk2(T::frequency()); | 102 | let presc = Prescaler::from_pclk2(T::frequency()); |
| 103 | unsafe { | 103 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); |
| 104 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); | 104 | T::regs().cr2().modify(|reg| { |
| 105 | 105 | reg.set_adon(crate::pac::adc::vals::Adon::ENABLED); | |
| 106 | T::regs().cr2().modify(|reg| { | 106 | }); |
| 107 | reg.set_adon(crate::pac::adc::vals::Adon::ENABLED); | ||
| 108 | }); | ||
| 109 | } | ||
| 110 | 107 | ||
| 111 | delay.delay_us(ADC_POWERUP_TIME_US); | 108 | delay.delay_us(ADC_POWERUP_TIME_US); |
| 112 | 109 | ||
| @@ -121,19 +118,15 @@ where | |||
| 121 | } | 118 | } |
| 122 | 119 | ||
| 123 | pub fn set_resolution(&mut self, resolution: Resolution) { | 120 | pub fn set_resolution(&mut self, resolution: Resolution) { |
| 124 | unsafe { | 121 | T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); |
| 125 | T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); | ||
| 126 | } | ||
| 127 | } | 122 | } |
| 128 | 123 | ||
| 129 | /// Enables internal voltage reference and returns [VrefInt], which can be used in | 124 | /// Enables internal voltage reference and returns [VrefInt], which can be used in |
| 130 | /// [Adc::read_internal()] to perform conversion. | 125 | /// [Adc::read_internal()] to perform conversion. |
| 131 | pub fn enable_vrefint(&self) -> VrefInt { | 126 | pub fn enable_vrefint(&self) -> VrefInt { |
| 132 | unsafe { | 127 | T::common_regs().ccr().modify(|reg| { |
| 133 | T::common_regs().ccr().modify(|reg| { | 128 | reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); |
| 134 | reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); | 129 | }); |
| 135 | }); | ||
| 136 | } | ||
| 137 | 130 | ||
| 138 | VrefInt {} | 131 | VrefInt {} |
| 139 | } | 132 | } |
| @@ -144,11 +137,9 @@ where | |||
| 144 | /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled, | 137 | /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled, |
| 145 | /// temperature sensor will return vbat value. | 138 | /// temperature sensor will return vbat value. |
| 146 | pub fn enable_temperature(&self) -> Temperature { | 139 | pub fn enable_temperature(&self) -> Temperature { |
| 147 | unsafe { | 140 | T::common_regs().ccr().modify(|reg| { |
| 148 | T::common_regs().ccr().modify(|reg| { | 141 | reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); |
| 149 | reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); | 142 | }); |
| 150 | }); | ||
| 151 | } | ||
| 152 | 143 | ||
| 153 | Temperature {} | 144 | Temperature {} |
| 154 | } | 145 | } |
| @@ -156,37 +147,33 @@ where | |||
| 156 | /// Enables vbat input and returns [Vbat], which can be used in | 147 | /// Enables vbat input and returns [Vbat], which can be used in |
| 157 | /// [Adc::read_internal()] to perform conversion. | 148 | /// [Adc::read_internal()] to perform conversion. |
| 158 | pub fn enable_vbat(&self) -> Vbat { | 149 | pub fn enable_vbat(&self) -> Vbat { |
| 159 | unsafe { | 150 | T::common_regs().ccr().modify(|reg| { |
| 160 | T::common_regs().ccr().modify(|reg| { | 151 | reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED); |
| 161 | reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED); | 152 | }); |
| 162 | }); | ||
| 163 | } | ||
| 164 | 153 | ||
| 165 | Vbat {} | 154 | Vbat {} |
| 166 | } | 155 | } |
| 167 | 156 | ||
| 168 | /// Perform a single conversion. | 157 | /// Perform a single conversion. |
| 169 | fn convert(&mut self) -> u16 { | 158 | fn convert(&mut self) -> u16 { |
| 170 | unsafe { | 159 | // clear end of conversion flag |
| 171 | // clear end of conversion flag | 160 | T::regs().sr().modify(|reg| { |
| 172 | T::regs().sr().modify(|reg| { | 161 | reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE); |
| 173 | reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE); | 162 | }); |
| 174 | }); | 163 | |
| 175 | 164 | // Start conversion | |
| 176 | // Start conversion | 165 | T::regs().cr2().modify(|reg| { |
| 177 | T::regs().cr2().modify(|reg| { | 166 | reg.set_swstart(true); |
| 178 | reg.set_swstart(true); | 167 | }); |
| 179 | }); | 168 | |
| 180 | 169 | while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED { | |
| 181 | while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED { | 170 | // spin //wait for actual start |
| 182 | // spin //wait for actual start | ||
| 183 | } | ||
| 184 | while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE { | ||
| 185 | // spin //wait for finish | ||
| 186 | } | ||
| 187 | |||
| 188 | T::regs().dr().read().0 as u16 | ||
| 189 | } | 171 | } |
| 172 | while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE { | ||
| 173 | // spin //wait for finish | ||
| 174 | } | ||
| 175 | |||
| 176 | T::regs().dr().read().0 as u16 | ||
| 190 | } | 177 | } |
| 191 | 178 | ||
| 192 | pub fn read<P>(&mut self, pin: &mut P) -> u16 | 179 | pub fn read<P>(&mut self, pin: &mut P) -> u16 |
| @@ -194,18 +181,16 @@ where | |||
| 194 | P: AdcPin<T>, | 181 | P: AdcPin<T>, |
| 195 | P: crate::gpio::sealed::Pin, | 182 | P: crate::gpio::sealed::Pin, |
| 196 | { | 183 | { |
| 197 | unsafe { | 184 | pin.set_as_analog(); |
| 198 | pin.set_as_analog(); | ||
| 199 | 185 | ||
| 200 | self.read_channel(pin.channel()) | 186 | self.read_channel(pin.channel()) |
| 201 | } | ||
| 202 | } | 187 | } |
| 203 | 188 | ||
| 204 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { | 189 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { |
| 205 | unsafe { self.read_channel(channel.channel()) } | 190 | self.read_channel(channel.channel()) |
| 206 | } | 191 | } |
| 207 | 192 | ||
| 208 | unsafe fn read_channel(&mut self, channel: u8) -> u16 { | 193 | fn read_channel(&mut self, channel: u8) -> u16 { |
| 209 | // Configure ADC | 194 | // Configure ADC |
| 210 | 195 | ||
| 211 | // Select channel | 196 | // Select channel |
| @@ -219,7 +204,7 @@ where | |||
| 219 | val | 204 | val |
| 220 | } | 205 | } |
| 221 | 206 | ||
| 222 | unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 207 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| 223 | let sample_time = sample_time.into(); | 208 | let sample_time = sample_time.into(); |
| 224 | if ch <= 9 { | 209 | if ch <= 9 { |
| 225 | T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); | 210 | T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 90aa7d3b9..94cdc86cd 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -12,7 +12,7 @@ pub const VREF_CALIB_MV: u32 = 3000; | |||
| 12 | /// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock | 12 | /// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock |
| 13 | /// configuration. | 13 | /// configuration. |
| 14 | fn enable() { | 14 | fn enable() { |
| 15 | critical_section::with(|_| unsafe { | 15 | critical_section::with(|_| { |
| 16 | #[cfg(stm32h7)] | 16 | #[cfg(stm32h7)] |
| 17 | crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); | 17 | crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); |
| 18 | #[cfg(stm32g0)] | 18 | #[cfg(stm32g0)] |
| @@ -62,29 +62,25 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 62 | pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { | 62 | pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { |
| 63 | into_ref!(adc); | 63 | into_ref!(adc); |
| 64 | enable(); | 64 | enable(); |
| 65 | unsafe { | 65 | T::regs().cr().modify(|reg| { |
| 66 | T::regs().cr().modify(|reg| { | 66 | #[cfg(not(adc_g0))] |
| 67 | #[cfg(not(adc_g0))] | 67 | reg.set_deeppwd(false); |
| 68 | reg.set_deeppwd(false); | 68 | reg.set_advregen(true); |
| 69 | reg.set_advregen(true); | 69 | }); |
| 70 | }); | 70 | |
| 71 | 71 | #[cfg(adc_g0)] | |
| 72 | #[cfg(adc_g0)] | 72 | T::regs().cfgr1().modify(|reg| { |
| 73 | T::regs().cfgr1().modify(|reg| { | 73 | reg.set_chselrmod(false); |
| 74 | reg.set_chselrmod(false); | 74 | }); |
| 75 | }); | ||
| 76 | } | ||
| 77 | 75 | ||
| 78 | delay.delay_us(20); | 76 | delay.delay_us(20); |
| 79 | 77 | ||
| 80 | unsafe { | 78 | T::regs().cr().modify(|reg| { |
| 81 | T::regs().cr().modify(|reg| { | 79 | reg.set_adcal(true); |
| 82 | reg.set_adcal(true); | 80 | }); |
| 83 | }); | ||
| 84 | 81 | ||
| 85 | while T::regs().cr().read().adcal() { | 82 | while T::regs().cr().read().adcal() { |
| 86 | // spin | 83 | // spin |
| 87 | } | ||
| 88 | } | 84 | } |
| 89 | 85 | ||
| 90 | delay.delay_us(1); | 86 | delay.delay_us(1); |
| @@ -96,11 +92,9 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 96 | } | 92 | } |
| 97 | 93 | ||
| 98 | pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { | 94 | pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt { |
| 99 | unsafe { | 95 | T::common_regs().ccr().modify(|reg| { |
| 100 | T::common_regs().ccr().modify(|reg| { | 96 | reg.set_vrefen(true); |
| 101 | reg.set_vrefen(true); | 97 | }); |
| 102 | }); | ||
| 103 | } | ||
| 104 | 98 | ||
| 105 | // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us | 99 | // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us |
| 106 | // to stabilize the internal voltage reference, we wait a little more. | 100 | // to stabilize the internal voltage reference, we wait a little more. |
| @@ -112,21 +106,17 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 112 | } | 106 | } |
| 113 | 107 | ||
| 114 | pub fn enable_temperature(&self) -> Temperature { | 108 | pub fn enable_temperature(&self) -> Temperature { |
| 115 | unsafe { | 109 | T::common_regs().ccr().modify(|reg| { |
| 116 | T::common_regs().ccr().modify(|reg| { | 110 | reg.set_ch17sel(true); |
| 117 | reg.set_ch17sel(true); | 111 | }); |
| 118 | }); | ||
| 119 | } | ||
| 120 | 112 | ||
| 121 | Temperature {} | 113 | Temperature {} |
| 122 | } | 114 | } |
| 123 | 115 | ||
| 124 | pub fn enable_vbat(&self) -> Vbat { | 116 | pub fn enable_vbat(&self) -> Vbat { |
| 125 | unsafe { | 117 | T::common_regs().ccr().modify(|reg| { |
| 126 | T::common_regs().ccr().modify(|reg| { | 118 | reg.set_ch18sel(true); |
| 127 | reg.set_ch18sel(true); | 119 | }); |
| 128 | }); | ||
| 129 | } | ||
| 130 | 120 | ||
| 131 | Vbat {} | 121 | Vbat {} |
| 132 | } | 122 | } |
| @@ -136,12 +126,10 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 136 | } | 126 | } |
| 137 | 127 | ||
| 138 | pub fn set_resolution(&mut self, resolution: Resolution) { | 128 | pub fn set_resolution(&mut self, resolution: Resolution) { |
| 139 | unsafe { | 129 | #[cfg(not(stm32g0))] |
| 140 | #[cfg(not(stm32g0))] | 130 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); |
| 141 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | 131 | #[cfg(stm32g0)] |
| 142 | #[cfg(stm32g0)] | 132 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); |
| 143 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||
| 144 | } | ||
| 145 | } | 133 | } |
| 146 | 134 | ||
| 147 | /* | 135 | /* |
| @@ -155,77 +143,73 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 155 | 143 | ||
| 156 | /// Perform a single conversion. | 144 | /// Perform a single conversion. |
| 157 | fn convert(&mut self) -> u16 { | 145 | fn convert(&mut self) -> u16 { |
| 158 | unsafe { | 146 | T::regs().isr().modify(|reg| { |
| 159 | T::regs().isr().modify(|reg| { | 147 | reg.set_eos(true); |
| 160 | reg.set_eos(true); | 148 | reg.set_eoc(true); |
| 161 | reg.set_eoc(true); | 149 | }); |
| 162 | }); | 150 | |
| 163 | 151 | // Start conversion | |
| 164 | // Start conversion | 152 | T::regs().cr().modify(|reg| { |
| 165 | T::regs().cr().modify(|reg| { | 153 | reg.set_adstart(true); |
| 166 | reg.set_adstart(true); | 154 | }); |
| 167 | }); | 155 | |
| 168 | 156 | while !T::regs().isr().read().eos() { | |
| 169 | while !T::regs().isr().read().eos() { | 157 | // spin |
| 170 | // spin | ||
| 171 | } | ||
| 172 | |||
| 173 | T::regs().dr().read().0 as u16 | ||
| 174 | } | 158 | } |
| 159 | |||
| 160 | T::regs().dr().read().0 as u16 | ||
| 175 | } | 161 | } |
| 176 | 162 | ||
| 177 | pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | 163 | pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { |
| 178 | unsafe { | 164 | // Make sure bits are off |
| 179 | // Make sure bits are off | 165 | while T::regs().cr().read().addis() { |
| 180 | while T::regs().cr().read().addis() { | 166 | // spin |
| 181 | // spin | ||
| 182 | } | ||
| 183 | |||
| 184 | // Enable ADC | ||
| 185 | T::regs().isr().modify(|reg| { | ||
| 186 | reg.set_adrdy(true); | ||
| 187 | }); | ||
| 188 | T::regs().cr().modify(|reg| { | ||
| 189 | reg.set_aden(true); | ||
| 190 | }); | ||
| 191 | |||
| 192 | while !T::regs().isr().read().adrdy() { | ||
| 193 | // spin | ||
| 194 | } | ||
| 195 | |||
| 196 | // Configure channel | ||
| 197 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||
| 198 | |||
| 199 | // Select channel | ||
| 200 | #[cfg(not(stm32g0))] | ||
| 201 | T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); | ||
| 202 | #[cfg(stm32g0)] | ||
| 203 | T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); | ||
| 204 | |||
| 205 | // Some models are affected by an erratum: | ||
| 206 | // If we perform conversions slower than 1 kHz, the first read ADC value can be | ||
| 207 | // corrupted, so we discard it and measure again. | ||
| 208 | // | ||
| 209 | // STM32L471xx: Section 2.7.3 | ||
| 210 | // STM32G4: Section 2.7.3 | ||
| 211 | #[cfg(any(rcc_l4, rcc_g4))] | ||
| 212 | let _ = self.convert(); | ||
| 213 | |||
| 214 | let val = self.convert(); | ||
| 215 | |||
| 216 | T::regs().cr().modify(|reg| reg.set_addis(true)); | ||
| 217 | |||
| 218 | val | ||
| 219 | } | 167 | } |
| 168 | |||
| 169 | // Enable ADC | ||
| 170 | T::regs().isr().modify(|reg| { | ||
| 171 | reg.set_adrdy(true); | ||
| 172 | }); | ||
| 173 | T::regs().cr().modify(|reg| { | ||
| 174 | reg.set_aden(true); | ||
| 175 | }); | ||
| 176 | |||
| 177 | while !T::regs().isr().read().adrdy() { | ||
| 178 | // spin | ||
| 179 | } | ||
| 180 | |||
| 181 | // Configure channel | ||
| 182 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||
| 183 | |||
| 184 | // Select channel | ||
| 185 | #[cfg(not(stm32g0))] | ||
| 186 | T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); | ||
| 187 | #[cfg(stm32g0)] | ||
| 188 | T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); | ||
| 189 | |||
| 190 | // Some models are affected by an erratum: | ||
| 191 | // If we perform conversions slower than 1 kHz, the first read ADC value can be | ||
| 192 | // corrupted, so we discard it and measure again. | ||
| 193 | // | ||
| 194 | // STM32L471xx: Section 2.7.3 | ||
| 195 | // STM32G4: Section 2.7.3 | ||
| 196 | #[cfg(any(rcc_l4, rcc_g4))] | ||
| 197 | let _ = self.convert(); | ||
| 198 | |||
| 199 | let val = self.convert(); | ||
| 200 | |||
| 201 | T::regs().cr().modify(|reg| reg.set_addis(true)); | ||
| 202 | |||
| 203 | val | ||
| 220 | } | 204 | } |
| 221 | 205 | ||
| 222 | #[cfg(stm32g0)] | 206 | #[cfg(stm32g0)] |
| 223 | unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { | 207 | fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { |
| 224 | T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); | 208 | T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); |
| 225 | } | 209 | } |
| 226 | 210 | ||
| 227 | #[cfg(not(stm32g0))] | 211 | #[cfg(not(stm32g0))] |
| 228 | unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 212 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| 229 | let sample_time = sample_time.into(); | 213 | let sample_time = sample_time.into(); |
| 230 | if ch <= 9 { | 214 | if ch <= 9 { |
| 231 | T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); | 215 | T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 4707b7c95..c51c6840f 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -46,8 +46,8 @@ foreach_peripheral!( | |||
| 46 | (adc, ADC1) => { | 46 | (adc, ADC1) => { |
| 47 | impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 { | 47 | impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 { |
| 48 | fn frequency() -> crate::time::Hertz { | 48 | fn frequency() -> crate::time::Hertz { |
| 49 | critical_section::with(|_| unsafe { | 49 | critical_section::with(|_| { |
| 50 | match crate::rcc::get_freqs().adc { | 50 | match unsafe { crate::rcc::get_freqs() }.adc { |
| 51 | Some(ck) => ck, | 51 | Some(ck) => ck, |
| 52 | None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") | 52 | None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") |
| 53 | } | 53 | } |
| @@ -55,7 +55,7 @@ foreach_peripheral!( | |||
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | fn enable() { | 57 | fn enable() { |
| 58 | critical_section::with(|_| unsafe { | 58 | critical_section::with(|_| { |
| 59 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) | 59 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) |
| 60 | }); | 60 | }); |
| 61 | ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); | 61 | ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); |
| @@ -63,7 +63,7 @@ foreach_peripheral!( | |||
| 63 | 63 | ||
| 64 | fn disable() { | 64 | fn disable() { |
| 65 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | 65 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { |
| 66 | critical_section::with(|_| unsafe { | 66 | critical_section::with(|_| { |
| 67 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); | 67 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); |
| 68 | }) | 68 | }) |
| 69 | } | 69 | } |
| @@ -72,7 +72,7 @@ foreach_peripheral!( | |||
| 72 | 72 | ||
| 73 | fn reset() { | 73 | fn reset() { |
| 74 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | 74 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { |
| 75 | critical_section::with(|_| unsafe { | 75 | critical_section::with(|_| { |
| 76 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); | 76 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); |
| 77 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); | 77 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); |
| 78 | }); | 78 | }); |
| @@ -85,8 +85,8 @@ foreach_peripheral!( | |||
| 85 | (adc, ADC2) => { | 85 | (adc, ADC2) => { |
| 86 | impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 { | 86 | impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 { |
| 87 | fn frequency() -> crate::time::Hertz { | 87 | fn frequency() -> crate::time::Hertz { |
| 88 | critical_section::with(|_| unsafe { | 88 | critical_section::with(|_| { |
| 89 | match crate::rcc::get_freqs().adc { | 89 | match unsafe { crate::rcc::get_freqs() }.adc { |
| 90 | Some(ck) => ck, | 90 | Some(ck) => ck, |
| 91 | None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") | 91 | None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") |
| 92 | } | 92 | } |
| @@ -94,7 +94,7 @@ foreach_peripheral!( | |||
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | fn enable() { | 96 | fn enable() { |
| 97 | critical_section::with(|_| unsafe { | 97 | critical_section::with(|_| { |
| 98 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) | 98 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) |
| 99 | }); | 99 | }); |
| 100 | ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); | 100 | ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); |
| @@ -102,7 +102,7 @@ foreach_peripheral!( | |||
| 102 | 102 | ||
| 103 | fn disable() { | 103 | fn disable() { |
| 104 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | 104 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { |
| 105 | critical_section::with(|_| unsafe { | 105 | critical_section::with(|_| { |
| 106 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); | 106 | crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); |
| 107 | }) | 107 | }) |
| 108 | } | 108 | } |
| @@ -111,7 +111,7 @@ foreach_peripheral!( | |||
| 111 | 111 | ||
| 112 | fn reset() { | 112 | fn reset() { |
| 113 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { | 113 | if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { |
| 114 | critical_section::with(|_| unsafe { | 114 | critical_section::with(|_| { |
| 115 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); | 115 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); |
| 116 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); | 116 | crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); |
| 117 | }); | 117 | }); |
| @@ -124,8 +124,8 @@ foreach_peripheral!( | |||
| 124 | (adc, ADC3) => { | 124 | (adc, ADC3) => { |
| 125 | impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 { | 125 | impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 { |
| 126 | fn frequency() -> crate::time::Hertz { | 126 | fn frequency() -> crate::time::Hertz { |
| 127 | critical_section::with(|_| unsafe { | 127 | critical_section::with(|_| { |
| 128 | match crate::rcc::get_freqs().adc { | 128 | match unsafe { crate::rcc::get_freqs() }.adc { |
| 129 | Some(ck) => ck, | 129 | Some(ck) => ck, |
| 130 | None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") | 130 | None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") |
| 131 | } | 131 | } |
| @@ -133,22 +133,22 @@ foreach_peripheral!( | |||
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | fn enable() { | 135 | fn enable() { |
| 136 | critical_section::with(|_| unsafe { | 136 | critical_section::with(|_| { |
| 137 | crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true)) | 137 | crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true)) |
| 138 | }); | 138 | }); |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | fn disable() { | 141 | fn disable() { |
| 142 | critical_section::with(|_| unsafe { | 142 | critical_section::with(|_| { |
| 143 | crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false)); | 143 | crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false)); |
| 144 | }) | 144 | }) |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | fn reset() { | 147 | fn reset() { |
| 148 | critical_section::with(|_| unsafe { | 148 | critical_section::with(|_| { |
| 149 | crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true)); | 149 | crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true)); |
| 150 | crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false)); | 150 | crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false)); |
| 151 | }); | 151 | }); |
| 152 | } | 152 | } |
| 153 | } | 153 | } |
| 154 | 154 | ||
| @@ -232,9 +232,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 232 | 232 | ||
| 233 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 233 | let prescaler = Prescaler::from_ker_ck(T::frequency()); |
| 234 | 234 | ||
| 235 | unsafe { | 235 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); |
| 236 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | ||
| 237 | } | ||
| 238 | 236 | ||
| 239 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 237 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); |
| 240 | info!("ADC frequency set to {} Hz", frequency.0); | 238 | info!("ADC frequency set to {} Hz", frequency.0); |
| @@ -251,9 +249,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 251 | } else { | 249 | } else { |
| 252 | Boost::LT50 | 250 | Boost::LT50 |
| 253 | }; | 251 | }; |
| 254 | unsafe { | 252 | T::regs().cr().modify(|w| w.set_boost(boost)); |
| 255 | T::regs().cr().modify(|w| w.set_boost(boost)); | ||
| 256 | } | ||
| 257 | 253 | ||
| 258 | let mut s = Self { | 254 | let mut s = Self { |
| 259 | adc, | 255 | adc, |
| @@ -272,84 +268,68 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 272 | } | 268 | } |
| 273 | 269 | ||
| 274 | fn power_up(&mut self, delay: &mut impl DelayUs<u16>) { | 270 | fn power_up(&mut self, delay: &mut impl DelayUs<u16>) { |
| 275 | unsafe { | 271 | T::regs().cr().modify(|reg| { |
| 276 | T::regs().cr().modify(|reg| { | 272 | reg.set_deeppwd(false); |
| 277 | reg.set_deeppwd(false); | 273 | reg.set_advregen(true); |
| 278 | reg.set_advregen(true); | 274 | }); |
| 279 | }); | ||
| 280 | } | ||
| 281 | 275 | ||
| 282 | delay.delay_us(10); | 276 | delay.delay_us(10); |
| 283 | } | 277 | } |
| 284 | 278 | ||
| 285 | fn configure_differential_inputs(&mut self) { | 279 | fn configure_differential_inputs(&mut self) { |
| 286 | unsafe { | 280 | T::regs().difsel().modify(|w| { |
| 287 | T::regs().difsel().modify(|w| { | 281 | for n in 0..20 { |
| 288 | for n in 0..20 { | 282 | w.set_difsel(n, Difsel::SINGLEENDED); |
| 289 | w.set_difsel(n, Difsel::SINGLEENDED); | 283 | } |
| 290 | } | 284 | }); |
| 291 | }) | ||
| 292 | }; | ||
| 293 | } | 285 | } |
| 294 | 286 | ||
| 295 | fn calibrate(&mut self) { | 287 | fn calibrate(&mut self) { |
| 296 | unsafe { | 288 | T::regs().cr().modify(|w| { |
| 297 | T::regs().cr().modify(|w| { | 289 | w.set_adcaldif(Adcaldif::SINGLEENDED); |
| 298 | w.set_adcaldif(Adcaldif::SINGLEENDED); | 290 | w.set_adcallin(true); |
| 299 | w.set_adcallin(true); | 291 | }); |
| 300 | }); | ||
| 301 | 292 | ||
| 302 | T::regs().cr().modify(|w| w.set_adcal(true)); | 293 | T::regs().cr().modify(|w| w.set_adcal(true)); |
| 303 | 294 | ||
| 304 | while T::regs().cr().read().adcal() {} | 295 | while T::regs().cr().read().adcal() {} |
| 305 | } | ||
| 306 | } | 296 | } |
| 307 | 297 | ||
| 308 | fn enable(&mut self) { | 298 | fn enable(&mut self) { |
| 309 | unsafe { | 299 | T::regs().isr().write(|w| w.set_adrdy(true)); |
| 310 | T::regs().isr().write(|w| w.set_adrdy(true)); | 300 | T::regs().cr().modify(|w| w.set_aden(true)); |
| 311 | T::regs().cr().modify(|w| w.set_aden(true)); | 301 | while !T::regs().isr().read().adrdy() {} |
| 312 | while !T::regs().isr().read().adrdy() {} | 302 | T::regs().isr().write(|w| w.set_adrdy(true)); |
| 313 | T::regs().isr().write(|w| w.set_adrdy(true)); | ||
| 314 | } | ||
| 315 | } | 303 | } |
| 316 | 304 | ||
| 317 | fn configure(&mut self) { | 305 | fn configure(&mut self) { |
| 318 | // single conversion mode, software trigger | 306 | // single conversion mode, software trigger |
| 319 | unsafe { | 307 | T::regs().cfgr().modify(|w| { |
| 320 | T::regs().cfgr().modify(|w| { | 308 | w.set_cont(false); |
| 321 | w.set_cont(false); | 309 | w.set_exten(Exten::DISABLED); |
| 322 | w.set_exten(Exten::DISABLED); | 310 | }); |
| 323 | }) | ||
| 324 | } | ||
| 325 | } | 311 | } |
| 326 | 312 | ||
| 327 | pub fn enable_vrefint(&self) -> VrefInt { | 313 | pub fn enable_vrefint(&self) -> VrefInt { |
| 328 | unsafe { | 314 | T::common_regs().ccr().modify(|reg| { |
| 329 | T::common_regs().ccr().modify(|reg| { | 315 | reg.set_vrefen(true); |
| 330 | reg.set_vrefen(true); | 316 | }); |
| 331 | }); | ||
| 332 | } | ||
| 333 | 317 | ||
| 334 | VrefInt {} | 318 | VrefInt {} |
| 335 | } | 319 | } |
| 336 | 320 | ||
| 337 | pub fn enable_temperature(&self) -> Temperature { | 321 | pub fn enable_temperature(&self) -> Temperature { |
| 338 | unsafe { | 322 | T::common_regs().ccr().modify(|reg| { |
| 339 | T::common_regs().ccr().modify(|reg| { | 323 | reg.set_vsenseen(true); |
| 340 | reg.set_vsenseen(true); | 324 | }); |
| 341 | }); | ||
| 342 | } | ||
| 343 | 325 | ||
| 344 | Temperature {} | 326 | Temperature {} |
| 345 | } | 327 | } |
| 346 | 328 | ||
| 347 | pub fn enable_vbat(&self) -> Vbat { | 329 | pub fn enable_vbat(&self) -> Vbat { |
| 348 | unsafe { | 330 | T::common_regs().ccr().modify(|reg| { |
| 349 | T::common_regs().ccr().modify(|reg| { | 331 | reg.set_vbaten(true); |
| 350 | reg.set_vbaten(true); | 332 | }); |
| 351 | }); | ||
| 352 | } | ||
| 353 | 333 | ||
| 354 | Vbat {} | 334 | Vbat {} |
| 355 | } | 335 | } |
| @@ -359,30 +339,26 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 359 | } | 339 | } |
| 360 | 340 | ||
| 361 | pub fn set_resolution(&mut self, resolution: Resolution) { | 341 | pub fn set_resolution(&mut self, resolution: Resolution) { |
| 362 | unsafe { | 342 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); |
| 363 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||
| 364 | } | ||
| 365 | } | 343 | } |
| 366 | 344 | ||
| 367 | /// Perform a single conversion. | 345 | /// Perform a single conversion. |
| 368 | fn convert(&mut self) -> u16 { | 346 | fn convert(&mut self) -> u16 { |
| 369 | unsafe { | 347 | T::regs().isr().modify(|reg| { |
| 370 | T::regs().isr().modify(|reg| { | 348 | reg.set_eos(true); |
| 371 | reg.set_eos(true); | 349 | reg.set_eoc(true); |
| 372 | reg.set_eoc(true); | 350 | }); |
| 373 | }); | ||
| 374 | |||
| 375 | // Start conversion | ||
| 376 | T::regs().cr().modify(|reg| { | ||
| 377 | reg.set_adstart(true); | ||
| 378 | }); | ||
| 379 | |||
| 380 | while !T::regs().isr().read().eos() { | ||
| 381 | // spin | ||
| 382 | } | ||
| 383 | 351 | ||
| 384 | T::regs().dr().read().0 as u16 | 352 | // Start conversion |
| 353 | T::regs().cr().modify(|reg| { | ||
| 354 | reg.set_adstart(true); | ||
| 355 | }); | ||
| 356 | |||
| 357 | while !T::regs().isr().read().eos() { | ||
| 358 | // spin | ||
| 385 | } | 359 | } |
| 360 | |||
| 361 | T::regs().dr().read().0 as u16 | ||
| 386 | } | 362 | } |
| 387 | 363 | ||
| 388 | pub fn read<P>(&mut self, pin: &mut P) -> u16 | 364 | pub fn read<P>(&mut self, pin: &mut P) -> u16 |
| @@ -390,18 +366,16 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 390 | P: AdcPin<T>, | 366 | P: AdcPin<T>, |
| 391 | P: crate::gpio::sealed::Pin, | 367 | P: crate::gpio::sealed::Pin, |
| 392 | { | 368 | { |
| 393 | unsafe { | 369 | pin.set_as_analog(); |
| 394 | pin.set_as_analog(); | ||
| 395 | 370 | ||
| 396 | self.read_channel(pin.channel()) | 371 | self.read_channel(pin.channel()) |
| 397 | } | ||
| 398 | } | 372 | } |
| 399 | 373 | ||
| 400 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { | 374 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { |
| 401 | unsafe { self.read_channel(channel.channel()) } | 375 | self.read_channel(channel.channel()) |
| 402 | } | 376 | } |
| 403 | 377 | ||
| 404 | unsafe fn read_channel(&mut self, channel: u8) -> u16 { | 378 | fn read_channel(&mut self, channel: u8) -> u16 { |
| 405 | // Configure channel | 379 | // Configure channel |
| 406 | Self::set_channel_sample_time(channel, self.sample_time); | 380 | Self::set_channel_sample_time(channel, self.sample_time); |
| 407 | 381 | ||
| @@ -417,7 +391,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 417 | self.convert() | 391 | self.convert() |
| 418 | } | 392 | } |
| 419 | 393 | ||
| 420 | unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 394 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| 421 | let sample_time = sample_time.into(); | 395 | let sample_time = sample_time.into(); |
| 422 | if ch <= 9 { | 396 | if ch <= 9 { |
| 423 | T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); | 397 | T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); |
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 08ba783ff..9cd40fd8b 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -105,10 +105,8 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 105 | ) -> Self { | 105 | ) -> Self { |
| 106 | into_ref!(peri, rx, tx); | 106 | into_ref!(peri, rx, tx); |
| 107 | 107 | ||
| 108 | unsafe { | 108 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 109 | rx.set_as_af(rx.af_num(), AFType::Input); | 109 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 110 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 111 | } | ||
| 112 | 110 | ||
| 113 | T::enable(); | 111 | T::enable(); |
| 114 | T::reset(); | 112 | T::reset(); |
| @@ -146,6 +144,9 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 146 | T::SCEInterrupt::steal().enable(); | 144 | T::SCEInterrupt::steal().enable(); |
| 147 | } | 145 | } |
| 148 | 146 | ||
| 147 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 148 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 149 | |||
| 149 | let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(); | 150 | let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(); |
| 150 | Self { can } | 151 | Self { can } |
| 151 | } | 152 | } |
| @@ -346,7 +347,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> { | |||
| 346 | fn drop(&mut self) { | 347 | fn drop(&mut self) { |
| 347 | // Cannot call `free()` because it moves the instance. | 348 | // Cannot call `free()` because it moves the instance. |
| 348 | // Manually reset the peripheral. | 349 | // Manually reset the peripheral. |
| 349 | unsafe { T::regs().mcr().write(|w| w.set_reset(true)) } | 350 | T::regs().mcr().write(|w| w.set_reset(true)); |
| 350 | T::disable(); | 351 | T::disable(); |
| 351 | } | 352 | } |
| 352 | } | 353 | } |
| @@ -422,7 +423,7 @@ unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { | |||
| 422 | foreach_peripheral!( | 423 | foreach_peripheral!( |
| 423 | (can, $inst:ident) => { | 424 | (can, $inst:ident) => { |
| 424 | impl sealed::Instance for peripherals::$inst { | 425 | impl sealed::Instance for peripherals::$inst { |
| 425 | const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.0 as *mut _; | 426 | const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; |
| 426 | 427 | ||
| 427 | fn regs() -> &'static crate::pac::can::Can { | 428 | fn regs() -> &'static crate::pac::can::Can { |
| 428 | &crate::pac::$inst | 429 | &crate::pac::$inst |
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index 393089eed..3946a2d47 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs | |||
| @@ -27,26 +27,24 @@ impl<'d> Crc<'d> { | |||
| 27 | 27 | ||
| 28 | /// Resets the CRC unit to default value (0xFFFF_FFFF) | 28 | /// Resets the CRC unit to default value (0xFFFF_FFFF) |
| 29 | pub fn reset(&mut self) { | 29 | pub fn reset(&mut self) { |
| 30 | unsafe { PAC_CRC.cr().write(|w| w.set_reset(true)) }; | 30 | PAC_CRC.cr().write(|w| w.set_reset(true)); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | /// Feeds a word to the peripheral and returns the current CRC value | 33 | /// Feeds a word to the peripheral and returns the current CRC value |
| 34 | pub fn feed_word(&mut self, word: u32) -> u32 { | 34 | pub fn feed_word(&mut self, word: u32) -> u32 { |
| 35 | // write a single byte to the device, and return the result | 35 | // write a single byte to the device, and return the result |
| 36 | unsafe { | 36 | PAC_CRC.dr().write_value(word); |
| 37 | PAC_CRC.dr().write_value(word); | ||
| 38 | } | ||
| 39 | self.read() | 37 | self.read() |
| 40 | } | 38 | } |
| 41 | /// Feed a slice of words to the peripheral and return the result. | 39 | /// Feed a slice of words to the peripheral and return the result. |
| 42 | pub fn feed_words(&mut self, words: &[u32]) -> u32 { | 40 | pub fn feed_words(&mut self, words: &[u32]) -> u32 { |
| 43 | for word in words { | 41 | for word in words { |
| 44 | unsafe { PAC_CRC.dr().write_value(*word) } | 42 | PAC_CRC.dr().write_value(*word); |
| 45 | } | 43 | } |
| 46 | 44 | ||
| 47 | self.read() | 45 | self.read() |
| 48 | } | 46 | } |
| 49 | pub fn read(&self) -> u32 { | 47 | pub fn read(&self) -> u32 { |
| 50 | unsafe { PAC_CRC.dr().read() } | 48 | PAC_CRC.dr().read() |
| 51 | } | 49 | } |
| 52 | } | 50 | } |
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index 8acb3a770..f337055a7 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs | |||
| @@ -85,95 +85,79 @@ impl<'d> Crc<'d> { | |||
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | pub fn reset(&mut self) { | 87 | pub fn reset(&mut self) { |
| 88 | unsafe { | 88 | PAC_CRC.cr().modify(|w| w.set_reset(true)); |
| 89 | PAC_CRC.cr().modify(|w| w.set_reset(true)); | ||
| 90 | } | ||
| 91 | } | 89 | } |
| 92 | 90 | ||
| 93 | /// Reconfigures the CRC peripheral. Doesn't reset. | 91 | /// Reconfigures the CRC peripheral. Doesn't reset. |
| 94 | fn reconfigure(&mut self) { | 92 | fn reconfigure(&mut self) { |
| 95 | unsafe { | 93 | // Init CRC value |
| 96 | // Init CRC value | 94 | PAC_CRC.init().write_value(self._config.crc_init_value); |
| 97 | PAC_CRC.init().write_value(self._config.crc_init_value); | 95 | #[cfg(crc_v3)] |
| 98 | #[cfg(crc_v3)] | 96 | PAC_CRC.pol().write_value(self._config.crc_poly); |
| 99 | PAC_CRC.pol().write_value(self._config.crc_poly); | ||
| 100 | 97 | ||
| 101 | // configure CR components | 98 | // configure CR components |
| 102 | // (reverse I/O, polysize, poly) | 99 | // (reverse I/O, polysize, poly) |
| 103 | PAC_CRC.cr().write(|w| { | 100 | PAC_CRC.cr().write(|w| { |
| 104 | // configure reverse output | 101 | // configure reverse output |
| 105 | w.set_rev_out(match self._config.reverse_out { | 102 | w.set_rev_out(match self._config.reverse_out { |
| 106 | true => vals::RevOut::REVERSED, | 103 | true => vals::RevOut::REVERSED, |
| 107 | false => vals::RevOut::NORMAL, | 104 | false => vals::RevOut::NORMAL, |
| 108 | }); | 105 | }); |
| 109 | // configure reverse input | 106 | // configure reverse input |
| 110 | w.set_rev_in(match self._config.reverse_in { | 107 | w.set_rev_in(match self._config.reverse_in { |
| 111 | InputReverseConfig::None => vals::RevIn::NORMAL, | 108 | InputReverseConfig::None => vals::RevIn::NORMAL, |
| 112 | InputReverseConfig::Byte => vals::RevIn::BYTE, | 109 | InputReverseConfig::Byte => vals::RevIn::BYTE, |
| 113 | InputReverseConfig::Halfword => vals::RevIn::HALFWORD, | 110 | InputReverseConfig::Halfword => vals::RevIn::HALFWORD, |
| 114 | InputReverseConfig::Word => vals::RevIn::WORD, | 111 | InputReverseConfig::Word => vals::RevIn::WORD, |
| 115 | }); | 112 | }); |
| 116 | // configure the polynomial. | 113 | // configure the polynomial. |
| 117 | #[cfg(crc_v3)] | 114 | #[cfg(crc_v3)] |
| 118 | w.set_polysize(match self._config.poly_size { | 115 | w.set_polysize(match self._config.poly_size { |
| 119 | PolySize::Width7 => vals::Polysize::POLYSIZE7, | 116 | PolySize::Width7 => vals::Polysize::POLYSIZE7, |
| 120 | PolySize::Width8 => vals::Polysize::POLYSIZE8, | 117 | PolySize::Width8 => vals::Polysize::POLYSIZE8, |
| 121 | PolySize::Width16 => vals::Polysize::POLYSIZE16, | 118 | PolySize::Width16 => vals::Polysize::POLYSIZE16, |
| 122 | PolySize::Width32 => vals::Polysize::POLYSIZE32, | 119 | PolySize::Width32 => vals::Polysize::POLYSIZE32, |
| 123 | }); | 120 | }); |
| 124 | }) | 121 | }); |
| 125 | } | ||
| 126 | 122 | ||
| 127 | self.reset(); | 123 | self.reset(); |
| 128 | } | 124 | } |
| 129 | 125 | ||
| 130 | /// Feeds a byte into the CRC peripheral. Returns the computed checksum. | 126 | /// Feeds a byte into the CRC peripheral. Returns the computed checksum. |
| 131 | pub fn feed_byte(&mut self, byte: u8) -> u32 { | 127 | pub fn feed_byte(&mut self, byte: u8) -> u32 { |
| 132 | unsafe { | 128 | PAC_CRC.dr8().write_value(byte); |
| 133 | PAC_CRC.dr8().write_value(byte); | 129 | PAC_CRC.dr().read() |
| 134 | PAC_CRC.dr().read() | ||
| 135 | } | ||
| 136 | } | 130 | } |
| 137 | 131 | ||
| 138 | /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. | 132 | /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. |
| 139 | pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 { | 133 | pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 { |
| 140 | for byte in bytes { | 134 | for byte in bytes { |
| 141 | unsafe { | 135 | PAC_CRC.dr8().write_value(*byte); |
| 142 | PAC_CRC.dr8().write_value(*byte); | ||
| 143 | } | ||
| 144 | } | 136 | } |
| 145 | unsafe { PAC_CRC.dr().read() } | 137 | PAC_CRC.dr().read() |
| 146 | } | 138 | } |
| 147 | /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. | 139 | /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. |
| 148 | pub fn feed_halfword(&mut self, halfword: u16) -> u32 { | 140 | pub fn feed_halfword(&mut self, halfword: u16) -> u32 { |
| 149 | unsafe { | 141 | PAC_CRC.dr16().write_value(halfword); |
| 150 | PAC_CRC.dr16().write_value(halfword); | 142 | PAC_CRC.dr().read() |
| 151 | PAC_CRC.dr().read() | ||
| 152 | } | ||
| 153 | } | 143 | } |
| 154 | /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. | 144 | /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. |
| 155 | pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { | 145 | pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { |
| 156 | for halfword in halfwords { | 146 | for halfword in halfwords { |
| 157 | unsafe { | 147 | PAC_CRC.dr16().write_value(*halfword); |
| 158 | PAC_CRC.dr16().write_value(*halfword); | ||
| 159 | } | ||
| 160 | } | 148 | } |
| 161 | unsafe { PAC_CRC.dr().read() } | 149 | PAC_CRC.dr().read() |
| 162 | } | 150 | } |
| 163 | /// Feeds a words into the CRC peripheral. Returns the computed checksum. | 151 | /// Feeds a words into the CRC peripheral. Returns the computed checksum. |
| 164 | pub fn feed_word(&mut self, word: u32) -> u32 { | 152 | pub fn feed_word(&mut self, word: u32) -> u32 { |
| 165 | unsafe { | 153 | PAC_CRC.dr().write_value(word as u32); |
| 166 | PAC_CRC.dr().write_value(word as u32); | 154 | PAC_CRC.dr().read() |
| 167 | PAC_CRC.dr().read() | ||
| 168 | } | ||
| 169 | } | 155 | } |
| 170 | /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. | 156 | /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. |
| 171 | pub fn feed_words(&mut self, words: &[u32]) -> u32 { | 157 | pub fn feed_words(&mut self, words: &[u32]) -> u32 { |
| 172 | for word in words { | 158 | for word in words { |
| 173 | unsafe { | 159 | PAC_CRC.dr().write_value(*word as u32); |
| 174 | PAC_CRC.dr().write_value(*word as u32); | ||
| 175 | } | ||
| 176 | } | 160 | } |
| 177 | unsafe { PAC_CRC.dr().read() } | 161 | PAC_CRC.dr().read() |
| 178 | } | 162 | } |
| 179 | } | 163 | } |
diff --git a/embassy-stm32/src/dac.rs b/embassy-stm32/src/dac.rs index 60e856c78..631118877 100644 --- a/embassy-stm32/src/dac.rs +++ b/embassy-stm32/src/dac.rs | |||
| @@ -121,13 +121,11 @@ impl<'d, T: Instance> Dac<'d, T> { | |||
| 121 | T::enable(); | 121 | T::enable(); |
| 122 | T::reset(); | 122 | T::reset(); |
| 123 | 123 | ||
| 124 | unsafe { | 124 | T::regs().cr().modify(|reg| { |
| 125 | T::regs().cr().modify(|reg| { | 125 | for ch in 0..channels { |
| 126 | for ch in 0..channels { | 126 | reg.set_en(ch as usize, true); |
| 127 | reg.set_en(ch as usize, true); | 127 | } |
| 128 | } | 128 | }); |
| 129 | }); | ||
| 130 | } | ||
| 131 | 129 | ||
| 132 | Self { channels, _peri: peri } | 130 | Self { channels, _peri: peri } |
| 133 | } | 131 | } |
| @@ -143,11 +141,9 @@ impl<'d, T: Instance> Dac<'d, T> { | |||
| 143 | 141 | ||
| 144 | fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { | 142 | fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { |
| 145 | self.check_channel_exists(ch)?; | 143 | self.check_channel_exists(ch)?; |
| 146 | unsafe { | 144 | T::regs().cr().modify(|reg| { |
| 147 | T::regs().cr().modify(|reg| { | 145 | reg.set_en(ch.index(), on); |
| 148 | reg.set_en(ch.index(), on); | 146 | }); |
| 149 | }) | ||
| 150 | } | ||
| 151 | Ok(()) | 147 | Ok(()) |
| 152 | } | 148 | } |
| 153 | 149 | ||
| @@ -162,56 +158,42 @@ impl<'d, T: Instance> Dac<'d, T> { | |||
| 162 | pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { | 158 | pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { |
| 163 | self.check_channel_exists(Channel::Ch1)?; | 159 | self.check_channel_exists(Channel::Ch1)?; |
| 164 | unwrap!(self.disable_channel(Channel::Ch1)); | 160 | unwrap!(self.disable_channel(Channel::Ch1)); |
| 165 | unsafe { | 161 | T::regs().cr().modify(|reg| { |
| 166 | T::regs().cr().modify(|reg| { | 162 | reg.set_tsel1(trigger.tsel()); |
| 167 | reg.set_tsel1(trigger.tsel()); | 163 | }); |
| 168 | }) | ||
| 169 | } | ||
| 170 | Ok(()) | 164 | Ok(()) |
| 171 | } | 165 | } |
| 172 | 166 | ||
| 173 | pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { | 167 | pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { |
| 174 | self.check_channel_exists(Channel::Ch2)?; | 168 | self.check_channel_exists(Channel::Ch2)?; |
| 175 | unwrap!(self.disable_channel(Channel::Ch2)); | 169 | unwrap!(self.disable_channel(Channel::Ch2)); |
| 176 | unsafe { | 170 | T::regs().cr().modify(|reg| { |
| 177 | T::regs().cr().modify(|reg| { | 171 | reg.set_tsel2(trigger.tsel()); |
| 178 | reg.set_tsel2(trigger.tsel()); | 172 | }); |
| 179 | }) | ||
| 180 | } | ||
| 181 | Ok(()) | 173 | Ok(()) |
| 182 | } | 174 | } |
| 183 | 175 | ||
| 184 | pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { | 176 | pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { |
| 185 | self.check_channel_exists(ch)?; | 177 | self.check_channel_exists(ch)?; |
| 186 | unsafe { | 178 | T::regs().swtrigr().write(|reg| { |
| 187 | T::regs().swtrigr().write(|reg| { | 179 | reg.set_swtrig(ch.index(), true); |
| 188 | reg.set_swtrig(ch.index(), true); | 180 | }); |
| 189 | }); | ||
| 190 | } | ||
| 191 | Ok(()) | 181 | Ok(()) |
| 192 | } | 182 | } |
| 193 | 183 | ||
| 194 | pub fn trigger_all(&mut self) { | 184 | pub fn trigger_all(&mut self) { |
| 195 | unsafe { | 185 | T::regs().swtrigr().write(|reg| { |
| 196 | T::regs().swtrigr().write(|reg| { | 186 | reg.set_swtrig(Channel::Ch1.index(), true); |
| 197 | reg.set_swtrig(Channel::Ch1.index(), true); | 187 | reg.set_swtrig(Channel::Ch2.index(), true); |
| 198 | reg.set_swtrig(Channel::Ch2.index(), true); | 188 | }); |
| 199 | }) | ||
| 200 | } | ||
| 201 | } | 189 | } |
| 202 | 190 | ||
| 203 | pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { | 191 | pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { |
| 204 | self.check_channel_exists(ch)?; | 192 | self.check_channel_exists(ch)?; |
| 205 | match value { | 193 | match value { |
| 206 | Value::Bit8(v) => unsafe { | 194 | Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)), |
| 207 | T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)); | 195 | Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)), |
| 208 | }, | 196 | Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)), |
| 209 | Value::Bit12(v, Alignment::Left) => unsafe { | ||
| 210 | T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)); | ||
| 211 | }, | ||
| 212 | Value::Bit12(v, Alignment::Right) => unsafe { | ||
| 213 | T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)); | ||
| 214 | }, | ||
| 215 | } | 197 | } |
| 216 | Ok(()) | 198 | Ok(()) |
| 217 | } | 199 | } |
| @@ -239,20 +221,20 @@ foreach_peripheral!( | |||
| 239 | } | 221 | } |
| 240 | 222 | ||
| 241 | fn reset() { | 223 | fn reset() { |
| 242 | critical_section::with(|_| unsafe { | 224 | critical_section::with(|_| { |
| 243 | crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); | 225 | crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); |
| 244 | crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); | 226 | crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); |
| 245 | }) | 227 | }) |
| 246 | } | 228 | } |
| 247 | 229 | ||
| 248 | fn enable() { | 230 | fn enable() { |
| 249 | critical_section::with(|_| unsafe { | 231 | critical_section::with(|_| { |
| 250 | crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); | 232 | crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); |
| 251 | }) | 233 | }) |
| 252 | } | 234 | } |
| 253 | 235 | ||
| 254 | fn disable() { | 236 | fn disable() { |
| 255 | critical_section::with(|_| unsafe { | 237 | critical_section::with(|_| { |
| 256 | crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)); | 238 | crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)); |
| 257 | }) | 239 | }) |
| 258 | } | 240 | } |
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 5f3fc6a93..78b026cb6 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs | |||
| @@ -8,7 +8,7 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 8 | use crate::dma::Transfer; | 8 | use crate::dma::Transfer; |
| 9 | use crate::gpio::sealed::AFType; | 9 | use crate::gpio::sealed::AFType; |
| 10 | use crate::gpio::Speed; | 10 | use crate::gpio::Speed; |
| 11 | use crate::interrupt::{Interrupt, InterruptExt}; | 11 | use crate::interrupt::typelevel::Interrupt; |
| 12 | use crate::{interrupt, Peripheral}; | 12 | use crate::{interrupt, Peripheral}; |
| 13 | 13 | ||
| 14 | /// Interrupt handler. | 14 | /// Interrupt handler. |
| @@ -16,7 +16,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 16 | _phantom: PhantomData<T>, | 16 | _phantom: PhantomData<T>, |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 19 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 20 | unsafe fn on_interrupt() { | 20 | unsafe fn on_interrupt() { |
| 21 | let ris = crate::pac::DCMI.ris().read(); | 21 | let ris = crate::pac::DCMI.ris().read(); |
| 22 | if ris.err_ris() { | 22 | if ris.err_ris() { |
| @@ -96,8 +96,7 @@ impl Default for Config { | |||
| 96 | macro_rules! config_pins { | 96 | macro_rules! config_pins { |
| 97 | ($($pin:ident),*) => { | 97 | ($($pin:ident),*) => { |
| 98 | into_ref!($($pin),*); | 98 | into_ref!($($pin),*); |
| 99 | // NOTE(unsafe) Exclusive access to the registers | 99 | critical_section::with(|_| { |
| 100 | critical_section::with(|_| unsafe { | ||
| 101 | $( | 100 | $( |
| 102 | $pin.set_as_af($pin.af_num(), AFType::Input); | 101 | $pin.set_as_af($pin.af_num(), AFType::Input); |
| 103 | $pin.set_speed(Speed::VeryHigh); | 102 | $pin.set_speed(Speed::VeryHigh); |
| @@ -119,7 +118,7 @@ where | |||
| 119 | pub fn new_8bit( | 118 | pub fn new_8bit( |
| 120 | peri: impl Peripheral<P = T> + 'd, | 119 | peri: impl Peripheral<P = T> + 'd, |
| 121 | dma: impl Peripheral<P = Dma> + 'd, | 120 | dma: impl Peripheral<P = Dma> + 'd, |
| 122 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 121 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 123 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 122 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| 124 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | 123 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, |
| 125 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | 124 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, |
| @@ -143,7 +142,7 @@ where | |||
| 143 | pub fn new_10bit( | 142 | pub fn new_10bit( |
| 144 | peri: impl Peripheral<P = T> + 'd, | 143 | peri: impl Peripheral<P = T> + 'd, |
| 145 | dma: impl Peripheral<P = Dma> + 'd, | 144 | dma: impl Peripheral<P = Dma> + 'd, |
| 146 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 145 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 147 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 146 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| 148 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | 147 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, |
| 149 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | 148 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, |
| @@ -169,7 +168,7 @@ where | |||
| 169 | pub fn new_12bit( | 168 | pub fn new_12bit( |
| 170 | peri: impl Peripheral<P = T> + 'd, | 169 | peri: impl Peripheral<P = T> + 'd, |
| 171 | dma: impl Peripheral<P = Dma> + 'd, | 170 | dma: impl Peripheral<P = Dma> + 'd, |
| 172 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 171 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 173 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 172 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| 174 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | 173 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, |
| 175 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | 174 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, |
| @@ -197,7 +196,7 @@ where | |||
| 197 | pub fn new_14bit( | 196 | pub fn new_14bit( |
| 198 | peri: impl Peripheral<P = T> + 'd, | 197 | peri: impl Peripheral<P = T> + 'd, |
| 199 | dma: impl Peripheral<P = Dma> + 'd, | 198 | dma: impl Peripheral<P = Dma> + 'd, |
| 200 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 199 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 201 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 200 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| 202 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | 201 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, |
| 203 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | 202 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, |
| @@ -227,7 +226,7 @@ where | |||
| 227 | pub fn new_es_8bit( | 226 | pub fn new_es_8bit( |
| 228 | peri: impl Peripheral<P = T> + 'd, | 227 | peri: impl Peripheral<P = T> + 'd, |
| 229 | dma: impl Peripheral<P = Dma> + 'd, | 228 | dma: impl Peripheral<P = Dma> + 'd, |
| 230 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 229 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 231 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 230 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| 232 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | 231 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, |
| 233 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | 232 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, |
| @@ -249,7 +248,7 @@ where | |||
| 249 | pub fn new_es_10bit( | 248 | pub fn new_es_10bit( |
| 250 | peri: impl Peripheral<P = T> + 'd, | 249 | peri: impl Peripheral<P = T> + 'd, |
| 251 | dma: impl Peripheral<P = Dma> + 'd, | 250 | dma: impl Peripheral<P = Dma> + 'd, |
| 252 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 251 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 253 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 252 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| 254 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | 253 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, |
| 255 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | 254 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, |
| @@ -273,7 +272,7 @@ where | |||
| 273 | pub fn new_es_12bit( | 272 | pub fn new_es_12bit( |
| 274 | peri: impl Peripheral<P = T> + 'd, | 273 | peri: impl Peripheral<P = T> + 'd, |
| 275 | dma: impl Peripheral<P = Dma> + 'd, | 274 | dma: impl Peripheral<P = Dma> + 'd, |
| 276 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 275 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 277 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 276 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| 278 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | 277 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, |
| 279 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | 278 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, |
| @@ -299,7 +298,7 @@ where | |||
| 299 | pub fn new_es_14bit( | 298 | pub fn new_es_14bit( |
| 300 | peri: impl Peripheral<P = T> + 'd, | 299 | peri: impl Peripheral<P = T> + 'd, |
| 301 | dma: impl Peripheral<P = Dma> + 'd, | 300 | dma: impl Peripheral<P = Dma> + 'd, |
| 302 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 301 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 303 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 302 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| 304 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | 303 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, |
| 305 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | 304 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, |
| @@ -334,25 +333,23 @@ where | |||
| 334 | T::reset(); | 333 | T::reset(); |
| 335 | T::enable(); | 334 | T::enable(); |
| 336 | 335 | ||
| 337 | unsafe { | 336 | peri.regs().cr().modify(|r| { |
| 338 | peri.regs().cr().modify(|r| { | 337 | r.set_cm(true); // disable continuous mode (snapshot mode) |
| 339 | r.set_cm(true); // disable continuous mode (snapshot mode) | 338 | r.set_ess(use_embedded_synchronization); |
| 340 | r.set_ess(use_embedded_synchronization); | 339 | r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge); |
| 341 | r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge); | 340 | r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High); |
| 342 | r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High); | 341 | r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High); |
| 343 | r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High); | 342 | r.set_fcrc(0x00); // capture every frame |
| 344 | r.set_fcrc(0x00); // capture every frame | 343 | r.set_edm(edm); // extended data mode |
| 345 | r.set_edm(edm); // extended data mode | 344 | }); |
| 346 | }); | ||
| 347 | } | ||
| 348 | 345 | ||
| 349 | unsafe { T::Interrupt::steal() }.unpend(); | 346 | T::Interrupt::unpend(); |
| 350 | unsafe { T::Interrupt::steal() }.enable(); | 347 | unsafe { T::Interrupt::enable() }; |
| 351 | 348 | ||
| 352 | Self { inner: peri, dma } | 349 | Self { inner: peri, dma } |
| 353 | } | 350 | } |
| 354 | 351 | ||
| 355 | unsafe fn toggle(enable: bool) { | 352 | fn toggle(enable: bool) { |
| 356 | crate::pac::DCMI.cr().modify(|r| { | 353 | crate::pac::DCMI.cr().modify(|r| { |
| 357 | r.set_enable(enable); | 354 | r.set_enable(enable); |
| 358 | r.set_capture(enable); | 355 | r.set_capture(enable); |
| @@ -360,23 +357,19 @@ where | |||
| 360 | } | 357 | } |
| 361 | 358 | ||
| 362 | fn enable_irqs() { | 359 | fn enable_irqs() { |
| 363 | unsafe { | 360 | crate::pac::DCMI.ier().modify(|r| { |
| 364 | crate::pac::DCMI.ier().modify(|r| { | 361 | r.set_err_ie(true); |
| 365 | r.set_err_ie(true); | 362 | r.set_ovr_ie(true); |
| 366 | r.set_ovr_ie(true); | 363 | r.set_frame_ie(true); |
| 367 | r.set_frame_ie(true); | 364 | }); |
| 368 | }); | ||
| 369 | } | ||
| 370 | } | 365 | } |
| 371 | 366 | ||
| 372 | fn clear_interrupt_flags() { | 367 | fn clear_interrupt_flags() { |
| 373 | unsafe { | 368 | crate::pac::DCMI.icr().write(|r| { |
| 374 | crate::pac::DCMI.icr().write(|r| { | 369 | r.set_ovr_isc(true); |
| 375 | r.set_ovr_isc(true); | 370 | r.set_err_isc(true); |
| 376 | r.set_err_isc(true); | 371 | r.set_frame_isc(true); |
| 377 | r.set_frame_isc(true); | 372 | }) |
| 378 | }) | ||
| 379 | } | ||
| 380 | } | 373 | } |
| 381 | 374 | ||
| 382 | /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer. | 375 | /// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer. |
| @@ -392,41 +385,30 @@ where | |||
| 392 | return self.capture_giant(buffer).await; | 385 | return self.capture_giant(buffer).await; |
| 393 | } | 386 | } |
| 394 | } | 387 | } |
| 388 | |||
| 395 | async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> { | 389 | async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> { |
| 396 | let r = self.inner.regs(); | 390 | let r = self.inner.regs(); |
| 397 | let src = r.dr().ptr() as *mut u32; | 391 | let src = r.dr().as_ptr() as *mut u32; |
| 398 | let request = self.dma.request(); | 392 | let request = self.dma.request(); |
| 399 | let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) }; | 393 | let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) }; |
| 400 | 394 | ||
| 401 | Self::clear_interrupt_flags(); | 395 | Self::clear_interrupt_flags(); |
| 402 | Self::enable_irqs(); | 396 | Self::enable_irqs(); |
| 403 | 397 | ||
| 404 | unsafe { Self::toggle(true) }; | 398 | Self::toggle(true); |
| 405 | 399 | ||
| 406 | let result = poll_fn(|cx| { | 400 | let result = poll_fn(|cx| { |
| 407 | STATE.waker.register(cx.waker()); | 401 | STATE.waker.register(cx.waker()); |
| 408 | 402 | ||
| 409 | let ris = unsafe { crate::pac::DCMI.ris().read() }; | 403 | let ris = crate::pac::DCMI.ris().read(); |
| 410 | if ris.err_ris() { | 404 | if ris.err_ris() { |
| 411 | unsafe { | 405 | crate::pac::DCMI.icr().write(|r| r.set_err_isc(true)); |
| 412 | crate::pac::DCMI.icr().write(|r| { | ||
| 413 | r.set_err_isc(true); | ||
| 414 | }) | ||
| 415 | }; | ||
| 416 | Poll::Ready(Err(Error::PeripheralError)) | 406 | Poll::Ready(Err(Error::PeripheralError)) |
| 417 | } else if ris.ovr_ris() { | 407 | } else if ris.ovr_ris() { |
| 418 | unsafe { | 408 | crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true)); |
| 419 | crate::pac::DCMI.icr().write(|r| { | ||
| 420 | r.set_ovr_isc(true); | ||
| 421 | }) | ||
| 422 | }; | ||
| 423 | Poll::Ready(Err(Error::Overrun)) | 409 | Poll::Ready(Err(Error::Overrun)) |
| 424 | } else if ris.frame_ris() { | 410 | } else if ris.frame_ris() { |
| 425 | unsafe { | 411 | crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true)); |
| 426 | crate::pac::DCMI.icr().write(|r| { | ||
| 427 | r.set_frame_isc(true); | ||
| 428 | }) | ||
| 429 | }; | ||
| 430 | Poll::Ready(Ok(())) | 412 | Poll::Ready(Ok(())) |
| 431 | } else { | 413 | } else { |
| 432 | Poll::Pending | 414 | Poll::Pending |
| @@ -435,7 +417,7 @@ where | |||
| 435 | 417 | ||
| 436 | let (_, result) = embassy_futures::join::join(dma_read, result).await; | 418 | let (_, result) = embassy_futures::join::join(dma_read, result).await; |
| 437 | 419 | ||
| 438 | unsafe { Self::toggle(false) }; | 420 | Self::toggle(false); |
| 439 | 421 | ||
| 440 | result | 422 | result |
| 441 | } | 423 | } |
| @@ -468,7 +450,7 @@ where | |||
| 468 | let request = channel.request(); | 450 | let request = channel.request(); |
| 469 | 451 | ||
| 470 | let r = self.inner.regs(); | 452 | let r = self.inner.regs(); |
| 471 | let src = r.dr().ptr() as *mut u32; | 453 | let src = r.dr().as_ptr() as *mut u32; |
| 472 | 454 | ||
| 473 | let mut transfer = unsafe { | 455 | let mut transfer = unsafe { |
| 474 | crate::dma::DoubleBuffered::new_read( | 456 | crate::dma::DoubleBuffered::new_read( |
| @@ -526,38 +508,26 @@ where | |||
| 526 | let result = poll_fn(|cx| { | 508 | let result = poll_fn(|cx| { |
| 527 | STATE.waker.register(cx.waker()); | 509 | STATE.waker.register(cx.waker()); |
| 528 | 510 | ||
| 529 | let ris = unsafe { crate::pac::DCMI.ris().read() }; | 511 | let ris = crate::pac::DCMI.ris().read(); |
| 530 | if ris.err_ris() { | 512 | if ris.err_ris() { |
| 531 | unsafe { | 513 | crate::pac::DCMI.icr().write(|r| r.set_err_isc(true)); |
| 532 | crate::pac::DCMI.icr().write(|r| { | ||
| 533 | r.set_err_isc(true); | ||
| 534 | }) | ||
| 535 | }; | ||
| 536 | Poll::Ready(Err(Error::PeripheralError)) | 514 | Poll::Ready(Err(Error::PeripheralError)) |
| 537 | } else if ris.ovr_ris() { | 515 | } else if ris.ovr_ris() { |
| 538 | unsafe { | 516 | crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true)); |
| 539 | crate::pac::DCMI.icr().write(|r| { | ||
| 540 | r.set_ovr_isc(true); | ||
| 541 | }) | ||
| 542 | }; | ||
| 543 | Poll::Ready(Err(Error::Overrun)) | 517 | Poll::Ready(Err(Error::Overrun)) |
| 544 | } else if ris.frame_ris() { | 518 | } else if ris.frame_ris() { |
| 545 | unsafe { | 519 | crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true)); |
| 546 | crate::pac::DCMI.icr().write(|r| { | ||
| 547 | r.set_frame_isc(true); | ||
| 548 | }) | ||
| 549 | }; | ||
| 550 | Poll::Ready(Ok(())) | 520 | Poll::Ready(Ok(())) |
| 551 | } else { | 521 | } else { |
| 552 | Poll::Pending | 522 | Poll::Pending |
| 553 | } | 523 | } |
| 554 | }); | 524 | }); |
| 555 | 525 | ||
| 556 | unsafe { Self::toggle(true) }; | 526 | Self::toggle(true); |
| 557 | 527 | ||
| 558 | let (_, result) = embassy_futures::join::join(dma_result, result).await; | 528 | let (_, result) = embassy_futures::join::join(dma_result, result).await; |
| 559 | 529 | ||
| 560 | unsafe { Self::toggle(false) }; | 530 | Self::toggle(false); |
| 561 | 531 | ||
| 562 | result | 532 | result |
| 563 | } | 533 | } |
| @@ -570,7 +540,7 @@ mod sealed { | |||
| 570 | } | 540 | } |
| 571 | 541 | ||
| 572 | pub trait Instance: sealed::Instance + 'static { | 542 | pub trait Instance: sealed::Instance + 'static { |
| 573 | type Interrupt: Interrupt; | 543 | type Interrupt: interrupt::typelevel::Interrupt; |
| 574 | } | 544 | } |
| 575 | 545 | ||
| 576 | pin_trait!(D0Pin, Instance); | 546 | pin_trait!(D0Pin, Instance); |
| @@ -602,7 +572,7 @@ macro_rules! impl_peripheral { | |||
| 602 | } | 572 | } |
| 603 | 573 | ||
| 604 | impl Instance for crate::peripherals::$inst { | 574 | impl Instance for crate::peripherals::$inst { |
| 605 | type Interrupt = crate::interrupt::$irq; | 575 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 606 | } | 576 | } |
| 607 | }; | 577 | }; |
| 608 | } | 578 | } |
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 9dafa26d0..a307c803c 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -6,7 +6,6 @@ use core::sync::atomic::{fence, Ordering}; | |||
| 6 | use core::task::{Context, Poll, Waker}; | 6 | use core::task::{Context, Poll, Waker}; |
| 7 | 7 | ||
| 8 | use atomic_polyfill::AtomicUsize; | 8 | use atomic_polyfill::AtomicUsize; |
| 9 | use embassy_cortex_m::interrupt::Priority; | ||
| 10 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
| 11 | use embassy_sync::waitqueue::AtomicWaker; | 10 | use embassy_sync::waitqueue::AtomicWaker; |
| 12 | 11 | ||
| @@ -14,7 +13,8 @@ use super::ringbuffer::{DmaCtrl, DmaRingBuffer, OverrunError}; | |||
| 14 | use super::word::{Word, WordSize}; | 13 | use super::word::{Word, WordSize}; |
| 15 | use super::Dir; | 14 | use super::Dir; |
| 16 | use crate::_generated::BDMA_CHANNEL_COUNT; | 15 | use crate::_generated::BDMA_CHANNEL_COUNT; |
| 17 | use crate::interrupt::{Interrupt, InterruptExt}; | 16 | use crate::interrupt::typelevel::Interrupt; |
| 17 | use crate::interrupt::Priority; | ||
| 18 | use crate::pac; | 18 | use crate::pac; |
| 19 | use crate::pac::bdma::{regs, vals}; | 19 | use crate::pac::bdma::{regs, vals}; |
| 20 | 20 | ||
| @@ -70,9 +70,8 @@ static STATE: State = State::new(); | |||
| 70 | pub(crate) unsafe fn init(irq_priority: Priority) { | 70 | pub(crate) unsafe fn init(irq_priority: Priority) { |
| 71 | foreach_interrupt! { | 71 | foreach_interrupt! { |
| 72 | ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { | 72 | ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { |
| 73 | let irq = crate::interrupt::$irq::steal(); | 73 | crate::interrupt::typelevel::$irq::set_priority(irq_priority); |
| 74 | irq.set_priority(irq_priority); | 74 | crate::interrupt::typelevel::$irq::enable(); |
| 75 | irq.enable(); | ||
| 76 | }; | 75 | }; |
| 77 | } | 76 | } |
| 78 | crate::_generated::init_bdma(); | 77 | crate::_generated::init_bdma(); |
| @@ -108,7 +107,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index | |||
| 108 | let cr = dma.ch(channel_num).cr(); | 107 | let cr = dma.ch(channel_num).cr(); |
| 109 | 108 | ||
| 110 | if isr.teif(channel_num) { | 109 | if isr.teif(channel_num) { |
| 111 | panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num); | 110 | panic!("DMA: error on BDMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num); |
| 112 | } | 111 | } |
| 113 | 112 | ||
| 114 | if isr.htif(channel_num) && cr.read().htie() { | 113 | if isr.htif(channel_num) && cr.read().htie() { |
| @@ -292,29 +291,25 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 292 | } | 291 | } |
| 293 | 292 | ||
| 294 | fn clear_irqs(&mut self) { | 293 | fn clear_irqs(&mut self) { |
| 295 | unsafe { | 294 | self.channel.regs().ifcr().write(|w| { |
| 296 | self.channel.regs().ifcr().write(|w| { | 295 | w.set_tcif(self.channel.num(), true); |
| 297 | w.set_tcif(self.channel.num(), true); | 296 | w.set_teif(self.channel.num(), true); |
| 298 | w.set_teif(self.channel.num(), true); | 297 | }); |
| 299 | }) | ||
| 300 | } | ||
| 301 | } | 298 | } |
| 302 | 299 | ||
| 303 | pub fn request_stop(&mut self) { | 300 | pub fn request_stop(&mut self) { |
| 304 | let ch = self.channel.regs().ch(self.channel.num()); | 301 | let ch = self.channel.regs().ch(self.channel.num()); |
| 305 | 302 | ||
| 306 | // Disable the channel. Keep the IEs enabled so the irqs still fire. | 303 | // Disable the channel. Keep the IEs enabled so the irqs still fire. |
| 307 | unsafe { | 304 | ch.cr().write(|w| { |
| 308 | ch.cr().write(|w| { | 305 | w.set_teie(true); |
| 309 | w.set_teie(true); | 306 | w.set_tcie(true); |
| 310 | w.set_tcie(true); | 307 | }); |
| 311 | }) | ||
| 312 | } | ||
| 313 | } | 308 | } |
| 314 | 309 | ||
| 315 | pub fn is_running(&mut self) -> bool { | 310 | pub fn is_running(&mut self) -> bool { |
| 316 | let ch = self.channel.regs().ch(self.channel.num()); | 311 | let ch = self.channel.regs().ch(self.channel.num()); |
| 317 | let en = unsafe { ch.cr().read() }.en(); | 312 | let en = ch.cr().read().en(); |
| 318 | let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; | 313 | let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; |
| 319 | en && !tcif | 314 | en && !tcif |
| 320 | } | 315 | } |
| @@ -323,11 +318,12 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 323 | /// Note: this will be zero for transfers that completed without cancellation. | 318 | /// Note: this will be zero for transfers that completed without cancellation. |
| 324 | pub fn get_remaining_transfers(&self) -> u16 { | 319 | pub fn get_remaining_transfers(&self) -> u16 { |
| 325 | let ch = self.channel.regs().ch(self.channel.num()); | 320 | let ch = self.channel.regs().ch(self.channel.num()); |
| 326 | unsafe { ch.ndtr().read() }.ndt() | 321 | ch.ndtr().read().ndt() |
| 327 | } | 322 | } |
| 328 | 323 | ||
| 329 | pub fn blocking_wait(mut self) { | 324 | pub fn blocking_wait(mut self) { |
| 330 | while self.is_running() {} | 325 | while self.is_running() {} |
| 326 | self.request_stop(); | ||
| 331 | 327 | ||
| 332 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | 328 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." |
| 333 | fence(Ordering::SeqCst); | 329 | fence(Ordering::SeqCst); |
| @@ -367,7 +363,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>); | |||
| 367 | impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { | 363 | impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { |
| 368 | fn get_remaining_transfers(&self) -> usize { | 364 | fn get_remaining_transfers(&self) -> usize { |
| 369 | let ch = self.0.regs().ch(self.0.num()); | 365 | let ch = self.0.regs().ch(self.0.num()); |
| 370 | unsafe { ch.ndtr().read() }.ndt() as usize | 366 | ch.ndtr().read().ndt() as usize |
| 371 | } | 367 | } |
| 372 | 368 | ||
| 373 | fn get_complete_count(&self) -> usize { | 369 | fn get_complete_count(&self) -> usize { |
| @@ -443,7 +439,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> { | |||
| 443 | 439 | ||
| 444 | pub fn start(&mut self) { | 440 | pub fn start(&mut self) { |
| 445 | let ch = self.channel.regs().ch(self.channel.num()); | 441 | let ch = self.channel.regs().ch(self.channel.num()); |
| 446 | unsafe { ch.cr().write_value(self.cr) } | 442 | ch.cr().write_value(self.cr) |
| 447 | } | 443 | } |
| 448 | 444 | ||
| 449 | pub fn clear(&mut self) { | 445 | pub fn clear(&mut self) { |
| @@ -470,31 +466,27 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> { | |||
| 470 | 466 | ||
| 471 | fn clear_irqs(&mut self) { | 467 | fn clear_irqs(&mut self) { |
| 472 | let dma = self.channel.regs(); | 468 | let dma = self.channel.regs(); |
| 473 | unsafe { | 469 | dma.ifcr().write(|w| { |
| 474 | dma.ifcr().write(|w| { | 470 | w.set_htif(self.channel.num(), true); |
| 475 | w.set_htif(self.channel.num(), true); | 471 | w.set_tcif(self.channel.num(), true); |
| 476 | w.set_tcif(self.channel.num(), true); | 472 | w.set_teif(self.channel.num(), true); |
| 477 | w.set_teif(self.channel.num(), true); | 473 | }); |
| 478 | }) | ||
| 479 | } | ||
| 480 | } | 474 | } |
| 481 | 475 | ||
| 482 | pub fn request_stop(&mut self) { | 476 | pub fn request_stop(&mut self) { |
| 483 | let ch = self.channel.regs().ch(self.channel.num()); | 477 | let ch = self.channel.regs().ch(self.channel.num()); |
| 484 | 478 | ||
| 485 | // Disable the channel. Keep the IEs enabled so the irqs still fire. | 479 | // Disable the channel. Keep the IEs enabled so the irqs still fire. |
| 486 | unsafe { | 480 | ch.cr().write(|w| { |
| 487 | ch.cr().write(|w| { | 481 | w.set_teie(true); |
| 488 | w.set_teie(true); | 482 | w.set_htie(true); |
| 489 | w.set_htie(true); | 483 | w.set_tcie(true); |
| 490 | w.set_tcie(true); | 484 | }); |
| 491 | }) | ||
| 492 | } | ||
| 493 | } | 485 | } |
| 494 | 486 | ||
| 495 | pub fn is_running(&mut self) -> bool { | 487 | pub fn is_running(&mut self) -> bool { |
| 496 | let ch = self.channel.regs().ch(self.channel.num()); | 488 | let ch = self.channel.regs().ch(self.channel.num()); |
| 497 | unsafe { ch.cr().read() }.en() | 489 | ch.cr().read().en() |
| 498 | } | 490 | } |
| 499 | } | 491 | } |
| 500 | 492 | ||
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 47b749ece..8abe541d3 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -5,7 +5,6 @@ use core::sync::atomic::{fence, Ordering}; | |||
| 5 | use core::task::{Context, Poll, Waker}; | 5 | use core::task::{Context, Poll, Waker}; |
| 6 | 6 | ||
| 7 | use atomic_polyfill::AtomicUsize; | 7 | use atomic_polyfill::AtomicUsize; |
| 8 | use embassy_cortex_m::interrupt::Priority; | ||
| 9 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 8 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 11 | 10 | ||
| @@ -13,7 +12,8 @@ use super::ringbuffer::{DmaCtrl, DmaRingBuffer, OverrunError}; | |||
| 13 | use super::word::{Word, WordSize}; | 12 | use super::word::{Word, WordSize}; |
| 14 | use super::Dir; | 13 | use super::Dir; |
| 15 | use crate::_generated::DMA_CHANNEL_COUNT; | 14 | use crate::_generated::DMA_CHANNEL_COUNT; |
| 16 | use crate::interrupt::{Interrupt, InterruptExt}; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 16 | use crate::interrupt::Priority; | ||
| 17 | use crate::pac::dma::{regs, vals}; | 17 | use crate::pac::dma::{regs, vals}; |
| 18 | use crate::{interrupt, pac}; | 18 | use crate::{interrupt, pac}; |
| 19 | 19 | ||
| @@ -149,9 +149,8 @@ static STATE: State = State::new(); | |||
| 149 | pub(crate) unsafe fn init(irq_priority: Priority) { | 149 | pub(crate) unsafe fn init(irq_priority: Priority) { |
| 150 | foreach_interrupt! { | 150 | foreach_interrupt! { |
| 151 | ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { | 151 | ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { |
| 152 | let irq = interrupt::$irq::steal(); | 152 | interrupt::typelevel::$irq::set_priority(irq_priority); |
| 153 | irq.set_priority(irq_priority); | 153 | interrupt::typelevel::$irq::enable(); |
| 154 | irq.enable(); | ||
| 155 | }; | 154 | }; |
| 156 | } | 155 | } |
| 157 | crate::_generated::init_dma(); | 156 | crate::_generated::init_dma(); |
| @@ -184,7 +183,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index: | |||
| 184 | let isr = dma.isr(channel_num / 4).read(); | 183 | let isr = dma.isr(channel_num / 4).read(); |
| 185 | 184 | ||
| 186 | if isr.teif(channel_num % 4) { | 185 | if isr.teif(channel_num % 4) { |
| 187 | panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num); | 186 | panic!("DMA: error on DMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num); |
| 188 | } | 187 | } |
| 189 | 188 | ||
| 190 | if isr.htif(channel_num % 4) && cr.read().htie() { | 189 | if isr.htif(channel_num % 4) && cr.read().htie() { |
| @@ -388,36 +387,32 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 388 | let isrn = self.channel.num() / 4; | 387 | let isrn = self.channel.num() / 4; |
| 389 | let isrbit = self.channel.num() % 4; | 388 | let isrbit = self.channel.num() % 4; |
| 390 | 389 | ||
| 391 | unsafe { | 390 | self.channel.regs().ifcr(isrn).write(|w| { |
| 392 | self.channel.regs().ifcr(isrn).write(|w| { | 391 | w.set_tcif(isrbit, true); |
| 393 | w.set_tcif(isrbit, true); | 392 | w.set_teif(isrbit, true); |
| 394 | w.set_teif(isrbit, true); | 393 | }); |
| 395 | }) | ||
| 396 | } | ||
| 397 | } | 394 | } |
| 398 | 395 | ||
| 399 | pub fn request_stop(&mut self) { | 396 | pub fn request_stop(&mut self) { |
| 400 | let ch = self.channel.regs().st(self.channel.num()); | 397 | let ch = self.channel.regs().st(self.channel.num()); |
| 401 | 398 | ||
| 402 | // Disable the channel. Keep the IEs enabled so the irqs still fire. | 399 | // Disable the channel. Keep the IEs enabled so the irqs still fire. |
| 403 | unsafe { | 400 | ch.cr().write(|w| { |
| 404 | ch.cr().write(|w| { | 401 | w.set_teie(true); |
| 405 | w.set_teie(true); | 402 | w.set_tcie(true); |
| 406 | w.set_tcie(true); | 403 | }); |
| 407 | }) | ||
| 408 | } | ||
| 409 | } | 404 | } |
| 410 | 405 | ||
| 411 | pub fn is_running(&mut self) -> bool { | 406 | pub fn is_running(&mut self) -> bool { |
| 412 | let ch = self.channel.regs().st(self.channel.num()); | 407 | let ch = self.channel.regs().st(self.channel.num()); |
| 413 | unsafe { ch.cr().read() }.en() | 408 | ch.cr().read().en() |
| 414 | } | 409 | } |
| 415 | 410 | ||
| 416 | /// Gets the total remaining transfers for the channel | 411 | /// Gets the total remaining transfers for the channel |
| 417 | /// Note: this will be zero for transfers that completed without cancellation. | 412 | /// Note: this will be zero for transfers that completed without cancellation. |
| 418 | pub fn get_remaining_transfers(&self) -> u16 { | 413 | pub fn get_remaining_transfers(&self) -> u16 { |
| 419 | let ch = self.channel.regs().st(self.channel.num()); | 414 | let ch = self.channel.regs().st(self.channel.num()); |
| 420 | unsafe { ch.ndtr().read() }.ndt() | 415 | ch.ndtr().read().ndt() |
| 421 | } | 416 | } |
| 422 | 417 | ||
| 423 | pub fn blocking_wait(mut self) { | 418 | pub fn blocking_wait(mut self) { |
| @@ -538,13 +533,11 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | |||
| 538 | let isrn = channel_number / 4; | 533 | let isrn = channel_number / 4; |
| 539 | let isrbit = channel_number % 4; | 534 | let isrbit = channel_number % 4; |
| 540 | 535 | ||
| 541 | unsafe { | 536 | dma.ifcr(isrn).write(|w| { |
| 542 | dma.ifcr(isrn).write(|w| { | 537 | w.set_htif(isrbit, true); |
| 543 | w.set_htif(isrbit, true); | 538 | w.set_tcif(isrbit, true); |
| 544 | w.set_tcif(isrbit, true); | 539 | w.set_teif(isrbit, true); |
| 545 | w.set_teif(isrbit, true); | 540 | }); |
| 546 | }) | ||
| 547 | } | ||
| 548 | } | 541 | } |
| 549 | 542 | ||
| 550 | pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { | 543 | pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { |
| @@ -559,7 +552,7 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | |||
| 559 | 552 | ||
| 560 | pub fn is_buffer0_accessible(&mut self) -> bool { | 553 | pub fn is_buffer0_accessible(&mut self) -> bool { |
| 561 | let ch = self.channel.regs().st(self.channel.num()); | 554 | let ch = self.channel.regs().st(self.channel.num()); |
| 562 | unsafe { ch.cr().read() }.ct() == vals::Ct::MEMORY1 | 555 | ch.cr().read().ct() == vals::Ct::MEMORY1 |
| 563 | } | 556 | } |
| 564 | 557 | ||
| 565 | pub fn set_waker(&mut self, waker: &Waker) { | 558 | pub fn set_waker(&mut self, waker: &Waker) { |
| @@ -570,24 +563,22 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | |||
| 570 | let ch = self.channel.regs().st(self.channel.num()); | 563 | let ch = self.channel.regs().st(self.channel.num()); |
| 571 | 564 | ||
| 572 | // Disable the channel. Keep the IEs enabled so the irqs still fire. | 565 | // Disable the channel. Keep the IEs enabled so the irqs still fire. |
| 573 | unsafe { | 566 | ch.cr().write(|w| { |
| 574 | ch.cr().write(|w| { | 567 | w.set_teie(true); |
| 575 | w.set_teie(true); | 568 | w.set_tcie(true); |
| 576 | w.set_tcie(true); | 569 | }); |
| 577 | }) | ||
| 578 | } | ||
| 579 | } | 570 | } |
| 580 | 571 | ||
| 581 | pub fn is_running(&mut self) -> bool { | 572 | pub fn is_running(&mut self) -> bool { |
| 582 | let ch = self.channel.regs().st(self.channel.num()); | 573 | let ch = self.channel.regs().st(self.channel.num()); |
| 583 | unsafe { ch.cr().read() }.en() | 574 | ch.cr().read().en() |
| 584 | } | 575 | } |
| 585 | 576 | ||
| 586 | /// Gets the total remaining transfers for the channel | 577 | /// Gets the total remaining transfers for the channel |
| 587 | /// Note: this will be zero for transfers that completed without cancellation. | 578 | /// Note: this will be zero for transfers that completed without cancellation. |
| 588 | pub fn get_remaining_transfers(&self) -> u16 { | 579 | pub fn get_remaining_transfers(&self) -> u16 { |
| 589 | let ch = self.channel.regs().st(self.channel.num()); | 580 | let ch = self.channel.regs().st(self.channel.num()); |
| 590 | unsafe { ch.ndtr().read() }.ndt() | 581 | ch.ndtr().read().ndt() |
| 591 | } | 582 | } |
| 592 | } | 583 | } |
| 593 | 584 | ||
| @@ -608,7 +599,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>); | |||
| 608 | impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { | 599 | impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { |
| 609 | fn get_remaining_transfers(&self) -> usize { | 600 | fn get_remaining_transfers(&self) -> usize { |
| 610 | let ch = self.0.regs().st(self.0.num()); | 601 | let ch = self.0.regs().st(self.0.num()); |
| 611 | unsafe { ch.ndtr().read() }.ndt() as usize | 602 | ch.ndtr().read().ndt() as usize |
| 612 | } | 603 | } |
| 613 | 604 | ||
| 614 | fn get_complete_count(&self) -> usize { | 605 | fn get_complete_count(&self) -> usize { |
| @@ -699,7 +690,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> { | |||
| 699 | 690 | ||
| 700 | pub fn start(&mut self) { | 691 | pub fn start(&mut self) { |
| 701 | let ch = self.channel.regs().st(self.channel.num()); | 692 | let ch = self.channel.regs().st(self.channel.num()); |
| 702 | unsafe { ch.cr().write_value(self.cr) } | 693 | ch.cr().write_value(self.cr); |
| 703 | } | 694 | } |
| 704 | 695 | ||
| 705 | pub fn clear(&mut self) { | 696 | pub fn clear(&mut self) { |
| @@ -730,31 +721,27 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> { | |||
| 730 | let isrn = channel_number / 4; | 721 | let isrn = channel_number / 4; |
| 731 | let isrbit = channel_number % 4; | 722 | let isrbit = channel_number % 4; |
| 732 | 723 | ||
| 733 | unsafe { | 724 | dma.ifcr(isrn).write(|w| { |
| 734 | dma.ifcr(isrn).write(|w| { | 725 | w.set_htif(isrbit, true); |
| 735 | w.set_htif(isrbit, true); | 726 | w.set_tcif(isrbit, true); |
| 736 | w.set_tcif(isrbit, true); | 727 | w.set_teif(isrbit, true); |
| 737 | w.set_teif(isrbit, true); | 728 | }); |
| 738 | }) | ||
| 739 | } | ||
| 740 | } | 729 | } |
| 741 | 730 | ||
| 742 | pub fn request_stop(&mut self) { | 731 | pub fn request_stop(&mut self) { |
| 743 | let ch = self.channel.regs().st(self.channel.num()); | 732 | let ch = self.channel.regs().st(self.channel.num()); |
| 744 | 733 | ||
| 745 | // Disable the channel. Keep the IEs enabled so the irqs still fire. | 734 | // Disable the channel. Keep the IEs enabled so the irqs still fire. |
| 746 | unsafe { | 735 | ch.cr().write(|w| { |
| 747 | ch.cr().write(|w| { | 736 | w.set_teie(true); |
| 748 | w.set_teie(true); | 737 | w.set_htie(true); |
| 749 | w.set_htie(true); | 738 | w.set_tcie(true); |
| 750 | w.set_tcie(true); | 739 | }); |
| 751 | }) | ||
| 752 | } | ||
| 753 | } | 740 | } |
| 754 | 741 | ||
| 755 | pub fn is_running(&mut self) -> bool { | 742 | pub fn is_running(&mut self) -> bool { |
| 756 | let ch = self.channel.regs().st(self.channel.num()); | 743 | let ch = self.channel.regs().st(self.channel.num()); |
| 757 | unsafe { ch.cr().read() }.en() | 744 | ch.cr().read().en() |
| 758 | } | 745 | } |
| 759 | } | 746 | } |
| 760 | 747 | ||
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index a8c4c5827..36fc03403 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | use crate::{pac, peripherals}; | 3 | use crate::{pac, peripherals}; |
| 4 | 4 | ||
| 5 | pub(crate) unsafe fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) { | 5 | pub(crate) fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) { |
| 6 | let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); | 6 | let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num()); |
| 7 | ch_mux_regs.write(|reg| { | 7 | ch_mux_regs.write(|reg| { |
| 8 | reg.set_nbreq(0); | 8 | reg.set_nbreq(0); |
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 5a516ccda..c600df92d 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs | |||
| @@ -5,14 +5,14 @@ use core::pin::Pin; | |||
| 5 | use core::sync::atomic::{fence, Ordering}; | 5 | use core::sync::atomic::{fence, Ordering}; |
| 6 | use core::task::{Context, Poll}; | 6 | use core::task::{Context, Poll}; |
| 7 | 7 | ||
| 8 | use embassy_cortex_m::interrupt::Priority; | ||
| 9 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 8 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 11 | 10 | ||
| 12 | use super::word::{Word, WordSize}; | 11 | use super::word::{Word, WordSize}; |
| 13 | use super::Dir; | 12 | use super::Dir; |
| 14 | use crate::_generated::GPDMA_CHANNEL_COUNT; | 13 | use crate::_generated::GPDMA_CHANNEL_COUNT; |
| 15 | use crate::interrupt::{Interrupt, InterruptExt}; | 14 | use crate::interrupt::typelevel::Interrupt; |
| 15 | use crate::interrupt::Priority; | ||
| 16 | use crate::pac; | 16 | use crate::pac; |
| 17 | use crate::pac::gpdma::vals; | 17 | use crate::pac::gpdma::vals; |
| 18 | 18 | ||
| @@ -56,9 +56,8 @@ static STATE: State = State::new(); | |||
| 56 | pub(crate) unsafe fn init(irq_priority: Priority) { | 56 | pub(crate) unsafe fn init(irq_priority: Priority) { |
| 57 | foreach_interrupt! { | 57 | foreach_interrupt! { |
| 58 | ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { | 58 | ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { |
| 59 | let irq = crate::interrupt::$irq::steal(); | 59 | crate::interrupt::typelevel::$irq::set_priority(irq_priority); |
| 60 | irq.set_priority(irq_priority); | 60 | crate::interrupt::typelevel::$irq::enable(); |
| 61 | irq.enable(); | ||
| 62 | }; | 61 | }; |
| 63 | } | 62 | } |
| 64 | crate::_generated::init_gpdma(); | 63 | crate::_generated::init_gpdma(); |
| @@ -93,13 +92,15 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in | |||
| 93 | if sr.dtef() { | 92 | if sr.dtef() { |
| 94 | panic!( | 93 | panic!( |
| 95 | "DMA: data transfer error on DMA@{:08x} channel {}", | 94 | "DMA: data transfer error on DMA@{:08x} channel {}", |
| 96 | dma.0 as u32, channel_num | 95 | dma.as_ptr() as u32, |
| 96 | channel_num | ||
| 97 | ); | 97 | ); |
| 98 | } | 98 | } |
| 99 | if sr.usef() { | 99 | if sr.usef() { |
| 100 | panic!( | 100 | panic!( |
| 101 | "DMA: user settings error on DMA@{:08x} channel {}", | 101 | "DMA: user settings error on DMA@{:08x} channel {}", |
| 102 | dma.0 as u32, channel_num | 102 | dma.as_ptr() as u32, |
| 103 | channel_num | ||
| 103 | ); | 104 | ); |
| 104 | } | 105 | } |
| 105 | 106 | ||
| @@ -299,26 +300,24 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 299 | let ch = self.channel.regs().ch(self.channel.num()); | 300 | let ch = self.channel.regs().ch(self.channel.num()); |
| 300 | 301 | ||
| 301 | // Disable the channel. Keep the IEs enabled so the irqs still fire. | 302 | // Disable the channel. Keep the IEs enabled so the irqs still fire. |
| 302 | unsafe { | 303 | ch.cr().write(|w| { |
| 303 | ch.cr().write(|w| { | 304 | w.set_tcie(true); |
| 304 | w.set_tcie(true); | 305 | w.set_useie(true); |
| 305 | w.set_useie(true); | 306 | w.set_dteie(true); |
| 306 | w.set_dteie(true); | 307 | w.set_suspie(true); |
| 307 | w.set_suspie(true); | 308 | }) |
| 308 | }) | ||
| 309 | } | ||
| 310 | } | 309 | } |
| 311 | 310 | ||
| 312 | pub fn is_running(&mut self) -> bool { | 311 | pub fn is_running(&mut self) -> bool { |
| 313 | let ch = self.channel.regs().ch(self.channel.num()); | 312 | let ch = self.channel.regs().ch(self.channel.num()); |
| 314 | !unsafe { ch.sr().read() }.tcf() | 313 | !ch.sr().read().tcf() |
| 315 | } | 314 | } |
| 316 | 315 | ||
| 317 | /// Gets the total remaining transfers for the channel | 316 | /// Gets the total remaining transfers for the channel |
| 318 | /// Note: this will be zero for transfers that completed without cancellation. | 317 | /// Note: this will be zero for transfers that completed without cancellation. |
| 319 | pub fn get_remaining_transfers(&self) -> u16 { | 318 | pub fn get_remaining_transfers(&self) -> u16 { |
| 320 | let ch = self.channel.regs().ch(self.channel.num()); | 319 | let ch = self.channel.regs().ch(self.channel.num()); |
| 321 | unsafe { ch.br1().read() }.bndt() | 320 | ch.br1().read().bndt() |
| 322 | } | 321 | } |
| 323 | 322 | ||
| 324 | pub fn blocking_wait(mut self) { | 323 | pub fn blocking_wait(mut self) { |
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 3ac0d1b3d..0858587bd 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -26,11 +26,11 @@ pub mod word; | |||
| 26 | 26 | ||
| 27 | use core::mem; | 27 | use core::mem; |
| 28 | 28 | ||
| 29 | use embassy_cortex_m::interrupt::Priority; | ||
| 30 | use embassy_hal_common::impl_peripheral; | 29 | use embassy_hal_common::impl_peripheral; |
| 31 | 30 | ||
| 32 | #[cfg(dmamux)] | 31 | #[cfg(dmamux)] |
| 33 | pub use self::dmamux::*; | 32 | pub use self::dmamux::*; |
| 33 | use crate::interrupt::Priority; | ||
| 34 | 34 | ||
| 35 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 35 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 36 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 36 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 8ef2c3584..b53c2d0fa 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs | |||
| @@ -5,7 +5,6 @@ mod tx_desc; | |||
| 5 | 5 | ||
| 6 | use core::sync::atomic::{fence, Ordering}; | 6 | use core::sync::atomic::{fence, Ordering}; |
| 7 | 7 | ||
| 8 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 9 | use embassy_hal_common::{into_ref, PeripheralRef}; | 8 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 10 | use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; | 9 | use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; |
| 11 | 10 | ||
| @@ -14,6 +13,7 @@ pub(crate) use self::tx_desc::{TDes, TDesRing}; | |||
| 14 | use super::*; | 13 | use super::*; |
| 15 | use crate::gpio::sealed::{AFType, Pin as __GpioPin}; | 14 | use crate::gpio::sealed::{AFType, Pin as __GpioPin}; |
| 16 | use crate::gpio::AnyPin; | 15 | use crate::gpio::AnyPin; |
| 16 | use crate::interrupt::InterruptExt; | ||
| 17 | #[cfg(eth_v1a)] | 17 | #[cfg(eth_v1a)] |
| 18 | use crate::pac::AFIO; | 18 | use crate::pac::AFIO; |
| 19 | #[cfg(any(eth_v1b, eth_v1c))] | 19 | #[cfg(any(eth_v1b, eth_v1c))] |
| @@ -24,23 +24,21 @@ use crate::{interrupt, Peripheral}; | |||
| 24 | /// Interrupt handler. | 24 | /// Interrupt handler. |
| 25 | pub struct InterruptHandler {} | 25 | pub struct InterruptHandler {} |
| 26 | 26 | ||
| 27 | impl interrupt::Handler<interrupt::ETH> for InterruptHandler { | 27 | impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandler { |
| 28 | unsafe fn on_interrupt() { | 28 | unsafe fn on_interrupt() { |
| 29 | WAKER.wake(); | 29 | WAKER.wake(); |
| 30 | 30 | ||
| 31 | // TODO: Check and clear more flags | 31 | // TODO: Check and clear more flags |
| 32 | unsafe { | 32 | let dma = ETH.ethernet_dma(); |
| 33 | let dma = ETH.ethernet_dma(); | 33 | |
| 34 | 34 | dma.dmasr().modify(|w| { | |
| 35 | dma.dmasr().modify(|w| { | 35 | w.set_ts(true); |
| 36 | w.set_ts(true); | 36 | w.set_rs(true); |
| 37 | w.set_rs(true); | 37 | w.set_nis(true); |
| 38 | w.set_nis(true); | 38 | }); |
| 39 | }); | 39 | // Delay two peripheral's clock |
| 40 | // Delay two peripheral's clock | 40 | dma.dmasr().read(); |
| 41 | dma.dmasr().read(); | 41 | dma.dmasr().read(); |
| 42 | dma.dmasr().read(); | ||
| 43 | } | ||
| 44 | } | 42 | } |
| 45 | } | 43 | } |
| 46 | 44 | ||
| @@ -59,7 +57,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> { | |||
| 59 | #[cfg(eth_v1a)] | 57 | #[cfg(eth_v1a)] |
| 60 | macro_rules! config_in_pins { | 58 | macro_rules! config_in_pins { |
| 61 | ($($pin:ident),*) => { | 59 | ($($pin:ident),*) => { |
| 62 | // NOTE(unsafe) Exclusive access to the registers | ||
| 63 | critical_section::with(|_| { | 60 | critical_section::with(|_| { |
| 64 | $( | 61 | $( |
| 65 | // TODO properly create a set_as_input function | 62 | // TODO properly create a set_as_input function |
| @@ -72,7 +69,6 @@ macro_rules! config_in_pins { | |||
| 72 | #[cfg(eth_v1a)] | 69 | #[cfg(eth_v1a)] |
| 73 | macro_rules! config_af_pins { | 70 | macro_rules! config_af_pins { |
| 74 | ($($pin:ident),*) => { | 71 | ($($pin:ident),*) => { |
| 75 | // NOTE(unsafe) Exclusive access to the registers | ||
| 76 | critical_section::with(|_| { | 72 | critical_section::with(|_| { |
| 77 | $( | 73 | $( |
| 78 | // We are lucky here, this configures to max speed (50MHz) | 74 | // We are lucky here, this configures to max speed (50MHz) |
| @@ -85,7 +81,6 @@ macro_rules! config_af_pins { | |||
| 85 | #[cfg(any(eth_v1b, eth_v1c))] | 81 | #[cfg(any(eth_v1b, eth_v1c))] |
| 86 | macro_rules! config_pins { | 82 | macro_rules! config_pins { |
| 87 | ($($pin:ident),*) => { | 83 | ($($pin:ident),*) => { |
| 88 | // NOTE(unsafe) Exclusive access to the registers | ||
| 89 | critical_section::with(|_| { | 84 | critical_section::with(|_| { |
| 90 | $( | 85 | $( |
| 91 | $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); | 86 | $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); |
| @@ -100,7 +95,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 100 | pub fn new<const TX: usize, const RX: usize>( | 95 | pub fn new<const TX: usize, const RX: usize>( |
| 101 | queue: &'d mut PacketQueue<TX, RX>, | 96 | queue: &'d mut PacketQueue<TX, RX>, |
| 102 | peri: impl Peripheral<P = T> + 'd, | 97 | peri: impl Peripheral<P = T> + 'd, |
| 103 | _irq: impl interrupt::Binding<interrupt::ETH, InterruptHandler> + 'd, | 98 | _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, |
| 104 | ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, | 99 | ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, |
| 105 | mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, | 100 | mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, |
| 106 | mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, | 101 | mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, |
| @@ -116,222 +111,208 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 116 | ) -> Self { | 111 | ) -> Self { |
| 117 | into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | 112 | into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); |
| 118 | 113 | ||
| 119 | unsafe { | 114 | // Enable the necessary Clocks |
| 120 | // Enable the necessary Clocks | 115 | #[cfg(eth_v1a)] |
| 121 | // NOTE(unsafe) We have exclusive access to the registers | 116 | critical_section::with(|_| { |
| 122 | #[cfg(eth_v1a)] | 117 | RCC.apb2enr().modify(|w| w.set_afioen(true)); |
| 123 | critical_section::with(|_| { | ||
| 124 | RCC.apb2enr().modify(|w| w.set_afioen(true)); | ||
| 125 | |||
| 126 | // Select RMII (Reduced Media Independent Interface) | ||
| 127 | // Must be done prior to enabling peripheral clock | ||
| 128 | AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true)); | ||
| 129 | |||
| 130 | RCC.ahbenr().modify(|w| { | ||
| 131 | w.set_ethen(true); | ||
| 132 | w.set_ethtxen(true); | ||
| 133 | w.set_ethrxen(true); | ||
| 134 | }); | ||
| 135 | }); | ||
| 136 | |||
| 137 | #[cfg(any(eth_v1b, eth_v1c))] | ||
| 138 | critical_section::with(|_| { | ||
| 139 | RCC.apb2enr().modify(|w| w.set_syscfgen(true)); | ||
| 140 | RCC.ahb1enr().modify(|w| { | ||
| 141 | w.set_ethen(true); | ||
| 142 | w.set_ethtxen(true); | ||
| 143 | w.set_ethrxen(true); | ||
| 144 | }); | ||
| 145 | |||
| 146 | // RMII (Reduced Media Independent Interface) | ||
| 147 | SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true)); | ||
| 148 | }); | ||
| 149 | |||
| 150 | #[cfg(eth_v1a)] | ||
| 151 | { | ||
| 152 | config_in_pins!(ref_clk, rx_d0, rx_d1); | ||
| 153 | config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en); | ||
| 154 | } | ||
| 155 | |||
| 156 | #[cfg(any(eth_v1b, eth_v1c))] | ||
| 157 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | ||
| 158 | |||
| 159 | // NOTE(unsafe) We have exclusive access to the registers | ||
| 160 | let dma = ETH.ethernet_dma(); | ||
| 161 | let mac = ETH.ethernet_mac(); | ||
| 162 | |||
| 163 | // Reset and wait | ||
| 164 | dma.dmabmr().modify(|w| w.set_sr(true)); | ||
| 165 | while dma.dmabmr().read().sr() {} | ||
| 166 | |||
| 167 | mac.maccr().modify(|w| { | ||
| 168 | w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times | ||
| 169 | w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping | ||
| 170 | w.set_fes(Fes::FES100); // fast ethernet speed | ||
| 171 | w.set_dm(Dm::FULLDUPLEX); // full duplex | ||
| 172 | // TODO: Carrier sense ? ECRSFD | ||
| 173 | }); | ||
| 174 | |||
| 175 | // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, | ||
| 176 | // so the LR write must happen after the HR write. | ||
| 177 | mac.maca0hr() | ||
| 178 | .modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); | ||
| 179 | mac.maca0lr().write(|w| { | ||
| 180 | w.set_maca0l( | ||
| 181 | u32::from(mac_addr[0]) | ||
| 182 | | (u32::from(mac_addr[1]) << 8) | ||
| 183 | | (u32::from(mac_addr[2]) << 16) | ||
| 184 | | (u32::from(mac_addr[3]) << 24), | ||
| 185 | ) | ||
| 186 | }); | ||
| 187 | |||
| 188 | // pause time | ||
| 189 | mac.macfcr().modify(|w| w.set_pt(0x100)); | ||
| 190 | |||
| 191 | // Transfer and Forward, Receive and Forward | ||
| 192 | dma.dmaomr().modify(|w| { | ||
| 193 | w.set_tsf(Tsf::STOREFORWARD); | ||
| 194 | w.set_rsf(Rsf::STOREFORWARD); | ||
| 195 | }); | ||
| 196 | 118 | ||
| 197 | dma.dmabmr().modify(|w| { | 119 | // Select RMII (Reduced Media Independent Interface) |
| 198 | w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ? | 120 | // Must be done prior to enabling peripheral clock |
| 199 | }); | 121 | AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true)); |
| 200 | 122 | ||
| 201 | // TODO MTU size setting not found for v1 ethernet, check if correct | 123 | RCC.ahbenr().modify(|w| { |
| 202 | 124 | w.set_ethen(true); | |
| 203 | // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called | 125 | w.set_ethtxen(true); |
| 204 | let hclk = crate::rcc::get_freqs().ahb1; | 126 | w.set_ethrxen(true); |
| 205 | let hclk_mhz = hclk.0 / 1_000_000; | ||
| 206 | |||
| 207 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||
| 208 | let clock_range = match hclk_mhz { | ||
| 209 | 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."), | ||
| 210 | 25..=34 => Cr::CR_20_35, // Divide by 16 | ||
| 211 | 35..=59 => Cr::CR_35_60, // Divide by 26 | ||
| 212 | 60..=99 => Cr::CR_60_100, // Divide by 42 | ||
| 213 | 100..=149 => Cr::CR_100_150, // Divide by 62 | ||
| 214 | 150..=216 => Cr::CR_150_168, // Divide by 102 | ||
| 215 | _ => { | ||
| 216 | panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||
| 217 | } | ||
| 218 | }; | ||
| 219 | |||
| 220 | let pins = [ | ||
| 221 | ref_clk.map_into(), | ||
| 222 | mdio.map_into(), | ||
| 223 | mdc.map_into(), | ||
| 224 | crs.map_into(), | ||
| 225 | rx_d0.map_into(), | ||
| 226 | rx_d1.map_into(), | ||
| 227 | tx_d0.map_into(), | ||
| 228 | tx_d1.map_into(), | ||
| 229 | tx_en.map_into(), | ||
| 230 | ]; | ||
| 231 | |||
| 232 | let mut this = Self { | ||
| 233 | _peri: peri, | ||
| 234 | pins, | ||
| 235 | _phy: phy, | ||
| 236 | clock_range, | ||
| 237 | phy_addr, | ||
| 238 | mac_addr, | ||
| 239 | tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), | ||
| 240 | rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | ||
| 241 | }; | ||
| 242 | |||
| 243 | fence(Ordering::SeqCst); | ||
| 244 | |||
| 245 | let mac = ETH.ethernet_mac(); | ||
| 246 | let dma = ETH.ethernet_dma(); | ||
| 247 | |||
| 248 | mac.maccr().modify(|w| { | ||
| 249 | w.set_re(true); | ||
| 250 | w.set_te(true); | ||
| 251 | }); | ||
| 252 | dma.dmaomr().modify(|w| { | ||
| 253 | w.set_ftf(Ftf::FLUSH); // flush transmit fifo (queue) | ||
| 254 | w.set_st(St::STARTED); // start transmitting channel | ||
| 255 | w.set_sr(DmaomrSr::STARTED); // start receiving channel | ||
| 256 | }); | 127 | }); |
| 128 | }); | ||
| 257 | 129 | ||
| 258 | this.rx.demand_poll(); | 130 | #[cfg(any(eth_v1b, eth_v1c))] |
| 259 | 131 | critical_section::with(|_| { | |
| 260 | // Enable interrupts | 132 | RCC.apb2enr().modify(|w| w.set_syscfgen(true)); |
| 261 | dma.dmaier().modify(|w| { | 133 | RCC.ahb1enr().modify(|w| { |
| 262 | w.set_nise(true); | 134 | w.set_ethen(true); |
| 263 | w.set_rie(true); | 135 | w.set_ethtxen(true); |
| 264 | w.set_tie(true); | 136 | w.set_ethrxen(true); |
| 265 | }); | 137 | }); |
| 266 | 138 | ||
| 267 | P::phy_reset(&mut this); | 139 | // RMII (Reduced Media Independent Interface) |
| 268 | P::phy_init(&mut this); | 140 | SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true)); |
| 141 | }); | ||
| 269 | 142 | ||
| 270 | interrupt::ETH::steal().unpend(); | 143 | #[cfg(eth_v1a)] |
| 271 | interrupt::ETH::steal().enable(); | 144 | { |
| 272 | 145 | config_in_pins!(ref_clk, rx_d0, rx_d1); | |
| 273 | this | 146 | config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en); |
| 274 | } | 147 | } |
| 148 | |||
| 149 | #[cfg(any(eth_v1b, eth_v1c))] | ||
| 150 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | ||
| 151 | |||
| 152 | let dma = ETH.ethernet_dma(); | ||
| 153 | let mac = ETH.ethernet_mac(); | ||
| 154 | |||
| 155 | // Reset and wait | ||
| 156 | dma.dmabmr().modify(|w| w.set_sr(true)); | ||
| 157 | while dma.dmabmr().read().sr() {} | ||
| 158 | |||
| 159 | mac.maccr().modify(|w| { | ||
| 160 | w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times | ||
| 161 | w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping | ||
| 162 | w.set_fes(Fes::FES100); // fast ethernet speed | ||
| 163 | w.set_dm(Dm::FULLDUPLEX); // full duplex | ||
| 164 | // TODO: Carrier sense ? ECRSFD | ||
| 165 | }); | ||
| 166 | |||
| 167 | // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, | ||
| 168 | // so the LR write must happen after the HR write. | ||
| 169 | mac.maca0hr() | ||
| 170 | .modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); | ||
| 171 | mac.maca0lr().write(|w| { | ||
| 172 | w.set_maca0l( | ||
| 173 | u32::from(mac_addr[0]) | ||
| 174 | | (u32::from(mac_addr[1]) << 8) | ||
| 175 | | (u32::from(mac_addr[2]) << 16) | ||
| 176 | | (u32::from(mac_addr[3]) << 24), | ||
| 177 | ) | ||
| 178 | }); | ||
| 179 | |||
| 180 | // pause time | ||
| 181 | mac.macfcr().modify(|w| w.set_pt(0x100)); | ||
| 182 | |||
| 183 | // Transfer and Forward, Receive and Forward | ||
| 184 | dma.dmaomr().modify(|w| { | ||
| 185 | w.set_tsf(Tsf::STOREFORWARD); | ||
| 186 | w.set_rsf(Rsf::STOREFORWARD); | ||
| 187 | }); | ||
| 188 | |||
| 189 | dma.dmabmr().modify(|w| { | ||
| 190 | w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ? | ||
| 191 | }); | ||
| 192 | |||
| 193 | // TODO MTU size setting not found for v1 ethernet, check if correct | ||
| 194 | |||
| 195 | // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called | ||
| 196 | let hclk = unsafe { crate::rcc::get_freqs() }.ahb1; | ||
| 197 | let hclk_mhz = hclk.0 / 1_000_000; | ||
| 198 | |||
| 199 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||
| 200 | let clock_range = match hclk_mhz { | ||
| 201 | 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."), | ||
| 202 | 25..=34 => Cr::CR_20_35, // Divide by 16 | ||
| 203 | 35..=59 => Cr::CR_35_60, // Divide by 26 | ||
| 204 | 60..=99 => Cr::CR_60_100, // Divide by 42 | ||
| 205 | 100..=149 => Cr::CR_100_150, // Divide by 62 | ||
| 206 | 150..=216 => Cr::CR_150_168, // Divide by 102 | ||
| 207 | _ => { | ||
| 208 | panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||
| 209 | } | ||
| 210 | }; | ||
| 211 | |||
| 212 | let pins = [ | ||
| 213 | ref_clk.map_into(), | ||
| 214 | mdio.map_into(), | ||
| 215 | mdc.map_into(), | ||
| 216 | crs.map_into(), | ||
| 217 | rx_d0.map_into(), | ||
| 218 | rx_d1.map_into(), | ||
| 219 | tx_d0.map_into(), | ||
| 220 | tx_d1.map_into(), | ||
| 221 | tx_en.map_into(), | ||
| 222 | ]; | ||
| 223 | |||
| 224 | let mut this = Self { | ||
| 225 | _peri: peri, | ||
| 226 | pins, | ||
| 227 | _phy: phy, | ||
| 228 | clock_range, | ||
| 229 | phy_addr, | ||
| 230 | mac_addr, | ||
| 231 | tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), | ||
| 232 | rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | ||
| 233 | }; | ||
| 234 | |||
| 235 | fence(Ordering::SeqCst); | ||
| 236 | |||
| 237 | let mac = ETH.ethernet_mac(); | ||
| 238 | let dma = ETH.ethernet_dma(); | ||
| 239 | |||
| 240 | mac.maccr().modify(|w| { | ||
| 241 | w.set_re(true); | ||
| 242 | w.set_te(true); | ||
| 243 | }); | ||
| 244 | dma.dmaomr().modify(|w| { | ||
| 245 | w.set_ftf(Ftf::FLUSH); // flush transmit fifo (queue) | ||
| 246 | w.set_st(St::STARTED); // start transmitting channel | ||
| 247 | w.set_sr(DmaomrSr::STARTED); // start receiving channel | ||
| 248 | }); | ||
| 249 | |||
| 250 | this.rx.demand_poll(); | ||
| 251 | |||
| 252 | // Enable interrupts | ||
| 253 | dma.dmaier().modify(|w| { | ||
| 254 | w.set_nise(true); | ||
| 255 | w.set_rie(true); | ||
| 256 | w.set_tie(true); | ||
| 257 | }); | ||
| 258 | |||
| 259 | P::phy_reset(&mut this); | ||
| 260 | P::phy_init(&mut this); | ||
| 261 | |||
| 262 | interrupt::ETH.unpend(); | ||
| 263 | unsafe { interrupt::ETH.enable() }; | ||
| 264 | |||
| 265 | this | ||
| 275 | } | 266 | } |
| 276 | } | 267 | } |
| 277 | 268 | ||
| 278 | unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { | 269 | unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { |
| 279 | fn smi_read(&mut self, reg: u8) -> u16 { | 270 | fn smi_read(&mut self, reg: u8) -> u16 { |
| 280 | // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` | 271 | let mac = ETH.ethernet_mac(); |
| 281 | unsafe { | 272 | |
| 282 | let mac = ETH.ethernet_mac(); | 273 | mac.macmiiar().modify(|w| { |
| 283 | 274 | w.set_pa(self.phy_addr); | |
| 284 | mac.macmiiar().modify(|w| { | 275 | w.set_mr(reg); |
| 285 | w.set_pa(self.phy_addr); | 276 | w.set_mw(Mw::READ); // read operation |
| 286 | w.set_mr(reg); | 277 | w.set_cr(self.clock_range); |
| 287 | w.set_mw(Mw::READ); // read operation | 278 | w.set_mb(MbProgress::BUSY); // indicate that operation is in progress |
| 288 | w.set_cr(self.clock_range); | 279 | }); |
| 289 | w.set_mb(MbProgress::BUSY); // indicate that operation is in progress | 280 | while mac.macmiiar().read().mb() == MbProgress::BUSY {} |
| 290 | }); | 281 | mac.macmiidr().read().md() |
| 291 | while mac.macmiiar().read().mb() == MbProgress::BUSY {} | ||
| 292 | mac.macmiidr().read().md() | ||
| 293 | } | ||
| 294 | } | 282 | } |
| 295 | 283 | ||
| 296 | fn smi_write(&mut self, reg: u8, val: u16) { | 284 | fn smi_write(&mut self, reg: u8, val: u16) { |
| 297 | // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` | 285 | let mac = ETH.ethernet_mac(); |
| 298 | unsafe { | 286 | |
| 299 | let mac = ETH.ethernet_mac(); | 287 | mac.macmiidr().write(|w| w.set_md(val)); |
| 300 | 288 | mac.macmiiar().modify(|w| { | |
| 301 | mac.macmiidr().write(|w| w.set_md(val)); | 289 | w.set_pa(self.phy_addr); |
| 302 | mac.macmiiar().modify(|w| { | 290 | w.set_mr(reg); |
| 303 | w.set_pa(self.phy_addr); | 291 | w.set_mw(Mw::WRITE); // write |
| 304 | w.set_mr(reg); | 292 | w.set_cr(self.clock_range); |
| 305 | w.set_mw(Mw::WRITE); // write | 293 | w.set_mb(MbProgress::BUSY); |
| 306 | w.set_cr(self.clock_range); | 294 | }); |
| 307 | w.set_mb(MbProgress::BUSY); | 295 | while mac.macmiiar().read().mb() == MbProgress::BUSY {} |
| 308 | }); | ||
| 309 | while mac.macmiiar().read().mb() == MbProgress::BUSY {} | ||
| 310 | } | ||
| 311 | } | 296 | } |
| 312 | } | 297 | } |
| 313 | 298 | ||
| 314 | impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { | 299 | impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { |
| 315 | fn drop(&mut self) { | 300 | fn drop(&mut self) { |
| 316 | // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers | 301 | let dma = ETH.ethernet_dma(); |
| 317 | unsafe { | 302 | let mac = ETH.ethernet_mac(); |
| 318 | let dma = ETH.ethernet_dma(); | ||
| 319 | let mac = ETH.ethernet_mac(); | ||
| 320 | |||
| 321 | // Disable the TX DMA and wait for any previous transmissions to be completed | ||
| 322 | dma.dmaomr().modify(|w| w.set_st(St::STOPPED)); | ||
| 323 | |||
| 324 | // Disable MAC transmitter and receiver | ||
| 325 | mac.maccr().modify(|w| { | ||
| 326 | w.set_re(false); | ||
| 327 | w.set_te(false); | ||
| 328 | }); | ||
| 329 | 303 | ||
| 330 | dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED)); | 304 | // Disable the TX DMA and wait for any previous transmissions to be completed |
| 331 | } | 305 | dma.dmaomr().modify(|w| w.set_st(St::STOPPED)); |
| 306 | |||
| 307 | // Disable MAC transmitter and receiver | ||
| 308 | mac.maccr().modify(|w| { | ||
| 309 | w.set_re(false); | ||
| 310 | w.set_te(false); | ||
| 311 | }); | ||
| 332 | 312 | ||
| 333 | // NOTE(unsafe) Exclusive access to the regs | 313 | dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED)); |
| 334 | critical_section::with(|_| unsafe { | 314 | |
| 315 | critical_section::with(|_| { | ||
| 335 | for pin in self.pins.iter_mut() { | 316 | for pin in self.pins.iter_mut() { |
| 336 | pin.set_as_disconnected(); | 317 | pin.set_as_disconnected(); |
| 337 | } | 318 | } |
diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs index 8b8566d92..01a073bb9 100644 --- a/embassy-stm32/src/eth/v1/rx_desc.rs +++ b/embassy-stm32/src/eth/v1/rx_desc.rs | |||
| @@ -146,12 +146,9 @@ impl<'a> RDesRing<'a> { | |||
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | // Register rx descriptor start | 148 | // Register rx descriptor start |
| 149 | // NOTE (unsafe) Used for atomic writes | 149 | ETH.ethernet_dma() |
| 150 | unsafe { | 150 | .dmardlar() |
| 151 | ETH.ethernet_dma() | 151 | .write(|w| w.0 = descriptors.as_ptr() as u32); |
| 152 | .dmardlar() | ||
| 153 | .write(|w| w.0 = descriptors.as_ptr() as u32); | ||
| 154 | }; | ||
| 155 | // We already have fences in `set_owned`, which is called in `setup` | 152 | // We already have fences in `set_owned`, which is called in `setup` |
| 156 | 153 | ||
| 157 | Self { | 154 | Self { |
| @@ -162,12 +159,12 @@ impl<'a> RDesRing<'a> { | |||
| 162 | } | 159 | } |
| 163 | 160 | ||
| 164 | pub(crate) fn demand_poll(&self) { | 161 | pub(crate) fn demand_poll(&self) { |
| 165 | unsafe { ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)) }; | 162 | ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)); |
| 166 | } | 163 | } |
| 167 | 164 | ||
| 168 | /// Get current `RunningState` | 165 | /// Get current `RunningState` |
| 169 | fn running_state(&self) -> RunningState { | 166 | fn running_state(&self) -> RunningState { |
| 170 | match unsafe { ETH.ethernet_dma().dmasr().read().rps() } { | 167 | match ETH.ethernet_dma().dmasr().read().rps() { |
| 171 | // Reset or Stop Receive Command issued | 168 | // Reset or Stop Receive Command issued |
| 172 | Rps::STOPPED => RunningState::Stopped, | 169 | Rps::STOPPED => RunningState::Stopped, |
| 173 | // Fetching receive transfer descriptor | 170 | // Fetching receive transfer descriptor |
diff --git a/embassy-stm32/src/eth/v1/tx_desc.rs b/embassy-stm32/src/eth/v1/tx_desc.rs index 0e63c5443..1317d20f4 100644 --- a/embassy-stm32/src/eth/v1/tx_desc.rs +++ b/embassy-stm32/src/eth/v1/tx_desc.rs | |||
| @@ -120,12 +120,9 @@ impl<'a> TDesRing<'a> { | |||
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | // Register txdescriptor start | 122 | // Register txdescriptor start |
| 123 | // NOTE (unsafe) Used for atomic writes | 123 | ETH.ethernet_dma() |
| 124 | unsafe { | 124 | .dmatdlar() |
| 125 | ETH.ethernet_dma() | 125 | .write(|w| w.0 = descriptors.as_ptr() as u32); |
| 126 | .dmatdlar() | ||
| 127 | .write(|w| w.0 = descriptors.as_ptr() as u32); | ||
| 128 | } | ||
| 129 | 126 | ||
| 130 | Self { | 127 | Self { |
| 131 | descriptors, | 128 | descriptors, |
| @@ -169,6 +166,6 @@ impl<'a> TDesRing<'a> { | |||
| 169 | self.index = 0 | 166 | self.index = 0 |
| 170 | } | 167 | } |
| 171 | // Request the DMA engine to poll the latest tx descriptor | 168 | // Request the DMA engine to poll the latest tx descriptor |
| 172 | unsafe { ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) } | 169 | ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) |
| 173 | } | 170 | } |
| 174 | } | 171 | } |
diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs index 2426596fb..e9799adf1 100644 --- a/embassy-stm32/src/eth/v2/descriptors.rs +++ b/embassy-stm32/src/eth/v2/descriptors.rs | |||
| @@ -73,14 +73,10 @@ impl<'a> TDesRing<'a> { | |||
| 73 | 73 | ||
| 74 | // Initialize the pointers in the DMA engine. (There will be a memory barrier later | 74 | // Initialize the pointers in the DMA engine. (There will be a memory barrier later |
| 75 | // before the DMA engine is enabled.) | 75 | // before the DMA engine is enabled.) |
| 76 | // NOTE (unsafe) Used for atomic writes | 76 | let dma = ETH.ethernet_dma(); |
| 77 | unsafe { | 77 | dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32); |
| 78 | let dma = ETH.ethernet_dma(); | 78 | dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1)); |
| 79 | 79 | dma.dmactx_dtpr().write(|w| w.0 = 0); | |
| 80 | dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32); | ||
| 81 | dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1)); | ||
| 82 | dma.dmactx_dtpr().write(|w| w.0 = 0); | ||
| 83 | } | ||
| 84 | 80 | ||
| 85 | Self { | 81 | Self { |
| 86 | descriptors, | 82 | descriptors, |
| @@ -129,8 +125,7 @@ impl<'a> TDesRing<'a> { | |||
| 129 | } | 125 | } |
| 130 | 126 | ||
| 131 | // signal DMA it can try again. | 127 | // signal DMA it can try again. |
| 132 | // NOTE(unsafe) Atomic write | 128 | ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0) |
| 133 | unsafe { ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0) } | ||
| 134 | } | 129 | } |
| 135 | } | 130 | } |
| 136 | 131 | ||
| @@ -199,13 +194,10 @@ impl<'a> RDesRing<'a> { | |||
| 199 | desc.set_ready(buffers[i].0.as_mut_ptr()); | 194 | desc.set_ready(buffers[i].0.as_mut_ptr()); |
| 200 | } | 195 | } |
| 201 | 196 | ||
| 202 | unsafe { | 197 | let dma = ETH.ethernet_dma(); |
| 203 | let dma = ETH.ethernet_dma(); | 198 | dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32); |
| 204 | 199 | dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1)); | |
| 205 | dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32); | 200 | dma.dmacrx_dtpr().write(|w| w.0 = 0); |
| 206 | dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1)); | ||
| 207 | dma.dmacrx_dtpr().write(|w| w.0 = 0); | ||
| 208 | } | ||
| 209 | 201 | ||
| 210 | Self { | 202 | Self { |
| 211 | descriptors, | 203 | descriptors, |
| @@ -254,8 +246,7 @@ impl<'a> RDesRing<'a> { | |||
| 254 | fence(Ordering::Release); | 246 | fence(Ordering::Release); |
| 255 | 247 | ||
| 256 | // signal DMA it can try again. | 248 | // signal DMA it can try again. |
| 257 | // NOTE(unsafe) Atomic write | 249 | ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0); |
| 258 | unsafe { ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0) } | ||
| 259 | 250 | ||
| 260 | // Increment index. | 251 | // Increment index. |
| 261 | self.index += 1; | 252 | self.index += 1; |
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index b56c3e8ab..600e1d3bc 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs | |||
| @@ -2,36 +2,34 @@ mod descriptors; | |||
| 2 | 2 | ||
| 3 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 4 | ||
| 5 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 6 | use embassy_hal_common::{into_ref, PeripheralRef}; | 5 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 7 | 6 | ||
| 8 | pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; | 7 | pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; |
| 9 | use super::*; | 8 | use super::*; |
| 10 | use crate::gpio::sealed::{AFType, Pin as _}; | 9 | use crate::gpio::sealed::{AFType, Pin as _}; |
| 11 | use crate::gpio::{AnyPin, Speed}; | 10 | use crate::gpio::{AnyPin, Speed}; |
| 11 | use crate::interrupt::InterruptExt; | ||
| 12 | use crate::pac::ETH; | 12 | use crate::pac::ETH; |
| 13 | use crate::{interrupt, Peripheral}; | 13 | use crate::{interrupt, Peripheral}; |
| 14 | 14 | ||
| 15 | /// Interrupt handler. | 15 | /// Interrupt handler. |
| 16 | pub struct InterruptHandler {} | 16 | pub struct InterruptHandler {} |
| 17 | 17 | ||
| 18 | impl interrupt::Handler<interrupt::ETH> for InterruptHandler { | 18 | impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandler { |
| 19 | unsafe fn on_interrupt() { | 19 | unsafe fn on_interrupt() { |
| 20 | WAKER.wake(); | 20 | WAKER.wake(); |
| 21 | 21 | ||
| 22 | // TODO: Check and clear more flags | 22 | // TODO: Check and clear more flags |
| 23 | unsafe { | 23 | let dma = ETH.ethernet_dma(); |
| 24 | let dma = ETH.ethernet_dma(); | 24 | |
| 25 | 25 | dma.dmacsr().modify(|w| { | |
| 26 | dma.dmacsr().modify(|w| { | 26 | w.set_ti(true); |
| 27 | w.set_ti(true); | 27 | w.set_ri(true); |
| 28 | w.set_ri(true); | 28 | w.set_nis(true); |
| 29 | w.set_nis(true); | 29 | }); |
| 30 | }); | 30 | // Delay two peripheral's clock |
| 31 | // Delay two peripheral's clock | 31 | dma.dmacsr().read(); |
| 32 | dma.dmacsr().read(); | 32 | dma.dmacsr().read(); |
| 33 | dma.dmacsr().read(); | ||
| 34 | } | ||
| 35 | } | 33 | } |
| 36 | } | 34 | } |
| 37 | 35 | ||
| @@ -50,7 +48,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> { | |||
| 50 | 48 | ||
| 51 | macro_rules! config_pins { | 49 | macro_rules! config_pins { |
| 52 | ($($pin:ident),*) => { | 50 | ($($pin:ident),*) => { |
| 53 | // NOTE(unsafe) Exclusive access to the registers | ||
| 54 | critical_section::with(|_| { | 51 | critical_section::with(|_| { |
| 55 | $( | 52 | $( |
| 56 | $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); | 53 | $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); |
| @@ -64,7 +61,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 64 | pub fn new<const TX: usize, const RX: usize>( | 61 | pub fn new<const TX: usize, const RX: usize>( |
| 65 | queue: &'d mut PacketQueue<TX, RX>, | 62 | queue: &'d mut PacketQueue<TX, RX>, |
| 66 | peri: impl Peripheral<P = T> + 'd, | 63 | peri: impl Peripheral<P = T> + 'd, |
| 67 | _irq: impl interrupt::Binding<interrupt::ETH, InterruptHandler> + 'd, | 64 | _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, |
| 68 | ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, | 65 | ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, |
| 69 | mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, | 66 | mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd, |
| 70 | mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, | 67 | mdc: impl Peripheral<P = impl MDCPin<T>> + 'd, |
| @@ -80,239 +77,225 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 80 | ) -> Self { | 77 | ) -> Self { |
| 81 | into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | 78 | into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); |
| 82 | 79 | ||
| 83 | unsafe { | 80 | // Enable the necessary Clocks |
| 84 | // Enable the necessary Clocks | 81 | #[cfg(not(rcc_h5))] |
| 85 | // NOTE(unsafe) We have exclusive access to the registers | 82 | critical_section::with(|_| { |
| 86 | #[cfg(not(rcc_h5))] | 83 | crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true)); |
| 87 | critical_section::with(|_| { | 84 | crate::pac::RCC.ahb1enr().modify(|w| { |
| 88 | crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true)); | 85 | w.set_eth1macen(true); |
| 89 | crate::pac::RCC.ahb1enr().modify(|w| { | 86 | w.set_eth1txen(true); |
| 90 | w.set_eth1macen(true); | 87 | w.set_eth1rxen(true); |
| 91 | w.set_eth1txen(true); | ||
| 92 | w.set_eth1rxen(true); | ||
| 93 | }); | ||
| 94 | |||
| 95 | // RMII | ||
| 96 | crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); | ||
| 97 | }); | ||
| 98 | |||
| 99 | #[cfg(rcc_h5)] | ||
| 100 | critical_section::with(|_| { | ||
| 101 | crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true)); | ||
| 102 | |||
| 103 | crate::pac::RCC.ahb1enr().modify(|w| { | ||
| 104 | w.set_ethen(true); | ||
| 105 | w.set_ethtxen(true); | ||
| 106 | w.set_ethrxen(true); | ||
| 107 | }); | ||
| 108 | |||
| 109 | // RMII | ||
| 110 | crate::pac::SBS | ||
| 111 | .pmcr() | ||
| 112 | .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4)); | ||
| 113 | }); | ||
| 114 | |||
| 115 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | ||
| 116 | |||
| 117 | // NOTE(unsafe) We have exclusive access to the registers | ||
| 118 | let dma = ETH.ethernet_dma(); | ||
| 119 | let mac = ETH.ethernet_mac(); | ||
| 120 | let mtl = ETH.ethernet_mtl(); | ||
| 121 | |||
| 122 | // Reset and wait | ||
| 123 | dma.dmamr().modify(|w| w.set_swr(true)); | ||
| 124 | while dma.dmamr().read().swr() {} | ||
| 125 | |||
| 126 | mac.maccr().modify(|w| { | ||
| 127 | w.set_ipg(0b000); // 96 bit times | ||
| 128 | w.set_acs(true); | ||
| 129 | w.set_fes(true); | ||
| 130 | w.set_dm(true); | ||
| 131 | // TODO: Carrier sense ? ECRSFD | ||
| 132 | }); | ||
| 133 | |||
| 134 | // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, | ||
| 135 | // so the LR write must happen after the HR write. | ||
| 136 | mac.maca0hr() | ||
| 137 | .modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); | ||
| 138 | mac.maca0lr().write(|w| { | ||
| 139 | w.set_addrlo( | ||
| 140 | u32::from(mac_addr[0]) | ||
| 141 | | (u32::from(mac_addr[1]) << 8) | ||
| 142 | | (u32::from(mac_addr[2]) << 16) | ||
| 143 | | (u32::from(mac_addr[3]) << 24), | ||
| 144 | ) | ||
| 145 | }); | ||
| 146 | |||
| 147 | mac.macqtx_fcr().modify(|w| w.set_pt(0x100)); | ||
| 148 | |||
| 149 | // disable all MMC RX interrupts | ||
| 150 | mac.mmc_rx_interrupt_mask().write(|w| { | ||
| 151 | w.set_rxcrcerpim(true); | ||
| 152 | w.set_rxalgnerpim(true); | ||
| 153 | w.set_rxucgpim(true); | ||
| 154 | w.set_rxlpiuscim(true); | ||
| 155 | w.set_rxlpitrcim(true) | ||
| 156 | }); | ||
| 157 | |||
| 158 | // disable all MMC TX interrupts | ||
| 159 | mac.mmc_tx_interrupt_mask().write(|w| { | ||
| 160 | w.set_txscolgpim(true); | ||
| 161 | w.set_txmcolgpim(true); | ||
| 162 | w.set_txgpktim(true); | ||
| 163 | w.set_txlpiuscim(true); | ||
| 164 | w.set_txlpitrcim(true); | ||
| 165 | }); | ||
| 166 | |||
| 167 | mtl.mtlrx_qomr().modify(|w| w.set_rsf(true)); | ||
| 168 | mtl.mtltx_qomr().modify(|w| w.set_tsf(true)); | ||
| 169 | |||
| 170 | dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ? | ||
| 171 | dma.dmacrx_cr().modify(|w| { | ||
| 172 | w.set_rxpbl(1); // 32 ? | ||
| 173 | w.set_rbsz(MTU as u16); | ||
| 174 | }); | 88 | }); |
| 175 | 89 | ||
| 176 | // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called | 90 | // RMII |
| 177 | let hclk = crate::rcc::get_freqs().ahb1; | 91 | crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); |
| 178 | let hclk_mhz = hclk.0 / 1_000_000; | 92 | }); |
| 179 | |||
| 180 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||
| 181 | let clock_range = match hclk_mhz { | ||
| 182 | 0..=34 => 2, // Divide by 16 | ||
| 183 | 35..=59 => 3, // Divide by 26 | ||
| 184 | 60..=99 => 0, // Divide by 42 | ||
| 185 | 100..=149 => 1, // Divide by 62 | ||
| 186 | 150..=249 => 4, // Divide by 102 | ||
| 187 | 250..=310 => 5, // Divide by 124 | ||
| 188 | _ => { | ||
| 189 | panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||
| 190 | } | ||
| 191 | }; | ||
| 192 | |||
| 193 | let pins = [ | ||
| 194 | ref_clk.map_into(), | ||
| 195 | mdio.map_into(), | ||
| 196 | mdc.map_into(), | ||
| 197 | crs.map_into(), | ||
| 198 | rx_d0.map_into(), | ||
| 199 | rx_d1.map_into(), | ||
| 200 | tx_d0.map_into(), | ||
| 201 | tx_d1.map_into(), | ||
| 202 | tx_en.map_into(), | ||
| 203 | ]; | ||
| 204 | |||
| 205 | let mut this = Self { | ||
| 206 | _peri: peri, | ||
| 207 | tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), | ||
| 208 | rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | ||
| 209 | pins, | ||
| 210 | _phy: phy, | ||
| 211 | clock_range, | ||
| 212 | phy_addr, | ||
| 213 | mac_addr, | ||
| 214 | }; | ||
| 215 | |||
| 216 | fence(Ordering::SeqCst); | ||
| 217 | |||
| 218 | let mac = ETH.ethernet_mac(); | ||
| 219 | let mtl = ETH.ethernet_mtl(); | ||
| 220 | let dma = ETH.ethernet_dma(); | ||
| 221 | |||
| 222 | mac.maccr().modify(|w| { | ||
| 223 | w.set_re(true); | ||
| 224 | w.set_te(true); | ||
| 225 | }); | ||
| 226 | mtl.mtltx_qomr().modify(|w| w.set_ftq(true)); | ||
| 227 | 93 | ||
| 228 | dma.dmactx_cr().modify(|w| w.set_st(true)); | 94 | #[cfg(rcc_h5)] |
| 229 | dma.dmacrx_cr().modify(|w| w.set_sr(true)); | 95 | critical_section::with(|_| { |
| 96 | crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true)); | ||
| 230 | 97 | ||
| 231 | // Enable interrupts | 98 | crate::pac::RCC.ahb1enr().modify(|w| { |
| 232 | dma.dmacier().modify(|w| { | 99 | w.set_ethen(true); |
| 233 | w.set_nie(true); | 100 | w.set_ethtxen(true); |
| 234 | w.set_rie(true); | 101 | w.set_ethrxen(true); |
| 235 | w.set_tie(true); | ||
| 236 | }); | 102 | }); |
| 237 | 103 | ||
| 238 | P::phy_reset(&mut this); | 104 | // RMII |
| 239 | P::phy_init(&mut this); | 105 | crate::pac::SBS |
| 240 | 106 | .pmcr() | |
| 241 | interrupt::ETH::steal().unpend(); | 107 | .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4)); |
| 242 | interrupt::ETH::steal().enable(); | 108 | }); |
| 243 | 109 | ||
| 244 | this | 110 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); |
| 245 | } | 111 | |
| 112 | let dma = ETH.ethernet_dma(); | ||
| 113 | let mac = ETH.ethernet_mac(); | ||
| 114 | let mtl = ETH.ethernet_mtl(); | ||
| 115 | |||
| 116 | // Reset and wait | ||
| 117 | dma.dmamr().modify(|w| w.set_swr(true)); | ||
| 118 | while dma.dmamr().read().swr() {} | ||
| 119 | |||
| 120 | mac.maccr().modify(|w| { | ||
| 121 | w.set_ipg(0b000); // 96 bit times | ||
| 122 | w.set_acs(true); | ||
| 123 | w.set_fes(true); | ||
| 124 | w.set_dm(true); | ||
| 125 | // TODO: Carrier sense ? ECRSFD | ||
| 126 | }); | ||
| 127 | |||
| 128 | // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, | ||
| 129 | // so the LR write must happen after the HR write. | ||
| 130 | mac.maca0hr() | ||
| 131 | .modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); | ||
| 132 | mac.maca0lr().write(|w| { | ||
| 133 | w.set_addrlo( | ||
| 134 | u32::from(mac_addr[0]) | ||
| 135 | | (u32::from(mac_addr[1]) << 8) | ||
| 136 | | (u32::from(mac_addr[2]) << 16) | ||
| 137 | | (u32::from(mac_addr[3]) << 24), | ||
| 138 | ) | ||
| 139 | }); | ||
| 140 | |||
| 141 | mac.macqtx_fcr().modify(|w| w.set_pt(0x100)); | ||
| 142 | |||
| 143 | // disable all MMC RX interrupts | ||
| 144 | mac.mmc_rx_interrupt_mask().write(|w| { | ||
| 145 | w.set_rxcrcerpim(true); | ||
| 146 | w.set_rxalgnerpim(true); | ||
| 147 | w.set_rxucgpim(true); | ||
| 148 | w.set_rxlpiuscim(true); | ||
| 149 | w.set_rxlpitrcim(true) | ||
| 150 | }); | ||
| 151 | |||
| 152 | // disable all MMC TX interrupts | ||
| 153 | mac.mmc_tx_interrupt_mask().write(|w| { | ||
| 154 | w.set_txscolgpim(true); | ||
| 155 | w.set_txmcolgpim(true); | ||
| 156 | w.set_txgpktim(true); | ||
| 157 | w.set_txlpiuscim(true); | ||
| 158 | w.set_txlpitrcim(true); | ||
| 159 | }); | ||
| 160 | |||
| 161 | mtl.mtlrx_qomr().modify(|w| w.set_rsf(true)); | ||
| 162 | mtl.mtltx_qomr().modify(|w| w.set_tsf(true)); | ||
| 163 | |||
| 164 | dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ? | ||
| 165 | dma.dmacrx_cr().modify(|w| { | ||
| 166 | w.set_rxpbl(1); // 32 ? | ||
| 167 | w.set_rbsz(MTU as u16); | ||
| 168 | }); | ||
| 169 | |||
| 170 | // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called | ||
| 171 | let hclk = unsafe { crate::rcc::get_freqs() }.ahb1; | ||
| 172 | let hclk_mhz = hclk.0 / 1_000_000; | ||
| 173 | |||
| 174 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||
| 175 | let clock_range = match hclk_mhz { | ||
| 176 | 0..=34 => 2, // Divide by 16 | ||
| 177 | 35..=59 => 3, // Divide by 26 | ||
| 178 | 60..=99 => 0, // Divide by 42 | ||
| 179 | 100..=149 => 1, // Divide by 62 | ||
| 180 | 150..=249 => 4, // Divide by 102 | ||
| 181 | 250..=310 => 5, // Divide by 124 | ||
| 182 | _ => { | ||
| 183 | panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||
| 184 | } | ||
| 185 | }; | ||
| 186 | |||
| 187 | let pins = [ | ||
| 188 | ref_clk.map_into(), | ||
| 189 | mdio.map_into(), | ||
| 190 | mdc.map_into(), | ||
| 191 | crs.map_into(), | ||
| 192 | rx_d0.map_into(), | ||
| 193 | rx_d1.map_into(), | ||
| 194 | tx_d0.map_into(), | ||
| 195 | tx_d1.map_into(), | ||
| 196 | tx_en.map_into(), | ||
| 197 | ]; | ||
| 198 | |||
| 199 | let mut this = Self { | ||
| 200 | _peri: peri, | ||
| 201 | tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), | ||
| 202 | rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | ||
| 203 | pins, | ||
| 204 | _phy: phy, | ||
| 205 | clock_range, | ||
| 206 | phy_addr, | ||
| 207 | mac_addr, | ||
| 208 | }; | ||
| 209 | |||
| 210 | fence(Ordering::SeqCst); | ||
| 211 | |||
| 212 | let mac = ETH.ethernet_mac(); | ||
| 213 | let mtl = ETH.ethernet_mtl(); | ||
| 214 | let dma = ETH.ethernet_dma(); | ||
| 215 | |||
| 216 | mac.maccr().modify(|w| { | ||
| 217 | w.set_re(true); | ||
| 218 | w.set_te(true); | ||
| 219 | }); | ||
| 220 | mtl.mtltx_qomr().modify(|w| w.set_ftq(true)); | ||
| 221 | |||
| 222 | dma.dmactx_cr().modify(|w| w.set_st(true)); | ||
| 223 | dma.dmacrx_cr().modify(|w| w.set_sr(true)); | ||
| 224 | |||
| 225 | // Enable interrupts | ||
| 226 | dma.dmacier().modify(|w| { | ||
| 227 | w.set_nie(true); | ||
| 228 | w.set_rie(true); | ||
| 229 | w.set_tie(true); | ||
| 230 | }); | ||
| 231 | |||
| 232 | P::phy_reset(&mut this); | ||
| 233 | P::phy_init(&mut this); | ||
| 234 | |||
| 235 | interrupt::ETH.unpend(); | ||
| 236 | unsafe { interrupt::ETH.enable() }; | ||
| 237 | |||
| 238 | this | ||
| 246 | } | 239 | } |
| 247 | } | 240 | } |
| 248 | 241 | ||
| 249 | unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { | 242 | unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { |
| 250 | fn smi_read(&mut self, reg: u8) -> u16 { | 243 | fn smi_read(&mut self, reg: u8) -> u16 { |
| 251 | // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` | 244 | let mac = ETH.ethernet_mac(); |
| 252 | unsafe { | 245 | |
| 253 | let mac = ETH.ethernet_mac(); | 246 | mac.macmdioar().modify(|w| { |
| 254 | 247 | w.set_pa(self.phy_addr); | |
| 255 | mac.macmdioar().modify(|w| { | 248 | w.set_rda(reg); |
| 256 | w.set_pa(self.phy_addr); | 249 | w.set_goc(0b11); // read |
| 257 | w.set_rda(reg); | 250 | w.set_cr(self.clock_range); |
| 258 | w.set_goc(0b11); // read | 251 | w.set_mb(true); |
| 259 | w.set_cr(self.clock_range); | 252 | }); |
| 260 | w.set_mb(true); | 253 | while mac.macmdioar().read().mb() {} |
| 261 | }); | 254 | mac.macmdiodr().read().md() |
| 262 | while mac.macmdioar().read().mb() {} | ||
| 263 | mac.macmdiodr().read().md() | ||
| 264 | } | ||
| 265 | } | 255 | } |
| 266 | 256 | ||
| 267 | fn smi_write(&mut self, reg: u8, val: u16) { | 257 | fn smi_write(&mut self, reg: u8, val: u16) { |
| 268 | // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` | 258 | let mac = ETH.ethernet_mac(); |
| 269 | unsafe { | 259 | |
| 270 | let mac = ETH.ethernet_mac(); | 260 | mac.macmdiodr().write(|w| w.set_md(val)); |
| 271 | 261 | mac.macmdioar().modify(|w| { | |
| 272 | mac.macmdiodr().write(|w| w.set_md(val)); | 262 | w.set_pa(self.phy_addr); |
| 273 | mac.macmdioar().modify(|w| { | 263 | w.set_rda(reg); |
| 274 | w.set_pa(self.phy_addr); | 264 | w.set_goc(0b01); // write |
| 275 | w.set_rda(reg); | 265 | w.set_cr(self.clock_range); |
| 276 | w.set_goc(0b01); // write | 266 | w.set_mb(true); |
| 277 | w.set_cr(self.clock_range); | 267 | }); |
| 278 | w.set_mb(true); | 268 | while mac.macmdioar().read().mb() {} |
| 279 | }); | ||
| 280 | while mac.macmdioar().read().mb() {} | ||
| 281 | } | ||
| 282 | } | 269 | } |
| 283 | } | 270 | } |
| 284 | 271 | ||
| 285 | impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { | 272 | impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { |
| 286 | fn drop(&mut self) { | 273 | fn drop(&mut self) { |
| 287 | // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers | 274 | let dma = ETH.ethernet_dma(); |
| 288 | unsafe { | 275 | let mac = ETH.ethernet_mac(); |
| 289 | let dma = ETH.ethernet_dma(); | 276 | let mtl = ETH.ethernet_mtl(); |
| 290 | let mac = ETH.ethernet_mac(); | 277 | |
| 291 | let mtl = ETH.ethernet_mtl(); | 278 | // Disable the TX DMA and wait for any previous transmissions to be completed |
| 292 | 279 | dma.dmactx_cr().modify(|w| w.set_st(false)); | |
| 293 | // Disable the TX DMA and wait for any previous transmissions to be completed | 280 | while { |
| 294 | dma.dmactx_cr().modify(|w| w.set_st(false)); | 281 | let txqueue = mtl.mtltx_qdr().read(); |
| 295 | while { | 282 | txqueue.trcsts() == 0b01 || txqueue.txqsts() |
| 296 | let txqueue = mtl.mtltx_qdr().read(); | 283 | } {} |
| 297 | txqueue.trcsts() == 0b01 || txqueue.txqsts() | 284 | |
| 298 | } {} | 285 | // Disable MAC transmitter and receiver |
| 299 | 286 | mac.maccr().modify(|w| { | |
| 300 | // Disable MAC transmitter and receiver | 287 | w.set_re(false); |
| 301 | mac.maccr().modify(|w| { | 288 | w.set_te(false); |
| 302 | w.set_re(false); | 289 | }); |
| 303 | w.set_te(false); | 290 | |
| 304 | }); | 291 | // Wait for previous receiver transfers to be completed and then disable the RX DMA |
| 292 | while { | ||
| 293 | let rxqueue = mtl.mtlrx_qdr().read(); | ||
| 294 | rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0 | ||
| 295 | } {} | ||
| 296 | dma.dmacrx_cr().modify(|w| w.set_sr(false)); | ||
| 305 | 297 | ||
| 306 | // Wait for previous receiver transfers to be completed and then disable the RX DMA | 298 | critical_section::with(|_| { |
| 307 | while { | ||
| 308 | let rxqueue = mtl.mtlrx_qdr().read(); | ||
| 309 | rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0 | ||
| 310 | } {} | ||
| 311 | dma.dmacrx_cr().modify(|w| w.set_sr(false)); | ||
| 312 | } | ||
| 313 | |||
| 314 | // NOTE(unsafe) Exclusive access to the regs | ||
| 315 | critical_section::with(|_| unsafe { | ||
| 316 | for pin in self.pins.iter_mut() { | 299 | for pin in self.pins.iter_mut() { |
| 317 | pin.set_as_disconnected(); | 300 | pin.set_as_disconnected(); |
| 318 | } | 301 | } |
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 10109e56a..3ff92c9e6 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs | |||
| @@ -206,7 +206,7 @@ struct ExtiInputFuture<'a> { | |||
| 206 | 206 | ||
| 207 | impl<'a> ExtiInputFuture<'a> { | 207 | impl<'a> ExtiInputFuture<'a> { |
| 208 | fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { | 208 | fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { |
| 209 | critical_section::with(|_| unsafe { | 209 | critical_section::with(|_| { |
| 210 | let pin = pin as usize; | 210 | let pin = pin as usize; |
| 211 | exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); | 211 | exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); |
| 212 | EXTI.rtsr(0).modify(|w| w.set_line(pin, rising)); | 212 | EXTI.rtsr(0).modify(|w| w.set_line(pin, rising)); |
| @@ -233,7 +233,7 @@ impl<'a> ExtiInputFuture<'a> { | |||
| 233 | 233 | ||
| 234 | impl<'a> Drop for ExtiInputFuture<'a> { | 234 | impl<'a> Drop for ExtiInputFuture<'a> { |
| 235 | fn drop(&mut self) { | 235 | fn drop(&mut self) { |
| 236 | critical_section::with(|_| unsafe { | 236 | critical_section::with(|_| { |
| 237 | let pin = self.pin as _; | 237 | let pin = self.pin as _; |
| 238 | cpu_regs().imr(0).modify(|w| w.set_line(pin, false)); | 238 | cpu_regs().imr(0).modify(|w| w.set_line(pin, false)); |
| 239 | }); | 239 | }); |
| @@ -246,7 +246,7 @@ impl<'a> Future for ExtiInputFuture<'a> { | |||
| 246 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | 246 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 247 | EXTI_WAKERS[self.pin as usize].register(cx.waker()); | 247 | EXTI_WAKERS[self.pin as usize].register(cx.waker()); |
| 248 | 248 | ||
| 249 | let imr = unsafe { cpu_regs().imr(0).read() }; | 249 | let imr = cpu_regs().imr(0).read(); |
| 250 | if !imr.line(self.pin as _) { | 250 | if !imr.line(self.pin as _) { |
| 251 | Poll::Ready(()) | 251 | Poll::Ready(()) |
| 252 | } else { | 252 | } else { |
| @@ -291,6 +291,7 @@ macro_rules! foreach_exti_irq { | |||
| 291 | 291 | ||
| 292 | macro_rules! impl_irq { | 292 | macro_rules! impl_irq { |
| 293 | ($e:ident) => { | 293 | ($e:ident) => { |
| 294 | #[cfg(feature = "rt")] | ||
| 294 | #[interrupt] | 295 | #[interrupt] |
| 295 | unsafe fn $e() { | 296 | unsafe fn $e() { |
| 296 | on_irq() | 297 | on_irq() |
| @@ -354,13 +355,13 @@ impl_exti!(EXTI15, 15); | |||
| 354 | 355 | ||
| 355 | macro_rules! enable_irq { | 356 | macro_rules! enable_irq { |
| 356 | ($e:ident) => { | 357 | ($e:ident) => { |
| 357 | crate::interrupt::$e::steal().enable(); | 358 | crate::interrupt::typelevel::$e::enable(); |
| 358 | }; | 359 | }; |
| 359 | } | 360 | } |
| 360 | 361 | ||
| 361 | /// safety: must be called only once | 362 | /// safety: must be called only once |
| 362 | pub(crate) unsafe fn init() { | 363 | pub(crate) unsafe fn init() { |
| 363 | use crate::interrupt::{Interrupt, InterruptExt}; | 364 | use crate::interrupt::typelevel::Interrupt; |
| 364 | 365 | ||
| 365 | foreach_exti_irq!(enable_irq); | 366 | foreach_exti_irq!(enable_irq); |
| 366 | 367 | ||
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index 3c3ece99a..70a5ded62 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | use core::marker::PhantomData; | 1 | use core::marker::PhantomData; |
| 2 | 2 | ||
| 3 | use atomic_polyfill::{fence, Ordering}; | 3 | use atomic_polyfill::{fence, Ordering}; |
| 4 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 5 | use embassy_hal_common::drop::OnDrop; | 4 | use embassy_hal_common::drop::OnDrop; |
| 6 | use embassy_hal_common::into_ref; | 5 | use embassy_hal_common::into_ref; |
| 7 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| @@ -11,6 +10,7 @@ use super::{ | |||
| 11 | blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE, | 10 | blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE, |
| 12 | WRITE_SIZE, | 11 | WRITE_SIZE, |
| 13 | }; | 12 | }; |
| 13 | use crate::interrupt::InterruptExt; | ||
| 14 | use crate::peripherals::FLASH; | 14 | use crate::peripherals::FLASH; |
| 15 | use crate::{interrupt, Peripheral}; | 15 | use crate::{interrupt, Peripheral}; |
| 16 | 16 | ||
| @@ -19,13 +19,12 @@ pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new | |||
| 19 | impl<'d> Flash<'d, Async> { | 19 | impl<'d> Flash<'d, Async> { |
| 20 | pub fn new( | 20 | pub fn new( |
| 21 | p: impl Peripheral<P = FLASH> + 'd, | 21 | p: impl Peripheral<P = FLASH> + 'd, |
| 22 | _irq: impl interrupt::Binding<crate::interrupt::FLASH, InterruptHandler> + 'd, | 22 | _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd, |
| 23 | ) -> Self { | 23 | ) -> Self { |
| 24 | into_ref!(p); | 24 | into_ref!(p); |
| 25 | 25 | ||
| 26 | let flash_irq = unsafe { crate::interrupt::FLASH::steal() }; | 26 | crate::interrupt::FLASH.unpend(); |
| 27 | flash_irq.unpend(); | 27 | unsafe { crate::interrupt::FLASH.enable() }; |
| 28 | flash_irq.enable(); | ||
| 29 | 28 | ||
| 30 | Self { | 29 | Self { |
| 31 | inner: p, | 30 | inner: p, |
| @@ -50,7 +49,7 @@ impl<'d> Flash<'d, Async> { | |||
| 50 | /// Interrupt handler | 49 | /// Interrupt handler |
| 51 | pub struct InterruptHandler; | 50 | pub struct InterruptHandler; |
| 52 | 51 | ||
| 53 | impl interrupt::Handler<crate::interrupt::FLASH> for InterruptHandler { | 52 | impl interrupt::typelevel::Handler<crate::interrupt::typelevel::FLASH> for InterruptHandler { |
| 54 | unsafe fn on_interrupt() { | 53 | unsafe fn on_interrupt() { |
| 55 | family::on_interrupt(); | 54 | family::on_interrupt(); |
| 56 | } | 55 | } |
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 5e1fc696f..242d99278 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs | |||
| @@ -192,7 +192,7 @@ impl FlashSector { | |||
| 192 | 192 | ||
| 193 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] | 193 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] |
| 194 | pub(crate) fn is_default_layout() -> bool { | 194 | pub(crate) fn is_default_layout() -> bool { |
| 195 | unsafe { !pac::FLASH.optcr().read().db1m() } | 195 | !pac::FLASH.optcr().read().db1m() |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | #[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))] | 198 | #[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))] |
| @@ -336,7 +336,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 336 | ret | 336 | ret |
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | pub(crate) unsafe fn clear_all_err() { | 339 | pub(crate) fn clear_all_err() { |
| 340 | pac::FLASH.sr().write(|w| { | 340 | pac::FLASH.sr().write(|w| { |
| 341 | w.set_pgserr(true); | 341 | w.set_pgserr(true); |
| 342 | w.set_pgperr(true); | 342 | w.set_pgperr(true); |
| @@ -345,7 +345,7 @@ pub(crate) unsafe fn clear_all_err() { | |||
| 345 | }); | 345 | }); |
| 346 | } | 346 | } |
| 347 | 347 | ||
| 348 | pub(crate) async unsafe fn wait_ready() -> Result<(), Error> { | 348 | pub(crate) async fn wait_ready() -> Result<(), Error> { |
| 349 | use core::task::Poll; | 349 | use core::task::Poll; |
| 350 | 350 | ||
| 351 | use futures::future::poll_fn; | 351 | use futures::future::poll_fn; |
| @@ -391,10 +391,10 @@ fn save_data_cache_state() { | |||
| 391 | let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2; | 391 | let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2; |
| 392 | if dual_bank { | 392 | if dual_bank { |
| 393 | // Disable data cache during write/erase if there are two banks, see errata 2.2.12 | 393 | // Disable data cache during write/erase if there are two banks, see errata 2.2.12 |
| 394 | let dcen = unsafe { pac::FLASH.acr().read().dcen() }; | 394 | let dcen = pac::FLASH.acr().read().dcen(); |
| 395 | DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed); | 395 | DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed); |
| 396 | if dcen { | 396 | if dcen { |
| 397 | unsafe { pac::FLASH.acr().modify(|w| w.set_dcen(false)) }; | 397 | pac::FLASH.acr().modify(|w| w.set_dcen(false)); |
| 398 | } | 398 | } |
| 399 | } | 399 | } |
| 400 | } | 400 | } |
| @@ -405,12 +405,10 @@ fn restore_data_cache_state() { | |||
| 405 | // Restore data cache if it was enabled | 405 | // Restore data cache if it was enabled |
| 406 | let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed); | 406 | let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed); |
| 407 | if dcen { | 407 | if dcen { |
| 408 | unsafe { | 408 | // Reset data cache before we enable it again |
| 409 | // Reset data cache before we enable it again | 409 | pac::FLASH.acr().modify(|w| w.set_dcrst(true)); |
| 410 | pac::FLASH.acr().modify(|w| w.set_dcrst(true)); | 410 | pac::FLASH.acr().modify(|w| w.set_dcrst(false)); |
| 411 | pac::FLASH.acr().modify(|w| w.set_dcrst(false)); | 411 | pac::FLASH.acr().modify(|w| w.set_dcen(true)) |
| 412 | pac::FLASH.acr().modify(|w| w.set_dcen(true)) | ||
| 413 | }; | ||
| 414 | } | 412 | } |
| 415 | } | 413 | } |
| 416 | } | 414 | } |
| @@ -445,7 +443,7 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) { | |||
| 445 | feature = "stm32f439vi", | 443 | feature = "stm32f439vi", |
| 446 | feature = "stm32f439zi", | 444 | feature = "stm32f439zi", |
| 447 | ))] | 445 | ))] |
| 448 | if second_bank_read && unsafe { pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() } { | 446 | if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { |
| 449 | panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); | 447 | panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); |
| 450 | } | 448 | } |
| 451 | 449 | ||
| @@ -479,11 +477,9 @@ fn pa12_is_output_pull_low() -> bool { | |||
| 479 | use pac::gpio::vals; | 477 | use pac::gpio::vals; |
| 480 | use pac::GPIOA; | 478 | use pac::GPIOA; |
| 481 | const PIN: usize = 12; | 479 | const PIN: usize = 12; |
| 482 | unsafe { | 480 | GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT |
| 483 | GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT | 481 | && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN |
| 484 | && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN | 482 | && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW |
| 485 | && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW | ||
| 486 | } | ||
| 487 | } | 483 | } |
| 488 | 484 | ||
| 489 | #[cfg(test)] | 485 | #[cfg(test)] |
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index b9129cb51..a4f3b9686 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs | |||
| @@ -16,7 +16,7 @@ unsafe impl<'d, T> stm32_fmc::FmcPeripheral for Fmc<'d, T> | |||
| 16 | where | 16 | where |
| 17 | T: Instance, | 17 | T: Instance, |
| 18 | { | 18 | { |
| 19 | const REGISTERS: *const () = T::REGS.0 as *const _; | 19 | const REGISTERS: *const () = T::REGS.as_ptr() as *const _; |
| 20 | 20 | ||
| 21 | fn enable(&mut self) { | 21 | fn enable(&mut self) { |
| 22 | <T as crate::rcc::sealed::RccPeripheral>::enable(); | 22 | <T as crate::rcc::sealed::RccPeripheral>::enable(); |
| @@ -28,9 +28,7 @@ where | |||
| 28 | // fsmc v1, v2 and v3 does not have the fmcen bit | 28 | // fsmc v1, v2 and v3 does not have the fmcen bit |
| 29 | // This is a "not" because it is expected that all future versions have this bit | 29 | // This is a "not" because it is expected that all future versions have this bit |
| 30 | #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))] | 30 | #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))] |
| 31 | unsafe { | 31 | T::REGS.bcr1().modify(|r| r.set_fmcen(true)); |
| 32 | T::REGS.bcr1().modify(|r| r.set_fmcen(true)) | ||
| 33 | }; | ||
| 34 | } | 32 | } |
| 35 | 33 | ||
| 36 | fn source_clock_hz(&self) -> u32 { | 34 | fn source_clock_hz(&self) -> u32 { |
| @@ -67,7 +65,7 @@ macro_rules! fmc_sdram_constructor { | |||
| 67 | chip: CHIP | 65 | chip: CHIP |
| 68 | ) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> { | 66 | ) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> { |
| 69 | 67 | ||
| 70 | critical_section::with(|_| unsafe { | 68 | critical_section::with(|_| { |
| 71 | config_pins!( | 69 | config_pins!( |
| 72 | $($addr_pin_name),*, | 70 | $($addr_pin_name),*, |
| 73 | $($ba_pin_name),*, | 71 | $($ba_pin_name),*, |
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 4895684e0..af3a8eaca 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs | |||
| @@ -46,7 +46,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 46 | /// Put the pin into input mode. | 46 | /// Put the pin into input mode. |
| 47 | #[inline] | 47 | #[inline] |
| 48 | pub fn set_as_input(&mut self, pull: Pull) { | 48 | pub fn set_as_input(&mut self, pull: Pull) { |
| 49 | critical_section::with(|_| unsafe { | 49 | critical_section::with(|_| { |
| 50 | let r = self.pin.block(); | 50 | let r = self.pin.block(); |
| 51 | let n = self.pin.pin() as usize; | 51 | let n = self.pin.pin() as usize; |
| 52 | #[cfg(gpio_v1)] | 52 | #[cfg(gpio_v1)] |
| @@ -84,7 +84,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 84 | /// at a specific level, call `set_high`/`set_low` on the pin first. | 84 | /// at a specific level, call `set_high`/`set_low` on the pin first. |
| 85 | #[inline] | 85 | #[inline] |
| 86 | pub fn set_as_output(&mut self, speed: Speed) { | 86 | pub fn set_as_output(&mut self, speed: Speed) { |
| 87 | critical_section::with(|_| unsafe { | 87 | critical_section::with(|_| { |
| 88 | let r = self.pin.block(); | 88 | let r = self.pin.block(); |
| 89 | let n = self.pin.pin() as usize; | 89 | let n = self.pin.pin() as usize; |
| 90 | #[cfg(gpio_v1)] | 90 | #[cfg(gpio_v1)] |
| @@ -116,7 +116,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 116 | /// at a specific level, call `set_high`/`set_low` on the pin first. | 116 | /// at a specific level, call `set_high`/`set_low` on the pin first. |
| 117 | #[inline] | 117 | #[inline] |
| 118 | pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) { | 118 | pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) { |
| 119 | critical_section::with(|_| unsafe { | 119 | critical_section::with(|_| { |
| 120 | let r = self.pin.block(); | 120 | let r = self.pin.block(); |
| 121 | let n = self.pin.pin() as usize; | 121 | let n = self.pin.pin() as usize; |
| 122 | #[cfg(gpio_v1)] | 122 | #[cfg(gpio_v1)] |
| @@ -147,7 +147,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 147 | 147 | ||
| 148 | #[inline] | 148 | #[inline] |
| 149 | pub fn is_low(&self) -> bool { | 149 | pub fn is_low(&self) -> bool { |
| 150 | let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as _) }; | 150 | let state = self.pin.block().idr().read().idr(self.pin.pin() as _); |
| 151 | state == vals::Idr::LOW | 151 | state == vals::Idr::LOW |
| 152 | } | 152 | } |
| 153 | 153 | ||
| @@ -164,7 +164,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 164 | /// Is the output pin set as low? | 164 | /// Is the output pin set as low? |
| 165 | #[inline] | 165 | #[inline] |
| 166 | pub fn is_set_low(&self) -> bool { | 166 | pub fn is_set_low(&self) -> bool { |
| 167 | let state = unsafe { self.pin.block().odr().read().odr(self.pin.pin() as _) }; | 167 | let state = self.pin.block().odr().read().odr(self.pin.pin() as _); |
| 168 | state == vals::Odr::LOW | 168 | state == vals::Odr::LOW |
| 169 | } | 169 | } |
| 170 | 170 | ||
| @@ -207,7 +207,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 207 | impl<'d, T: Pin> Drop for Flex<'d, T> { | 207 | impl<'d, T: Pin> Drop for Flex<'d, T> { |
| 208 | #[inline] | 208 | #[inline] |
| 209 | fn drop(&mut self) { | 209 | fn drop(&mut self) { |
| 210 | critical_section::with(|_| unsafe { | 210 | critical_section::with(|_| { |
| 211 | let r = self.pin.block(); | 211 | let r = self.pin.block(); |
| 212 | let n = self.pin.pin() as usize; | 212 | let n = self.pin.pin() as usize; |
| 213 | #[cfg(gpio_v1)] | 213 | #[cfg(gpio_v1)] |
| @@ -341,9 +341,9 @@ impl From<bool> for Level { | |||
| 341 | } | 341 | } |
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | impl Into<bool> for Level { | 344 | impl From<Level> for bool { |
| 345 | fn into(self) -> bool { | 345 | fn from(level: Level) -> bool { |
| 346 | match self { | 346 | match level { |
| 347 | Level::Low => false, | 347 | Level::Low => false, |
| 348 | Level::High => true, | 348 | Level::High => true, |
| 349 | } | 349 | } |
| @@ -534,29 +534,25 @@ pub(crate) mod sealed { | |||
| 534 | /// Set the output as high. | 534 | /// Set the output as high. |
| 535 | #[inline] | 535 | #[inline] |
| 536 | fn set_high(&self) { | 536 | fn set_high(&self) { |
| 537 | unsafe { | 537 | let n = self._pin() as _; |
| 538 | let n = self._pin() as _; | 538 | self.block().bsrr().write(|w| w.set_bs(n, true)); |
| 539 | self.block().bsrr().write(|w| w.set_bs(n, true)); | ||
| 540 | } | ||
| 541 | } | 539 | } |
| 542 | 540 | ||
| 543 | /// Set the output as low. | 541 | /// Set the output as low. |
| 544 | #[inline] | 542 | #[inline] |
| 545 | fn set_low(&self) { | 543 | fn set_low(&self) { |
| 546 | unsafe { | 544 | let n = self._pin() as _; |
| 547 | let n = self._pin() as _; | 545 | self.block().bsrr().write(|w| w.set_br(n, true)); |
| 548 | self.block().bsrr().write(|w| w.set_br(n, true)); | ||
| 549 | } | ||
| 550 | } | 546 | } |
| 551 | 547 | ||
| 552 | #[inline] | 548 | #[inline] |
| 553 | unsafe fn set_as_af(&self, af_num: u8, af_type: AFType) { | 549 | fn set_as_af(&self, af_num: u8, af_type: AFType) { |
| 554 | self.set_as_af_pull(af_num, af_type, Pull::None); | 550 | self.set_as_af_pull(af_num, af_type, Pull::None); |
| 555 | } | 551 | } |
| 556 | 552 | ||
| 557 | #[cfg(gpio_v1)] | 553 | #[cfg(gpio_v1)] |
| 558 | #[inline] | 554 | #[inline] |
| 559 | unsafe fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) { | 555 | fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) { |
| 560 | // F1 uses the AFIO register for remapping. | 556 | // F1 uses the AFIO register for remapping. |
| 561 | // For now, this is not implemented, so af_num is ignored | 557 | // For now, this is not implemented, so af_num is ignored |
| 562 | // _af_num should be zero here, since it is not set by stm32-data | 558 | // _af_num should be zero here, since it is not set by stm32-data |
| @@ -599,7 +595,7 @@ pub(crate) mod sealed { | |||
| 599 | 595 | ||
| 600 | #[cfg(gpio_v2)] | 596 | #[cfg(gpio_v2)] |
| 601 | #[inline] | 597 | #[inline] |
| 602 | unsafe fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) { | 598 | fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) { |
| 603 | let pin = self._pin() as usize; | 599 | let pin = self._pin() as usize; |
| 604 | let block = self.block(); | 600 | let block = self.block(); |
| 605 | block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num)); | 601 | block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num)); |
| @@ -614,7 +610,7 @@ pub(crate) mod sealed { | |||
| 614 | } | 610 | } |
| 615 | 611 | ||
| 616 | #[inline] | 612 | #[inline] |
| 617 | unsafe fn set_as_analog(&self) { | 613 | fn set_as_analog(&self) { |
| 618 | let pin = self._pin() as usize; | 614 | let pin = self._pin() as usize; |
| 619 | let block = self.block(); | 615 | let block = self.block(); |
| 620 | #[cfg(gpio_v1)] | 616 | #[cfg(gpio_v1)] |
| @@ -635,12 +631,12 @@ pub(crate) mod sealed { | |||
| 635 | /// This is currently the same as set_as_analog but is semantically different really. | 631 | /// This is currently the same as set_as_analog but is semantically different really. |
| 636 | /// Drivers should set_as_disconnected pins when dropped. | 632 | /// Drivers should set_as_disconnected pins when dropped. |
| 637 | #[inline] | 633 | #[inline] |
| 638 | unsafe fn set_as_disconnected(&self) { | 634 | fn set_as_disconnected(&self) { |
| 639 | self.set_as_analog(); | 635 | self.set_as_analog(); |
| 640 | } | 636 | } |
| 641 | 637 | ||
| 642 | #[inline] | 638 | #[inline] |
| 643 | unsafe fn set_speed(&self, speed: Speed) { | 639 | fn set_speed(&self, speed: Speed) { |
| 644 | let pin = self._pin() as usize; | 640 | let pin = self._pin() as usize; |
| 645 | 641 | ||
| 646 | #[cfg(gpio_v1)] | 642 | #[cfg(gpio_v1)] |
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index f898fcc8b..b35678ed9 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use crate::interrupt::Interrupt; | 3 | use crate::interrupt; |
| 4 | 4 | ||
| 5 | #[cfg_attr(i2c_v1, path = "v1.rs")] | 5 | #[cfg_attr(i2c_v1, path = "v1.rs")] |
| 6 | #[cfg_attr(i2c_v2, path = "v2.rs")] | 6 | #[cfg_attr(i2c_v2, path = "v2.rs")] |
| @@ -35,7 +35,7 @@ pub(crate) mod sealed { | |||
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | pub trait Instance: sealed::Instance + 'static { | 37 | pub trait Instance: sealed::Instance + 'static { |
| 38 | type Interrupt: Interrupt; | 38 | type Interrupt: interrupt::typelevel::Interrupt; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | pin_trait!(SclPin, Instance); | 41 | pin_trait!(SclPin, Instance); |
| @@ -57,7 +57,7 @@ foreach_interrupt!( | |||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | impl Instance for peripherals::$inst { | 59 | impl Instance for peripherals::$inst { |
| 60 | type Interrupt = crate::interrupt::$irq; | 60 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 61 | } | 61 | } |
| 62 | }; | 62 | }; |
| 63 | ); | 63 | ); |
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index b9be2e587..aa485cd86 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -16,7 +16,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 16 | _phantom: PhantomData<T>, | 16 | _phantom: PhantomData<T>, |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 19 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 20 | unsafe fn on_interrupt() {} | 20 | unsafe fn on_interrupt() {} |
| 21 | } | 21 | } |
| 22 | 22 | ||
| @@ -57,7 +57,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 57 | _peri: impl Peripheral<P = T> + 'd, | 57 | _peri: impl Peripheral<P = T> + 'd, |
| 58 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | 58 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, |
| 59 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | 59 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, |
| 60 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 60 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 61 | tx_dma: impl Peripheral<P = TXDMA> + 'd, | 61 | tx_dma: impl Peripheral<P = TXDMA> + 'd, |
| 62 | rx_dma: impl Peripheral<P = RXDMA> + 'd, | 62 | rx_dma: impl Peripheral<P = RXDMA> + 'd, |
| 63 | freq: Hertz, | 63 | freq: Hertz, |
| @@ -68,53 +68,45 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 68 | T::enable(); | 68 | T::enable(); |
| 69 | T::reset(); | 69 | T::reset(); |
| 70 | 70 | ||
| 71 | unsafe { | 71 | scl.set_as_af_pull( |
| 72 | scl.set_as_af_pull( | 72 | scl.af_num(), |
| 73 | scl.af_num(), | 73 | AFType::OutputOpenDrain, |
| 74 | AFType::OutputOpenDrain, | 74 | match config.scl_pullup { |
| 75 | match config.scl_pullup { | 75 | true => Pull::Up, |
| 76 | true => Pull::Up, | 76 | false => Pull::None, |
| 77 | false => Pull::None, | 77 | }, |
| 78 | }, | 78 | ); |
| 79 | ); | 79 | sda.set_as_af_pull( |
| 80 | sda.set_as_af_pull( | 80 | sda.af_num(), |
| 81 | sda.af_num(), | 81 | AFType::OutputOpenDrain, |
| 82 | AFType::OutputOpenDrain, | 82 | match config.sda_pullup { |
| 83 | match config.sda_pullup { | 83 | true => Pull::Up, |
| 84 | true => Pull::Up, | 84 | false => Pull::None, |
| 85 | false => Pull::None, | 85 | }, |
| 86 | }, | 86 | ); |
| 87 | ); | ||
| 88 | } | ||
| 89 | 87 | ||
| 90 | unsafe { | 88 | T::regs().cr1().modify(|reg| { |
| 91 | T::regs().cr1().modify(|reg| { | 89 | reg.set_pe(false); |
| 92 | reg.set_pe(false); | 90 | //reg.set_anfoff(false); |
| 93 | //reg.set_anfoff(false); | 91 | }); |
| 94 | }); | ||
| 95 | } | ||
| 96 | 92 | ||
| 97 | let timings = Timings::new(T::frequency(), freq.into()); | 93 | let timings = Timings::new(T::frequency(), freq.into()); |
| 98 | 94 | ||
| 99 | unsafe { | 95 | T::regs().cr2().modify(|reg| { |
| 100 | T::regs().cr2().modify(|reg| { | 96 | reg.set_freq(timings.freq); |
| 101 | reg.set_freq(timings.freq); | 97 | }); |
| 102 | }); | 98 | T::regs().ccr().modify(|reg| { |
| 103 | T::regs().ccr().modify(|reg| { | 99 | reg.set_f_s(timings.mode.f_s()); |
| 104 | reg.set_f_s(timings.mode.f_s()); | 100 | reg.set_duty(timings.duty.duty()); |
| 105 | reg.set_duty(timings.duty.duty()); | 101 | reg.set_ccr(timings.ccr); |
| 106 | reg.set_ccr(timings.ccr); | 102 | }); |
| 107 | }); | 103 | T::regs().trise().modify(|reg| { |
| 108 | T::regs().trise().modify(|reg| { | 104 | reg.set_trise(timings.trise); |
| 109 | reg.set_trise(timings.trise); | 105 | }); |
| 110 | }); | ||
| 111 | } | ||
| 112 | 106 | ||
| 113 | unsafe { | 107 | T::regs().cr1().modify(|reg| { |
| 114 | T::regs().cr1().modify(|reg| { | 108 | reg.set_pe(true); |
| 115 | reg.set_pe(true); | 109 | }); |
| 116 | }); | ||
| 117 | } | ||
| 118 | 110 | ||
| 119 | Self { | 111 | Self { |
| 120 | phantom: PhantomData, | 112 | phantom: PhantomData, |
| @@ -123,7 +115,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 123 | } | 115 | } |
| 124 | } | 116 | } |
| 125 | 117 | ||
| 126 | unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { | 118 | fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { |
| 127 | // Note that flags should only be cleared once they have been registered. If flags are | 119 | // Note that flags should only be cleared once they have been registered. If flags are |
| 128 | // cleared otherwise, there may be an inherent race condition and flags may be missed. | 120 | // cleared otherwise, there may be an inherent race condition and flags may be missed. |
| 129 | let sr1 = T::regs().sr1().read(); | 121 | let sr1 = T::regs().sr1().read(); |
| @@ -162,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 162 | Ok(sr1) | 154 | Ok(sr1) |
| 163 | } | 155 | } |
| 164 | 156 | ||
| 165 | unsafe fn write_bytes( | 157 | fn write_bytes( |
| 166 | &mut self, | 158 | &mut self, |
| 167 | addr: u8, | 159 | addr: u8, |
| 168 | bytes: &[u8], | 160 | bytes: &[u8], |
| @@ -211,7 +203,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 211 | Ok(()) | 203 | Ok(()) |
| 212 | } | 204 | } |
| 213 | 205 | ||
| 214 | unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | 206 | fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 215 | // Wait until we're ready for sending | 207 | // Wait until we're ready for sending |
| 216 | while { | 208 | while { |
| 217 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | 209 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |
| @@ -234,7 +226,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 234 | Ok(()) | 226 | Ok(()) |
| 235 | } | 227 | } |
| 236 | 228 | ||
| 237 | unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { | 229 | fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { |
| 238 | while { | 230 | while { |
| 239 | // Check for any potential error conditions. | 231 | // Check for any potential error conditions. |
| 240 | self.check_and_clear_error_flags()?; | 232 | self.check_and_clear_error_flags()?; |
| @@ -256,56 +248,52 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 256 | ) -> Result<(), Error> { | 248 | ) -> Result<(), Error> { |
| 257 | if let Some((last, buffer)) = buffer.split_last_mut() { | 249 | if let Some((last, buffer)) = buffer.split_last_mut() { |
| 258 | // Send a START condition and set ACK bit | 250 | // Send a START condition and set ACK bit |
| 259 | unsafe { | 251 | T::regs().cr1().modify(|reg| { |
| 260 | T::regs().cr1().modify(|reg| { | 252 | reg.set_start(true); |
| 261 | reg.set_start(true); | 253 | reg.set_ack(true); |
| 262 | reg.set_ack(true); | 254 | }); |
| 263 | }); | ||
| 264 | } | ||
| 265 | 255 | ||
| 266 | // Wait until START condition was generated | 256 | // Wait until START condition was generated |
| 267 | while unsafe { !self.check_and_clear_error_flags()?.start() } { | 257 | while !self.check_and_clear_error_flags()?.start() { |
| 268 | check_timeout()?; | 258 | check_timeout()?; |
| 269 | } | 259 | } |
| 270 | 260 | ||
| 271 | // Also wait until signalled we're master and everything is waiting for us | 261 | // Also wait until signalled we're master and everything is waiting for us |
| 272 | while { | 262 | while { |
| 273 | let sr2 = unsafe { T::regs().sr2().read() }; | 263 | let sr2 = T::regs().sr2().read(); |
| 274 | !sr2.msl() && !sr2.busy() | 264 | !sr2.msl() && !sr2.busy() |
| 275 | } { | 265 | } { |
| 276 | check_timeout()?; | 266 | check_timeout()?; |
| 277 | } | 267 | } |
| 278 | 268 | ||
| 279 | // Set up current address, we're trying to talk to | 269 | // Set up current address, we're trying to talk to |
| 280 | unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) } | 270 | T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)); |
| 281 | 271 | ||
| 282 | // Wait until address was sent | 272 | // Wait until address was sent |
| 283 | // Wait for the address to be acknowledged | 273 | // Wait for the address to be acknowledged |
| 284 | while unsafe { !self.check_and_clear_error_flags()?.addr() } { | 274 | while !self.check_and_clear_error_flags()?.addr() { |
| 285 | check_timeout()?; | 275 | check_timeout()?; |
| 286 | } | 276 | } |
| 287 | 277 | ||
| 288 | // Clear condition by reading SR2 | 278 | // Clear condition by reading SR2 |
| 289 | let _ = unsafe { T::regs().sr2().read() }; | 279 | let _ = T::regs().sr2().read(); |
| 290 | 280 | ||
| 291 | // Receive bytes into buffer | 281 | // Receive bytes into buffer |
| 292 | for c in buffer { | 282 | for c in buffer { |
| 293 | *c = unsafe { self.recv_byte(&check_timeout)? }; | 283 | *c = self.recv_byte(&check_timeout)?; |
| 294 | } | 284 | } |
| 295 | 285 | ||
| 296 | // Prepare to send NACK then STOP after next byte | 286 | // Prepare to send NACK then STOP after next byte |
| 297 | unsafe { | 287 | T::regs().cr1().modify(|reg| { |
| 298 | T::regs().cr1().modify(|reg| { | 288 | reg.set_ack(false); |
| 299 | reg.set_ack(false); | 289 | reg.set_stop(true); |
| 300 | reg.set_stop(true); | 290 | }); |
| 301 | }) | ||
| 302 | } | ||
| 303 | 291 | ||
| 304 | // Receive last byte | 292 | // Receive last byte |
| 305 | *last = unsafe { self.recv_byte(&check_timeout)? }; | 293 | *last = self.recv_byte(&check_timeout)?; |
| 306 | 294 | ||
| 307 | // Wait for the STOP to be sent. | 295 | // Wait for the STOP to be sent. |
| 308 | while unsafe { T::regs().cr1().read().stop() } { | 296 | while T::regs().cr1().read().stop() { |
| 309 | check_timeout()?; | 297 | check_timeout()?; |
| 310 | } | 298 | } |
| 311 | 299 | ||
| @@ -326,15 +314,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 326 | write: &[u8], | 314 | write: &[u8], |
| 327 | check_timeout: impl Fn() -> Result<(), Error>, | 315 | check_timeout: impl Fn() -> Result<(), Error>, |
| 328 | ) -> Result<(), Error> { | 316 | ) -> Result<(), Error> { |
| 329 | unsafe { | 317 | self.write_bytes(addr, write, &check_timeout)?; |
| 330 | self.write_bytes(addr, write, &check_timeout)?; | 318 | // Send a STOP condition |
| 331 | // Send a STOP condition | 319 | T::regs().cr1().modify(|reg| reg.set_stop(true)); |
| 332 | T::regs().cr1().modify(|reg| reg.set_stop(true)); | 320 | // Wait for STOP condition to transmit. |
| 333 | // Wait for STOP condition to transmit. | 321 | while T::regs().cr1().read().stop() { |
| 334 | while T::regs().cr1().read().stop() { | 322 | check_timeout()?; |
| 335 | check_timeout()?; | 323 | } |
| 336 | } | ||
| 337 | }; | ||
| 338 | 324 | ||
| 339 | // Fallthrough is success | 325 | // Fallthrough is success |
| 340 | Ok(()) | 326 | Ok(()) |
| @@ -351,7 +337,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 351 | read: &mut [u8], | 337 | read: &mut [u8], |
| 352 | check_timeout: impl Fn() -> Result<(), Error>, | 338 | check_timeout: impl Fn() -> Result<(), Error>, |
| 353 | ) -> Result<(), Error> { | 339 | ) -> Result<(), Error> { |
| 354 | unsafe { self.write_bytes(addr, write, &check_timeout)? }; | 340 | self.write_bytes(addr, write, &check_timeout)?; |
| 355 | self.blocking_read_timeout(addr, read, &check_timeout)?; | 341 | self.blocking_read_timeout(addr, read, &check_timeout)?; |
| 356 | 342 | ||
| 357 | Ok(()) | 343 | Ok(()) |
| @@ -478,8 +464,6 @@ impl Timings { | |||
| 478 | assert!(freq >= 2 && freq <= 50); | 464 | assert!(freq >= 2 && freq <= 50); |
| 479 | 465 | ||
| 480 | // Configure bus frequency into I2C peripheral | 466 | // Configure bus frequency into I2C peripheral |
| 481 | //self.i2c.cr2.write(|w| unsafe { w.freq().bits(freq as u8) }); | ||
| 482 | |||
| 483 | let trise = if speed <= 100_000 { | 467 | let trise = if speed <= 100_000 { |
| 484 | freq + 1 | 468 | freq + 1 |
| 485 | } else { | 469 | } else { |
| @@ -539,18 +523,16 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> { | |||
| 539 | type Config = Hertz; | 523 | type Config = Hertz; |
| 540 | fn set_config(&mut self, config: &Self::Config) { | 524 | fn set_config(&mut self, config: &Self::Config) { |
| 541 | let timings = Timings::new(T::frequency(), *config); | 525 | let timings = Timings::new(T::frequency(), *config); |
| 542 | unsafe { | 526 | T::regs().cr2().modify(|reg| { |
| 543 | T::regs().cr2().modify(|reg| { | 527 | reg.set_freq(timings.freq); |
| 544 | reg.set_freq(timings.freq); | 528 | }); |
| 545 | }); | 529 | T::regs().ccr().modify(|reg| { |
| 546 | T::regs().ccr().modify(|reg| { | 530 | reg.set_f_s(timings.mode.f_s()); |
| 547 | reg.set_f_s(timings.mode.f_s()); | 531 | reg.set_duty(timings.duty.duty()); |
| 548 | reg.set_duty(timings.duty.duty()); | 532 | reg.set_ccr(timings.ccr); |
| 549 | reg.set_ccr(timings.ccr); | 533 | }); |
| 550 | }); | 534 | T::regs().trise().modify(|reg| { |
| 551 | T::regs().trise().modify(|reg| { | 535 | reg.set_trise(timings.trise); |
| 552 | reg.set_trise(timings.trise); | 536 | }); |
| 553 | }); | ||
| 554 | } | ||
| 555 | } | 537 | } |
| 556 | } | 538 | } |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 642ddc18c..1f036d55c 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -3,7 +3,6 @@ use core::future::poll_fn; | |||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 7 | use embassy_embedded_hal::SetConfig; | 6 | use embassy_embedded_hal::SetConfig; |
| 8 | use embassy_hal_common::drop::OnDrop; | 7 | use embassy_hal_common::drop::OnDrop; |
| 9 | use embassy_hal_common::{into_ref, PeripheralRef}; | 8 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| @@ -13,6 +12,7 @@ use crate::dma::{NoDma, Transfer}; | |||
| 13 | use crate::gpio::sealed::AFType; | 12 | use crate::gpio::sealed::AFType; |
| 14 | use crate::gpio::Pull; | 13 | use crate::gpio::Pull; |
| 15 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; | 14 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; |
| 15 | use crate::interrupt::typelevel::Interrupt; | ||
| 16 | use crate::pac::i2c; | 16 | use crate::pac::i2c; |
| 17 | use crate::time::Hertz; | 17 | use crate::time::Hertz; |
| 18 | use crate::{interrupt, Peripheral}; | 18 | use crate::{interrupt, Peripheral}; |
| @@ -22,7 +22,7 @@ pub struct InterruptHandler<T: Instance> { | |||
| 22 | _phantom: PhantomData<T>, | 22 | _phantom: PhantomData<T>, |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 25 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 26 | unsafe fn on_interrupt() { | 26 | unsafe fn on_interrupt() { |
| 27 | let regs = T::regs(); | 27 | let regs = T::regs(); |
| 28 | let isr = regs.isr().read(); | 28 | let isr = regs.isr().read(); |
| @@ -78,7 +78,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 78 | peri: impl Peripheral<P = T> + 'd, | 78 | peri: impl Peripheral<P = T> + 'd, |
| 79 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | 79 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, |
| 80 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | 80 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, |
| 81 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 81 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 82 | tx_dma: impl Peripheral<P = TXDMA> + 'd, | 82 | tx_dma: impl Peripheral<P = TXDMA> + 'd, |
| 83 | rx_dma: impl Peripheral<P = RXDMA> + 'd, | 83 | rx_dma: impl Peripheral<P = RXDMA> + 'd, |
| 84 | freq: Hertz, | 84 | freq: Hertz, |
| @@ -89,52 +89,44 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 89 | T::enable(); | 89 | T::enable(); |
| 90 | T::reset(); | 90 | T::reset(); |
| 91 | 91 | ||
| 92 | unsafe { | 92 | scl.set_as_af_pull( |
| 93 | scl.set_as_af_pull( | 93 | scl.af_num(), |
| 94 | scl.af_num(), | 94 | AFType::OutputOpenDrain, |
| 95 | AFType::OutputOpenDrain, | 95 | match config.scl_pullup { |
| 96 | match config.scl_pullup { | 96 | true => Pull::Up, |
| 97 | true => Pull::Up, | 97 | false => Pull::None, |
| 98 | false => Pull::None, | 98 | }, |
| 99 | }, | 99 | ); |
| 100 | ); | 100 | sda.set_as_af_pull( |
| 101 | sda.set_as_af_pull( | 101 | sda.af_num(), |
| 102 | sda.af_num(), | 102 | AFType::OutputOpenDrain, |
| 103 | AFType::OutputOpenDrain, | 103 | match config.sda_pullup { |
| 104 | match config.sda_pullup { | 104 | true => Pull::Up, |
| 105 | true => Pull::Up, | 105 | false => Pull::None, |
| 106 | false => Pull::None, | 106 | }, |
| 107 | }, | 107 | ); |
| 108 | ); | 108 | |
| 109 | } | 109 | T::regs().cr1().modify(|reg| { |
| 110 | 110 | reg.set_pe(false); | |
| 111 | unsafe { | 111 | reg.set_anfoff(false); |
| 112 | T::regs().cr1().modify(|reg| { | 112 | }); |
| 113 | reg.set_pe(false); | ||
| 114 | reg.set_anfoff(false); | ||
| 115 | }); | ||
| 116 | } | ||
| 117 | 113 | ||
| 118 | let timings = Timings::new(T::frequency(), freq.into()); | 114 | let timings = Timings::new(T::frequency(), freq.into()); |
| 119 | 115 | ||
| 120 | unsafe { | 116 | T::regs().timingr().write(|reg| { |
| 121 | T::regs().timingr().write(|reg| { | 117 | reg.set_presc(timings.prescale); |
| 122 | reg.set_presc(timings.prescale); | 118 | reg.set_scll(timings.scll); |
| 123 | reg.set_scll(timings.scll); | 119 | reg.set_sclh(timings.sclh); |
| 124 | reg.set_sclh(timings.sclh); | 120 | reg.set_sdadel(timings.sdadel); |
| 125 | reg.set_sdadel(timings.sdadel); | 121 | reg.set_scldel(timings.scldel); |
| 126 | reg.set_scldel(timings.scldel); | 122 | }); |
| 127 | }); | ||
| 128 | } | ||
| 129 | 123 | ||
| 130 | unsafe { | 124 | T::regs().cr1().modify(|reg| { |
| 131 | T::regs().cr1().modify(|reg| { | 125 | reg.set_pe(true); |
| 132 | reg.set_pe(true); | 126 | }); |
| 133 | }); | ||
| 134 | } | ||
| 135 | 127 | ||
| 136 | unsafe { T::Interrupt::steal() }.unpend(); | 128 | T::Interrupt::unpend(); |
| 137 | unsafe { T::Interrupt::steal() }.enable(); | 129 | unsafe { T::Interrupt::enable() }; |
| 138 | 130 | ||
| 139 | Self { | 131 | Self { |
| 140 | _peri: peri, | 132 | _peri: peri, |
| @@ -144,12 +136,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 144 | } | 136 | } |
| 145 | 137 | ||
| 146 | fn master_stop(&mut self) { | 138 | fn master_stop(&mut self) { |
| 147 | unsafe { | 139 | T::regs().cr2().write(|w| w.set_stop(true)); |
| 148 | T::regs().cr2().write(|w| w.set_stop(true)); | ||
| 149 | } | ||
| 150 | } | 140 | } |
| 151 | 141 | ||
| 152 | unsafe fn master_read( | 142 | fn master_read( |
| 153 | address: u8, | 143 | address: u8, |
| 154 | length: usize, | 144 | length: usize, |
| 155 | stop: Stop, | 145 | stop: Stop, |
| @@ -191,7 +181,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 191 | Ok(()) | 181 | Ok(()) |
| 192 | } | 182 | } |
| 193 | 183 | ||
| 194 | unsafe fn master_write( | 184 | fn master_write( |
| 195 | address: u8, | 185 | address: u8, |
| 196 | length: usize, | 186 | length: usize, |
| 197 | stop: Stop, | 187 | stop: Stop, |
| @@ -229,7 +219,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 229 | Ok(()) | 219 | Ok(()) |
| 230 | } | 220 | } |
| 231 | 221 | ||
| 232 | unsafe fn master_continue( | 222 | fn master_continue( |
| 233 | length: usize, | 223 | length: usize, |
| 234 | reload: bool, | 224 | reload: bool, |
| 235 | check_timeout: impl Fn() -> Result<(), Error>, | 225 | check_timeout: impl Fn() -> Result<(), Error>, |
| @@ -259,13 +249,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 259 | //$i2c.txdr.write(|w| w.txdata().bits(0)); | 249 | //$i2c.txdr.write(|w| w.txdata().bits(0)); |
| 260 | //} | 250 | //} |
| 261 | 251 | ||
| 262 | unsafe { | 252 | if T::regs().isr().read().txis() { |
| 263 | if T::regs().isr().read().txis() { | 253 | T::regs().txdr().write(|w| w.set_txdata(0)); |
| 264 | T::regs().txdr().write(|w| w.set_txdata(0)); | 254 | } |
| 265 | } | 255 | if !T::regs().isr().read().txe() { |
| 266 | if !T::regs().isr().read().txe() { | 256 | T::regs().isr().modify(|w| w.set_txe(true)) |
| 267 | T::regs().isr().modify(|w| w.set_txe(true)) | ||
| 268 | } | ||
| 269 | } | 257 | } |
| 270 | 258 | ||
| 271 | // If TXDR is not flagged as empty, write 1 to flush it | 259 | // If TXDR is not flagged as empty, write 1 to flush it |
| @@ -276,21 +264,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 276 | 264 | ||
| 277 | fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | 265 | fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 278 | loop { | 266 | loop { |
| 279 | unsafe { | 267 | let isr = T::regs().isr().read(); |
| 280 | let isr = T::regs().isr().read(); | 268 | if isr.txe() { |
| 281 | if isr.txe() { | 269 | return Ok(()); |
| 282 | return Ok(()); | 270 | } else if isr.berr() { |
| 283 | } else if isr.berr() { | 271 | T::regs().icr().write(|reg| reg.set_berrcf(true)); |
| 284 | T::regs().icr().write(|reg| reg.set_berrcf(true)); | 272 | return Err(Error::Bus); |
| 285 | return Err(Error::Bus); | 273 | } else if isr.arlo() { |
| 286 | } else if isr.arlo() { | 274 | T::regs().icr().write(|reg| reg.set_arlocf(true)); |
| 287 | T::regs().icr().write(|reg| reg.set_arlocf(true)); | 275 | return Err(Error::Arbitration); |
| 288 | return Err(Error::Arbitration); | 276 | } else if isr.nackf() { |
| 289 | } else if isr.nackf() { | 277 | T::regs().icr().write(|reg| reg.set_nackcf(true)); |
| 290 | T::regs().icr().write(|reg| reg.set_nackcf(true)); | 278 | self.flush_txdr(); |
| 291 | self.flush_txdr(); | 279 | return Err(Error::Nack); |
| 292 | return Err(Error::Nack); | ||
| 293 | } | ||
| 294 | } | 280 | } |
| 295 | 281 | ||
| 296 | check_timeout()?; | 282 | check_timeout()?; |
| @@ -299,21 +285,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 299 | 285 | ||
| 300 | fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | 286 | fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 301 | loop { | 287 | loop { |
| 302 | unsafe { | 288 | let isr = T::regs().isr().read(); |
| 303 | let isr = T::regs().isr().read(); | 289 | if isr.rxne() { |
| 304 | if isr.rxne() { | 290 | return Ok(()); |
| 305 | return Ok(()); | 291 | } else if isr.berr() { |
| 306 | } else if isr.berr() { | 292 | T::regs().icr().write(|reg| reg.set_berrcf(true)); |
| 307 | T::regs().icr().write(|reg| reg.set_berrcf(true)); | 293 | return Err(Error::Bus); |
| 308 | return Err(Error::Bus); | 294 | } else if isr.arlo() { |
| 309 | } else if isr.arlo() { | 295 | T::regs().icr().write(|reg| reg.set_arlocf(true)); |
| 310 | T::regs().icr().write(|reg| reg.set_arlocf(true)); | 296 | return Err(Error::Arbitration); |
| 311 | return Err(Error::Arbitration); | 297 | } else if isr.nackf() { |
| 312 | } else if isr.nackf() { | 298 | T::regs().icr().write(|reg| reg.set_nackcf(true)); |
| 313 | T::regs().icr().write(|reg| reg.set_nackcf(true)); | 299 | self.flush_txdr(); |
| 314 | self.flush_txdr(); | 300 | return Err(Error::Nack); |
| 315 | return Err(Error::Nack); | ||
| 316 | } | ||
| 317 | } | 301 | } |
| 318 | 302 | ||
| 319 | check_timeout()?; | 303 | check_timeout()?; |
| @@ -322,21 +306,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 322 | 306 | ||
| 323 | fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | 307 | fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 324 | loop { | 308 | loop { |
| 325 | unsafe { | 309 | let isr = T::regs().isr().read(); |
| 326 | let isr = T::regs().isr().read(); | 310 | if isr.tc() { |
| 327 | if isr.tc() { | 311 | return Ok(()); |
| 328 | return Ok(()); | 312 | } else if isr.berr() { |
| 329 | } else if isr.berr() { | 313 | T::regs().icr().write(|reg| reg.set_berrcf(true)); |
| 330 | T::regs().icr().write(|reg| reg.set_berrcf(true)); | 314 | return Err(Error::Bus); |
| 331 | return Err(Error::Bus); | 315 | } else if isr.arlo() { |
| 332 | } else if isr.arlo() { | 316 | T::regs().icr().write(|reg| reg.set_arlocf(true)); |
| 333 | T::regs().icr().write(|reg| reg.set_arlocf(true)); | 317 | return Err(Error::Arbitration); |
| 334 | return Err(Error::Arbitration); | 318 | } else if isr.nackf() { |
| 335 | } else if isr.nackf() { | 319 | T::regs().icr().write(|reg| reg.set_nackcf(true)); |
| 336 | T::regs().icr().write(|reg| reg.set_nackcf(true)); | 320 | self.flush_txdr(); |
| 337 | self.flush_txdr(); | 321 | return Err(Error::Nack); |
| 338 | return Err(Error::Nack); | ||
| 339 | } | ||
| 340 | } | 322 | } |
| 341 | 323 | ||
| 342 | check_timeout()?; | 324 | check_timeout()?; |
| @@ -358,32 +340,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 358 | }; | 340 | }; |
| 359 | let last_chunk_idx = total_chunks.saturating_sub(1); | 341 | let last_chunk_idx = total_chunks.saturating_sub(1); |
| 360 | 342 | ||
| 361 | unsafe { | 343 | Self::master_read( |
| 362 | Self::master_read( | 344 | address, |
| 363 | address, | 345 | read.len().min(255), |
| 364 | read.len().min(255), | 346 | Stop::Automatic, |
| 365 | Stop::Automatic, | 347 | last_chunk_idx != 0, |
| 366 | last_chunk_idx != 0, | 348 | restart, |
| 367 | restart, | 349 | &check_timeout, |
| 368 | &check_timeout, | 350 | )?; |
| 369 | )?; | ||
| 370 | } | ||
| 371 | 351 | ||
| 372 | for (number, chunk) in read.chunks_mut(255).enumerate() { | 352 | for (number, chunk) in read.chunks_mut(255).enumerate() { |
| 373 | if number != 0 { | 353 | if number != 0 { |
| 374 | // NOTE(unsafe) We have &mut self | 354 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; |
| 375 | unsafe { | ||
| 376 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; | ||
| 377 | } | ||
| 378 | } | 355 | } |
| 379 | 356 | ||
| 380 | for byte in chunk { | 357 | for byte in chunk { |
| 381 | // Wait until we have received something | 358 | // Wait until we have received something |
| 382 | self.wait_rxne(&check_timeout)?; | 359 | self.wait_rxne(&check_timeout)?; |
| 383 | 360 | ||
| 384 | unsafe { | 361 | *byte = T::regs().rxdr().read().rxdata(); |
| 385 | *byte = T::regs().rxdr().read().rxdata(); | ||
| 386 | } | ||
| 387 | } | 362 | } |
| 388 | } | 363 | } |
| 389 | Ok(()) | 364 | Ok(()) |
| @@ -407,23 +382,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 407 | // I2C start | 382 | // I2C start |
| 408 | // | 383 | // |
| 409 | // ST SAD+W | 384 | // ST SAD+W |
| 410 | // NOTE(unsafe) We have &mut self | 385 | Self::master_write( |
| 411 | unsafe { | 386 | address, |
| 412 | Self::master_write( | 387 | write.len().min(255), |
| 413 | address, | 388 | Stop::Software, |
| 414 | write.len().min(255), | 389 | last_chunk_idx != 0, |
| 415 | Stop::Software, | 390 | &check_timeout, |
| 416 | last_chunk_idx != 0, | 391 | )?; |
| 417 | &check_timeout, | ||
| 418 | )?; | ||
| 419 | } | ||
| 420 | 392 | ||
| 421 | for (number, chunk) in write.chunks(255).enumerate() { | 393 | for (number, chunk) in write.chunks(255).enumerate() { |
| 422 | if number != 0 { | 394 | if number != 0 { |
| 423 | // NOTE(unsafe) We have &mut self | 395 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; |
| 424 | unsafe { | ||
| 425 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; | ||
| 426 | } | ||
| 427 | } | 396 | } |
| 428 | 397 | ||
| 429 | for byte in chunk { | 398 | for byte in chunk { |
| @@ -432,9 +401,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 432 | // through) | 401 | // through) |
| 433 | self.wait_txe(&check_timeout)?; | 402 | self.wait_txe(&check_timeout)?; |
| 434 | 403 | ||
| 435 | unsafe { | 404 | T::regs().txdr().write(|w| w.set_txdata(*byte)); |
| 436 | T::regs().txdr().write(|w| w.set_txdata(*byte)); | ||
| 437 | } | ||
| 438 | } | 405 | } |
| 439 | } | 406 | } |
| 440 | // Wait until the write finishes | 407 | // Wait until the write finishes |
| @@ -467,7 +434,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 467 | w.set_tcie(true); | 434 | w.set_tcie(true); |
| 468 | } | 435 | } |
| 469 | }); | 436 | }); |
| 470 | let dst = regs.txdr().ptr() as *mut u8; | 437 | let dst = regs.txdr().as_ptr() as *mut u8; |
| 471 | 438 | ||
| 472 | let ch = &mut self.tx_dma; | 439 | let ch = &mut self.tx_dma; |
| 473 | let request = ch.request(); | 440 | let request = ch.request(); |
| @@ -479,37 +446,30 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 479 | 446 | ||
| 480 | let on_drop = OnDrop::new(|| { | 447 | let on_drop = OnDrop::new(|| { |
| 481 | let regs = T::regs(); | 448 | let regs = T::regs(); |
| 482 | unsafe { | 449 | regs.cr1().modify(|w| { |
| 483 | regs.cr1().modify(|w| { | 450 | if last_slice { |
| 484 | if last_slice { | 451 | w.set_txdmaen(false); |
| 485 | w.set_txdmaen(false); | 452 | } |
| 486 | } | 453 | w.set_tcie(false); |
| 487 | w.set_tcie(false); | 454 | }) |
| 488 | }) | ||
| 489 | } | ||
| 490 | }); | 455 | }); |
| 491 | 456 | ||
| 492 | poll_fn(|cx| { | 457 | poll_fn(|cx| { |
| 493 | state.waker.register(cx.waker()); | 458 | state.waker.register(cx.waker()); |
| 494 | 459 | ||
| 495 | let isr = unsafe { T::regs().isr().read() }; | 460 | let isr = T::regs().isr().read(); |
| 496 | if remaining_len == total_len { | 461 | if remaining_len == total_len { |
| 497 | // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers | ||
| 498 | if first_slice { | 462 | if first_slice { |
| 499 | unsafe { | 463 | Self::master_write( |
| 500 | Self::master_write( | 464 | address, |
| 501 | address, | 465 | total_len.min(255), |
| 502 | total_len.min(255), | 466 | Stop::Software, |
| 503 | Stop::Software, | 467 | (total_len > 255) || !last_slice, |
| 504 | (total_len > 255) || !last_slice, | 468 | &check_timeout, |
| 505 | &check_timeout, | 469 | )?; |
| 506 | )?; | ||
| 507 | } | ||
| 508 | } else { | 470 | } else { |
| 509 | unsafe { | 471 | Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; |
| 510 | Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; | 472 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 511 | T::regs().cr1().modify(|w| w.set_tcie(true)); | ||
| 512 | } | ||
| 513 | } | 473 | } |
| 514 | } else if !(isr.tcr() || isr.tc()) { | 474 | } else if !(isr.tcr() || isr.tc()) { |
| 515 | // poll_fn was woken without an interrupt present | 475 | // poll_fn was woken without an interrupt present |
| @@ -519,13 +479,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 519 | } else { | 479 | } else { |
| 520 | let last_piece = (remaining_len <= 255) && last_slice; | 480 | let last_piece = (remaining_len <= 255) && last_slice; |
| 521 | 481 | ||
| 522 | // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers | 482 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { |
| 523 | unsafe { | 483 | return Poll::Ready(Err(e)); |
| 524 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { | ||
| 525 | return Poll::Ready(Err(e)); | ||
| 526 | } | ||
| 527 | T::regs().cr1().modify(|w| w.set_tcie(true)); | ||
| 528 | } | 484 | } |
| 485 | T::regs().cr1().modify(|w| w.set_tcie(true)); | ||
| 529 | } | 486 | } |
| 530 | 487 | ||
| 531 | remaining_len = remaining_len.saturating_sub(255); | 488 | remaining_len = remaining_len.saturating_sub(255); |
| @@ -564,7 +521,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 564 | w.set_rxdmaen(true); | 521 | w.set_rxdmaen(true); |
| 565 | w.set_tcie(true); | 522 | w.set_tcie(true); |
| 566 | }); | 523 | }); |
| 567 | let src = regs.rxdr().ptr() as *mut u8; | 524 | let src = regs.rxdr().as_ptr() as *mut u8; |
| 568 | 525 | ||
| 569 | let ch = &mut self.rx_dma; | 526 | let ch = &mut self.rx_dma; |
| 570 | let request = ch.request(); | 527 | let request = ch.request(); |
| @@ -576,30 +533,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 576 | 533 | ||
| 577 | let on_drop = OnDrop::new(|| { | 534 | let on_drop = OnDrop::new(|| { |
| 578 | let regs = T::regs(); | 535 | let regs = T::regs(); |
| 579 | unsafe { | 536 | regs.cr1().modify(|w| { |
| 580 | regs.cr1().modify(|w| { | 537 | w.set_rxdmaen(false); |
| 581 | w.set_rxdmaen(false); | 538 | w.set_tcie(false); |
| 582 | w.set_tcie(false); | 539 | }) |
| 583 | }) | ||
| 584 | } | ||
| 585 | }); | 540 | }); |
| 586 | 541 | ||
| 587 | poll_fn(|cx| { | 542 | poll_fn(|cx| { |
| 588 | state.waker.register(cx.waker()); | 543 | state.waker.register(cx.waker()); |
| 589 | 544 | ||
| 590 | let isr = unsafe { T::regs().isr().read() }; | 545 | let isr = T::regs().isr().read(); |
| 591 | if remaining_len == total_len { | 546 | if remaining_len == total_len { |
| 592 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers | 547 | Self::master_read( |
| 593 | unsafe { | 548 | address, |
| 594 | Self::master_read( | 549 | total_len.min(255), |
| 595 | address, | 550 | Stop::Software, |
| 596 | total_len.min(255), | 551 | total_len > 255, |
| 597 | Stop::Software, | 552 | restart, |
| 598 | total_len > 255, | 553 | &check_timeout, |
| 599 | restart, | 554 | )?; |
| 600 | &check_timeout, | ||
| 601 | )?; | ||
| 602 | } | ||
| 603 | } else if !(isr.tcr() || isr.tc()) { | 555 | } else if !(isr.tcr() || isr.tc()) { |
| 604 | // poll_fn was woken without an interrupt present | 556 | // poll_fn was woken without an interrupt present |
| 605 | return Poll::Pending; | 557 | return Poll::Pending; |
| @@ -608,13 +560,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 608 | } else { | 560 | } else { |
| 609 | let last_piece = remaining_len <= 255; | 561 | let last_piece = remaining_len <= 255; |
| 610 | 562 | ||
| 611 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers | 563 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { |
| 612 | unsafe { | 564 | return Poll::Ready(Err(e)); |
| 613 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { | ||
| 614 | return Poll::Ready(Err(e)); | ||
| 615 | } | ||
| 616 | T::regs().cr1().modify(|w| w.set_tcie(true)); | ||
| 617 | } | 565 | } |
| 566 | T::regs().cr1().modify(|w| w.set_tcie(true)); | ||
| 618 | } | 567 | } |
| 619 | 568 | ||
| 620 | remaining_len = remaining_len.saturating_sub(255); | 569 | remaining_len = remaining_len.saturating_sub(255); |
| @@ -758,16 +707,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 758 | let first_length = write[0].len(); | 707 | let first_length = write[0].len(); |
| 759 | let last_slice_index = write.len() - 1; | 708 | let last_slice_index = write.len() - 1; |
| 760 | 709 | ||
| 761 | // NOTE(unsafe) We have &mut self | 710 | Self::master_write( |
| 762 | unsafe { | 711 | address, |
| 763 | Self::master_write( | 712 | first_length.min(255), |
| 764 | address, | 713 | Stop::Software, |
| 765 | first_length.min(255), | 714 | (first_length > 255) || (last_slice_index != 0), |
| 766 | Stop::Software, | 715 | &check_timeout, |
| 767 | (first_length > 255) || (last_slice_index != 0), | 716 | )?; |
| 768 | &check_timeout, | ||
| 769 | )?; | ||
| 770 | } | ||
| 771 | 717 | ||
| 772 | for (idx, slice) in write.iter().enumerate() { | 718 | for (idx, slice) in write.iter().enumerate() { |
| 773 | let slice_len = slice.len(); | 719 | let slice_len = slice.len(); |
| @@ -780,26 +726,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 780 | let last_chunk_idx = total_chunks.saturating_sub(1); | 726 | let last_chunk_idx = total_chunks.saturating_sub(1); |
| 781 | 727 | ||
| 782 | if idx != 0 { | 728 | if idx != 0 { |
| 783 | // NOTE(unsafe) We have &mut self | 729 | Self::master_continue( |
| 784 | unsafe { | 730 | slice_len.min(255), |
| 785 | Self::master_continue( | 731 | (idx != last_slice_index) || (slice_len > 255), |
| 786 | slice_len.min(255), | 732 | &check_timeout, |
| 787 | (idx != last_slice_index) || (slice_len > 255), | 733 | )?; |
| 788 | &check_timeout, | ||
| 789 | )?; | ||
| 790 | } | ||
| 791 | } | 734 | } |
| 792 | 735 | ||
| 793 | for (number, chunk) in slice.chunks(255).enumerate() { | 736 | for (number, chunk) in slice.chunks(255).enumerate() { |
| 794 | if number != 0 { | 737 | if number != 0 { |
| 795 | // NOTE(unsafe) We have &mut self | 738 | Self::master_continue( |
| 796 | unsafe { | 739 | chunk.len(), |
| 797 | Self::master_continue( | 740 | (number != last_chunk_idx) || (idx != last_slice_index), |
| 798 | chunk.len(), | 741 | &check_timeout, |
| 799 | (number != last_chunk_idx) || (idx != last_slice_index), | 742 | )?; |
| 800 | &check_timeout, | ||
| 801 | )?; | ||
| 802 | } | ||
| 803 | } | 743 | } |
| 804 | 744 | ||
| 805 | for byte in chunk { | 745 | for byte in chunk { |
| @@ -810,9 +750,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 810 | 750 | ||
| 811 | // Put byte on the wire | 751 | // Put byte on the wire |
| 812 | //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); | 752 | //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); |
| 813 | unsafe { | 753 | T::regs().txdr().write(|w| w.set_txdata(*byte)); |
| 814 | T::regs().txdr().write(|w| w.set_txdata(*byte)); | ||
| 815 | } | ||
| 816 | } | 754 | } |
| 817 | } | 755 | } |
| 818 | } | 756 | } |
| @@ -1061,14 +999,12 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> { | |||
| 1061 | type Config = Hertz; | 999 | type Config = Hertz; |
| 1062 | fn set_config(&mut self, config: &Self::Config) { | 1000 | fn set_config(&mut self, config: &Self::Config) { |
| 1063 | let timings = Timings::new(T::frequency(), *config); | 1001 | let timings = Timings::new(T::frequency(), *config); |
| 1064 | unsafe { | 1002 | T::regs().timingr().write(|reg| { |
| 1065 | T::regs().timingr().write(|reg| { | 1003 | reg.set_presc(timings.prescale); |
| 1066 | reg.set_presc(timings.prescale); | 1004 | reg.set_scll(timings.scll); |
| 1067 | reg.set_scll(timings.scll); | 1005 | reg.set_sclh(timings.sclh); |
| 1068 | reg.set_sclh(timings.sclh); | 1006 | reg.set_sdadel(timings.sdadel); |
| 1069 | reg.set_sdadel(timings.sdadel); | 1007 | reg.set_scldel(timings.scldel); |
| 1070 | reg.set_scldel(timings.scldel); | 1008 | }); |
| 1071 | }); | ||
| 1072 | } | ||
| 1073 | } | 1009 | } |
| 1074 | } | 1010 | } |
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 2bb199f68..62dda69b4 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs | |||
| @@ -153,19 +153,17 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | |||
| 153 | ) -> Self { | 153 | ) -> Self { |
| 154 | into_ref!(sd, ws, ck, mck); | 154 | into_ref!(sd, ws, ck, mck); |
| 155 | 155 | ||
| 156 | unsafe { | 156 | sd.set_as_af(sd.af_num(), AFType::OutputPushPull); |
| 157 | sd.set_as_af(sd.af_num(), AFType::OutputPushPull); | 157 | sd.set_speed(crate::gpio::Speed::VeryHigh); |
| 158 | sd.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 159 | 158 | ||
| 160 | ws.set_as_af(ws.af_num(), AFType::OutputPushPull); | 159 | ws.set_as_af(ws.af_num(), AFType::OutputPushPull); |
| 161 | ws.set_speed(crate::gpio::Speed::VeryHigh); | 160 | ws.set_speed(crate::gpio::Speed::VeryHigh); |
| 162 | 161 | ||
| 163 | ck.set_as_af(ck.af_num(), AFType::OutputPushPull); | 162 | ck.set_as_af(ck.af_num(), AFType::OutputPushPull); |
| 164 | ck.set_speed(crate::gpio::Speed::VeryHigh); | 163 | ck.set_speed(crate::gpio::Speed::VeryHigh); |
| 165 | 164 | ||
| 166 | mck.set_as_af(mck.af_num(), AFType::OutputPushPull); | 165 | mck.set_as_af(mck.af_num(), AFType::OutputPushPull); |
| 167 | mck.set_speed(crate::gpio::Speed::VeryHigh); | 166 | mck.set_speed(crate::gpio::Speed::VeryHigh); |
| 168 | } | ||
| 169 | 167 | ||
| 170 | let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default()); | 168 | let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default()); |
| 171 | 169 | ||
| @@ -178,7 +176,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | |||
| 178 | let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); | 176 | let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); |
| 179 | 177 | ||
| 180 | #[cfg(any(spi_v1, spi_f1))] | 178 | #[cfg(any(spi_v1, spi_f1))] |
| 181 | unsafe { | 179 | { |
| 182 | use stm32_metapac::spi::vals::{I2scfg, Odd}; | 180 | use stm32_metapac::spi::vals::{I2scfg, Odd}; |
| 183 | 181 | ||
| 184 | // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud | 182 | // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud |
| @@ -232,10 +230,6 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | |||
| 232 | w.set_i2se(true) | 230 | w.set_i2se(true) |
| 233 | }); | 231 | }); |
| 234 | } | 232 | } |
| 235 | #[cfg(spi_v2)] | ||
| 236 | unsafe {} | ||
| 237 | #[cfg(any(spi_v3, spi_v4))] | ||
| 238 | unsafe {} | ||
| 239 | 233 | ||
| 240 | Self { | 234 | Self { |
| 241 | _peri: spi, | 235 | _peri: spi, |
| @@ -264,12 +258,10 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | |||
| 264 | 258 | ||
| 265 | impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> { | 259 | impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> { |
| 266 | fn drop(&mut self) { | 260 | fn drop(&mut self) { |
| 267 | unsafe { | 261 | self.sd.as_ref().map(|x| x.set_as_disconnected()); |
| 268 | self.sd.as_ref().map(|x| x.set_as_disconnected()); | 262 | self.ws.as_ref().map(|x| x.set_as_disconnected()); |
| 269 | self.ws.as_ref().map(|x| x.set_as_disconnected()); | 263 | self.ck.as_ref().map(|x| x.set_as_disconnected()); |
| 270 | self.ck.as_ref().map(|x| x.set_as_disconnected()); | 264 | self.mck.as_ref().map(|x| x.set_as_disconnected()); |
| 271 | self.mck.as_ref().map(|x| x.set_as_disconnected()); | ||
| 272 | } | ||
| 273 | } | 265 | } |
| 274 | } | 266 | } |
| 275 | 267 | ||
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs new file mode 100644 index 000000000..3062226c7 --- /dev/null +++ b/embassy-stm32/src/ipcc.rs | |||
| @@ -0,0 +1,337 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::task::Poll; | ||
| 3 | |||
| 4 | use atomic_polyfill::{compiler_fence, Ordering}; | ||
| 5 | |||
| 6 | use self::sealed::Instance; | ||
| 7 | use crate::interrupt; | ||
| 8 | use crate::interrupt::typelevel::Interrupt; | ||
| 9 | use crate::peripherals::IPCC; | ||
| 10 | use crate::rcc::sealed::RccPeripheral; | ||
| 11 | |||
| 12 | /// Interrupt handler. | ||
| 13 | pub struct ReceiveInterruptHandler {} | ||
| 14 | |||
| 15 | impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for ReceiveInterruptHandler { | ||
| 16 | unsafe fn on_interrupt() { | ||
| 17 | let regs = IPCC::regs(); | ||
| 18 | |||
| 19 | let channels = [ | ||
| 20 | IpccChannel::Channel1, | ||
| 21 | IpccChannel::Channel2, | ||
| 22 | IpccChannel::Channel3, | ||
| 23 | IpccChannel::Channel4, | ||
| 24 | IpccChannel::Channel5, | ||
| 25 | IpccChannel::Channel6, | ||
| 26 | ]; | ||
| 27 | |||
| 28 | // Status register gives channel occupied status. For rx, use cpu1. | ||
| 29 | let sr = regs.cpu(1).sr().read(); | ||
| 30 | regs.cpu(0).mr().modify(|w| { | ||
| 31 | for channel in channels { | ||
| 32 | if sr.chf(channel as usize) { | ||
| 33 | // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt | ||
| 34 | w.set_chom(channel as usize, true); | ||
| 35 | |||
| 36 | // There shouldn't be a race because the channel is masked only if the interrupt has fired | ||
| 37 | IPCC::state().rx_waker_for(channel).wake(); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | }) | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | pub struct TransmitInterruptHandler {} | ||
| 45 | |||
| 46 | impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler { | ||
| 47 | unsafe fn on_interrupt() { | ||
| 48 | let regs = IPCC::regs(); | ||
| 49 | |||
| 50 | let channels = [ | ||
| 51 | IpccChannel::Channel1, | ||
| 52 | IpccChannel::Channel2, | ||
| 53 | IpccChannel::Channel3, | ||
| 54 | IpccChannel::Channel4, | ||
| 55 | IpccChannel::Channel5, | ||
| 56 | IpccChannel::Channel6, | ||
| 57 | ]; | ||
| 58 | |||
| 59 | // Status register gives channel occupied status. For tx, use cpu0. | ||
| 60 | let sr = regs.cpu(0).sr().read(); | ||
| 61 | regs.cpu(0).mr().modify(|w| { | ||
| 62 | for channel in channels { | ||
| 63 | if !sr.chf(channel as usize) { | ||
| 64 | // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt | ||
| 65 | w.set_chfm(channel as usize, true); | ||
| 66 | |||
| 67 | // There shouldn't be a race because the channel is masked only if the interrupt has fired | ||
| 68 | IPCC::state().tx_waker_for(channel).wake(); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | }); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | #[non_exhaustive] | ||
| 76 | #[derive(Clone, Copy, Default)] | ||
| 77 | pub struct Config { | ||
| 78 | // TODO: add IPCC peripheral configuration, if any, here | ||
| 79 | // reserved for future use | ||
| 80 | } | ||
| 81 | |||
| 82 | #[derive(Debug, Clone, Copy)] | ||
| 83 | #[repr(C)] | ||
| 84 | pub enum IpccChannel { | ||
| 85 | Channel1 = 0, | ||
| 86 | Channel2 = 1, | ||
| 87 | Channel3 = 2, | ||
| 88 | Channel4 = 3, | ||
| 89 | Channel5 = 4, | ||
| 90 | Channel6 = 5, | ||
| 91 | } | ||
| 92 | |||
| 93 | pub struct Ipcc; | ||
| 94 | |||
| 95 | impl Ipcc { | ||
| 96 | pub fn enable(_config: Config) { | ||
| 97 | IPCC::enable(); | ||
| 98 | IPCC::reset(); | ||
| 99 | IPCC::set_cpu2(true); | ||
| 100 | |||
| 101 | _configure_pwr(); | ||
| 102 | |||
| 103 | let regs = IPCC::regs(); | ||
| 104 | |||
| 105 | regs.cpu(0).cr().modify(|w| { | ||
| 106 | w.set_rxoie(true); | ||
| 107 | w.set_txfie(true); | ||
| 108 | }); | ||
| 109 | |||
| 110 | // enable interrupts | ||
| 111 | crate::interrupt::typelevel::IPCC_C1_RX::unpend(); | ||
| 112 | crate::interrupt::typelevel::IPCC_C1_TX::unpend(); | ||
| 113 | |||
| 114 | unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() }; | ||
| 115 | unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() }; | ||
| 116 | } | ||
| 117 | |||
| 118 | /// Send data to an IPCC channel. The closure is called to write the data when appropriate. | ||
| 119 | pub async fn send(channel: IpccChannel, f: impl FnOnce()) { | ||
| 120 | let regs = IPCC::regs(); | ||
| 121 | |||
| 122 | Self::flush(channel).await; | ||
| 123 | compiler_fence(Ordering::SeqCst); | ||
| 124 | |||
| 125 | f(); | ||
| 126 | |||
| 127 | compiler_fence(Ordering::SeqCst); | ||
| 128 | |||
| 129 | trace!("ipcc: ch {}: send data", channel as u8); | ||
| 130 | regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)); | ||
| 131 | } | ||
| 132 | |||
| 133 | /// Wait for the tx channel to become clear | ||
| 134 | pub async fn flush(channel: IpccChannel) { | ||
| 135 | let regs = IPCC::regs(); | ||
| 136 | |||
| 137 | // This is a race, but is nice for debugging | ||
| 138 | if regs.cpu(0).sr().read().chf(channel as usize) { | ||
| 139 | trace!("ipcc: ch {}: wait for tx free", channel as u8); | ||
| 140 | } | ||
| 141 | |||
| 142 | poll_fn(|cx| { | ||
| 143 | IPCC::state().tx_waker_for(channel).register(cx.waker()); | ||
| 144 | // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt | ||
| 145 | regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false)); | ||
| 146 | |||
| 147 | compiler_fence(Ordering::SeqCst); | ||
| 148 | |||
| 149 | if !regs.cpu(0).sr().read().chf(channel as usize) { | ||
| 150 | // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt | ||
| 151 | regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)); | ||
| 152 | |||
| 153 | Poll::Ready(()) | ||
| 154 | } else { | ||
| 155 | Poll::Pending | ||
| 156 | } | ||
| 157 | }) | ||
| 158 | .await; | ||
| 159 | } | ||
| 160 | |||
| 161 | /// Receive data from an IPCC channel. The closure is called to read the data when appropriate. | ||
| 162 | pub async fn receive<R>(channel: IpccChannel, mut f: impl FnMut() -> Option<R>) -> R { | ||
| 163 | let regs = IPCC::regs(); | ||
| 164 | |||
| 165 | loop { | ||
| 166 | // This is a race, but is nice for debugging | ||
| 167 | if !regs.cpu(1).sr().read().chf(channel as usize) { | ||
| 168 | trace!("ipcc: ch {}: wait for rx occupied", channel as u8); | ||
| 169 | } | ||
| 170 | |||
| 171 | poll_fn(|cx| { | ||
| 172 | IPCC::state().rx_waker_for(channel).register(cx.waker()); | ||
| 173 | // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt | ||
| 174 | regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false)); | ||
| 175 | |||
| 176 | compiler_fence(Ordering::SeqCst); | ||
| 177 | |||
| 178 | if regs.cpu(1).sr().read().chf(channel as usize) { | ||
| 179 | // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt | ||
| 180 | regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)); | ||
| 181 | |||
| 182 | Poll::Ready(()) | ||
| 183 | } else { | ||
| 184 | Poll::Pending | ||
| 185 | } | ||
| 186 | }) | ||
| 187 | .await; | ||
| 188 | |||
| 189 | trace!("ipcc: ch {}: read data", channel as u8); | ||
| 190 | compiler_fence(Ordering::SeqCst); | ||
| 191 | |||
| 192 | match f() { | ||
| 193 | Some(ret) => return ret, | ||
| 194 | None => {} | ||
| 195 | } | ||
| 196 | |||
| 197 | trace!("ipcc: ch {}: clear rx", channel as u8); | ||
| 198 | compiler_fence(Ordering::SeqCst); | ||
| 199 | // If the channel is clear and the read function returns none, fetch more data | ||
| 200 | regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | impl sealed::Instance for crate::peripherals::IPCC { | ||
| 206 | fn regs() -> crate::pac::ipcc::Ipcc { | ||
| 207 | crate::pac::IPCC | ||
| 208 | } | ||
| 209 | |||
| 210 | fn set_cpu2(enabled: bool) { | ||
| 211 | crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)); | ||
| 212 | } | ||
| 213 | |||
| 214 | fn state() -> &'static self::sealed::State { | ||
| 215 | static STATE: self::sealed::State = self::sealed::State::new(); | ||
| 216 | &STATE | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | pub(crate) mod sealed { | ||
| 221 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 222 | |||
| 223 | use super::*; | ||
| 224 | |||
| 225 | pub struct State { | ||
| 226 | rx_wakers: [AtomicWaker; 6], | ||
| 227 | tx_wakers: [AtomicWaker; 6], | ||
| 228 | } | ||
| 229 | |||
| 230 | impl State { | ||
| 231 | pub const fn new() -> Self { | ||
| 232 | const WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 233 | |||
| 234 | Self { | ||
| 235 | rx_wakers: [WAKER; 6], | ||
| 236 | tx_wakers: [WAKER; 6], | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | pub fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { | ||
| 241 | match channel { | ||
| 242 | IpccChannel::Channel1 => &self.rx_wakers[0], | ||
| 243 | IpccChannel::Channel2 => &self.rx_wakers[1], | ||
| 244 | IpccChannel::Channel3 => &self.rx_wakers[2], | ||
| 245 | IpccChannel::Channel4 => &self.rx_wakers[3], | ||
| 246 | IpccChannel::Channel5 => &self.rx_wakers[4], | ||
| 247 | IpccChannel::Channel6 => &self.rx_wakers[5], | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | pub fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { | ||
| 252 | match channel { | ||
| 253 | IpccChannel::Channel1 => &self.tx_wakers[0], | ||
| 254 | IpccChannel::Channel2 => &self.tx_wakers[1], | ||
| 255 | IpccChannel::Channel3 => &self.tx_wakers[2], | ||
| 256 | IpccChannel::Channel4 => &self.tx_wakers[3], | ||
| 257 | IpccChannel::Channel5 => &self.tx_wakers[4], | ||
| 258 | IpccChannel::Channel6 => &self.tx_wakers[5], | ||
| 259 | } | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | pub trait Instance: crate::rcc::RccPeripheral { | ||
| 264 | fn regs() -> crate::pac::ipcc::Ipcc; | ||
| 265 | fn set_cpu2(enabled: bool); | ||
| 266 | fn state() -> &'static State; | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | fn _configure_pwr() { | ||
| 271 | // TODO: move this to RCC | ||
| 272 | |||
| 273 | let pwr = crate::pac::PWR; | ||
| 274 | let rcc = crate::pac::RCC; | ||
| 275 | |||
| 276 | rcc.cfgr().modify(|w| w.set_stopwuck(true)); | ||
| 277 | |||
| 278 | pwr.cr1().modify(|w| w.set_dbp(true)); | ||
| 279 | pwr.cr1().modify(|w| w.set_dbp(true)); | ||
| 280 | |||
| 281 | // configure LSE | ||
| 282 | rcc.bdcr().modify(|w| w.set_lseon(true)); | ||
| 283 | |||
| 284 | // select system clock source = PLL | ||
| 285 | // set PLL coefficients | ||
| 286 | // m: 2, | ||
| 287 | // n: 12, | ||
| 288 | // r: 3, | ||
| 289 | // q: 4, | ||
| 290 | // p: 3, | ||
| 291 | let src_bits = 0b11; | ||
| 292 | let pllp = (3 - 1) & 0b11111; | ||
| 293 | let pllq = (4 - 1) & 0b111; | ||
| 294 | let pllr = (3 - 1) & 0b111; | ||
| 295 | let plln = 12 & 0b1111111; | ||
| 296 | let pllm = (2 - 1) & 0b111; | ||
| 297 | rcc.pllcfgr().modify(|w| { | ||
| 298 | w.set_pllsrc(src_bits); | ||
| 299 | w.set_pllm(pllm); | ||
| 300 | w.set_plln(plln); | ||
| 301 | w.set_pllr(pllr); | ||
| 302 | w.set_pllp(pllp); | ||
| 303 | w.set_pllpen(true); | ||
| 304 | w.set_pllq(pllq); | ||
| 305 | w.set_pllqen(true); | ||
| 306 | }); | ||
| 307 | // enable PLL | ||
| 308 | rcc.cr().modify(|w| w.set_pllon(true)); | ||
| 309 | rcc.cr().write(|w| w.set_hsion(false)); | ||
| 310 | // while !rcc.cr().read().pllrdy() {} | ||
| 311 | |||
| 312 | // configure SYSCLK mux to use PLL clocl | ||
| 313 | rcc.cfgr().modify(|w| w.set_sw(0b11)); | ||
| 314 | |||
| 315 | // configure CPU1 & CPU2 dividers | ||
| 316 | rcc.cfgr().modify(|w| w.set_hpre(0)); // not divided | ||
| 317 | rcc.extcfgr().modify(|w| { | ||
| 318 | w.set_c2hpre(0b1000); // div2 | ||
| 319 | w.set_shdhpre(0); // not divided | ||
| 320 | }); | ||
| 321 | |||
| 322 | // apply APB1 / APB2 values | ||
| 323 | rcc.cfgr().modify(|w| { | ||
| 324 | w.set_ppre1(0b000); // not divided | ||
| 325 | w.set_ppre2(0b000); // not divided | ||
| 326 | }); | ||
| 327 | |||
| 328 | // TODO: required | ||
| 329 | // set RF wake-up clock = LSE | ||
| 330 | rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); | ||
| 331 | |||
| 332 | // set LPTIM1 & LPTIM2 clock source | ||
| 333 | rcc.ccipr().modify(|w| { | ||
| 334 | w.set_lptim1sel(0b00); // PCLK | ||
| 335 | w.set_lptim2sel(0b00); // PCLK | ||
| 336 | }); | ||
| 337 | } | ||
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 6533509eb..45a7b5476 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -41,6 +41,8 @@ pub mod crc; | |||
| 41 | pub mod flash; | 41 | pub mod flash; |
| 42 | #[cfg(all(spi_v1, rcc_f4))] | 42 | #[cfg(all(spi_v1, rcc_f4))] |
| 43 | pub mod i2s; | 43 | pub mod i2s; |
| 44 | #[cfg(stm32wb)] | ||
| 45 | pub mod ipcc; | ||
| 44 | pub mod pwm; | 46 | pub mod pwm; |
| 45 | #[cfg(quadspi)] | 47 | #[cfg(quadspi)] |
| 46 | pub mod qspi; | 48 | pub mod qspi; |
| @@ -52,8 +54,6 @@ pub mod rtc; | |||
| 52 | pub mod sdmmc; | 54 | pub mod sdmmc; |
| 53 | #[cfg(spi)] | 55 | #[cfg(spi)] |
| 54 | pub mod spi; | 56 | pub mod spi; |
| 55 | #[cfg(stm32wb)] | ||
| 56 | pub mod tl_mbox; | ||
| 57 | #[cfg(usart)] | 57 | #[cfg(usart)] |
| 58 | pub mod usart; | 58 | pub mod usart; |
| 59 | #[cfg(usb)] | 59 | #[cfg(usb)] |
| @@ -72,52 +72,47 @@ pub(crate) mod _generated { | |||
| 72 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); | 72 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | pub mod interrupt { | 75 | pub use crate::_generated::interrupt; |
| 76 | //! Interrupt definitions and macros to bind them. | 76 | |
| 77 | pub use cortex_m::interrupt::{CriticalSection, Mutex}; | 77 | /// Macro to bind interrupts to handlers. |
| 78 | pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority}; | 78 | /// |
| 79 | 79 | /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) | |
| 80 | pub use crate::_generated::interrupt::*; | 80 | /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to |
| 81 | 81 | /// prove at compile-time that the right interrupts have been bound. | |
| 82 | /// Macro to bind interrupts to handlers. | 82 | // developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`. |
| 83 | /// | 83 | #[macro_export] |
| 84 | /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) | 84 | macro_rules! bind_interrupts { |
| 85 | /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to | 85 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { |
| 86 | /// prove at compile-time that the right interrupts have been bound. | 86 | $vis struct $name; |
| 87 | // developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`. | 87 | |
| 88 | #[macro_export] | 88 | $( |
| 89 | macro_rules! bind_interrupts { | 89 | #[allow(non_snake_case)] |
| 90 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { | 90 | #[no_mangle] |
| 91 | $vis struct $name; | 91 | unsafe extern "C" fn $irq() { |
| 92 | |||
| 93 | $( | ||
| 94 | #[allow(non_snake_case)] | ||
| 95 | #[no_mangle] | ||
| 96 | unsafe extern "C" fn $irq() { | ||
| 97 | $( | ||
| 98 | <$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt(); | ||
| 99 | )* | ||
| 100 | } | ||
| 101 | |||
| 102 | $( | 92 | $( |
| 103 | unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {} | 93 | <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); |
| 104 | )* | 94 | )* |
| 95 | } | ||
| 96 | |||
| 97 | $( | ||
| 98 | unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} | ||
| 105 | )* | 99 | )* |
| 106 | }; | 100 | )* |
| 107 | } | 101 | }; |
| 108 | } | 102 | } |
| 109 | 103 | ||
| 110 | // Reexports | 104 | // Reexports |
| 111 | pub use _generated::{peripherals, Peripherals}; | 105 | pub use _generated::{peripherals, Peripherals}; |
| 112 | pub use embassy_cortex_m::executor; | ||
| 113 | use embassy_cortex_m::interrupt::Priority; | ||
| 114 | pub use embassy_cortex_m::interrupt::_export::interrupt; | ||
| 115 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 106 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
| 116 | #[cfg(feature = "unstable-pac")] | 107 | #[cfg(feature = "unstable-pac")] |
| 117 | pub use stm32_metapac as pac; | 108 | pub use stm32_metapac as pac; |
| 118 | #[cfg(not(feature = "unstable-pac"))] | 109 | #[cfg(not(feature = "unstable-pac"))] |
| 119 | pub(crate) use stm32_metapac as pac; | 110 | pub(crate) use stm32_metapac as pac; |
| 120 | 111 | ||
| 112 | use crate::interrupt::Priority; | ||
| 113 | #[cfg(feature = "rt")] | ||
| 114 | pub use crate::pac::NVIC_PRIO_BITS; | ||
| 115 | |||
| 121 | #[non_exhaustive] | 116 | #[non_exhaustive] |
| 122 | pub struct Config { | 117 | pub struct Config { |
| 123 | pub rcc: rcc::Config, | 118 | pub rcc: rcc::Config, |
| @@ -151,35 +146,35 @@ impl Default for Config { | |||
| 151 | pub fn init(config: Config) -> Peripherals { | 146 | pub fn init(config: Config) -> Peripherals { |
| 152 | let p = Peripherals::take(); | 147 | let p = Peripherals::take(); |
| 153 | 148 | ||
| 154 | unsafe { | 149 | #[cfg(dbgmcu)] |
| 155 | #[cfg(dbgmcu)] | 150 | if config.enable_debug_during_sleep { |
| 156 | if config.enable_debug_during_sleep { | 151 | crate::pac::DBGMCU.cr().modify(|cr| { |
| 157 | crate::pac::DBGMCU.cr().modify(|cr| { | 152 | #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))] |
| 158 | #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))] | 153 | { |
| 159 | { | 154 | cr.set_dbg_stop(true); |
| 160 | cr.set_dbg_stop(true); | 155 | cr.set_dbg_standby(true); |
| 161 | cr.set_dbg_standby(true); | 156 | } |
| 162 | } | 157 | #[cfg(any( |
| 163 | #[cfg(any( | 158 | dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, |
| 164 | dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, | 159 | dbgmcu_l4, dbgmcu_wb, dbgmcu_wl |
| 165 | dbgmcu_l4, dbgmcu_wb, dbgmcu_wl | 160 | ))] |
| 166 | ))] | 161 | { |
| 167 | { | 162 | cr.set_dbg_sleep(true); |
| 168 | cr.set_dbg_sleep(true); | 163 | cr.set_dbg_stop(true); |
| 169 | cr.set_dbg_stop(true); | 164 | cr.set_dbg_standby(true); |
| 170 | cr.set_dbg_standby(true); | 165 | } |
| 171 | } | 166 | #[cfg(dbgmcu_h7)] |
| 172 | #[cfg(dbgmcu_h7)] | 167 | { |
| 173 | { | 168 | cr.set_d1dbgcken(true); |
| 174 | cr.set_d1dbgcken(true); | 169 | cr.set_d3dbgcken(true); |
| 175 | cr.set_d3dbgcken(true); | 170 | cr.set_dbgsleep_d1(true); |
| 176 | cr.set_dbgsleep_d1(true); | 171 | cr.set_dbgstby_d1(true); |
| 177 | cr.set_dbgstby_d1(true); | 172 | cr.set_dbgstop_d1(true); |
| 178 | cr.set_dbgstop_d1(true); | 173 | } |
| 179 | } | 174 | }); |
| 180 | }); | 175 | } |
| 181 | } | ||
| 182 | 176 | ||
| 177 | unsafe { | ||
| 183 | gpio::init(); | 178 | gpio::init(); |
| 184 | dma::init( | 179 | dma::init( |
| 185 | #[cfg(bdma)] | 180 | #[cfg(bdma)] |
diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs index cfb79947c..0e153202e 100644 --- a/embassy-stm32/src/pwm/complementary_pwm.rs +++ b/embassy-stm32/src/pwm/complementary_pwm.rs | |||
| @@ -21,7 +21,7 @@ macro_rules! complementary_channel_impl { | |||
| 21 | impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { | 21 | impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { |
| 22 | pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { | 22 | pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { |
| 23 | into_ref!(pin); | 23 | into_ref!(pin); |
| 24 | critical_section::with(|_| unsafe { | 24 | critical_section::with(|_| { |
| 25 | pin.set_low(); | 25 | pin.set_low(); |
| 26 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | 26 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); |
| 27 | #[cfg(gpio_v2)] | 27 | #[cfg(gpio_v2)] |
| @@ -72,33 +72,27 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 72 | this.inner.set_frequency(freq); | 72 | this.inner.set_frequency(freq); |
| 73 | this.inner.start(); | 73 | this.inner.start(); |
| 74 | 74 | ||
| 75 | unsafe { | 75 | this.inner.enable_outputs(true); |
| 76 | this.inner.enable_outputs(true); | 76 | |
| 77 | 77 | this.inner | |
| 78 | this.inner | 78 | .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); |
| 79 | .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); | 79 | this.inner |
| 80 | this.inner | 80 | .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); |
| 81 | .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); | 81 | this.inner |
| 82 | this.inner | 82 | .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); |
| 83 | .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); | 83 | this.inner |
| 84 | this.inner | 84 | .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); |
| 85 | .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); | ||
| 86 | } | ||
| 87 | this | 85 | this |
| 88 | } | 86 | } |
| 89 | 87 | ||
| 90 | pub fn enable(&mut self, channel: Channel) { | 88 | pub fn enable(&mut self, channel: Channel) { |
| 91 | unsafe { | 89 | self.inner.enable_channel(channel, true); |
| 92 | self.inner.enable_channel(channel, true); | 90 | self.inner.enable_complementary_channel(channel, true); |
| 93 | self.inner.enable_complementary_channel(channel, true); | ||
| 94 | } | ||
| 95 | } | 91 | } |
| 96 | 92 | ||
| 97 | pub fn disable(&mut self, channel: Channel) { | 93 | pub fn disable(&mut self, channel: Channel) { |
| 98 | unsafe { | 94 | self.inner.enable_complementary_channel(channel, false); |
| 99 | self.inner.enable_complementary_channel(channel, false); | 95 | self.inner.enable_channel(channel, false); |
| 100 | self.inner.enable_channel(channel, false); | ||
| 101 | } | ||
| 102 | } | 96 | } |
| 103 | 97 | ||
| 104 | pub fn set_freq(&mut self, freq: Hertz) { | 98 | pub fn set_freq(&mut self, freq: Hertz) { |
| @@ -106,22 +100,20 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 106 | } | 100 | } |
| 107 | 101 | ||
| 108 | pub fn get_max_duty(&self) -> u16 { | 102 | pub fn get_max_duty(&self) -> u16 { |
| 109 | unsafe { self.inner.get_max_compare_value() } | 103 | self.inner.get_max_compare_value() |
| 110 | } | 104 | } |
| 111 | 105 | ||
| 112 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 106 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 113 | assert!(duty < self.get_max_duty()); | 107 | assert!(duty < self.get_max_duty()); |
| 114 | unsafe { self.inner.set_compare_value(channel, duty) } | 108 | self.inner.set_compare_value(channel, duty) |
| 115 | } | 109 | } |
| 116 | 110 | ||
| 117 | /// Set the dead time as a proportion of max_duty | 111 | /// Set the dead time as a proportion of max_duty |
| 118 | pub fn set_dead_time(&mut self, value: u16) { | 112 | pub fn set_dead_time(&mut self, value: u16) { |
| 119 | let (ckd, value) = compute_dead_time_value(value); | 113 | let (ckd, value) = compute_dead_time_value(value); |
| 120 | 114 | ||
| 121 | unsafe { | 115 | self.inner.set_dead_time_clock_division(ckd); |
| 122 | self.inner.set_dead_time_clock_division(ckd); | 116 | self.inner.set_dead_time_value(value); |
| 123 | self.inner.set_dead_time_value(value); | ||
| 124 | } | ||
| 125 | } | 117 | } |
| 126 | } | 118 | } |
| 127 | 119 | ||
diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index 0bef07089..5aba2663e 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs | |||
| @@ -59,33 +59,33 @@ pub(crate) mod sealed { | |||
| 59 | 59 | ||
| 60 | pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance { | 60 | pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance { |
| 61 | /// Global output enable. Does not do anything on non-advanced timers. | 61 | /// Global output enable. Does not do anything on non-advanced timers. |
| 62 | unsafe fn enable_outputs(&mut self, enable: bool); | 62 | fn enable_outputs(&mut self, enable: bool); |
| 63 | 63 | ||
| 64 | unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | 64 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); |
| 65 | 65 | ||
| 66 | unsafe fn enable_channel(&mut self, channel: Channel, enable: bool); | 66 | fn enable_channel(&mut self, channel: Channel, enable: bool); |
| 67 | 67 | ||
| 68 | unsafe fn set_compare_value(&mut self, channel: Channel, value: u16); | 68 | fn set_compare_value(&mut self, channel: Channel, value: u16); |
| 69 | 69 | ||
| 70 | unsafe fn get_max_compare_value(&self) -> u16; | 70 | fn get_max_compare_value(&self) -> u16; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { | 73 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { |
| 74 | unsafe fn set_dead_time_clock_division(&mut self, value: Ckd); | 74 | fn set_dead_time_clock_division(&mut self, value: Ckd); |
| 75 | 75 | ||
| 76 | unsafe fn set_dead_time_value(&mut self, value: u8); | 76 | fn set_dead_time_value(&mut self, value: u8); |
| 77 | 77 | ||
| 78 | unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); | 78 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { | 81 | pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { |
| 82 | unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | 82 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); |
| 83 | 83 | ||
| 84 | unsafe fn enable_channel(&mut self, channel: Channel, enable: bool); | 84 | fn enable_channel(&mut self, channel: Channel, enable: bool); |
| 85 | 85 | ||
| 86 | unsafe fn set_compare_value(&mut self, channel: Channel, value: u32); | 86 | fn set_compare_value(&mut self, channel: Channel, value: u32); |
| 87 | 87 | ||
| 88 | unsafe fn get_max_compare_value(&self) -> u32; | 88 | fn get_max_compare_value(&self) -> u32; |
| 89 | } | 89 | } |
| 90 | } | 90 | } |
| 91 | 91 | ||
| @@ -108,9 +108,9 @@ pub trait CaptureCompare32bitInstance: | |||
| 108 | macro_rules! impl_compare_capable_16bit { | 108 | macro_rules! impl_compare_capable_16bit { |
| 109 | ($inst:ident) => { | 109 | ($inst:ident) => { |
| 110 | impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { | 110 | impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { |
| 111 | unsafe fn enable_outputs(&mut self, _enable: bool) {} | 111 | fn enable_outputs(&mut self, _enable: bool) {} |
| 112 | 112 | ||
| 113 | unsafe fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) { | 113 | fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) { |
| 114 | use crate::timer::sealed::GeneralPurpose16bitInstance; | 114 | use crate::timer::sealed::GeneralPurpose16bitInstance; |
| 115 | let r = Self::regs_gp16(); | 115 | let r = Self::regs_gp16(); |
| 116 | let raw_channel: usize = channel.raw(); | 116 | let raw_channel: usize = channel.raw(); |
| @@ -118,19 +118,19 @@ macro_rules! impl_compare_capable_16bit { | |||
| 118 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | 118 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { | 121 | fn enable_channel(&mut self, channel: Channel, enable: bool) { |
| 122 | use crate::timer::sealed::GeneralPurpose16bitInstance; | 122 | use crate::timer::sealed::GeneralPurpose16bitInstance; |
| 123 | Self::regs_gp16() | 123 | Self::regs_gp16() |
| 124 | .ccer() | 124 | .ccer() |
| 125 | .modify(|w| w.set_cce(channel.raw(), enable)); | 125 | .modify(|w| w.set_cce(channel.raw(), enable)); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) { | 128 | fn set_compare_value(&mut self, channel: Channel, value: u16) { |
| 129 | use crate::timer::sealed::GeneralPurpose16bitInstance; | 129 | use crate::timer::sealed::GeneralPurpose16bitInstance; |
| 130 | Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | 130 | Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | unsafe fn get_max_compare_value(&self) -> u16 { | 133 | fn get_max_compare_value(&self) -> u16 { |
| 134 | use crate::timer::sealed::GeneralPurpose16bitInstance; | 134 | use crate::timer::sealed::GeneralPurpose16bitInstance; |
| 135 | Self::regs_gp16().arr().read().arr() | 135 | Self::regs_gp16().arr().read().arr() |
| 136 | } | 136 | } |
| @@ -150,7 +150,7 @@ foreach_interrupt! { | |||
| 150 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { | 150 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { |
| 151 | impl_compare_capable_16bit!($inst); | 151 | impl_compare_capable_16bit!($inst); |
| 152 | impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { | 152 | impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { |
| 153 | unsafe fn set_output_compare_mode( | 153 | fn set_output_compare_mode( |
| 154 | &mut self, | 154 | &mut self, |
| 155 | channel: crate::pwm::Channel, | 155 | channel: crate::pwm::Channel, |
| 156 | mode: OutputCompareMode, | 156 | mode: OutputCompareMode, |
| @@ -160,17 +160,17 @@ foreach_interrupt! { | |||
| 160 | Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | 160 | Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { | 163 | fn enable_channel(&mut self, channel: Channel, enable: bool) { |
| 164 | use crate::timer::sealed::GeneralPurpose32bitInstance; | 164 | use crate::timer::sealed::GeneralPurpose32bitInstance; |
| 165 | Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); | 165 | Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | unsafe fn set_compare_value(&mut self, channel: Channel, value: u32) { | 168 | fn set_compare_value(&mut self, channel: Channel, value: u32) { |
| 169 | use crate::timer::sealed::GeneralPurpose32bitInstance; | 169 | use crate::timer::sealed::GeneralPurpose32bitInstance; |
| 170 | Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | 170 | Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | unsafe fn get_max_compare_value(&self) -> u32 { | 173 | fn get_max_compare_value(&self) -> u32 { |
| 174 | use crate::timer::sealed::GeneralPurpose32bitInstance; | 174 | use crate::timer::sealed::GeneralPurpose32bitInstance; |
| 175 | Self::regs_gp32().arr().read().arr() as u32 | 175 | Self::regs_gp32().arr().read().arr() as u32 |
| 176 | } | 176 | } |
| @@ -185,13 +185,13 @@ foreach_interrupt! { | |||
| 185 | 185 | ||
| 186 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { | 186 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { |
| 187 | impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { | 187 | impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { |
| 188 | unsafe fn enable_outputs(&mut self, enable: bool) { | 188 | fn enable_outputs(&mut self, enable: bool) { |
| 189 | use crate::timer::sealed::AdvancedControlInstance; | 189 | use crate::timer::sealed::AdvancedControlInstance; |
| 190 | let r = Self::regs_advanced(); | 190 | let r = Self::regs_advanced(); |
| 191 | r.bdtr().modify(|w| w.set_moe(enable)); | 191 | r.bdtr().modify(|w| w.set_moe(enable)); |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | unsafe fn set_output_compare_mode( | 194 | fn set_output_compare_mode( |
| 195 | &mut self, | 195 | &mut self, |
| 196 | channel: crate::pwm::Channel, | 196 | channel: crate::pwm::Channel, |
| 197 | mode: OutputCompareMode, | 197 | mode: OutputCompareMode, |
| @@ -203,21 +203,21 @@ foreach_interrupt! { | |||
| 203 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | 203 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) { | 206 | fn enable_channel(&mut self, channel: Channel, enable: bool) { |
| 207 | use crate::timer::sealed::AdvancedControlInstance; | 207 | use crate::timer::sealed::AdvancedControlInstance; |
| 208 | Self::regs_advanced() | 208 | Self::regs_advanced() |
| 209 | .ccer() | 209 | .ccer() |
| 210 | .modify(|w| w.set_cce(channel.raw(), enable)); | 210 | .modify(|w| w.set_cce(channel.raw(), enable)); |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) { | 213 | fn set_compare_value(&mut self, channel: Channel, value: u16) { |
| 214 | use crate::timer::sealed::AdvancedControlInstance; | 214 | use crate::timer::sealed::AdvancedControlInstance; |
| 215 | Self::regs_advanced() | 215 | Self::regs_advanced() |
| 216 | .ccr(channel.raw()) | 216 | .ccr(channel.raw()) |
| 217 | .modify(|w| w.set_ccr(value)); | 217 | .modify(|w| w.set_ccr(value)); |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | unsafe fn get_max_compare_value(&self) -> u16 { | 220 | fn get_max_compare_value(&self) -> u16 { |
| 221 | use crate::timer::sealed::AdvancedControlInstance; | 221 | use crate::timer::sealed::AdvancedControlInstance; |
| 222 | Self::regs_advanced().arr().read().arr() | 222 | Self::regs_advanced().arr().read().arr() |
| 223 | } | 223 | } |
| @@ -228,17 +228,17 @@ foreach_interrupt! { | |||
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { | 230 | impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { |
| 231 | unsafe fn set_dead_time_clock_division(&mut self, value: Ckd) { | 231 | fn set_dead_time_clock_division(&mut self, value: Ckd) { |
| 232 | use crate::timer::sealed::AdvancedControlInstance; | 232 | use crate::timer::sealed::AdvancedControlInstance; |
| 233 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); | 233 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | unsafe fn set_dead_time_value(&mut self, value: u8) { | 236 | fn set_dead_time_value(&mut self, value: u8) { |
| 237 | use crate::timer::sealed::AdvancedControlInstance; | 237 | use crate::timer::sealed::AdvancedControlInstance; |
| 238 | Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); | 238 | Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { | 241 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { |
| 242 | use crate::timer::sealed::AdvancedControlInstance; | 242 | use crate::timer::sealed::AdvancedControlInstance; |
| 243 | Self::regs_advanced() | 243 | Self::regs_advanced() |
| 244 | .ccer() | 244 | .ccer() |
diff --git a/embassy-stm32/src/pwm/simple_pwm.rs b/embassy-stm32/src/pwm/simple_pwm.rs index b045a2d78..995f59c23 100644 --- a/embassy-stm32/src/pwm/simple_pwm.rs +++ b/embassy-stm32/src/pwm/simple_pwm.rs | |||
| @@ -24,7 +24,7 @@ macro_rules! channel_impl { | |||
| 24 | impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { | 24 | impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { |
| 25 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { | 25 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { |
| 26 | into_ref!(pin); | 26 | into_ref!(pin); |
| 27 | critical_section::with(|_| unsafe { | 27 | critical_section::with(|_| { |
| 28 | pin.set_low(); | 28 | pin.set_low(); |
| 29 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | 29 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); |
| 30 | #[cfg(gpio_v2)] | 30 | #[cfg(gpio_v2)] |
| @@ -71,31 +71,25 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 71 | this.inner.set_frequency(freq); | 71 | this.inner.set_frequency(freq); |
| 72 | this.inner.start(); | 72 | this.inner.start(); |
| 73 | 73 | ||
| 74 | unsafe { | 74 | this.inner.enable_outputs(true); |
| 75 | this.inner.enable_outputs(true); | 75 | |
| 76 | 76 | this.inner | |
| 77 | this.inner | 77 | .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); |
| 78 | .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); | 78 | this.inner |
| 79 | this.inner | 79 | .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); |
| 80 | .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); | 80 | this.inner |
| 81 | this.inner | 81 | .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); |
| 82 | .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); | 82 | this.inner |
| 83 | this.inner | 83 | .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); |
| 84 | .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); | ||
| 85 | } | ||
| 86 | this | 84 | this |
| 87 | } | 85 | } |
| 88 | 86 | ||
| 89 | pub fn enable(&mut self, channel: Channel) { | 87 | pub fn enable(&mut self, channel: Channel) { |
| 90 | unsafe { | 88 | self.inner.enable_channel(channel, true); |
| 91 | self.inner.enable_channel(channel, true); | ||
| 92 | } | ||
| 93 | } | 89 | } |
| 94 | 90 | ||
| 95 | pub fn disable(&mut self, channel: Channel) { | 91 | pub fn disable(&mut self, channel: Channel) { |
| 96 | unsafe { | 92 | self.inner.enable_channel(channel, false); |
| 97 | self.inner.enable_channel(channel, false); | ||
| 98 | } | ||
| 99 | } | 93 | } |
| 100 | 94 | ||
| 101 | pub fn set_freq(&mut self, freq: Hertz) { | 95 | pub fn set_freq(&mut self, freq: Hertz) { |
| @@ -103,11 +97,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 103 | } | 97 | } |
| 104 | 98 | ||
| 105 | pub fn get_max_duty(&self) -> u16 { | 99 | pub fn get_max_duty(&self) -> u16 { |
| 106 | unsafe { self.inner.get_max_compare_value() } | 100 | self.inner.get_max_compare_value() |
| 107 | } | 101 | } |
| 108 | 102 | ||
| 109 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 103 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 110 | assert!(duty < self.get_max_duty()); | 104 | assert!(duty < self.get_max_duty()); |
| 111 | unsafe { self.inner.set_compare_value(channel, duty) } | 105 | self.inner.set_compare_value(channel, duty) |
| 112 | } | 106 | } |
| 113 | } | 107 | } |
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index c3126b37f..e9db934bf 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs | |||
| @@ -96,20 +96,18 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 96 | ) -> Self { | 96 | ) -> Self { |
| 97 | into_ref!(peri, d0, d1, d2, d3, sck, nss); | 97 | into_ref!(peri, d0, d1, d2, d3, sck, nss); |
| 98 | 98 | ||
| 99 | unsafe { | 99 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); |
| 100 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | 100 | sck.set_speed(crate::gpio::Speed::VeryHigh); |
| 101 | sck.set_speed(crate::gpio::Speed::VeryHigh); | 101 | nss.set_as_af(nss.af_num(), AFType::OutputPushPull); |
| 102 | nss.set_as_af(nss.af_num(), AFType::OutputPushPull); | 102 | nss.set_speed(crate::gpio::Speed::VeryHigh); |
| 103 | nss.set_speed(crate::gpio::Speed::VeryHigh); | 103 | d0.set_as_af(d0.af_num(), AFType::OutputPushPull); |
| 104 | d0.set_as_af(d0.af_num(), AFType::OutputPushPull); | 104 | d0.set_speed(crate::gpio::Speed::VeryHigh); |
| 105 | d0.set_speed(crate::gpio::Speed::VeryHigh); | 105 | d1.set_as_af(d1.af_num(), AFType::OutputPushPull); |
| 106 | d1.set_as_af(d1.af_num(), AFType::OutputPushPull); | 106 | d1.set_speed(crate::gpio::Speed::VeryHigh); |
| 107 | d1.set_speed(crate::gpio::Speed::VeryHigh); | 107 | d2.set_as_af(d2.af_num(), AFType::OutputPushPull); |
| 108 | d2.set_as_af(d2.af_num(), AFType::OutputPushPull); | 108 | d2.set_speed(crate::gpio::Speed::VeryHigh); |
| 109 | d2.set_speed(crate::gpio::Speed::VeryHigh); | 109 | d3.set_as_af(d3.af_num(), AFType::OutputPushPull); |
| 110 | d3.set_as_af(d3.af_num(), AFType::OutputPushPull); | 110 | d3.set_speed(crate::gpio::Speed::VeryHigh); |
| 111 | d3.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 112 | } | ||
| 113 | 111 | ||
| 114 | Self::new_inner( | 112 | Self::new_inner( |
| 115 | peri, | 113 | peri, |
| @@ -138,21 +136,19 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 138 | into_ref!(peri, dma); | 136 | into_ref!(peri, dma); |
| 139 | 137 | ||
| 140 | T::enable(); | 138 | T::enable(); |
| 141 | unsafe { | 139 | T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into())); |
| 142 | T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into())); | ||
| 143 | 140 | ||
| 144 | while T::REGS.sr().read().busy() {} | 141 | while T::REGS.sr().read().busy() {} |
| 145 | 142 | ||
| 146 | T::REGS.cr().write(|w| { | 143 | T::REGS.cr().write(|w| { |
| 147 | w.set_prescaler(config.prescaler); | 144 | w.set_prescaler(config.prescaler); |
| 148 | w.set_en(true); | 145 | w.set_en(true); |
| 149 | }); | 146 | }); |
| 150 | T::REGS.dcr().write(|w| { | 147 | T::REGS.dcr().write(|w| { |
| 151 | w.set_fsize(config.memory_size.into()); | 148 | w.set_fsize(config.memory_size.into()); |
| 152 | w.set_csht(config.cs_high_time.into()); | 149 | w.set_csht(config.cs_high_time.into()); |
| 153 | w.set_ckmode(false); | 150 | w.set_ckmode(false); |
| 154 | }); | 151 | }); |
| 155 | } | ||
| 156 | 152 | ||
| 157 | Self { | 153 | Self { |
| 158 | _peri: peri, | 154 | _peri: peri, |
| @@ -168,148 +164,140 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 168 | } | 164 | } |
| 169 | 165 | ||
| 170 | pub fn command(&mut self, transaction: TransferConfig) { | 166 | pub fn command(&mut self, transaction: TransferConfig) { |
| 171 | unsafe { | 167 | T::REGS.cr().modify(|v| v.set_dmaen(false)); |
| 172 | T::REGS.cr().modify(|v| v.set_dmaen(false)); | 168 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 173 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||
| 174 | 169 | ||
| 175 | while !T::REGS.sr().read().tcf() {} | 170 | while !T::REGS.sr().read().tcf() {} |
| 176 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | 171 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); |
| 177 | } | ||
| 178 | } | 172 | } |
| 179 | 173 | ||
| 180 | pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { | 174 | pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { |
| 181 | unsafe { | 175 | T::REGS.cr().modify(|v| v.set_dmaen(false)); |
| 182 | T::REGS.cr().modify(|v| v.set_dmaen(false)); | 176 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 183 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | 177 | |
| 184 | 178 | if let Some(len) = transaction.data_len { | |
| 185 | if let Some(len) = transaction.data_len { | 179 | let current_ar = T::REGS.ar().read().address(); |
| 186 | let current_ar = T::REGS.ar().read().address(); | 180 | T::REGS.ccr().modify(|v| { |
| 187 | T::REGS.ccr().modify(|v| { | 181 | v.set_fmode(QspiMode::IndirectRead.into()); |
| 188 | v.set_fmode(QspiMode::IndirectRead.into()); | 182 | }); |
| 189 | }); | 183 | T::REGS.ar().write(|v| { |
| 190 | T::REGS.ar().write(|v| { | 184 | v.set_address(current_ar); |
| 191 | v.set_address(current_ar); | 185 | }); |
| 192 | }); | ||
| 193 | |||
| 194 | for idx in 0..len { | ||
| 195 | while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} | ||
| 196 | buf[idx] = *(T::REGS.dr().ptr() as *mut u8); | ||
| 197 | } | ||
| 198 | } | ||
| 199 | 186 | ||
| 200 | while !T::REGS.sr().read().tcf() {} | 187 | for idx in 0..len { |
| 201 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | 188 | while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} |
| 189 | buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; | ||
| 190 | } | ||
| 202 | } | 191 | } |
| 192 | |||
| 193 | while !T::REGS.sr().read().tcf() {} | ||
| 194 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | ||
| 203 | } | 195 | } |
| 204 | 196 | ||
| 205 | pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { | 197 | pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { |
| 206 | unsafe { | 198 | T::REGS.cr().modify(|v| v.set_dmaen(false)); |
| 207 | T::REGS.cr().modify(|v| v.set_dmaen(false)); | 199 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 208 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||
| 209 | |||
| 210 | if let Some(len) = transaction.data_len { | ||
| 211 | T::REGS.ccr().modify(|v| { | ||
| 212 | v.set_fmode(QspiMode::IndirectWrite.into()); | ||
| 213 | }); | ||
| 214 | |||
| 215 | for idx in 0..len { | ||
| 216 | while !T::REGS.sr().read().ftf() {} | ||
| 217 | *(T::REGS.dr().ptr() as *mut u8) = buf[idx]; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | 200 | ||
| 221 | while !T::REGS.sr().read().tcf() {} | 201 | if let Some(len) = transaction.data_len { |
| 222 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | 202 | T::REGS.ccr().modify(|v| { |
| 203 | v.set_fmode(QspiMode::IndirectWrite.into()); | ||
| 204 | }); | ||
| 205 | |||
| 206 | for idx in 0..len { | ||
| 207 | while !T::REGS.sr().read().ftf() {} | ||
| 208 | unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) }; | ||
| 209 | } | ||
| 223 | } | 210 | } |
| 211 | |||
| 212 | while !T::REGS.sr().read().tcf() {} | ||
| 213 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | ||
| 224 | } | 214 | } |
| 225 | 215 | ||
| 226 | pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) | 216 | pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) |
| 227 | where | 217 | where |
| 228 | Dma: QuadDma<T>, | 218 | Dma: QuadDma<T>, |
| 229 | { | 219 | { |
| 230 | unsafe { | 220 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 231 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | 221 | |
| 232 | 222 | T::REGS.ccr().modify(|v| { | |
| 233 | T::REGS.ccr().modify(|v| { | 223 | v.set_fmode(QspiMode::IndirectRead.into()); |
| 234 | v.set_fmode(QspiMode::IndirectRead.into()); | 224 | }); |
| 235 | }); | 225 | let current_ar = T::REGS.ar().read().address(); |
| 236 | let current_ar = T::REGS.ar().read().address(); | 226 | T::REGS.ar().write(|v| { |
| 237 | T::REGS.ar().write(|v| { | 227 | v.set_address(current_ar); |
| 238 | v.set_address(current_ar); | 228 | }); |
| 239 | }); | 229 | |
| 240 | 230 | let request = self.dma.request(); | |
| 241 | let request = self.dma.request(); | 231 | let transfer = unsafe { |
| 242 | let transfer = Transfer::new_read( | 232 | Transfer::new_read( |
| 243 | &mut self.dma, | 233 | &mut self.dma, |
| 244 | request, | 234 | request, |
| 245 | T::REGS.dr().ptr() as *mut u8, | 235 | T::REGS.dr().as_ptr() as *mut u8, |
| 246 | buf, | 236 | buf, |
| 247 | Default::default(), | 237 | Default::default(), |
| 248 | ); | 238 | ) |
| 239 | }; | ||
| 249 | 240 | ||
| 250 | T::REGS.cr().modify(|v| v.set_dmaen(true)); | 241 | T::REGS.cr().modify(|v| v.set_dmaen(true)); |
| 251 | 242 | ||
| 252 | transfer.blocking_wait(); | 243 | transfer.blocking_wait(); |
| 253 | } | ||
| 254 | } | 244 | } |
| 255 | 245 | ||
| 256 | pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) | 246 | pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) |
| 257 | where | 247 | where |
| 258 | Dma: QuadDma<T>, | 248 | Dma: QuadDma<T>, |
| 259 | { | 249 | { |
| 260 | unsafe { | 250 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 261 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | ||
| 262 | 251 | ||
| 263 | T::REGS.ccr().modify(|v| { | 252 | T::REGS.ccr().modify(|v| { |
| 264 | v.set_fmode(QspiMode::IndirectWrite.into()); | 253 | v.set_fmode(QspiMode::IndirectWrite.into()); |
| 265 | }); | 254 | }); |
| 266 | 255 | ||
| 267 | let request = self.dma.request(); | 256 | let request = self.dma.request(); |
| 268 | let transfer = Transfer::new_write( | 257 | let transfer = unsafe { |
| 258 | Transfer::new_write( | ||
| 269 | &mut self.dma, | 259 | &mut self.dma, |
| 270 | request, | 260 | request, |
| 271 | buf, | 261 | buf, |
| 272 | T::REGS.dr().ptr() as *mut u8, | 262 | T::REGS.dr().as_ptr() as *mut u8, |
| 273 | Default::default(), | 263 | Default::default(), |
| 274 | ); | 264 | ) |
| 265 | }; | ||
| 275 | 266 | ||
| 276 | T::REGS.cr().modify(|v| v.set_dmaen(true)); | 267 | T::REGS.cr().modify(|v| v.set_dmaen(true)); |
| 277 | 268 | ||
| 278 | transfer.blocking_wait(); | 269 | transfer.blocking_wait(); |
| 279 | } | ||
| 280 | } | 270 | } |
| 281 | 271 | ||
| 282 | fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { | 272 | fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { |
| 283 | unsafe { | 273 | T::REGS.fcr().modify(|v| { |
| 284 | T::REGS.fcr().modify(|v| { | 274 | v.set_csmf(true); |
| 285 | v.set_csmf(true); | 275 | v.set_ctcf(true); |
| 286 | v.set_ctcf(true); | 276 | v.set_ctef(true); |
| 287 | v.set_ctef(true); | 277 | v.set_ctof(true); |
| 288 | v.set_ctof(true); | 278 | }); |
| 289 | }); | ||
| 290 | 279 | ||
| 291 | while T::REGS.sr().read().busy() {} | 280 | while T::REGS.sr().read().busy() {} |
| 292 | 281 | ||
| 293 | if let Some(len) = transaction.data_len { | 282 | if let Some(len) = transaction.data_len { |
| 294 | T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); | 283 | T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); |
| 295 | } | 284 | } |
| 296 | 285 | ||
| 297 | T::REGS.ccr().write(|v| { | 286 | T::REGS.ccr().write(|v| { |
| 298 | v.set_fmode(fmode.into()); | 287 | v.set_fmode(fmode.into()); |
| 299 | v.set_imode(transaction.iwidth.into()); | 288 | v.set_imode(transaction.iwidth.into()); |
| 300 | v.set_instruction(transaction.instruction); | 289 | v.set_instruction(transaction.instruction); |
| 301 | v.set_admode(transaction.awidth.into()); | 290 | v.set_admode(transaction.awidth.into()); |
| 302 | v.set_adsize(self.config.address_size.into()); | 291 | v.set_adsize(self.config.address_size.into()); |
| 303 | v.set_dmode(transaction.dwidth.into()); | 292 | v.set_dmode(transaction.dwidth.into()); |
| 304 | v.set_abmode(QspiWidth::NONE.into()); | 293 | v.set_abmode(QspiWidth::NONE.into()); |
| 305 | v.set_dcyc(transaction.dummy.into()); | 294 | v.set_dcyc(transaction.dummy.into()); |
| 295 | }); | ||
| 296 | |||
| 297 | if let Some(addr) = transaction.address { | ||
| 298 | T::REGS.ar().write(|v| { | ||
| 299 | v.set_address(addr); | ||
| 306 | }); | 300 | }); |
| 307 | |||
| 308 | if let Some(addr) = transaction.address { | ||
| 309 | T::REGS.ar().write(|v| { | ||
| 310 | v.set_address(addr); | ||
| 311 | }); | ||
| 312 | } | ||
| 313 | } | 301 | } |
| 314 | } | 302 | } |
| 315 | } | 303 | } |
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index e0929ca49..bc430afb2 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs | |||
| @@ -36,18 +36,18 @@ pub struct Config { | |||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | #[cfg(stm32f410)] | 38 | #[cfg(stm32f410)] |
| 39 | unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { | 39 | fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { |
| 40 | None | 40 | None |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | // Not currently implemented, but will be in the future | 43 | // Not currently implemented, but will be in the future |
| 44 | #[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] | 44 | #[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] |
| 45 | unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { | 45 | fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { |
| 46 | None | 46 | None |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] | 49 | #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] |
| 50 | unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> { | 50 | fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> { |
| 51 | let min_div = 2; | 51 | let min_div = 2; |
| 52 | let max_div = 7; | 52 | let max_div = 7; |
| 53 | let target = match plli2s { | 53 | let target = match plli2s { |
| @@ -82,13 +82,7 @@ unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> { | |||
| 82 | Some(output) | 82 | Some(output) |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | unsafe fn setup_pll( | 85 | fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Option<u32>, pll48clk: bool) -> PllResults { |
| 86 | pllsrcclk: u32, | ||
| 87 | use_hse: bool, | ||
| 88 | pllsysclk: Option<u32>, | ||
| 89 | plli2s: Option<u32>, | ||
| 90 | pll48clk: bool, | ||
| 91 | ) -> PllResults { | ||
| 92 | use crate::pac::rcc::vals::{Pllp, Pllsrc}; | 86 | use crate::pac::rcc::vals::{Pllp, Pllsrc}; |
| 93 | 87 | ||
| 94 | let sysclk = pllsysclk.unwrap_or(pllsrcclk); | 88 | let sysclk = pllsysclk.unwrap_or(pllsrcclk); |
| @@ -320,7 +314,7 @@ impl<'d, T: McoInstance> Mco<'d, T> { | |||
| 320 | } | 314 | } |
| 321 | } | 315 | } |
| 322 | 316 | ||
| 323 | unsafe fn flash_setup(sysclk: u32) { | 317 | fn flash_setup(sysclk: u32) { |
| 324 | use crate::pac::flash::vals::Latency; | 318 | use crate::pac::flash::vals::Latency; |
| 325 | 319 | ||
| 326 | // Be conservative with voltage ranges | 320 | // Be conservative with voltage ranges |
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs index 2d21326a3..71215cac5 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs | |||
| @@ -25,7 +25,7 @@ pub struct Config { | |||
| 25 | pub pll48: bool, | 25 | pub pll48: bool, |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { | 28 | fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { |
| 29 | use crate::pac::rcc::vals::{Pllp, Pllsrc}; | 29 | use crate::pac::rcc::vals::{Pllp, Pllsrc}; |
| 30 | 30 | ||
| 31 | let sysclk = pllsysclk.unwrap_or(pllsrcclk); | 31 | let sysclk = pllsysclk.unwrap_or(pllsrcclk); |
| @@ -97,7 +97,7 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48 | |||
| 97 | } | 97 | } |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | unsafe fn flash_setup(sysclk: u32) { | 100 | fn flash_setup(sysclk: u32) { |
| 101 | use crate::pac::flash::vals::Latency; | 101 | use crate::pac::flash::vals::Latency; |
| 102 | 102 | ||
| 103 | // Be conservative with voltage ranges | 103 | // Be conservative with voltage ranges |
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 3e138c7ab..17c73c36b 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs | |||
| @@ -245,7 +245,7 @@ impl Default for Config { | |||
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | impl PllConfig { | 247 | impl PllConfig { |
| 248 | pub(crate) unsafe fn init(self) -> u32 { | 248 | pub(crate) fn init(self) -> u32 { |
| 249 | assert!(self.n >= 8 && self.n <= 86); | 249 | assert!(self.n >= 8 && self.n <= 86); |
| 250 | let (src, input_freq) = match self.source { | 250 | let (src, input_freq) = match self.source { |
| 251 | PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0), | 251 | PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0), |
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 7e748c7b5..9401af4c3 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | use stm32_metapac::rcc::vals::{Hpre, Ppre, Sw}; | 1 | use stm32_metapac::flash::vals::Latency; |
| 2 | use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw}; | ||
| 3 | use stm32_metapac::FLASH; | ||
| 2 | 4 | ||
| 3 | use crate::pac::{PWR, RCC}; | 5 | use crate::pac::{PWR, RCC}; |
| 4 | use crate::rcc::{set_freqs, Clocks}; | 6 | use crate::rcc::{set_freqs, Clocks}; |
| @@ -15,6 +17,7 @@ pub const LSI_FREQ: Hertz = Hertz(32_000); | |||
| 15 | pub enum ClockSrc { | 17 | pub enum ClockSrc { |
| 16 | HSE(Hertz), | 18 | HSE(Hertz), |
| 17 | HSI16, | 19 | HSI16, |
| 20 | PLL, | ||
| 18 | } | 21 | } |
| 19 | 22 | ||
| 20 | /// AHB prescaler | 23 | /// AHB prescaler |
| @@ -41,6 +44,222 @@ pub enum APBPrescaler { | |||
| 41 | Div16, | 44 | Div16, |
| 42 | } | 45 | } |
| 43 | 46 | ||
| 47 | /// PLL clock input source | ||
| 48 | #[derive(Clone, Copy, Debug)] | ||
| 49 | pub enum PllSrc { | ||
| 50 | HSI16, | ||
| 51 | HSE(Hertz), | ||
| 52 | } | ||
| 53 | |||
| 54 | impl Into<Pllsrc> for PllSrc { | ||
| 55 | fn into(self) -> Pllsrc { | ||
| 56 | match self { | ||
| 57 | PllSrc::HSE(..) => Pllsrc::HSE, | ||
| 58 | PllSrc::HSI16 => Pllsrc::HSI16, | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | seq_macro::seq!(P in 2..=31 { | ||
| 64 | /// Output divider for the PLL P output. | ||
| 65 | #[derive(Clone, Copy)] | ||
| 66 | pub enum PllP { | ||
| 67 | // Note: If PLL P is set to 0 the PLLP bit controls the output division. There does not seem to | ||
| 68 | // a good reason to do this so the API does not support it. | ||
| 69 | // Div1 is invalid | ||
| 70 | #( | ||
| 71 | Div~P, | ||
| 72 | )* | ||
| 73 | } | ||
| 74 | |||
| 75 | impl From<PllP> for u8 { | ||
| 76 | /// Returns the register value for the P output divider. | ||
| 77 | fn from(val: PllP) -> u8 { | ||
| 78 | match val { | ||
| 79 | #( | ||
| 80 | PllP::Div~P => P, | ||
| 81 | )* | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } | ||
| 85 | }); | ||
| 86 | |||
| 87 | impl PllP { | ||
| 88 | /// Returns the numeric value of the P output divider. | ||
| 89 | pub fn to_div(self) -> u32 { | ||
| 90 | let val: u8 = self.into(); | ||
| 91 | val as u32 | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | /// Output divider for the PLL Q output. | ||
| 96 | #[derive(Clone, Copy)] | ||
| 97 | pub enum PllQ { | ||
| 98 | Div2, | ||
| 99 | Div4, | ||
| 100 | Div6, | ||
| 101 | Div8, | ||
| 102 | } | ||
| 103 | |||
| 104 | impl PllQ { | ||
| 105 | /// Returns the numeric value of the Q output divider. | ||
| 106 | pub fn to_div(self) -> u32 { | ||
| 107 | let val: u8 = self.into(); | ||
| 108 | (val as u32 + 1) * 2 | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | impl From<PllQ> for u8 { | ||
| 113 | /// Returns the register value for the Q output divider. | ||
| 114 | fn from(val: PllQ) -> u8 { | ||
| 115 | match val { | ||
| 116 | PllQ::Div2 => 0b00, | ||
| 117 | PllQ::Div4 => 0b01, | ||
| 118 | PllQ::Div6 => 0b10, | ||
| 119 | PllQ::Div8 => 0b11, | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | /// Output divider for the PLL R output. | ||
| 125 | #[derive(Clone, Copy)] | ||
| 126 | pub enum PllR { | ||
| 127 | Div2, | ||
| 128 | Div4, | ||
| 129 | Div6, | ||
| 130 | Div8, | ||
| 131 | } | ||
| 132 | |||
| 133 | impl PllR { | ||
| 134 | /// Returns the numeric value of the R output divider. | ||
| 135 | pub fn to_div(self) -> u32 { | ||
| 136 | let val: u8 = self.into(); | ||
| 137 | (val as u32 + 1) * 2 | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | impl From<PllR> for u8 { | ||
| 142 | /// Returns the register value for the R output divider. | ||
| 143 | fn from(val: PllR) -> u8 { | ||
| 144 | match val { | ||
| 145 | PllR::Div2 => 0b00, | ||
| 146 | PllR::Div4 => 0b01, | ||
| 147 | PllR::Div6 => 0b10, | ||
| 148 | PllR::Div8 => 0b11, | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | seq_macro::seq!(N in 8..=127 { | ||
| 154 | /// Multiplication factor for the PLL VCO input clock. | ||
| 155 | #[derive(Clone, Copy)] | ||
| 156 | pub enum PllN { | ||
| 157 | #( | ||
| 158 | Mul~N, | ||
| 159 | )* | ||
| 160 | } | ||
| 161 | |||
| 162 | impl From<PllN> for u8 { | ||
| 163 | /// Returns the register value for the N multiplication factor. | ||
| 164 | fn from(val: PllN) -> u8 { | ||
| 165 | match val { | ||
| 166 | #( | ||
| 167 | PllN::Mul~N => N, | ||
| 168 | )* | ||
| 169 | } | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | impl PllN { | ||
| 174 | /// Returns the numeric value of the N multiplication factor. | ||
| 175 | pub fn to_mul(self) -> u32 { | ||
| 176 | match self { | ||
| 177 | #( | ||
| 178 | PllN::Mul~N => N, | ||
| 179 | )* | ||
| 180 | } | ||
| 181 | } | ||
| 182 | } | ||
| 183 | }); | ||
| 184 | |||
| 185 | /// PLL Pre-division. This must be set such that the PLL input is between 2.66 MHz and 16 MHz. | ||
| 186 | #[derive(Copy, Clone)] | ||
| 187 | pub enum PllM { | ||
| 188 | Div1, | ||
| 189 | Div2, | ||
| 190 | Div3, | ||
| 191 | Div4, | ||
| 192 | Div5, | ||
| 193 | Div6, | ||
| 194 | Div7, | ||
| 195 | Div8, | ||
| 196 | Div9, | ||
| 197 | Div10, | ||
| 198 | Div11, | ||
| 199 | Div12, | ||
| 200 | Div13, | ||
| 201 | Div14, | ||
| 202 | Div15, | ||
| 203 | Div16, | ||
| 204 | } | ||
| 205 | |||
| 206 | impl PllM { | ||
| 207 | /// Returns the numeric value of the M pre-division. | ||
| 208 | pub fn to_div(self) -> u32 { | ||
| 209 | let val: u8 = self.into(); | ||
| 210 | val as u32 + 1 | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | impl From<PllM> for u8 { | ||
| 215 | /// Returns the register value for the M pre-division. | ||
| 216 | fn from(val: PllM) -> u8 { | ||
| 217 | match val { | ||
| 218 | PllM::Div1 => 0b0000, | ||
| 219 | PllM::Div2 => 0b0001, | ||
| 220 | PllM::Div3 => 0b0010, | ||
| 221 | PllM::Div4 => 0b0011, | ||
| 222 | PllM::Div5 => 0b0100, | ||
| 223 | PllM::Div6 => 0b0101, | ||
| 224 | PllM::Div7 => 0b0110, | ||
| 225 | PllM::Div8 => 0b0111, | ||
| 226 | PllM::Div9 => 0b1000, | ||
| 227 | PllM::Div10 => 0b1001, | ||
| 228 | PllM::Div11 => 0b1010, | ||
| 229 | PllM::Div12 => 0b1011, | ||
| 230 | PllM::Div13 => 0b1100, | ||
| 231 | PllM::Div14 => 0b1101, | ||
| 232 | PllM::Div15 => 0b1110, | ||
| 233 | PllM::Div16 => 0b1111, | ||
| 234 | } | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | /// PLL Configuration | ||
| 239 | /// | ||
| 240 | /// Use this struct to configure the PLL source, input frequency, multiplication factor, and output | ||
| 241 | /// dividers. Be sure to keep check the datasheet for your specific part for the appropriate | ||
| 242 | /// frequency ranges for each of these settings. | ||
| 243 | pub struct Pll { | ||
| 244 | /// PLL Source clock selection. | ||
| 245 | pub source: PllSrc, | ||
| 246 | |||
| 247 | /// PLL pre-divider | ||
| 248 | pub prediv_m: PllM, | ||
| 249 | |||
| 250 | /// PLL multiplication factor for VCO | ||
| 251 | pub mul_n: PllN, | ||
| 252 | |||
| 253 | /// PLL division factor for P clock (ADC Clock) | ||
| 254 | pub div_p: Option<PllP>, | ||
| 255 | |||
| 256 | /// PLL division factor for Q clock (USB, I2S23, SAI1, FDCAN, QSPI) | ||
| 257 | pub div_q: Option<PllQ>, | ||
| 258 | |||
| 259 | /// PLL division factor for R clock (SYSCLK) | ||
| 260 | pub div_r: Option<PllR>, | ||
| 261 | } | ||
| 262 | |||
| 44 | impl AHBPrescaler { | 263 | impl AHBPrescaler { |
| 45 | const fn div(self) -> u32 { | 264 | const fn div(self) -> u32 { |
| 46 | match self { | 265 | match self { |
| @@ -104,6 +323,9 @@ pub struct Config { | |||
| 104 | pub apb1_pre: APBPrescaler, | 323 | pub apb1_pre: APBPrescaler, |
| 105 | pub apb2_pre: APBPrescaler, | 324 | pub apb2_pre: APBPrescaler, |
| 106 | pub low_power_run: bool, | 325 | pub low_power_run: bool, |
| 326 | /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration | ||
| 327 | /// MUST turn on the PLLR output. | ||
| 328 | pub pll: Option<Pll>, | ||
| 107 | } | 329 | } |
| 108 | 330 | ||
| 109 | impl Default for Config { | 331 | impl Default for Config { |
| @@ -115,11 +337,80 @@ impl Default for Config { | |||
| 115 | apb1_pre: APBPrescaler::NotDivided, | 337 | apb1_pre: APBPrescaler::NotDivided, |
| 116 | apb2_pre: APBPrescaler::NotDivided, | 338 | apb2_pre: APBPrescaler::NotDivided, |
| 117 | low_power_run: false, | 339 | low_power_run: false, |
| 340 | pll: None, | ||
| 118 | } | 341 | } |
| 119 | } | 342 | } |
| 120 | } | 343 | } |
| 121 | 344 | ||
| 345 | pub struct PllFreq { | ||
| 346 | pub pll_p: Option<Hertz>, | ||
| 347 | pub pll_q: Option<Hertz>, | ||
| 348 | pub pll_r: Option<Hertz>, | ||
| 349 | } | ||
| 350 | |||
| 122 | pub(crate) unsafe fn init(config: Config) { | 351 | pub(crate) unsafe fn init(config: Config) { |
| 352 | let pll_freq = config.pll.map(|pll_config| { | ||
| 353 | let src_freq = match pll_config.source { | ||
| 354 | PllSrc::HSI16 => { | ||
| 355 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 356 | while !RCC.cr().read().hsirdy() {} | ||
| 357 | |||
| 358 | HSI_FREQ.0 | ||
| 359 | } | ||
| 360 | PllSrc::HSE(freq) => { | ||
| 361 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 362 | while !RCC.cr().read().hserdy() {} | ||
| 363 | freq.0 | ||
| 364 | } | ||
| 365 | }; | ||
| 366 | |||
| 367 | // Disable PLL before configuration | ||
| 368 | RCC.cr().modify(|w| w.set_pllon(false)); | ||
| 369 | while RCC.cr().read().pllrdy() {} | ||
| 370 | |||
| 371 | let internal_freq = src_freq / pll_config.prediv_m.to_div() * pll_config.mul_n.to_mul(); | ||
| 372 | |||
| 373 | RCC.pllcfgr().write(|w| { | ||
| 374 | w.set_plln(pll_config.mul_n.into()); | ||
| 375 | w.set_pllm(pll_config.prediv_m.into()); | ||
| 376 | w.set_pllsrc(pll_config.source.into()); | ||
| 377 | }); | ||
| 378 | |||
| 379 | let pll_p_freq = pll_config.div_p.map(|div_p| { | ||
| 380 | RCC.pllcfgr().modify(|w| { | ||
| 381 | w.set_pllpdiv(div_p.into()); | ||
| 382 | w.set_pllpen(true); | ||
| 383 | }); | ||
| 384 | Hertz(internal_freq / div_p.to_div()) | ||
| 385 | }); | ||
| 386 | |||
| 387 | let pll_q_freq = pll_config.div_q.map(|div_q| { | ||
| 388 | RCC.pllcfgr().modify(|w| { | ||
| 389 | w.set_pllq(div_q.into()); | ||
| 390 | w.set_pllqen(true); | ||
| 391 | }); | ||
| 392 | Hertz(internal_freq / div_q.to_div()) | ||
| 393 | }); | ||
| 394 | |||
| 395 | let pll_r_freq = pll_config.div_r.map(|div_r| { | ||
| 396 | RCC.pllcfgr().modify(|w| { | ||
| 397 | w.set_pllr(div_r.into()); | ||
| 398 | w.set_pllren(true); | ||
| 399 | }); | ||
| 400 | Hertz(internal_freq / div_r.to_div()) | ||
| 401 | }); | ||
| 402 | |||
| 403 | // Enable the PLL | ||
| 404 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 405 | while !RCC.cr().read().pllrdy() {} | ||
| 406 | |||
| 407 | PllFreq { | ||
| 408 | pll_p: pll_p_freq, | ||
| 409 | pll_q: pll_q_freq, | ||
| 410 | pll_r: pll_r_freq, | ||
| 411 | } | ||
| 412 | }); | ||
| 413 | |||
| 123 | let (sys_clk, sw) = match config.mux { | 414 | let (sys_clk, sw) = match config.mux { |
| 124 | ClockSrc::HSI16 => { | 415 | ClockSrc::HSI16 => { |
| 125 | // Enable HSI16 | 416 | // Enable HSI16 |
| @@ -135,6 +426,47 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 135 | 426 | ||
| 136 | (freq.0, Sw::HSE) | 427 | (freq.0, Sw::HSE) |
| 137 | } | 428 | } |
| 429 | ClockSrc::PLL => { | ||
| 430 | assert!(pll_freq.is_some()); | ||
| 431 | assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); | ||
| 432 | |||
| 433 | let freq = pll_freq.unwrap().pll_r.unwrap().0; | ||
| 434 | |||
| 435 | assert!(freq <= 170_000_000); | ||
| 436 | |||
| 437 | if freq >= 150_000_000 { | ||
| 438 | // Enable Core Boost mode on freq >= 150Mhz ([RM0440] p234) | ||
| 439 | PWR.cr5().modify(|w| w.set_r1mode(false)); | ||
| 440 | // Set flash wait state in boost mode based on frequency ([RM0440] p191) | ||
| 441 | if freq <= 36_000_000 { | ||
| 442 | FLASH.acr().modify(|w| w.set_latency(Latency::WS0)); | ||
| 443 | } else if freq <= 68_000_000 { | ||
| 444 | FLASH.acr().modify(|w| w.set_latency(Latency::WS1)); | ||
| 445 | } else if freq <= 102_000_000 { | ||
| 446 | FLASH.acr().modify(|w| w.set_latency(Latency::WS2)); | ||
| 447 | } else if freq <= 136_000_000 { | ||
| 448 | FLASH.acr().modify(|w| w.set_latency(Latency::WS3)); | ||
| 449 | } else { | ||
| 450 | FLASH.acr().modify(|w| w.set_latency(Latency::WS4)); | ||
| 451 | } | ||
| 452 | } else { | ||
| 453 | PWR.cr5().modify(|w| w.set_r1mode(true)); | ||
| 454 | // Set flash wait state in normal mode based on frequency ([RM0440] p191) | ||
| 455 | if freq <= 30_000_000 { | ||
| 456 | FLASH.acr().modify(|w| w.set_latency(Latency::WS0)); | ||
| 457 | } else if freq <= 60_000_000 { | ||
| 458 | FLASH.acr().modify(|w| w.set_latency(Latency::WS1)); | ||
| 459 | } else if freq <= 80_000_000 { | ||
| 460 | FLASH.acr().modify(|w| w.set_latency(Latency::WS2)); | ||
| 461 | } else if freq <= 120_000_000 { | ||
| 462 | FLASH.acr().modify(|w| w.set_latency(Latency::WS3)); | ||
| 463 | } else { | ||
| 464 | FLASH.acr().modify(|w| w.set_latency(Latency::WS4)); | ||
| 465 | } | ||
| 466 | } | ||
| 467 | |||
| 468 | (freq, Sw::PLLRCLK) | ||
| 469 | } | ||
| 138 | }; | 470 | }; |
| 139 | 471 | ||
| 140 | RCC.cfgr().modify(|w| { | 472 | RCC.cfgr().modify(|w| { |
diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs index 17fbc6056..4025a4e05 100644 --- a/embassy-stm32/src/rcc/h5.rs +++ b/embassy-stm32/src/rcc/h5.rs | |||
| @@ -462,7 +462,7 @@ struct PllOutput { | |||
| 462 | r: Option<Hertz>, | 462 | r: Option<Hertz>, |
| 463 | } | 463 | } |
| 464 | 464 | ||
| 465 | unsafe fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { | 465 | fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { |
| 466 | let Some(config) = config else { | 466 | let Some(config) = config else { |
| 467 | // Stop PLL | 467 | // Stop PLL |
| 468 | RCC.cr().modify(|w| w.set_pllon(num, false)); | 468 | RCC.cr().modify(|w| w.set_pllon(num, false)); |
| @@ -595,12 +595,9 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) { | |||
| 595 | 595 | ||
| 596 | defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); | 596 | defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); |
| 597 | 597 | ||
| 598 | // NOTE(unsafe) Atomic write | 598 | FLASH.acr().write(|w| { |
| 599 | unsafe { | 599 | w.set_wrhighfreq(wrhighfreq); |
| 600 | FLASH.acr().write(|w| { | 600 | w.set_latency(latency); |
| 601 | w.set_wrhighfreq(wrhighfreq); | 601 | }); |
| 602 | w.set_latency(latency); | 602 | while FLASH.acr().read().latency() != latency {} |
| 603 | }); | ||
| 604 | while FLASH.acr().read().latency() != latency {} | ||
| 605 | } | ||
| 606 | } | 603 | } |
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index 0185f7ae8..daa1cd61f 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs | |||
| @@ -253,14 +253,11 @@ fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { | |||
| 253 | }, | 253 | }, |
| 254 | }; | 254 | }; |
| 255 | 255 | ||
| 256 | // NOTE(unsafe) Atomic write | 256 | FLASH.acr().write(|w| { |
| 257 | unsafe { | 257 | w.set_wrhighfreq(progr_delay); |
| 258 | FLASH.acr().write(|w| { | 258 | w.set_latency(wait_states) |
| 259 | w.set_wrhighfreq(progr_delay); | 259 | }); |
| 260 | w.set_latency(wait_states) | 260 | while FLASH.acr().read().latency() != wait_states {} |
| 261 | }); | ||
| 262 | while FLASH.acr().read().latency() != wait_states {} | ||
| 263 | } | ||
| 264 | } | 261 | } |
| 265 | 262 | ||
| 266 | pub enum McoClock { | 263 | pub enum McoClock { |
| @@ -474,7 +471,6 @@ pub(crate) unsafe fn init(mut config: Config) { | |||
| 474 | // Configure traceclk from PLL if needed | 471 | // Configure traceclk from PLL if needed |
| 475 | traceclk_setup(&mut config, sys_use_pll1_p); | 472 | traceclk_setup(&mut config, sys_use_pll1_p); |
| 476 | 473 | ||
| 477 | // NOTE(unsafe) We have exclusive access to the RCC | ||
| 478 | let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0); | 474 | let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0); |
| 479 | let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1); | 475 | let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1); |
| 480 | let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2); | 476 | let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2); |
| @@ -756,7 +752,7 @@ mod pll { | |||
| 756 | /// # Safety | 752 | /// # Safety |
| 757 | /// | 753 | /// |
| 758 | /// Must have exclusive access to the RCC register block | 754 | /// Must have exclusive access to the RCC register block |
| 759 | unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults { | 755 | fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults { |
| 760 | use crate::pac::rcc::vals::{Pllrge, Pllvcosel}; | 756 | use crate::pac::rcc::vals::{Pllrge, Pllvcosel}; |
| 761 | 757 | ||
| 762 | let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln); | 758 | let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln); |
| @@ -785,11 +781,7 @@ mod pll { | |||
| 785 | /// # Safety | 781 | /// # Safety |
| 786 | /// | 782 | /// |
| 787 | /// Must have exclusive access to the RCC register block | 783 | /// Must have exclusive access to the RCC register block |
| 788 | pub(super) unsafe fn pll_setup( | 784 | pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) { |
| 789 | pll_src: u32, | ||
| 790 | config: &PllConfig, | ||
| 791 | plln: usize, | ||
| 792 | ) -> (Option<u32>, Option<u32>, Option<u32>) { | ||
| 793 | use crate::pac::rcc::vals::Divp; | 785 | use crate::pac::rcc::vals::Divp; |
| 794 | 786 | ||
| 795 | match config.p_ck { | 787 | match config.p_ck { |
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 1e16b8478..b2faec53d 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs | |||
| @@ -34,40 +34,34 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 34 | pub fn reset(&mut self) { | 34 | pub fn reset(&mut self) { |
| 35 | // rng_v2 locks up on seed error, needs reset | 35 | // rng_v2 locks up on seed error, needs reset |
| 36 | #[cfg(rng_v2)] | 36 | #[cfg(rng_v2)] |
| 37 | if unsafe { T::regs().sr().read().seis() } { | 37 | if T::regs().sr().read().seis() { |
| 38 | T::reset(); | 38 | T::reset(); |
| 39 | } | 39 | } |
| 40 | unsafe { | 40 | T::regs().cr().modify(|reg| { |
| 41 | T::regs().cr().modify(|reg| { | 41 | reg.set_rngen(true); |
| 42 | reg.set_rngen(true); | 42 | reg.set_ie(true); |
| 43 | reg.set_ie(true); | 43 | }); |
| 44 | }); | 44 | T::regs().sr().modify(|reg| { |
| 45 | T::regs().sr().modify(|reg| { | 45 | reg.set_seis(false); |
| 46 | reg.set_seis(false); | 46 | reg.set_ceis(false); |
| 47 | reg.set_ceis(false); | 47 | }); |
| 48 | }); | ||
| 49 | } | ||
| 50 | // Reference manual says to discard the first. | 48 | // Reference manual says to discard the first. |
| 51 | let _ = self.next_u32(); | 49 | let _ = self.next_u32(); |
| 52 | } | 50 | } |
| 53 | 51 | ||
| 54 | pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { | 52 | pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { |
| 55 | unsafe { | 53 | T::regs().cr().modify(|reg| { |
| 56 | T::regs().cr().modify(|reg| { | 54 | reg.set_rngen(true); |
| 57 | reg.set_rngen(true); | 55 | }); |
| 58 | }) | ||
| 59 | } | ||
| 60 | 56 | ||
| 61 | for chunk in dest.chunks_mut(4) { | 57 | for chunk in dest.chunks_mut(4) { |
| 62 | poll_fn(|cx| { | 58 | poll_fn(|cx| { |
| 63 | RNG_WAKER.register(cx.waker()); | 59 | RNG_WAKER.register(cx.waker()); |
| 64 | unsafe { | 60 | T::regs().cr().modify(|reg| { |
| 65 | T::regs().cr().modify(|reg| { | 61 | reg.set_ie(true); |
| 66 | reg.set_ie(true); | 62 | }); |
| 67 | }); | ||
| 68 | } | ||
| 69 | 63 | ||
| 70 | let bits = unsafe { T::regs().sr().read() }; | 64 | let bits = T::regs().sr().read(); |
| 71 | 65 | ||
| 72 | if bits.drdy() { | 66 | if bits.drdy() { |
| 73 | Poll::Ready(Ok(())) | 67 | Poll::Ready(Ok(())) |
| @@ -82,7 +76,7 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 82 | } | 76 | } |
| 83 | }) | 77 | }) |
| 84 | .await?; | 78 | .await?; |
| 85 | let random_bytes = unsafe { T::regs().dr().read() }.to_be_bytes(); | 79 | let random_bytes = T::regs().dr().read().to_be_bytes(); |
| 86 | for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) { | 80 | for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) { |
| 87 | *dest = *src | 81 | *dest = *src |
| 88 | } | 82 | } |
| @@ -95,11 +89,11 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 95 | impl<'d, T: Instance> RngCore for Rng<'d, T> { | 89 | impl<'d, T: Instance> RngCore for Rng<'d, T> { |
| 96 | fn next_u32(&mut self) -> u32 { | 90 | fn next_u32(&mut self) -> u32 { |
| 97 | loop { | 91 | loop { |
| 98 | let sr = unsafe { T::regs().sr().read() }; | 92 | let sr = T::regs().sr().read(); |
| 99 | if sr.seis() | sr.ceis() { | 93 | if sr.seis() | sr.ceis() { |
| 100 | self.reset(); | 94 | self.reset(); |
| 101 | } else if sr.drdy() { | 95 | } else if sr.drdy() { |
| 102 | return unsafe { T::regs().dr().read() }; | 96 | return T::regs().dr().read(); |
| 103 | } | 97 | } |
| 104 | } | 98 | } |
| 105 | } | 99 | } |
| @@ -149,6 +143,7 @@ foreach_peripheral!( | |||
| 149 | }; | 143 | }; |
| 150 | ); | 144 | ); |
| 151 | 145 | ||
| 146 | #[cfg(feature = "rt")] | ||
| 152 | macro_rules! irq { | 147 | macro_rules! irq { |
| 153 | ($irq:ident) => { | 148 | ($irq:ident) => { |
| 154 | mod rng_irq { | 149 | mod rng_irq { |
| @@ -166,6 +161,7 @@ macro_rules! irq { | |||
| 166 | }; | 161 | }; |
| 167 | } | 162 | } |
| 168 | 163 | ||
| 164 | #[cfg(feature = "rt")] | ||
| 169 | foreach_interrupt!( | 165 | foreach_interrupt!( |
| 170 | (RNG) => { | 166 | (RNG) => { |
| 171 | irq!(RNG); | 167 | irq!(RNG); |
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index 0a590c1bb..a9c48d88d 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs | |||
| @@ -154,29 +154,27 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) { | |||
| 154 | let yr_offset = (yr - 1970_u16) as u8; | 154 | let yr_offset = (yr - 1970_u16) as u8; |
| 155 | let (yt, yu) = byte_to_bcd2(yr_offset); | 155 | let (yt, yu) = byte_to_bcd2(yr_offset); |
| 156 | 156 | ||
| 157 | unsafe { | 157 | use crate::pac::rtc::vals::Ampm; |
| 158 | use crate::pac::rtc::vals::Ampm; | 158 | |
| 159 | 159 | rtc.tr().write(|w| { | |
| 160 | rtc.tr().write(|w| { | 160 | w.set_ht(ht); |
| 161 | w.set_ht(ht); | 161 | w.set_hu(hu); |
| 162 | w.set_hu(hu); | 162 | w.set_mnt(mnt); |
| 163 | w.set_mnt(mnt); | 163 | w.set_mnu(mnu); |
| 164 | w.set_mnu(mnu); | 164 | w.set_st(st); |
| 165 | w.set_st(st); | 165 | w.set_su(su); |
| 166 | w.set_su(su); | 166 | w.set_pm(Ampm::AM); |
| 167 | w.set_pm(Ampm::AM); | 167 | }); |
| 168 | }); | 168 | |
| 169 | 169 | rtc.dr().write(|w| { | |
| 170 | rtc.dr().write(|w| { | 170 | w.set_dt(dt); |
| 171 | w.set_dt(dt); | 171 | w.set_du(du); |
| 172 | w.set_du(du); | 172 | w.set_mt(mt > 0); |
| 173 | w.set_mt(mt > 0); | 173 | w.set_mu(mu); |
| 174 | w.set_mu(mu); | 174 | w.set_yt(yt); |
| 175 | w.set_yt(yt); | 175 | w.set_yu(yu); |
| 176 | w.set_yu(yu); | 176 | w.set_wdu(day_of_week_to_u8(t.day_of_week)); |
| 177 | w.set_wdu(day_of_week_to_u8(t.day_of_week)); | 177 | }); |
| 178 | }); | ||
| 179 | } | ||
| 180 | } | 178 | } |
| 181 | 179 | ||
| 182 | pub(super) fn datetime( | 180 | pub(super) fn datetime( |
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 962927fb1..12a2ac795 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -113,7 +113,7 @@ impl Default for RtcCalibrationCyclePeriod { | |||
| 113 | 113 | ||
| 114 | impl<'d, T: Instance> Rtc<'d, T> { | 114 | impl<'d, T: Instance> Rtc<'d, T> { |
| 115 | pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self { | 115 | pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self { |
| 116 | unsafe { T::enable_peripheral_clk() }; | 116 | T::enable_peripheral_clk(); |
| 117 | 117 | ||
| 118 | let mut rtc_struct = Self { | 118 | let mut rtc_struct = Self { |
| 119 | phantom: PhantomData, | 119 | phantom: PhantomData, |
| @@ -144,34 +144,32 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 144 | /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. | 144 | /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. |
| 145 | pub fn now(&self) -> Result<DateTime, RtcError> { | 145 | pub fn now(&self) -> Result<DateTime, RtcError> { |
| 146 | let r = T::regs(); | 146 | let r = T::regs(); |
| 147 | unsafe { | 147 | let tr = r.tr().read(); |
| 148 | let tr = r.tr().read(); | 148 | let second = bcd2_to_byte((tr.st(), tr.su())); |
| 149 | let second = bcd2_to_byte((tr.st(), tr.su())); | 149 | let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); |
| 150 | let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); | 150 | let hour = bcd2_to_byte((tr.ht(), tr.hu())); |
| 151 | let hour = bcd2_to_byte((tr.ht(), tr.hu())); | 151 | // Reading either RTC_SSR or RTC_TR locks the values in the higher-order |
| 152 | // Reading either RTC_SSR or RTC_TR locks the values in the higher-order | 152 | // calendar shadow registers until RTC_DR is read. |
| 153 | // calendar shadow registers until RTC_DR is read. | 153 | let dr = r.dr().read(); |
| 154 | let dr = r.dr().read(); | 154 | |
| 155 | 155 | let weekday = dr.wdu(); | |
| 156 | let weekday = dr.wdu(); | 156 | let day = bcd2_to_byte((dr.dt(), dr.du())); |
| 157 | let day = bcd2_to_byte((dr.dt(), dr.du())); | 157 | let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); |
| 158 | let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); | 158 | let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; |
| 159 | let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; | 159 | |
| 160 | 160 | self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) | |
| 161 | self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) | ||
| 162 | } | ||
| 163 | } | 161 | } |
| 164 | 162 | ||
| 165 | /// Check if daylight savings time is active. | 163 | /// Check if daylight savings time is active. |
| 166 | pub fn get_daylight_savings(&self) -> bool { | 164 | pub fn get_daylight_savings(&self) -> bool { |
| 167 | let cr = unsafe { T::regs().cr().read() }; | 165 | let cr = T::regs().cr().read(); |
| 168 | cr.bkp() | 166 | cr.bkp() |
| 169 | } | 167 | } |
| 170 | 168 | ||
| 171 | /// Enable/disable daylight savings time. | 169 | /// Enable/disable daylight savings time. |
| 172 | pub fn set_daylight_savings(&mut self, daylight_savings: bool) { | 170 | pub fn set_daylight_savings(&mut self, daylight_savings: bool) { |
| 173 | self.write(true, |rtc| { | 171 | self.write(true, |rtc| { |
| 174 | unsafe { rtc.cr().modify(|w| w.set_bkp(daylight_savings)) }; | 172 | rtc.cr().modify(|w| w.set_bkp(daylight_savings)); |
| 175 | }) | 173 | }) |
| 176 | } | 174 | } |
| 177 | 175 | ||
| @@ -228,7 +226,7 @@ pub(crate) mod sealed { | |||
| 228 | crate::pac::RTC | 226 | crate::pac::RTC |
| 229 | } | 227 | } |
| 230 | 228 | ||
| 231 | unsafe fn enable_peripheral_clk() {} | 229 | fn enable_peripheral_clk() {} |
| 232 | 230 | ||
| 233 | /// Read content of the backup register. | 231 | /// Read content of the backup register. |
| 234 | /// | 232 | /// |
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index adaafe67a..e1615b34c 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs | |||
| @@ -8,74 +8,72 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | |||
| 8 | /// It this changes the RTC clock source the time will be reset | 8 | /// It this changes the RTC clock source the time will be reset |
| 9 | pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { | 9 | pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { |
| 10 | // Unlock the backup domain | 10 | // Unlock the backup domain |
| 11 | unsafe { | 11 | let clock_config = rtc_config.clock_config as u8; |
| 12 | let clock_config = rtc_config.clock_config as u8; | ||
| 13 | 12 | ||
| 14 | #[cfg(not(rtc_v2wb))] | 13 | #[cfg(not(rtc_v2wb))] |
| 15 | use stm32_metapac::rcc::vals::Rtcsel; | 14 | use stm32_metapac::rcc::vals::Rtcsel; |
| 16 | 15 | ||
| 17 | #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] | 16 | #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] |
| 18 | let cr = crate::pac::PWR.cr(); | 17 | let cr = crate::pac::PWR.cr(); |
| 19 | #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] | 18 | #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] |
| 20 | let cr = crate::pac::PWR.cr1(); | 19 | let cr = crate::pac::PWR.cr1(); |
| 21 | 20 | ||
| 22 | // TODO: Missing from PAC for l0 and f0? | 21 | // TODO: Missing from PAC for l0 and f0? |
| 23 | #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] | 22 | #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] |
| 24 | { | 23 | { |
| 25 | cr.modify(|w| w.set_dbp(true)); | 24 | cr.modify(|w| w.set_dbp(true)); |
| 26 | while !cr.read().dbp() {} | 25 | while !cr.read().dbp() {} |
| 27 | } | 26 | } |
| 28 | 27 | ||
| 29 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | 28 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] |
| 30 | let reg = crate::pac::RCC.bdcr().read(); | 29 | let reg = crate::pac::RCC.bdcr().read(); |
| 31 | #[cfg(any(rtc_v2l0, rtc_v2l1))] | 30 | #[cfg(any(rtc_v2l0, rtc_v2l1))] |
| 32 | let reg = crate::pac::RCC.csr().read(); | 31 | let reg = crate::pac::RCC.csr().read(); |
| 33 | 32 | ||
| 34 | #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] | 33 | #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] |
| 35 | assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | 34 | assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); |
| 36 | 35 | ||
| 37 | #[cfg(rtc_v2wb)] | 36 | #[cfg(rtc_v2wb)] |
| 38 | let rtcsel = reg.rtcsel(); | 37 | let rtcsel = reg.rtcsel(); |
| 39 | #[cfg(not(rtc_v2wb))] | 38 | #[cfg(not(rtc_v2wb))] |
| 40 | let rtcsel = reg.rtcsel().0; | 39 | let rtcsel = reg.rtcsel().0; |
| 41 | 40 | ||
| 42 | if !reg.rtcen() || rtcsel != clock_config { | 41 | if !reg.rtcen() || rtcsel != clock_config { |
| 43 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | 42 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] |
| 44 | crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); | 43 | crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); |
| 45 | 44 | ||
| 45 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | ||
| 46 | let cr = crate::pac::RCC.bdcr(); | ||
| 47 | #[cfg(any(rtc_v2l0, rtc_v2l1))] | ||
| 48 | let cr = crate::pac::RCC.csr(); | ||
| 49 | |||
| 50 | cr.modify(|w| { | ||
| 51 | // Reset | ||
| 46 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | 52 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] |
| 47 | let cr = crate::pac::RCC.bdcr(); | 53 | w.set_bdrst(false); |
| 48 | #[cfg(any(rtc_v2l0, rtc_v2l1))] | 54 | |
| 49 | let cr = crate::pac::RCC.csr(); | 55 | // Select RTC source |
| 50 | 56 | #[cfg(not(rtc_v2wb))] | |
| 51 | cr.modify(|w| { | 57 | w.set_rtcsel(Rtcsel(clock_config)); |
| 52 | // Reset | 58 | #[cfg(rtc_v2wb)] |
| 53 | #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] | 59 | w.set_rtcsel(clock_config); |
| 54 | w.set_bdrst(false); | 60 | w.set_rtcen(true); |
| 55 | 61 | ||
| 56 | // Select RTC source | 62 | // Restore bcdr |
| 57 | #[cfg(not(rtc_v2wb))] | 63 | #[cfg(any(rtc_v2l4, rtc_v2wb))] |
| 58 | w.set_rtcsel(Rtcsel(clock_config)); | 64 | w.set_lscosel(reg.lscosel()); |
| 59 | #[cfg(rtc_v2wb)] | 65 | #[cfg(any(rtc_v2l4, rtc_v2wb))] |
| 60 | w.set_rtcsel(clock_config); | 66 | w.set_lscoen(reg.lscoen()); |
| 61 | w.set_rtcen(true); | 67 | |
| 62 | 68 | w.set_lseon(reg.lseon()); | |
| 63 | // Restore bcdr | 69 | |
| 64 | #[cfg(any(rtc_v2l4, rtc_v2wb))] | 70 | #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] |
| 65 | w.set_lscosel(reg.lscosel()); | 71 | w.set_lsedrv(reg.lsedrv()); |
| 66 | #[cfg(any(rtc_v2l4, rtc_v2wb))] | 72 | w.set_lsebyp(reg.lsebyp()); |
| 67 | w.set_lscoen(reg.lscoen()); | 73 | }); |
| 68 | |||
| 69 | w.set_lseon(reg.lseon()); | ||
| 70 | |||
| 71 | #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] | ||
| 72 | w.set_lsedrv(reg.lsedrv()); | ||
| 73 | w.set_lsebyp(reg.lsebyp()); | ||
| 74 | }); | ||
| 75 | } | ||
| 76 | } | 74 | } |
| 77 | 75 | ||
| 78 | self.write(true, |rtc| unsafe { | 76 | self.write(true, |rtc| { |
| 79 | rtc.cr().modify(|w| { | 77 | rtc.cr().modify(|w| { |
| 80 | #[cfg(rtc_v2f2)] | 78 | #[cfg(rtc_v2f2)] |
| 81 | w.set_fmt(false); | 79 | w.set_fmt(false); |
| @@ -117,47 +115,45 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | |||
| 117 | clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM; | 115 | clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM; |
| 118 | 116 | ||
| 119 | self.write(false, |rtc| { | 117 | self.write(false, |rtc| { |
| 120 | unsafe { | 118 | rtc.calr().write(|w| { |
| 121 | rtc.calr().write(|w| { | 119 | match period { |
| 122 | match period { | 120 | super::RtcCalibrationCyclePeriod::Seconds8 => { |
| 123 | super::RtcCalibrationCyclePeriod::Seconds8 => { | 121 | w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND); |
| 124 | w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND); | ||
| 125 | } | ||
| 126 | super::RtcCalibrationCyclePeriod::Seconds16 => { | ||
| 127 | w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND); | ||
| 128 | } | ||
| 129 | super::RtcCalibrationCyclePeriod::Seconds32 => { | ||
| 130 | // Set neither `calw8` nor `calw16` to use 32 seconds | ||
| 131 | } | ||
| 132 | } | 122 | } |
| 133 | 123 | super::RtcCalibrationCyclePeriod::Seconds16 => { | |
| 134 | // Extra pulses during calibration cycle period: CALP * 512 - CALM | 124 | w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND); |
| 135 | // | 125 | } |
| 136 | // CALP sets whether pulses are added or omitted. | 126 | super::RtcCalibrationCyclePeriod::Seconds32 => { |
| 137 | // | 127 | // Set neither `calw8` nor `calw16` to use 32 seconds |
| 138 | // CALM contains how many pulses (out of 512) are masked in a | ||
| 139 | // given calibration cycle period. | ||
| 140 | if clock_drift > 0.0 { | ||
| 141 | // Maximum (about 512.2) rounds to 512. | ||
| 142 | clock_drift += 0.5; | ||
| 143 | |||
| 144 | // When the offset is positive (0 to 512), the opposite of | ||
| 145 | // the offset (512 - offset) is masked, i.e. for the | ||
| 146 | // maximum offset (512), 0 pulses are masked. | ||
| 147 | w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ); | ||
| 148 | w.set_calm(512 - clock_drift as u16); | ||
| 149 | } else { | ||
| 150 | // Minimum (about -510.7) rounds to -511. | ||
| 151 | clock_drift -= 0.5; | ||
| 152 | |||
| 153 | // When the offset is negative or zero (-511 to 0), | ||
| 154 | // the absolute offset is masked, i.e. for the minimum | ||
| 155 | // offset (-511), 511 pulses are masked. | ||
| 156 | w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE); | ||
| 157 | w.set_calm((clock_drift * -1.0) as u16); | ||
| 158 | } | 128 | } |
| 159 | }); | 129 | } |
| 160 | } | 130 | |
| 131 | // Extra pulses during calibration cycle period: CALP * 512 - CALM | ||
| 132 | // | ||
| 133 | // CALP sets whether pulses are added or omitted. | ||
| 134 | // | ||
| 135 | // CALM contains how many pulses (out of 512) are masked in a | ||
| 136 | // given calibration cycle period. | ||
| 137 | if clock_drift > 0.0 { | ||
| 138 | // Maximum (about 512.2) rounds to 512. | ||
| 139 | clock_drift += 0.5; | ||
| 140 | |||
| 141 | // When the offset is positive (0 to 512), the opposite of | ||
| 142 | // the offset (512 - offset) is masked, i.e. for the | ||
| 143 | // maximum offset (512), 0 pulses are masked. | ||
| 144 | w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ); | ||
| 145 | w.set_calm(512 - clock_drift as u16); | ||
| 146 | } else { | ||
| 147 | // Minimum (about -510.7) rounds to -511. | ||
| 148 | clock_drift -= 0.5; | ||
| 149 | |||
| 150 | // When the offset is negative or zero (-511 to 0), | ||
| 151 | // the absolute offset is masked, i.e. for the minimum | ||
| 152 | // offset (-511), 511 pulses are masked. | ||
| 153 | w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE); | ||
| 154 | w.set_calm((clock_drift * -1.0) as u16); | ||
| 155 | } | ||
| 156 | }); | ||
| 161 | }) | 157 | }) |
| 162 | } | 158 | } |
| 163 | 159 | ||
| @@ -168,31 +164,27 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | |||
| 168 | let r = T::regs(); | 164 | let r = T::regs(); |
| 169 | // Disable write protection. | 165 | // Disable write protection. |
| 170 | // This is safe, as we're only writin the correct and expected values. | 166 | // This is safe, as we're only writin the correct and expected values. |
| 171 | unsafe { | 167 | r.wpr().write(|w| w.set_key(0xca)); |
| 172 | r.wpr().write(|w| w.set_key(0xca)); | 168 | r.wpr().write(|w| w.set_key(0x53)); |
| 173 | r.wpr().write(|w| w.set_key(0x53)); | 169 | |
| 174 | 170 | // true if initf bit indicates RTC peripheral is in init mode | |
| 175 | // true if initf bit indicates RTC peripheral is in init mode | 171 | if init_mode && !r.isr().read().initf() { |
| 176 | if init_mode && !r.isr().read().initf() { | 172 | // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode |
| 177 | // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode | 173 | r.isr().modify(|w| w.set_init(Init::INITMODE)); |
| 178 | r.isr().modify(|w| w.set_init(Init::INITMODE)); | 174 | // wait till init state entered |
| 179 | // wait till init state entered | 175 | // ~2 RTCCLK cycles |
| 180 | // ~2 RTCCLK cycles | 176 | while !r.isr().read().initf() {} |
| 181 | while !r.isr().read().initf() {} | ||
| 182 | } | ||
| 183 | } | 177 | } |
| 184 | 178 | ||
| 185 | let result = f(&r); | 179 | let result = f(&r); |
| 186 | 180 | ||
| 187 | unsafe { | 181 | if init_mode { |
| 188 | if init_mode { | 182 | r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode |
| 189 | r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode | ||
| 190 | } | ||
| 191 | |||
| 192 | // Re-enable write protection. | ||
| 193 | // This is safe, as the field accepts the full range of 8-bit values. | ||
| 194 | r.wpr().write(|w| w.set_key(0xff)); | ||
| 195 | } | 183 | } |
| 184 | |||
| 185 | // Re-enable write protection. | ||
| 186 | // This is safe, as the field accepts the full range of 8-bit values. | ||
| 187 | r.wpr().write(|w| w.set_key(0xff)); | ||
| 196 | result | 188 | result |
| 197 | } | 189 | } |
| 198 | } | 190 | } |
| @@ -200,7 +192,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | |||
| 200 | impl sealed::Instance for crate::peripherals::RTC { | 192 | impl sealed::Instance for crate::peripherals::RTC { |
| 201 | const BACKUP_REGISTER_COUNT: usize = 20; | 193 | const BACKUP_REGISTER_COUNT: usize = 20; |
| 202 | 194 | ||
| 203 | unsafe fn enable_peripheral_clk() { | 195 | fn enable_peripheral_clk() { |
| 204 | #[cfg(any(rtc_v2l4, rtc_v2wb))] | 196 | #[cfg(any(rtc_v2l4, rtc_v2wb))] |
| 205 | { | 197 | { |
| 206 | // enable peripheral clock for communication | 198 | // enable peripheral clock for communication |
| @@ -213,7 +205,7 @@ impl sealed::Instance for crate::peripherals::RTC { | |||
| 213 | 205 | ||
| 214 | fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> { | 206 | fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> { |
| 215 | if register < Self::BACKUP_REGISTER_COUNT { | 207 | if register < Self::BACKUP_REGISTER_COUNT { |
| 216 | Some(unsafe { rtc.bkpr(register).read().bkp() }) | 208 | Some(rtc.bkpr(register).read().bkp()) |
| 217 | } else { | 209 | } else { |
| 218 | None | 210 | None |
| 219 | } | 211 | } |
| @@ -221,7 +213,7 @@ impl sealed::Instance for crate::peripherals::RTC { | |||
| 221 | 213 | ||
| 222 | fn write_backup_register(rtc: &Rtc, register: usize, value: u32) { | 214 | fn write_backup_register(rtc: &Rtc, register: usize, value: u32) { |
| 223 | if register < Self::BACKUP_REGISTER_COUNT { | 215 | if register < Self::BACKUP_REGISTER_COUNT { |
| 224 | unsafe { rtc.bkpr(register).write(|w| w.set_bkp(value)) } | 216 | rtc.bkpr(register).write(|w| w.set_bkp(value)); |
| 225 | } | 217 | } |
| 226 | } | 218 | } |
| 227 | } | 219 | } |
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 546fe88c7..7c91046a2 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs | |||
| @@ -8,75 +8,66 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | |||
| 8 | /// It this changes the RTC clock source the time will be reset | 8 | /// It this changes the RTC clock source the time will be reset |
| 9 | pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { | 9 | pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) { |
| 10 | // Unlock the backup domain | 10 | // Unlock the backup domain |
| 11 | unsafe { | 11 | #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] |
| 12 | #[cfg(any(rtc_v3u5, rcc_g0, rcc_g4))] | 12 | { |
| 13 | use crate::pac::rcc::vals::Rtcsel; | 13 | crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); |
| 14 | #[cfg(not(any(rtc_v3u5, rcc_g0, rcc_g4, rcc_wl5, rcc_wle)))] | 14 | while !crate::pac::PWR.cr1().read().dbp() {} |
| 15 | use crate::pac::rtc::vals::Rtcsel; | 15 | } |
| 16 | 16 | #[cfg(any(rcc_wl5, rcc_wle))] | |
| 17 | #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] | 17 | { |
| 18 | { | 18 | use crate::pac::pwr::vals::Dbp; |
| 19 | crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); | 19 | |
| 20 | while !crate::pac::PWR.cr1().read().dbp() {} | 20 | crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); |
| 21 | } | 21 | while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} |
| 22 | #[cfg(any(rcc_wl5, rcc_wle))] | 22 | } |
| 23 | { | 23 | |
| 24 | use crate::pac::pwr::vals::Dbp; | 24 | let reg = crate::pac::RCC.bdcr().read(); |
| 25 | 25 | assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | |
| 26 | crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); | 26 | |
| 27 | while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} | 27 | let config_rtcsel = rtc_config.clock_config as u8; |
| 28 | } | 28 | #[cfg(not(any(rcc_wl5, rcc_wle)))] |
| 29 | 29 | let config_rtcsel = crate::pac::rcc::vals::Rtcsel(config_rtcsel); | |
| 30 | let reg = crate::pac::RCC.bdcr().read(); | 30 | |
| 31 | assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); | 31 | if !reg.rtcen() || reg.rtcsel() != config_rtcsel { |
| 32 | 32 | crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); | |
| 33 | let config_rtcsel = rtc_config.clock_config as u8; | 33 | |
| 34 | #[cfg(not(any(rcc_wl5, rcc_wle)))] | 34 | crate::pac::RCC.bdcr().modify(|w| { |
| 35 | let config_rtcsel = Rtcsel(config_rtcsel); | 35 | // Reset |
| 36 | 36 | w.set_bdrst(false); | |
| 37 | if !reg.rtcen() || reg.rtcsel() != config_rtcsel { | 37 | |
| 38 | crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); | 38 | // Select RTC source |
| 39 | 39 | w.set_rtcsel(config_rtcsel); | |
| 40 | crate::pac::RCC.bdcr().modify(|w| { | 40 | |
| 41 | // Reset | 41 | w.set_rtcen(true); |
| 42 | w.set_bdrst(false); | 42 | |
| 43 | 43 | // Restore bcdr | |
| 44 | // Select RTC source | 44 | w.set_lscosel(reg.lscosel()); |
| 45 | w.set_rtcsel(config_rtcsel); | 45 | w.set_lscoen(reg.lscoen()); |
| 46 | 46 | ||
| 47 | w.set_rtcen(true); | 47 | w.set_lseon(reg.lseon()); |
| 48 | 48 | w.set_lsedrv(reg.lsedrv()); | |
| 49 | // Restore bcdr | 49 | w.set_lsebyp(reg.lsebyp()); |
| 50 | w.set_lscosel(reg.lscosel()); | 50 | }); |
| 51 | w.set_lscoen(reg.lscoen()); | ||
| 52 | |||
| 53 | w.set_lseon(reg.lseon()); | ||
| 54 | w.set_lsedrv(reg.lsedrv()); | ||
| 55 | w.set_lsebyp(reg.lsebyp()); | ||
| 56 | }); | ||
| 57 | } | ||
| 58 | } | 51 | } |
| 59 | 52 | ||
| 60 | self.write(true, |rtc| { | 53 | self.write(true, |rtc| { |
| 61 | unsafe { | 54 | rtc.cr().modify(|w| { |
| 62 | rtc.cr().modify(|w| { | 55 | w.set_fmt(Fmt::TWENTYFOURHOUR); |
| 63 | w.set_fmt(Fmt::TWENTYFOURHOUR); | 56 | w.set_osel(Osel::DISABLED); |
| 64 | w.set_osel(Osel::DISABLED); | 57 | w.set_pol(Pol::HIGH); |
| 65 | w.set_pol(Pol::HIGH); | 58 | }); |
| 66 | }); | 59 | |
| 67 | 60 | rtc.prer().modify(|w| { | |
| 68 | rtc.prer().modify(|w| { | 61 | w.set_prediv_s(rtc_config.sync_prescaler); |
| 69 | w.set_prediv_s(rtc_config.sync_prescaler); | 62 | w.set_prediv_a(rtc_config.async_prescaler); |
| 70 | w.set_prediv_a(rtc_config.async_prescaler); | 63 | }); |
| 71 | }); | 64 | |
| 72 | 65 | // TODO: configuration for output pins | |
| 73 | // TODO: configuration for output pins | 66 | rtc.cr().modify(|w| { |
| 74 | rtc.cr().modify(|w| { | 67 | w.set_out2en(false); |
| 75 | w.set_out2en(false); | 68 | w.set_tampalrm_type(TampalrmType::PUSHPULL); |
| 76 | w.set_tampalrm_type(TampalrmType::PUSHPULL); | 69 | w.set_tampalrm_pu(TampalrmPu::NOPULLUP); |
| 77 | w.set_tampalrm_pu(TampalrmPu::NOPULLUP); | 70 | }); |
| 78 | }); | ||
| 79 | } | ||
| 80 | }); | 71 | }); |
| 81 | 72 | ||
| 82 | self.rtc_config = rtc_config; | 73 | self.rtc_config = rtc_config; |
| @@ -104,47 +95,45 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | |||
| 104 | clock_drift = clock_drift / Self::RTC_CALR_RESOLUTION_PPM; | 95 | clock_drift = clock_drift / Self::RTC_CALR_RESOLUTION_PPM; |
| 105 | 96 | ||
| 106 | self.write(false, |rtc| { | 97 | self.write(false, |rtc| { |
| 107 | unsafe { | 98 | rtc.calr().write(|w| { |
| 108 | rtc.calr().write(|w| { | 99 | match period { |
| 109 | match period { | 100 | RtcCalibrationCyclePeriod::Seconds8 => { |
| 110 | RtcCalibrationCyclePeriod::Seconds8 => { | 101 | w.set_calw8(Calw8::EIGHTSECONDS); |
| 111 | w.set_calw8(Calw8::EIGHTSECONDS); | ||
| 112 | } | ||
| 113 | RtcCalibrationCyclePeriod::Seconds16 => { | ||
| 114 | w.set_calw16(Calw16::SIXTEENSECONDS); | ||
| 115 | } | ||
| 116 | RtcCalibrationCyclePeriod::Seconds32 => { | ||
| 117 | // Set neither `calw8` nor `calw16` to use 32 seconds | ||
| 118 | } | ||
| 119 | } | 102 | } |
| 120 | 103 | RtcCalibrationCyclePeriod::Seconds16 => { | |
| 121 | // Extra pulses during calibration cycle period: CALP * 512 - CALM | 104 | w.set_calw16(Calw16::SIXTEENSECONDS); |
| 122 | // | ||
| 123 | // CALP sets whether pulses are added or omitted. | ||
| 124 | // | ||
| 125 | // CALM contains how many pulses (out of 512) are masked in a | ||
| 126 | // given calibration cycle period. | ||
| 127 | if clock_drift > 0.0 { | ||
| 128 | // Maximum (about 512.2) rounds to 512. | ||
| 129 | clock_drift += 0.5; | ||
| 130 | |||
| 131 | // When the offset is positive (0 to 512), the opposite of | ||
| 132 | // the offset (512 - offset) is masked, i.e. for the | ||
| 133 | // maximum offset (512), 0 pulses are masked. | ||
| 134 | w.set_calp(Calp::INCREASEFREQ); | ||
| 135 | w.set_calm(512 - clock_drift as u16); | ||
| 136 | } else { | ||
| 137 | // Minimum (about -510.7) rounds to -511. | ||
| 138 | clock_drift -= 0.5; | ||
| 139 | |||
| 140 | // When the offset is negative or zero (-511 to 0), | ||
| 141 | // the absolute offset is masked, i.e. for the minimum | ||
| 142 | // offset (-511), 511 pulses are masked. | ||
| 143 | w.set_calp(Calp::NOCHANGE); | ||
| 144 | w.set_calm((clock_drift * -1.0) as u16); | ||
| 145 | } | 105 | } |
| 146 | }); | 106 | RtcCalibrationCyclePeriod::Seconds32 => { |
| 147 | } | 107 | // Set neither `calw8` nor `calw16` to use 32 seconds |
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | // Extra pulses during calibration cycle period: CALP * 512 - CALM | ||
| 112 | // | ||
| 113 | // CALP sets whether pulses are added or omitted. | ||
| 114 | // | ||
| 115 | // CALM contains how many pulses (out of 512) are masked in a | ||
| 116 | // given calibration cycle period. | ||
| 117 | if clock_drift > 0.0 { | ||
| 118 | // Maximum (about 512.2) rounds to 512. | ||
| 119 | clock_drift += 0.5; | ||
| 120 | |||
| 121 | // When the offset is positive (0 to 512), the opposite of | ||
| 122 | // the offset (512 - offset) is masked, i.e. for the | ||
| 123 | // maximum offset (512), 0 pulses are masked. | ||
| 124 | w.set_calp(Calp::INCREASEFREQ); | ||
| 125 | w.set_calm(512 - clock_drift as u16); | ||
| 126 | } else { | ||
| 127 | // Minimum (about -510.7) rounds to -511. | ||
| 128 | clock_drift -= 0.5; | ||
| 129 | |||
| 130 | // When the offset is negative or zero (-511 to 0), | ||
| 131 | // the absolute offset is masked, i.e. for the minimum | ||
| 132 | // offset (-511), 511 pulses are masked. | ||
| 133 | w.set_calp(Calp::NOCHANGE); | ||
| 134 | w.set_calm((clock_drift * -1.0) as u16); | ||
| 135 | } | ||
| 136 | }); | ||
| 148 | }) | 137 | }) |
| 149 | } | 138 | } |
| 150 | 139 | ||
| @@ -155,29 +144,26 @@ impl<'d, T: Instance> super::Rtc<'d, T> { | |||
| 155 | let r = T::regs(); | 144 | let r = T::regs(); |
| 156 | // Disable write protection. | 145 | // Disable write protection. |
| 157 | // This is safe, as we're only writin the correct and expected values. | 146 | // This is safe, as we're only writin the correct and expected values. |
| 158 | unsafe { | 147 | r.wpr().write(|w| w.set_key(Key::DEACTIVATE1)); |
| 159 | r.wpr().write(|w| w.set_key(Key::DEACTIVATE1)); | 148 | r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); |
| 160 | r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); | 149 | |
| 161 | 150 | if init_mode && !r.icsr().read().initf() { | |
| 162 | if init_mode && !r.icsr().read().initf() { | 151 | r.icsr().modify(|w| w.set_init(Init::INITMODE)); |
| 163 | r.icsr().modify(|w| w.set_init(Init::INITMODE)); | 152 | // wait till init state entered |
| 164 | // wait till init state entered | 153 | // ~2 RTCCLK cycles |
| 165 | // ~2 RTCCLK cycles | 154 | while !r.icsr().read().initf() {} |
| 166 | while !r.icsr().read().initf() {} | ||
| 167 | } | ||
| 168 | } | 155 | } |
| 169 | 156 | ||
| 170 | let result = f(&r); | 157 | let result = f(&r); |
| 171 | 158 | ||
| 172 | unsafe { | 159 | if init_mode { |
| 173 | if init_mode { | 160 | r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode |
| 174 | r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode | ||
| 175 | } | ||
| 176 | |||
| 177 | // Re-enable write protection. | ||
| 178 | // This is safe, as the field accepts the full range of 8-bit values. | ||
| 179 | r.wpr().write(|w| w.set_key(Key::ACTIVATE)); | ||
| 180 | } | 161 | } |
| 162 | |||
| 163 | // Re-enable write protection. | ||
| 164 | // This is safe, as the field accepts the full range of 8-bit values. | ||
| 165 | r.wpr().write(|w| w.set_key(Key::ACTIVATE)); | ||
| 166 | |||
| 181 | result | 167 | result |
| 182 | } | 168 | } |
| 183 | } | 169 | } |
| @@ -197,7 +183,7 @@ impl sealed::Instance for crate::peripherals::RTC { | |||
| 197 | fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) { | 183 | fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) { |
| 198 | if register < Self::BACKUP_REGISTER_COUNT { | 184 | if register < Self::BACKUP_REGISTER_COUNT { |
| 199 | // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC | 185 | // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC |
| 200 | //unsafe { self.rtc.bkpr()[register].write(|w| w.bits(value)) } | 186 | //self.rtc.bkpr()[register].write(|w| w.bits(value)) |
| 201 | } | 187 | } |
| 202 | } | 188 | } |
| 203 | } | 189 | } |
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index be03a1bac..80a336a48 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -14,7 +14,7 @@ use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, | |||
| 14 | use crate::dma::NoDma; | 14 | use crate::dma::NoDma; |
| 15 | use crate::gpio::sealed::{AFType, Pin}; | 15 | use crate::gpio::sealed::{AFType, Pin}; |
| 16 | use crate::gpio::{AnyPin, Pull, Speed}; | 16 | use crate::gpio::{AnyPin, Pull, Speed}; |
| 17 | use crate::interrupt::{Interrupt, InterruptExt}; | 17 | use crate::interrupt::typelevel::Interrupt; |
| 18 | use crate::pac::sdmmc::Sdmmc as RegBlock; | 18 | use crate::pac::sdmmc::Sdmmc as RegBlock; |
| 19 | use crate::rcc::RccPeripheral; | 19 | use crate::rcc::RccPeripheral; |
| 20 | use crate::time::Hertz; | 20 | use crate::time::Hertz; |
| @@ -28,21 +28,18 @@ pub struct InterruptHandler<T: Instance> { | |||
| 28 | impl<T: Instance> InterruptHandler<T> { | 28 | impl<T: Instance> InterruptHandler<T> { |
| 29 | fn data_interrupts(enable: bool) { | 29 | fn data_interrupts(enable: bool) { |
| 30 | let regs = T::regs(); | 30 | let regs = T::regs(); |
| 31 | // NOTE(unsafe) Atomic write | 31 | regs.maskr().write(|w| { |
| 32 | unsafe { | 32 | w.set_dcrcfailie(enable); |
| 33 | regs.maskr().write(|w| { | 33 | w.set_dtimeoutie(enable); |
| 34 | w.set_dcrcfailie(enable); | 34 | w.set_dataendie(enable); |
| 35 | w.set_dtimeoutie(enable); | ||
| 36 | w.set_dataendie(enable); | ||
| 37 | 35 | ||
| 38 | #[cfg(sdmmc_v2)] | 36 | #[cfg(sdmmc_v2)] |
| 39 | w.set_dabortie(enable); | 37 | w.set_dabortie(enable); |
| 40 | }); | 38 | }); |
| 41 | } | ||
| 42 | } | 39 | } |
| 43 | } | 40 | } |
| 44 | 41 | ||
| 45 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 42 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 46 | unsafe fn on_interrupt() { | 43 | unsafe fn on_interrupt() { |
| 47 | Self::data_interrupts(false); | 44 | Self::data_interrupts(false); |
| 48 | T::state().wake(); | 45 | T::state().wake(); |
| @@ -276,7 +273,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> { | |||
| 276 | impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | 273 | impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { |
| 277 | pub fn new_1bit( | 274 | pub fn new_1bit( |
| 278 | sdmmc: impl Peripheral<P = T> + 'd, | 275 | sdmmc: impl Peripheral<P = T> + 'd, |
| 279 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 276 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 280 | dma: impl Peripheral<P = Dma> + 'd, | 277 | dma: impl Peripheral<P = Dma> + 'd, |
| 281 | clk: impl Peripheral<P = impl CkPin<T>> + 'd, | 278 | clk: impl Peripheral<P = impl CkPin<T>> + 'd, |
| 282 | cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, | 279 | cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, |
| @@ -285,7 +282,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | |||
| 285 | ) -> Self { | 282 | ) -> Self { |
| 286 | into_ref!(clk, cmd, d0); | 283 | into_ref!(clk, cmd, d0); |
| 287 | 284 | ||
| 288 | critical_section::with(|_| unsafe { | 285 | critical_section::with(|_| { |
| 289 | clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); | 286 | clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); |
| 290 | cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); | 287 | cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); |
| 291 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); | 288 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); |
| @@ -310,7 +307,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | |||
| 310 | 307 | ||
| 311 | pub fn new_4bit( | 308 | pub fn new_4bit( |
| 312 | sdmmc: impl Peripheral<P = T> + 'd, | 309 | sdmmc: impl Peripheral<P = T> + 'd, |
| 313 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 310 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 314 | dma: impl Peripheral<P = Dma> + 'd, | 311 | dma: impl Peripheral<P = Dma> + 'd, |
| 315 | clk: impl Peripheral<P = impl CkPin<T>> + 'd, | 312 | clk: impl Peripheral<P = impl CkPin<T>> + 'd, |
| 316 | cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, | 313 | cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, |
| @@ -322,7 +319,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | |||
| 322 | ) -> Self { | 319 | ) -> Self { |
| 323 | into_ref!(clk, cmd, d0, d1, d2, d3); | 320 | into_ref!(clk, cmd, d0, d1, d2, d3); |
| 324 | 321 | ||
| 325 | critical_section::with(|_| unsafe { | 322 | critical_section::with(|_| { |
| 326 | clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); | 323 | clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); |
| 327 | cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); | 324 | cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); |
| 328 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); | 325 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); |
| @@ -356,7 +353,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | |||
| 356 | impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | 353 | impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { |
| 357 | pub fn new_1bit( | 354 | pub fn new_1bit( |
| 358 | sdmmc: impl Peripheral<P = T> + 'd, | 355 | sdmmc: impl Peripheral<P = T> + 'd, |
| 359 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 356 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 360 | clk: impl Peripheral<P = impl CkPin<T>> + 'd, | 357 | clk: impl Peripheral<P = impl CkPin<T>> + 'd, |
| 361 | cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, | 358 | cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, |
| 362 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 359 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| @@ -364,7 +361,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | |||
| 364 | ) -> Self { | 361 | ) -> Self { |
| 365 | into_ref!(clk, cmd, d0); | 362 | into_ref!(clk, cmd, d0); |
| 366 | 363 | ||
| 367 | critical_section::with(|_| unsafe { | 364 | critical_section::with(|_| { |
| 368 | clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); | 365 | clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); |
| 369 | cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); | 366 | cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); |
| 370 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); | 367 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); |
| @@ -389,7 +386,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | |||
| 389 | 386 | ||
| 390 | pub fn new_4bit( | 387 | pub fn new_4bit( |
| 391 | sdmmc: impl Peripheral<P = T> + 'd, | 388 | sdmmc: impl Peripheral<P = T> + 'd, |
| 392 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 389 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 393 | clk: impl Peripheral<P = impl CkPin<T>> + 'd, | 390 | clk: impl Peripheral<P = impl CkPin<T>> + 'd, |
| 394 | cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, | 391 | cmd: impl Peripheral<P = impl CmdPin<T>> + 'd, |
| 395 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 392 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| @@ -400,7 +397,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | |||
| 400 | ) -> Self { | 397 | ) -> Self { |
| 401 | into_ref!(clk, cmd, d0, d1, d2, d3); | 398 | into_ref!(clk, cmd, d0, d1, d2, d3); |
| 402 | 399 | ||
| 403 | critical_section::with(|_| unsafe { | 400 | critical_section::with(|_| { |
| 404 | clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); | 401 | clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None); |
| 405 | cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); | 402 | cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up); |
| 406 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); | 403 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up); |
| @@ -447,30 +444,28 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 447 | T::enable(); | 444 | T::enable(); |
| 448 | T::reset(); | 445 | T::reset(); |
| 449 | 446 | ||
| 450 | unsafe { T::Interrupt::steal() }.unpend(); | 447 | T::Interrupt::unpend(); |
| 451 | unsafe { T::Interrupt::steal() }.enable(); | 448 | unsafe { T::Interrupt::enable() }; |
| 452 | 449 | ||
| 453 | let regs = T::regs(); | 450 | let regs = T::regs(); |
| 454 | unsafe { | 451 | regs.clkcr().write(|w| { |
| 455 | regs.clkcr().write(|w| { | 452 | w.set_pwrsav(false); |
| 456 | w.set_pwrsav(false); | 453 | w.set_negedge(false); |
| 457 | w.set_negedge(false); | ||
| 458 | |||
| 459 | // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors. | ||
| 460 | // See chip erratas for more details. | ||
| 461 | #[cfg(sdmmc_v1)] | ||
| 462 | w.set_hwfc_en(false); | ||
| 463 | #[cfg(sdmmc_v2)] | ||
| 464 | w.set_hwfc_en(true); | ||
| 465 | 454 | ||
| 466 | #[cfg(sdmmc_v1)] | 455 | // Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors. |
| 467 | w.set_clken(true); | 456 | // See chip erratas for more details. |
| 468 | }); | 457 | #[cfg(sdmmc_v1)] |
| 458 | w.set_hwfc_en(false); | ||
| 459 | #[cfg(sdmmc_v2)] | ||
| 460 | w.set_hwfc_en(true); | ||
| 469 | 461 | ||
| 470 | // Power off, writen 00: Clock to the card is stopped; | 462 | #[cfg(sdmmc_v1)] |
| 471 | // D[7:0], CMD, and CK are driven high. | 463 | w.set_clken(true); |
| 472 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); | 464 | }); |
| 473 | } | 465 | |
| 466 | // Power off, writen 00: Clock to the card is stopped; | ||
| 467 | // D[7:0], CMD, and CK are driven high. | ||
| 468 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); | ||
| 474 | 469 | ||
| 475 | Self { | 470 | Self { |
| 476 | _peri: sdmmc, | 471 | _peri: sdmmc, |
| @@ -495,14 +490,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 495 | fn data_active() -> bool { | 490 | fn data_active() -> bool { |
| 496 | let regs = T::regs(); | 491 | let regs = T::regs(); |
| 497 | 492 | ||
| 498 | // NOTE(unsafe) Atomic read with no side-effects | 493 | let status = regs.star().read(); |
| 499 | unsafe { | 494 | #[cfg(sdmmc_v1)] |
| 500 | let status = regs.star().read(); | 495 | return status.rxact() || status.txact(); |
| 501 | #[cfg(sdmmc_v1)] | 496 | #[cfg(sdmmc_v2)] |
| 502 | return status.rxact() || status.txact(); | 497 | return status.dpsmact(); |
| 503 | #[cfg(sdmmc_v2)] | ||
| 504 | return status.dpsmact(); | ||
| 505 | } | ||
| 506 | } | 498 | } |
| 507 | 499 | ||
| 508 | /// Coammand transfer is in progress | 500 | /// Coammand transfer is in progress |
| @@ -510,14 +502,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 510 | fn cmd_active() -> bool { | 502 | fn cmd_active() -> bool { |
| 511 | let regs = T::regs(); | 503 | let regs = T::regs(); |
| 512 | 504 | ||
| 513 | // NOTE(unsafe) Atomic read with no side-effects | 505 | let status = regs.star().read(); |
| 514 | unsafe { | 506 | #[cfg(sdmmc_v1)] |
| 515 | let status = regs.star().read(); | 507 | return status.cmdact(); |
| 516 | #[cfg(sdmmc_v1)] | 508 | #[cfg(sdmmc_v2)] |
| 517 | return status.cmdact(); | 509 | return status.cpsmact(); |
| 518 | #[cfg(sdmmc_v2)] | ||
| 519 | return status.cpsmact(); | ||
| 520 | } | ||
| 521 | } | 510 | } |
| 522 | 511 | ||
| 523 | /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) | 512 | /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) |
| @@ -542,44 +531,41 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 542 | Self::wait_idle(); | 531 | Self::wait_idle(); |
| 543 | Self::clear_interrupt_flags(); | 532 | Self::clear_interrupt_flags(); |
| 544 | 533 | ||
| 545 | // NOTE(unsafe) We have exclusive access to the regisers | 534 | regs.dtimer() |
| 546 | unsafe { | 535 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); |
| 547 | regs.dtimer() | 536 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); |
| 548 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 549 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | ||
| 550 | 537 | ||
| 551 | #[cfg(sdmmc_v1)] | 538 | #[cfg(sdmmc_v1)] |
| 552 | let transfer = { | 539 | let transfer = unsafe { |
| 553 | let request = self.dma.request(); | 540 | let request = self.dma.request(); |
| 554 | Transfer::new_read( | 541 | Transfer::new_read( |
| 555 | &mut self.dma, | 542 | &mut self.dma, |
| 556 | request, | 543 | request, |
| 557 | regs.fifor().ptr() as *mut u32, | 544 | regs.fifor().as_ptr() as *mut u32, |
| 558 | buffer, | 545 | buffer, |
| 559 | DMA_TRANSFER_OPTIONS, | 546 | DMA_TRANSFER_OPTIONS, |
| 560 | ) | 547 | ) |
| 561 | }; | 548 | }; |
| 562 | #[cfg(sdmmc_v2)] | 549 | #[cfg(sdmmc_v2)] |
| 563 | let transfer = { | 550 | let transfer = { |
| 564 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); | 551 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); |
| 565 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); | 552 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); |
| 566 | Transfer { | 553 | Transfer { |
| 567 | _dummy: core::marker::PhantomData, | 554 | _dummy: core::marker::PhantomData, |
| 568 | } | 555 | } |
| 569 | }; | 556 | }; |
| 570 | 557 | ||
| 571 | regs.dctrl().modify(|w| { | 558 | regs.dctrl().modify(|w| { |
| 572 | w.set_dblocksize(block_size); | 559 | w.set_dblocksize(block_size); |
| 573 | w.set_dtdir(true); | 560 | w.set_dtdir(true); |
| 574 | #[cfg(sdmmc_v1)] | 561 | #[cfg(sdmmc_v1)] |
| 575 | { | 562 | { |
| 576 | w.set_dmaen(true); | 563 | w.set_dmaen(true); |
| 577 | w.set_dten(true); | 564 | w.set_dten(true); |
| 578 | } | 565 | } |
| 579 | }); | 566 | }); |
| 580 | 567 | ||
| 581 | transfer | 568 | transfer |
| 582 | } | ||
| 583 | } | 569 | } |
| 584 | 570 | ||
| 585 | /// # Safety | 571 | /// # Safety |
| @@ -598,59 +584,54 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 598 | Self::wait_idle(); | 584 | Self::wait_idle(); |
| 599 | Self::clear_interrupt_flags(); | 585 | Self::clear_interrupt_flags(); |
| 600 | 586 | ||
| 601 | // NOTE(unsafe) We have exclusive access to the regisers | 587 | regs.dtimer() |
| 602 | unsafe { | 588 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); |
| 603 | regs.dtimer() | 589 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); |
| 604 | .write(|w| w.set_datatime(self.config.data_transfer_timeout)); | ||
| 605 | regs.dlenr().write(|w| w.set_datalength(length_bytes)); | ||
| 606 | 590 | ||
| 607 | #[cfg(sdmmc_v1)] | 591 | #[cfg(sdmmc_v1)] |
| 608 | let transfer = { | 592 | let transfer = unsafe { |
| 609 | let request = self.dma.request(); | 593 | let request = self.dma.request(); |
| 610 | Transfer::new_write( | 594 | Transfer::new_write( |
| 611 | &mut self.dma, | 595 | &mut self.dma, |
| 612 | request, | 596 | request, |
| 613 | buffer, | 597 | buffer, |
| 614 | regs.fifor().ptr() as *mut u32, | 598 | regs.fifor().as_ptr() as *mut u32, |
| 615 | DMA_TRANSFER_OPTIONS, | 599 | DMA_TRANSFER_OPTIONS, |
| 616 | ) | 600 | ) |
| 617 | }; | 601 | }; |
| 618 | #[cfg(sdmmc_v2)] | 602 | #[cfg(sdmmc_v2)] |
| 619 | let transfer = { | 603 | let transfer = { |
| 620 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32)); | 604 | regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32)); |
| 621 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); | 605 | regs.idmactrlr().modify(|w| w.set_idmaen(true)); |
| 622 | Transfer { | 606 | Transfer { |
| 623 | _dummy: core::marker::PhantomData, | 607 | _dummy: core::marker::PhantomData, |
| 624 | } | 608 | } |
| 625 | }; | 609 | }; |
| 626 | 610 | ||
| 627 | regs.dctrl().modify(|w| { | 611 | regs.dctrl().modify(|w| { |
| 628 | w.set_dblocksize(block_size); | 612 | w.set_dblocksize(block_size); |
| 629 | w.set_dtdir(false); | 613 | w.set_dtdir(false); |
| 630 | #[cfg(sdmmc_v1)] | 614 | #[cfg(sdmmc_v1)] |
| 631 | { | 615 | { |
| 632 | w.set_dmaen(true); | 616 | w.set_dmaen(true); |
| 633 | w.set_dten(true); | 617 | w.set_dten(true); |
| 634 | } | 618 | } |
| 635 | }); | 619 | }); |
| 636 | 620 | ||
| 637 | transfer | 621 | transfer |
| 638 | } | ||
| 639 | } | 622 | } |
| 640 | 623 | ||
| 641 | /// Stops the DMA datapath | 624 | /// Stops the DMA datapath |
| 642 | fn stop_datapath() { | 625 | fn stop_datapath() { |
| 643 | let regs = T::regs(); | 626 | let regs = T::regs(); |
| 644 | 627 | ||
| 645 | unsafe { | 628 | #[cfg(sdmmc_v1)] |
| 646 | #[cfg(sdmmc_v1)] | 629 | regs.dctrl().modify(|w| { |
| 647 | regs.dctrl().modify(|w| { | 630 | w.set_dmaen(false); |
| 648 | w.set_dmaen(false); | 631 | w.set_dten(false); |
| 649 | w.set_dten(false); | 632 | }); |
| 650 | }); | 633 | #[cfg(sdmmc_v2)] |
| 651 | #[cfg(sdmmc_v2)] | 634 | regs.idmactrlr().modify(|w| w.set_idmaen(false)); |
| 652 | regs.idmactrlr().modify(|w| w.set_idmaen(false)); | ||
| 653 | } | ||
| 654 | } | 635 | } |
| 655 | 636 | ||
| 656 | /// Sets the CLKDIV field in CLKCR. Updates clock field in self | 637 | /// Sets the CLKDIV field in CLKCR. Updates clock field in self |
| @@ -673,16 +654,13 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 673 | assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); | 654 | assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); |
| 674 | self.clock = new_clock; | 655 | self.clock = new_clock; |
| 675 | 656 | ||
| 676 | // NOTE(unsafe) We have exclusive access to the regblock | 657 | // CPSMACT and DPSMACT must be 0 to set CLKDIV |
| 677 | unsafe { | 658 | Self::wait_idle(); |
| 678 | // CPSMACT and DPSMACT must be 0 to set CLKDIV | 659 | regs.clkcr().modify(|w| { |
| 679 | Self::wait_idle(); | 660 | w.set_clkdiv(clkdiv); |
| 680 | regs.clkcr().modify(|w| { | 661 | #[cfg(sdmmc_v1)] |
| 681 | w.set_clkdiv(clkdiv); | 662 | w.set_bypass(_bypass); |
| 682 | #[cfg(sdmmc_v1)] | 663 | }); |
| 683 | w.set_bypass(_bypass); | ||
| 684 | }); | ||
| 685 | } | ||
| 686 | 664 | ||
| 687 | Ok(()) | 665 | Ok(()) |
| 688 | } | 666 | } |
| @@ -710,7 +688,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 710 | 688 | ||
| 711 | // Arm `OnDrop` after the buffer, so it will be dropped first | 689 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 712 | let regs = T::regs(); | 690 | let regs = T::regs(); |
| 713 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | 691 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 714 | 692 | ||
| 715 | let transfer = self.prepare_datapath_read(&mut status, 64, 6); | 693 | let transfer = self.prepare_datapath_read(&mut status, 64, 6); |
| 716 | InterruptHandler::<T>::data_interrupts(true); | 694 | InterruptHandler::<T>::data_interrupts(true); |
| @@ -718,7 +696,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 718 | 696 | ||
| 719 | let res = poll_fn(|cx| { | 697 | let res = poll_fn(|cx| { |
| 720 | T::state().register(cx.waker()); | 698 | T::state().register(cx.waker()); |
| 721 | let status = unsafe { regs.star().read() }; | 699 | let status = regs.star().read(); |
| 722 | 700 | ||
| 723 | if status.dcrcfail() { | 701 | if status.dcrcfail() { |
| 724 | return Poll::Ready(Err(Error::Crc)); | 702 | return Poll::Ready(Err(Error::Crc)); |
| @@ -769,8 +747,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 769 | 747 | ||
| 770 | Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13 | 748 | Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13 |
| 771 | 749 | ||
| 772 | // NOTE(unsafe) Atomic read with no side-effects | 750 | let r1 = regs.respr(0).read().cardstatus(); |
| 773 | let r1 = unsafe { regs.respr(0).read().cardstatus() }; | ||
| 774 | Ok(r1.into()) | 751 | Ok(r1.into()) |
| 775 | } | 752 | } |
| 776 | 753 | ||
| @@ -786,7 +763,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 786 | 763 | ||
| 787 | // Arm `OnDrop` after the buffer, so it will be dropped first | 764 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 788 | let regs = T::regs(); | 765 | let regs = T::regs(); |
| 789 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | 766 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 790 | 767 | ||
| 791 | let transfer = self.prepare_datapath_read(&mut status, 64, 6); | 768 | let transfer = self.prepare_datapath_read(&mut status, 64, 6); |
| 792 | InterruptHandler::<T>::data_interrupts(true); | 769 | InterruptHandler::<T>::data_interrupts(true); |
| @@ -794,7 +771,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 794 | 771 | ||
| 795 | let res = poll_fn(|cx| { | 772 | let res = poll_fn(|cx| { |
| 796 | T::state().register(cx.waker()); | 773 | T::state().register(cx.waker()); |
| 797 | let status = unsafe { regs.star().read() }; | 774 | let status = regs.star().read(); |
| 798 | 775 | ||
| 799 | if status.dcrcfail() { | 776 | if status.dcrcfail() { |
| 800 | return Poll::Ready(Err(Error::Crc)); | 777 | return Poll::Ready(Err(Error::Crc)); |
| @@ -840,35 +817,32 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 840 | #[inline(always)] | 817 | #[inline(always)] |
| 841 | fn clear_interrupt_flags() { | 818 | fn clear_interrupt_flags() { |
| 842 | let regs = T::regs(); | 819 | let regs = T::regs(); |
| 843 | // NOTE(unsafe) Atomic write | 820 | regs.icr().write(|w| { |
| 844 | unsafe { | 821 | w.set_ccrcfailc(true); |
| 845 | regs.icr().write(|w| { | 822 | w.set_dcrcfailc(true); |
| 846 | w.set_ccrcfailc(true); | 823 | w.set_ctimeoutc(true); |
| 847 | w.set_dcrcfailc(true); | 824 | w.set_dtimeoutc(true); |
| 848 | w.set_ctimeoutc(true); | 825 | w.set_txunderrc(true); |
| 849 | w.set_dtimeoutc(true); | 826 | w.set_rxoverrc(true); |
| 850 | w.set_txunderrc(true); | 827 | w.set_cmdrendc(true); |
| 851 | w.set_rxoverrc(true); | 828 | w.set_cmdsentc(true); |
| 852 | w.set_cmdrendc(true); | 829 | w.set_dataendc(true); |
| 853 | w.set_cmdsentc(true); | 830 | w.set_dbckendc(true); |
| 854 | w.set_dataendc(true); | 831 | w.set_sdioitc(true); |
| 855 | w.set_dbckendc(true); | ||
| 856 | w.set_sdioitc(true); | ||
| 857 | 832 | ||
| 858 | #[cfg(sdmmc_v2)] | 833 | #[cfg(sdmmc_v2)] |
| 859 | { | 834 | { |
| 860 | w.set_dholdc(true); | 835 | w.set_dholdc(true); |
| 861 | w.set_dabortc(true); | 836 | w.set_dabortc(true); |
| 862 | w.set_busyd0endc(true); | 837 | w.set_busyd0endc(true); |
| 863 | w.set_ackfailc(true); | 838 | w.set_ackfailc(true); |
| 864 | w.set_acktimeoutc(true); | 839 | w.set_acktimeoutc(true); |
| 865 | w.set_vswendc(true); | 840 | w.set_vswendc(true); |
| 866 | w.set_ckstopc(true); | 841 | w.set_ckstopc(true); |
| 867 | w.set_idmatec(true); | 842 | w.set_idmatec(true); |
| 868 | w.set_idmabtcc(true); | 843 | w.set_idmabtcc(true); |
| 869 | } | 844 | } |
| 870 | }); | 845 | }); |
| 871 | } | ||
| 872 | } | 846 | } |
| 873 | 847 | ||
| 874 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { | 848 | async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { |
| @@ -880,7 +854,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 880 | 854 | ||
| 881 | // Arm `OnDrop` after the buffer, so it will be dropped first | 855 | // Arm `OnDrop` after the buffer, so it will be dropped first |
| 882 | let regs = T::regs(); | 856 | let regs = T::regs(); |
| 883 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | 857 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 884 | 858 | ||
| 885 | let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); | 859 | let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); |
| 886 | InterruptHandler::<T>::data_interrupts(true); | 860 | InterruptHandler::<T>::data_interrupts(true); |
| @@ -888,7 +862,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 888 | 862 | ||
| 889 | let res = poll_fn(|cx| { | 863 | let res = poll_fn(|cx| { |
| 890 | T::state().register(cx.waker()); | 864 | T::state().register(cx.waker()); |
| 891 | let status = unsafe { regs.star().read() }; | 865 | let status = regs.star().read(); |
| 892 | 866 | ||
| 893 | if status.dcrcfail() { | 867 | if status.dcrcfail() { |
| 894 | return Poll::Ready(Err(Error::Crc)); | 868 | return Poll::Ready(Err(Error::Crc)); |
| @@ -921,59 +895,53 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 921 | let regs = T::regs(); | 895 | let regs = T::regs(); |
| 922 | 896 | ||
| 923 | Self::clear_interrupt_flags(); | 897 | Self::clear_interrupt_flags(); |
| 924 | // NOTE(safety) Atomic operations | 898 | // CP state machine must be idle |
| 925 | unsafe { | 899 | while Self::cmd_active() {} |
| 926 | // CP state machine must be idle | ||
| 927 | while Self::cmd_active() {} | ||
| 928 | 900 | ||
| 929 | // Command arg | 901 | // Command arg |
| 930 | regs.argr().write(|w| w.set_cmdarg(cmd.arg)); | 902 | regs.argr().write(|w| w.set_cmdarg(cmd.arg)); |
| 931 | |||
| 932 | // Command index and start CP State Machine | ||
| 933 | regs.cmdr().write(|w| { | ||
| 934 | w.set_waitint(false); | ||
| 935 | w.set_waitresp(cmd.resp as u8); | ||
| 936 | w.set_cmdindex(cmd.cmd); | ||
| 937 | w.set_cpsmen(true); | ||
| 938 | 903 | ||
| 939 | #[cfg(sdmmc_v2)] | 904 | // Command index and start CP State Machine |
| 940 | { | 905 | regs.cmdr().write(|w| { |
| 941 | // Special mode in CP State Machine | 906 | w.set_waitint(false); |
| 942 | // CMD12: Stop Transmission | 907 | w.set_waitresp(cmd.resp as u8); |
| 943 | let cpsm_stop_transmission = cmd.cmd == 12; | 908 | w.set_cmdindex(cmd.cmd); |
| 944 | w.set_cmdstop(cpsm_stop_transmission); | 909 | w.set_cpsmen(true); |
| 945 | w.set_cmdtrans(data); | ||
| 946 | } | ||
| 947 | }); | ||
| 948 | 910 | ||
| 949 | let mut status; | 911 | #[cfg(sdmmc_v2)] |
| 950 | if cmd.resp == Response::None { | 912 | { |
| 951 | // Wait for CMDSENT or a timeout | 913 | // Special mode in CP State Machine |
| 952 | while { | 914 | // CMD12: Stop Transmission |
| 953 | status = regs.star().read(); | 915 | let cpsm_stop_transmission = cmd.cmd == 12; |
| 954 | !(status.ctimeout() || status.cmdsent()) | 916 | w.set_cmdstop(cpsm_stop_transmission); |
| 955 | } {} | 917 | w.set_cmdtrans(data); |
| 956 | } else { | ||
| 957 | // Wait for CMDREND or CCRCFAIL or a timeout | ||
| 958 | while { | ||
| 959 | status = regs.star().read(); | ||
| 960 | !(status.ctimeout() || status.cmdrend() || status.ccrcfail()) | ||
| 961 | } {} | ||
| 962 | } | 918 | } |
| 919 | }); | ||
| 963 | 920 | ||
| 964 | if status.ctimeout() { | 921 | let mut status; |
| 965 | return Err(Error::Timeout); | 922 | if cmd.resp == Response::None { |
| 966 | } else if status.ccrcfail() { | 923 | // Wait for CMDSENT or a timeout |
| 967 | return Err(Error::Crc); | 924 | while { |
| 968 | } | 925 | status = regs.star().read(); |
| 969 | Ok(()) | 926 | !(status.ctimeout() || status.cmdsent()) |
| 927 | } {} | ||
| 928 | } else { | ||
| 929 | // Wait for CMDREND or CCRCFAIL or a timeout | ||
| 930 | while { | ||
| 931 | status = regs.star().read(); | ||
| 932 | !(status.ctimeout() || status.cmdrend() || status.ccrcfail()) | ||
| 933 | } {} | ||
| 934 | } | ||
| 935 | |||
| 936 | if status.ctimeout() { | ||
| 937 | return Err(Error::Timeout); | ||
| 938 | } else if status.ccrcfail() { | ||
| 939 | return Err(Error::Crc); | ||
| 970 | } | 940 | } |
| 941 | Ok(()) | ||
| 971 | } | 942 | } |
| 972 | 943 | ||
| 973 | /// # Safety | 944 | fn on_drop() { |
| 974 | /// | ||
| 975 | /// Ensure that `regs` has exclusive access to the regblocks | ||
| 976 | unsafe fn on_drop() { | ||
| 977 | let regs = T::regs(); | 945 | let regs = T::regs(); |
| 978 | if Self::data_active() { | 946 | if Self::data_active() { |
| 979 | Self::clear_interrupt_flags(); | 947 | Self::clear_interrupt_flags(); |
| @@ -1017,141 +985,138 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1017 | false => BusWidth::One, | 985 | false => BusWidth::One, |
| 1018 | }; | 986 | }; |
| 1019 | 987 | ||
| 1020 | // NOTE(unsafe) We have exclusive access to the peripheral | 988 | // While the SD/SDIO card or eMMC is in identification mode, |
| 1021 | unsafe { | 989 | // the SDMMC_CK frequency must be no more than 400 kHz. |
| 1022 | // While the SD/SDIO card or eMMC is in identification mode, | 990 | let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); |
| 1023 | // the SDMMC_CK frequency must be no more than 400 kHz. | 991 | self.clock = init_clock; |
| 1024 | let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); | ||
| 1025 | self.clock = init_clock; | ||
| 1026 | |||
| 1027 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 1028 | Self::wait_idle(); | ||
| 1029 | |||
| 1030 | regs.clkcr().modify(|w| { | ||
| 1031 | w.set_widbus(0); | ||
| 1032 | w.set_clkdiv(clkdiv); | ||
| 1033 | #[cfg(sdmmc_v1)] | ||
| 1034 | w.set_bypass(_bypass); | ||
| 1035 | }); | ||
| 1036 | 992 | ||
| 1037 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); | 993 | // CPSMACT and DPSMACT must be 0 to set WIDBUS |
| 1038 | Self::cmd(Cmd::idle(), false)?; | 994 | Self::wait_idle(); |
| 1039 | 995 | ||
| 1040 | // Check if cards supports CMD8 (with pattern) | 996 | regs.clkcr().modify(|w| { |
| 1041 | Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; | 997 | w.set_widbus(0); |
| 1042 | let r1 = regs.respr(0).read().cardstatus(); | 998 | w.set_clkdiv(clkdiv); |
| 999 | #[cfg(sdmmc_v1)] | ||
| 1000 | w.set_bypass(_bypass); | ||
| 1001 | }); | ||
| 1043 | 1002 | ||
| 1044 | let mut card = if r1 == 0x1AA { | 1003 | regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); |
| 1045 | // Card echoed back the pattern. Must be at least v2 | 1004 | Self::cmd(Cmd::idle(), false)?; |
| 1046 | Card::default() | ||
| 1047 | } else { | ||
| 1048 | return Err(Error::UnsupportedCardVersion); | ||
| 1049 | }; | ||
| 1050 | 1005 | ||
| 1051 | let ocr = loop { | 1006 | // Check if cards supports CMD8 (with pattern) |
| 1052 | // Signal that next command is a app command | 1007 | Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; |
| 1053 | Self::cmd(Cmd::app_cmd(0), false)?; // CMD55 | 1008 | let r1 = regs.respr(0).read().cardstatus(); |
| 1054 | 1009 | ||
| 1055 | let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 | 1010 | let mut card = if r1 == 0x1AA { |
| 1056 | | CmdAppOper::HIGH_CAPACITY as u32 | 1011 | // Card echoed back the pattern. Must be at least v2 |
| 1057 | | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; | 1012 | Card::default() |
| 1013 | } else { | ||
| 1014 | return Err(Error::UnsupportedCardVersion); | ||
| 1015 | }; | ||
| 1058 | 1016 | ||
| 1059 | // Initialize card | 1017 | let ocr = loop { |
| 1060 | match Self::cmd(Cmd::app_op_cmd(arg), false) { | 1018 | // Signal that next command is a app command |
| 1061 | // ACMD41 | 1019 | Self::cmd(Cmd::app_cmd(0), false)?; // CMD55 |
| 1062 | Ok(_) => (), | ||
| 1063 | Err(Error::Crc) => (), | ||
| 1064 | Err(err) => return Err(err), | ||
| 1065 | } | ||
| 1066 | let ocr: OCR = regs.respr(0).read().cardstatus().into(); | ||
| 1067 | if !ocr.is_busy() { | ||
| 1068 | // Power up done | ||
| 1069 | break ocr; | ||
| 1070 | } | ||
| 1071 | }; | ||
| 1072 | 1020 | ||
| 1073 | if ocr.high_capacity() { | 1021 | let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 |
| 1074 | // Card is SDHC or SDXC or SDUC | 1022 | | CmdAppOper::HIGH_CAPACITY as u32 |
| 1075 | card.card_type = CardCapacity::SDHC; | 1023 | | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; |
| 1076 | } else { | ||
| 1077 | card.card_type = CardCapacity::SDSC; | ||
| 1078 | } | ||
| 1079 | card.ocr = ocr; | ||
| 1080 | |||
| 1081 | Self::cmd(Cmd::all_send_cid(), false)?; // CMD2 | ||
| 1082 | let cid0 = regs.respr(0).read().cardstatus() as u128; | ||
| 1083 | let cid1 = regs.respr(1).read().cardstatus() as u128; | ||
| 1084 | let cid2 = regs.respr(2).read().cardstatus() as u128; | ||
| 1085 | let cid3 = regs.respr(3).read().cardstatus() as u128; | ||
| 1086 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | ||
| 1087 | card.cid = cid.into(); | ||
| 1088 | |||
| 1089 | Self::cmd(Cmd::send_rel_addr(), false)?; | ||
| 1090 | card.rca = regs.respr(0).read().cardstatus() >> 16; | ||
| 1091 | |||
| 1092 | Self::cmd(Cmd::send_csd(card.rca << 16), false)?; | ||
| 1093 | let csd0 = regs.respr(0).read().cardstatus() as u128; | ||
| 1094 | let csd1 = regs.respr(1).read().cardstatus() as u128; | ||
| 1095 | let csd2 = regs.respr(2).read().cardstatus() as u128; | ||
| 1096 | let csd3 = regs.respr(3).read().cardstatus() as u128; | ||
| 1097 | let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); | ||
| 1098 | card.csd = csd.into(); | ||
| 1099 | |||
| 1100 | self.select_card(Some(&card))?; | ||
| 1101 | |||
| 1102 | self.get_scr(&mut card).await?; | ||
| 1103 | |||
| 1104 | // Set bus width | ||
| 1105 | let (width, acmd_arg) = match bus_width { | ||
| 1106 | BusWidth::Eight => unimplemented!(), | ||
| 1107 | BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), | ||
| 1108 | _ => (BusWidth::One, 0), | ||
| 1109 | }; | ||
| 1110 | Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; | ||
| 1111 | Self::cmd(Cmd::cmd6(acmd_arg), false)?; | ||
| 1112 | |||
| 1113 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 1114 | Self::wait_idle(); | ||
| 1115 | |||
| 1116 | regs.clkcr().modify(|w| { | ||
| 1117 | w.set_widbus(match width { | ||
| 1118 | BusWidth::One => 0, | ||
| 1119 | BusWidth::Four => 1, | ||
| 1120 | BusWidth::Eight => 2, | ||
| 1121 | _ => panic!("Invalid Bus Width"), | ||
| 1122 | }) | ||
| 1123 | }); | ||
| 1124 | 1024 | ||
| 1125 | // Set Clock | 1025 | // Initialize card |
| 1126 | if freq.0 <= 25_000_000 { | 1026 | match Self::cmd(Cmd::app_op_cmd(arg), false) { |
| 1127 | // Final clock frequency | 1027 | // ACMD41 |
| 1128 | self.clkcr_set_clkdiv(freq.0, width)?; | 1028 | Ok(_) => (), |
| 1129 | } else { | 1029 | Err(Error::Crc) => (), |
| 1130 | // Switch to max clock for SDR12 | 1030 | Err(err) => return Err(err), |
| 1131 | self.clkcr_set_clkdiv(25_000_000, width)?; | ||
| 1132 | } | 1031 | } |
| 1032 | let ocr: OCR = regs.respr(0).read().cardstatus().into(); | ||
| 1033 | if !ocr.is_busy() { | ||
| 1034 | // Power up done | ||
| 1035 | break ocr; | ||
| 1036 | } | ||
| 1037 | }; | ||
| 1038 | |||
| 1039 | if ocr.high_capacity() { | ||
| 1040 | // Card is SDHC or SDXC or SDUC | ||
| 1041 | card.card_type = CardCapacity::SDHC; | ||
| 1042 | } else { | ||
| 1043 | card.card_type = CardCapacity::SDSC; | ||
| 1044 | } | ||
| 1045 | card.ocr = ocr; | ||
| 1046 | |||
| 1047 | Self::cmd(Cmd::all_send_cid(), false)?; // CMD2 | ||
| 1048 | let cid0 = regs.respr(0).read().cardstatus() as u128; | ||
| 1049 | let cid1 = regs.respr(1).read().cardstatus() as u128; | ||
| 1050 | let cid2 = regs.respr(2).read().cardstatus() as u128; | ||
| 1051 | let cid3 = regs.respr(3).read().cardstatus() as u128; | ||
| 1052 | let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); | ||
| 1053 | card.cid = cid.into(); | ||
| 1054 | |||
| 1055 | Self::cmd(Cmd::send_rel_addr(), false)?; | ||
| 1056 | card.rca = regs.respr(0).read().cardstatus() >> 16; | ||
| 1057 | |||
| 1058 | Self::cmd(Cmd::send_csd(card.rca << 16), false)?; | ||
| 1059 | let csd0 = regs.respr(0).read().cardstatus() as u128; | ||
| 1060 | let csd1 = regs.respr(1).read().cardstatus() as u128; | ||
| 1061 | let csd2 = regs.respr(2).read().cardstatus() as u128; | ||
| 1062 | let csd3 = regs.respr(3).read().cardstatus() as u128; | ||
| 1063 | let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); | ||
| 1064 | card.csd = csd.into(); | ||
| 1065 | |||
| 1066 | self.select_card(Some(&card))?; | ||
| 1067 | |||
| 1068 | self.get_scr(&mut card).await?; | ||
| 1069 | |||
| 1070 | // Set bus width | ||
| 1071 | let (width, acmd_arg) = match bus_width { | ||
| 1072 | BusWidth::Eight => unimplemented!(), | ||
| 1073 | BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), | ||
| 1074 | _ => (BusWidth::One, 0), | ||
| 1075 | }; | ||
| 1076 | Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; | ||
| 1077 | Self::cmd(Cmd::cmd6(acmd_arg), false)?; | ||
| 1078 | |||
| 1079 | // CPSMACT and DPSMACT must be 0 to set WIDBUS | ||
| 1080 | Self::wait_idle(); | ||
| 1133 | 1081 | ||
| 1134 | self.card = Some(card); | 1082 | regs.clkcr().modify(|w| { |
| 1083 | w.set_widbus(match width { | ||
| 1084 | BusWidth::One => 0, | ||
| 1085 | BusWidth::Four => 1, | ||
| 1086 | BusWidth::Eight => 2, | ||
| 1087 | _ => panic!("Invalid Bus Width"), | ||
| 1088 | }) | ||
| 1089 | }); | ||
| 1090 | |||
| 1091 | // Set Clock | ||
| 1092 | if freq.0 <= 25_000_000 { | ||
| 1093 | // Final clock frequency | ||
| 1094 | self.clkcr_set_clkdiv(freq.0, width)?; | ||
| 1095 | } else { | ||
| 1096 | // Switch to max clock for SDR12 | ||
| 1097 | self.clkcr_set_clkdiv(25_000_000, width)?; | ||
| 1098 | } | ||
| 1135 | 1099 | ||
| 1136 | // Read status | 1100 | self.card = Some(card); |
| 1137 | self.read_sd_status().await?; | ||
| 1138 | 1101 | ||
| 1139 | if freq.0 > 25_000_000 { | 1102 | // Read status |
| 1140 | // Switch to SDR25 | 1103 | self.read_sd_status().await?; |
| 1141 | self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; | ||
| 1142 | 1104 | ||
| 1143 | if self.signalling == Signalling::SDR25 { | 1105 | if freq.0 > 25_000_000 { |
| 1144 | // Set final clock frequency | 1106 | // Switch to SDR25 |
| 1145 | self.clkcr_set_clkdiv(freq.0, width)?; | 1107 | self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; |
| 1146 | 1108 | ||
| 1147 | if self.read_status(&card)?.state() != CurrentState::Transfer { | 1109 | if self.signalling == Signalling::SDR25 { |
| 1148 | return Err(Error::SignalingSwitchFailed); | 1110 | // Set final clock frequency |
| 1149 | } | 1111 | self.clkcr_set_clkdiv(freq.0, width)?; |
| 1112 | |||
| 1113 | if self.read_status(&card)?.state() != CurrentState::Transfer { | ||
| 1114 | return Err(Error::SignalingSwitchFailed); | ||
| 1150 | } | 1115 | } |
| 1151 | } | 1116 | } |
| 1152 | // Read status after signalling change | ||
| 1153 | self.read_sd_status().await?; | ||
| 1154 | } | 1117 | } |
| 1118 | // Read status after signalling change | ||
| 1119 | self.read_sd_status().await?; | ||
| 1155 | 1120 | ||
| 1156 | Ok(()) | 1121 | Ok(()) |
| 1157 | } | 1122 | } |
| @@ -1172,7 +1137,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1172 | Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 | 1137 | Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 |
| 1173 | 1138 | ||
| 1174 | let regs = T::regs(); | 1139 | let regs = T::regs(); |
| 1175 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | 1140 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 1176 | 1141 | ||
| 1177 | let transfer = self.prepare_datapath_read(buffer, 512, 9); | 1142 | let transfer = self.prepare_datapath_read(buffer, 512, 9); |
| 1178 | InterruptHandler::<T>::data_interrupts(true); | 1143 | InterruptHandler::<T>::data_interrupts(true); |
| @@ -1180,7 +1145,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1180 | 1145 | ||
| 1181 | let res = poll_fn(|cx| { | 1146 | let res = poll_fn(|cx| { |
| 1182 | T::state().register(cx.waker()); | 1147 | T::state().register(cx.waker()); |
| 1183 | let status = unsafe { regs.star().read() }; | 1148 | let status = regs.star().read(); |
| 1184 | 1149 | ||
| 1185 | if status.dcrcfail() { | 1150 | if status.dcrcfail() { |
| 1186 | return Poll::Ready(Err(Error::Crc)); | 1151 | return Poll::Ready(Err(Error::Crc)); |
| @@ -1217,7 +1182,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1217 | Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 | 1182 | Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 |
| 1218 | 1183 | ||
| 1219 | let regs = T::regs(); | 1184 | let regs = T::regs(); |
| 1220 | let on_drop = OnDrop::new(|| unsafe { Self::on_drop() }); | 1185 | let on_drop = OnDrop::new(|| Self::on_drop()); |
| 1221 | 1186 | ||
| 1222 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes | 1187 | // sdmmc_v1 uses different cmd/dma order than v2, but only for writes |
| 1223 | #[cfg(sdmmc_v1)] | 1188 | #[cfg(sdmmc_v1)] |
| @@ -1231,7 +1196,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1231 | 1196 | ||
| 1232 | let res = poll_fn(|cx| { | 1197 | let res = poll_fn(|cx| { |
| 1233 | T::state().register(cx.waker()); | 1198 | T::state().register(cx.waker()); |
| 1234 | let status = unsafe { regs.star().read() }; | 1199 | let status = regs.star().read(); |
| 1235 | 1200 | ||
| 1236 | if status.dcrcfail() { | 1201 | if status.dcrcfail() { |
| 1237 | return Poll::Ready(Err(Error::Crc)); | 1202 | return Poll::Ready(Err(Error::Crc)); |
| @@ -1288,10 +1253,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1288 | 1253 | ||
| 1289 | impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { | 1254 | impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { |
| 1290 | fn drop(&mut self) { | 1255 | fn drop(&mut self) { |
| 1291 | unsafe { T::Interrupt::steal() }.disable(); | 1256 | T::Interrupt::disable(); |
| 1292 | unsafe { Self::on_drop() }; | 1257 | Self::on_drop(); |
| 1293 | 1258 | ||
| 1294 | critical_section::with(|_| unsafe { | 1259 | critical_section::with(|_| { |
| 1295 | self.clk.set_as_disconnected(); | 1260 | self.clk.set_as_disconnected(); |
| 1296 | self.cmd.set_as_disconnected(); | 1261 | self.cmd.set_as_disconnected(); |
| 1297 | self.d0.set_as_disconnected(); | 1262 | self.d0.set_as_disconnected(); |
| @@ -1401,7 +1366,7 @@ pub(crate) mod sealed { | |||
| 1401 | use super::*; | 1366 | use super::*; |
| 1402 | 1367 | ||
| 1403 | pub trait Instance { | 1368 | pub trait Instance { |
| 1404 | type Interrupt: Interrupt; | 1369 | type Interrupt: interrupt::typelevel::Interrupt; |
| 1405 | 1370 | ||
| 1406 | fn regs() -> RegBlock; | 1371 | fn regs() -> RegBlock; |
| 1407 | fn state() -> &'static AtomicWaker; | 1372 | fn state() -> &'static AtomicWaker; |
| @@ -1490,7 +1455,7 @@ cfg_if::cfg_if! { | |||
| 1490 | foreach_peripheral!( | 1455 | foreach_peripheral!( |
| 1491 | (sdmmc, $inst:ident) => { | 1456 | (sdmmc, $inst:ident) => { |
| 1492 | impl sealed::Instance for peripherals::$inst { | 1457 | impl sealed::Instance for peripherals::$inst { |
| 1493 | type Interrupt = crate::interrupt::$inst; | 1458 | type Interrupt = crate::interrupt::typelevel::$inst; |
| 1494 | 1459 | ||
| 1495 | fn regs() -> RegBlock { | 1460 | fn regs() -> RegBlock { |
| 1496 | crate::pac::$inst | 1461 | crate::pac::$inst |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 580971e45..1cddac992 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -98,14 +98,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 98 | Polarity::IdleHigh => Pull::Up, | 98 | Polarity::IdleHigh => Pull::Up, |
| 99 | }; | 99 | }; |
| 100 | 100 | ||
| 101 | unsafe { | 101 | sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode); |
| 102 | sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode); | 102 | sck.set_speed(crate::gpio::Speed::VeryHigh); |
| 103 | sck.set_speed(crate::gpio::Speed::VeryHigh); | 103 | mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); |
| 104 | mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); | 104 | mosi.set_speed(crate::gpio::Speed::VeryHigh); |
| 105 | mosi.set_speed(crate::gpio::Speed::VeryHigh); | 105 | miso.set_as_af(miso.af_num(), AFType::Input); |
| 106 | miso.set_as_af(miso.af_num(), AFType::Input); | 106 | miso.set_speed(crate::gpio::Speed::VeryHigh); |
| 107 | miso.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 108 | } | ||
| 109 | 107 | ||
| 110 | Self::new_inner( | 108 | Self::new_inner( |
| 111 | peri, | 109 | peri, |
| @@ -129,12 +127,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 129 | config: Config, | 127 | config: Config, |
| 130 | ) -> Self { | 128 | ) -> Self { |
| 131 | into_ref!(sck, miso); | 129 | into_ref!(sck, miso); |
| 132 | unsafe { | 130 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); |
| 133 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | 131 | sck.set_speed(crate::gpio::Speed::VeryHigh); |
| 134 | sck.set_speed(crate::gpio::Speed::VeryHigh); | 132 | miso.set_as_af(miso.af_num(), AFType::Input); |
| 135 | miso.set_as_af(miso.af_num(), AFType::Input); | 133 | miso.set_speed(crate::gpio::Speed::VeryHigh); |
| 136 | miso.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 137 | } | ||
| 138 | 134 | ||
| 139 | Self::new_inner( | 135 | Self::new_inner( |
| 140 | peri, | 136 | peri, |
| @@ -158,12 +154,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 158 | config: Config, | 154 | config: Config, |
| 159 | ) -> Self { | 155 | ) -> Self { |
| 160 | into_ref!(sck, mosi); | 156 | into_ref!(sck, mosi); |
| 161 | unsafe { | 157 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); |
| 162 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | 158 | sck.set_speed(crate::gpio::Speed::VeryHigh); |
| 163 | sck.set_speed(crate::gpio::Speed::VeryHigh); | 159 | mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); |
| 164 | mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull); | 160 | mosi.set_speed(crate::gpio::Speed::VeryHigh); |
| 165 | mosi.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 166 | } | ||
| 167 | 161 | ||
| 168 | Self::new_inner( | 162 | Self::new_inner( |
| 169 | peri, | 163 | peri, |
| @@ -186,10 +180,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 186 | config: Config, | 180 | config: Config, |
| 187 | ) -> Self { | 181 | ) -> Self { |
| 188 | into_ref!(mosi); | 182 | into_ref!(mosi); |
| 189 | unsafe { | 183 | mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down); |
| 190 | mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down); | 184 | mosi.set_speed(crate::gpio::Speed::Medium); |
| 191 | mosi.set_speed(crate::gpio::Speed::Medium); | ||
| 192 | } | ||
| 193 | 185 | ||
| 194 | Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config) | 186 | Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config) |
| 195 | } | 187 | } |
| @@ -247,7 +239,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 247 | T::reset(); | 239 | T::reset(); |
| 248 | 240 | ||
| 249 | #[cfg(any(spi_v1, spi_f1))] | 241 | #[cfg(any(spi_v1, spi_f1))] |
| 250 | unsafe { | 242 | { |
| 251 | T::REGS.cr2().modify(|w| { | 243 | T::REGS.cr2().modify(|w| { |
| 252 | w.set_ssoe(false); | 244 | w.set_ssoe(false); |
| 253 | }); | 245 | }); |
| @@ -270,7 +262,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 270 | }); | 262 | }); |
| 271 | } | 263 | } |
| 272 | #[cfg(spi_v2)] | 264 | #[cfg(spi_v2)] |
| 273 | unsafe { | 265 | { |
| 274 | T::REGS.cr2().modify(|w| { | 266 | T::REGS.cr2().modify(|w| { |
| 275 | let (ds, frxth) = <u8 as sealed::Word>::CONFIG; | 267 | let (ds, frxth) = <u8 as sealed::Word>::CONFIG; |
| 276 | w.set_frxth(frxth); | 268 | w.set_frxth(frxth); |
| @@ -292,7 +284,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 292 | }); | 284 | }); |
| 293 | } | 285 | } |
| 294 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 286 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 295 | unsafe { | 287 | { |
| 296 | T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); | 288 | T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); |
| 297 | T::REGS.cfg2().modify(|w| { | 289 | T::REGS.cfg2().modify(|w| { |
| 298 | //w.set_ssoe(true); | 290 | //w.set_ssoe(true); |
| @@ -343,29 +335,25 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 343 | let lsbfirst = config.raw_byte_order(); | 335 | let lsbfirst = config.raw_byte_order(); |
| 344 | 336 | ||
| 345 | #[cfg(any(spi_v1, spi_f1, spi_v2))] | 337 | #[cfg(any(spi_v1, spi_f1, spi_v2))] |
| 346 | unsafe { | 338 | T::REGS.cr1().modify(|w| { |
| 347 | T::REGS.cr1().modify(|w| { | 339 | w.set_cpha(cpha); |
| 348 | w.set_cpha(cpha); | 340 | w.set_cpol(cpol); |
| 349 | w.set_cpol(cpol); | 341 | w.set_lsbfirst(lsbfirst); |
| 350 | w.set_lsbfirst(lsbfirst); | 342 | }); |
| 351 | }); | ||
| 352 | } | ||
| 353 | 343 | ||
| 354 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 344 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 355 | unsafe { | 345 | T::REGS.cfg2().modify(|w| { |
| 356 | T::REGS.cfg2().modify(|w| { | 346 | w.set_cpha(cpha); |
| 357 | w.set_cpha(cpha); | 347 | w.set_cpol(cpol); |
| 358 | w.set_cpol(cpol); | 348 | w.set_lsbfirst(lsbfirst); |
| 359 | w.set_lsbfirst(lsbfirst); | 349 | }); |
| 360 | }); | ||
| 361 | } | ||
| 362 | } | 350 | } |
| 363 | 351 | ||
| 364 | pub fn get_current_config(&self) -> Config { | 352 | pub fn get_current_config(&self) -> Config { |
| 365 | #[cfg(any(spi_v1, spi_f1, spi_v2))] | 353 | #[cfg(any(spi_v1, spi_f1, spi_v2))] |
| 366 | let cfg = unsafe { T::REGS.cr1().read() }; | 354 | let cfg = T::REGS.cr1().read(); |
| 367 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 355 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 368 | let cfg = unsafe { T::REGS.cfg2().read() }; | 356 | let cfg = T::REGS.cfg2().read(); |
| 369 | let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { | 357 | let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { |
| 370 | Polarity::IdleLow | 358 | Polarity::IdleLow |
| 371 | } else { | 359 | } else { |
| @@ -395,7 +383,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 395 | } | 383 | } |
| 396 | 384 | ||
| 397 | #[cfg(any(spi_v1, spi_f1))] | 385 | #[cfg(any(spi_v1, spi_f1))] |
| 398 | unsafe { | 386 | { |
| 399 | T::REGS.cr1().modify(|reg| { | 387 | T::REGS.cr1().modify(|reg| { |
| 400 | reg.set_spe(false); | 388 | reg.set_spe(false); |
| 401 | reg.set_dff(word_size) | 389 | reg.set_dff(word_size) |
| @@ -405,7 +393,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 405 | }); | 393 | }); |
| 406 | } | 394 | } |
| 407 | #[cfg(spi_v2)] | 395 | #[cfg(spi_v2)] |
| 408 | unsafe { | 396 | { |
| 409 | T::REGS.cr1().modify(|w| { | 397 | T::REGS.cr1().modify(|w| { |
| 410 | w.set_spe(false); | 398 | w.set_spe(false); |
| 411 | }); | 399 | }); |
| @@ -418,7 +406,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 418 | }); | 406 | }); |
| 419 | } | 407 | } |
| 420 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 408 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 421 | unsafe { | 409 | { |
| 422 | T::REGS.cr1().modify(|w| { | 410 | T::REGS.cr1().modify(|w| { |
| 423 | w.set_csusp(true); | 411 | w.set_csusp(true); |
| 424 | }); | 412 | }); |
| @@ -447,26 +435,22 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 447 | } | 435 | } |
| 448 | 436 | ||
| 449 | self.set_word_size(W::CONFIG); | 437 | self.set_word_size(W::CONFIG); |
| 450 | unsafe { | 438 | T::REGS.cr1().modify(|w| { |
| 451 | T::REGS.cr1().modify(|w| { | 439 | w.set_spe(false); |
| 452 | w.set_spe(false); | 440 | }); |
| 453 | }); | ||
| 454 | } | ||
| 455 | 441 | ||
| 456 | let tx_request = self.txdma.request(); | 442 | let tx_request = self.txdma.request(); |
| 457 | let tx_dst = T::REGS.tx_ptr(); | 443 | let tx_dst = T::REGS.tx_ptr(); |
| 458 | let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; | 444 | let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; |
| 459 | 445 | ||
| 460 | unsafe { | 446 | set_txdmaen(T::REGS, true); |
| 461 | set_txdmaen(T::REGS, true); | 447 | T::REGS.cr1().modify(|w| { |
| 462 | T::REGS.cr1().modify(|w| { | 448 | w.set_spe(true); |
| 463 | w.set_spe(true); | 449 | }); |
| 464 | }); | 450 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 465 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 451 | T::REGS.cr1().modify(|w| { |
| 466 | T::REGS.cr1().modify(|w| { | 452 | w.set_cstart(true); |
| 467 | w.set_cstart(true); | 453 | }); |
| 468 | }); | ||
| 469 | } | ||
| 470 | 454 | ||
| 471 | tx_f.await; | 455 | tx_f.await; |
| 472 | 456 | ||
| @@ -485,11 +469,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 485 | } | 469 | } |
| 486 | 470 | ||
| 487 | self.set_word_size(W::CONFIG); | 471 | self.set_word_size(W::CONFIG); |
| 488 | unsafe { | 472 | T::REGS.cr1().modify(|w| { |
| 489 | T::REGS.cr1().modify(|w| { | 473 | w.set_spe(false); |
| 490 | w.set_spe(false); | 474 | }); |
| 491 | }); | ||
| 492 | } | ||
| 493 | 475 | ||
| 494 | // SPIv3 clears rxfifo on SPE=0 | 476 | // SPIv3 clears rxfifo on SPE=0 |
| 495 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 477 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] |
| @@ -517,16 +499,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 517 | ) | 499 | ) |
| 518 | }; | 500 | }; |
| 519 | 501 | ||
| 520 | unsafe { | 502 | set_txdmaen(T::REGS, true); |
| 521 | set_txdmaen(T::REGS, true); | 503 | T::REGS.cr1().modify(|w| { |
| 522 | T::REGS.cr1().modify(|w| { | 504 | w.set_spe(true); |
| 523 | w.set_spe(true); | 505 | }); |
| 524 | }); | 506 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 525 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 507 | T::REGS.cr1().modify(|w| { |
| 526 | T::REGS.cr1().modify(|w| { | 508 | w.set_cstart(true); |
| 527 | w.set_cstart(true); | 509 | }); |
| 528 | }); | ||
| 529 | } | ||
| 530 | 510 | ||
| 531 | join(tx_f, rx_f).await; | 511 | join(tx_f, rx_f).await; |
| 532 | 512 | ||
| @@ -548,11 +528,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 548 | } | 528 | } |
| 549 | 529 | ||
| 550 | self.set_word_size(W::CONFIG); | 530 | self.set_word_size(W::CONFIG); |
| 551 | unsafe { | 531 | T::REGS.cr1().modify(|w| { |
| 552 | T::REGS.cr1().modify(|w| { | 532 | w.set_spe(false); |
| 553 | w.set_spe(false); | 533 | }); |
| 554 | }); | ||
| 555 | } | ||
| 556 | 534 | ||
| 557 | // SPIv3 clears rxfifo on SPE=0 | 535 | // SPIv3 clears rxfifo on SPE=0 |
| 558 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 536 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] |
| @@ -568,16 +546,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 568 | let tx_dst = T::REGS.tx_ptr(); | 546 | let tx_dst = T::REGS.tx_ptr(); |
| 569 | let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) }; | 547 | let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) }; |
| 570 | 548 | ||
| 571 | unsafe { | 549 | set_txdmaen(T::REGS, true); |
| 572 | set_txdmaen(T::REGS, true); | 550 | T::REGS.cr1().modify(|w| { |
| 573 | T::REGS.cr1().modify(|w| { | 551 | w.set_spe(true); |
| 574 | w.set_spe(true); | 552 | }); |
| 575 | }); | 553 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 576 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 554 | T::REGS.cr1().modify(|w| { |
| 577 | T::REGS.cr1().modify(|w| { | 555 | w.set_cstart(true); |
| 578 | w.set_cstart(true); | 556 | }); |
| 579 | }); | ||
| 580 | } | ||
| 581 | 557 | ||
| 582 | join(tx_f, rx_f).await; | 558 | join(tx_f, rx_f).await; |
| 583 | 559 | ||
| @@ -603,7 +579,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 603 | } | 579 | } |
| 604 | 580 | ||
| 605 | pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { | 581 | pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { |
| 606 | unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } | 582 | T::REGS.cr1().modify(|w| w.set_spe(true)); |
| 607 | flush_rx_fifo(T::REGS); | 583 | flush_rx_fifo(T::REGS); |
| 608 | self.set_word_size(W::CONFIG); | 584 | self.set_word_size(W::CONFIG); |
| 609 | for word in words.iter() { | 585 | for word in words.iter() { |
| @@ -613,7 +589,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 613 | } | 589 | } |
| 614 | 590 | ||
| 615 | pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { | 591 | pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { |
| 616 | unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } | 592 | T::REGS.cr1().modify(|w| w.set_spe(true)); |
| 617 | flush_rx_fifo(T::REGS); | 593 | flush_rx_fifo(T::REGS); |
| 618 | self.set_word_size(W::CONFIG); | 594 | self.set_word_size(W::CONFIG); |
| 619 | for word in words.iter_mut() { | 595 | for word in words.iter_mut() { |
| @@ -623,7 +599,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 623 | } | 599 | } |
| 624 | 600 | ||
| 625 | pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { | 601 | pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { |
| 626 | unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } | 602 | T::REGS.cr1().modify(|w| w.set_spe(true)); |
| 627 | flush_rx_fifo(T::REGS); | 603 | flush_rx_fifo(T::REGS); |
| 628 | self.set_word_size(W::CONFIG); | 604 | self.set_word_size(W::CONFIG); |
| 629 | for word in words.iter_mut() { | 605 | for word in words.iter_mut() { |
| @@ -633,7 +609,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 633 | } | 609 | } |
| 634 | 610 | ||
| 635 | pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { | 611 | pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { |
| 636 | unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) } | 612 | T::REGS.cr1().modify(|w| w.set_spe(true)); |
| 637 | flush_rx_fifo(T::REGS); | 613 | flush_rx_fifo(T::REGS); |
| 638 | self.set_word_size(W::CONFIG); | 614 | self.set_word_size(W::CONFIG); |
| 639 | let len = read.len().max(write.len()); | 615 | let len = read.len().max(write.len()); |
| @@ -650,11 +626,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 650 | 626 | ||
| 651 | impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { | 627 | impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { |
| 652 | fn drop(&mut self) { | 628 | fn drop(&mut self) { |
| 653 | unsafe { | 629 | self.sck.as_ref().map(|x| x.set_as_disconnected()); |
| 654 | self.sck.as_ref().map(|x| x.set_as_disconnected()); | 630 | self.mosi.as_ref().map(|x| x.set_as_disconnected()); |
| 655 | self.mosi.as_ref().map(|x| x.set_as_disconnected()); | 631 | self.miso.as_ref().map(|x| x.set_as_disconnected()); |
| 656 | self.miso.as_ref().map(|x| x.set_as_disconnected()); | ||
| 657 | } | ||
| 658 | } | 632 | } |
| 659 | } | 633 | } |
| 660 | 634 | ||
| @@ -690,7 +664,7 @@ impl RegsExt for Regs { | |||
| 690 | let dr = self.dr(); | 664 | let dr = self.dr(); |
| 691 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 665 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 692 | let dr = self.txdr(); | 666 | let dr = self.txdr(); |
| 693 | dr.ptr() as *mut W | 667 | dr.as_ptr() as *mut W |
| 694 | } | 668 | } |
| 695 | 669 | ||
| 696 | fn rx_ptr<W>(&self) -> *mut W { | 670 | fn rx_ptr<W>(&self) -> *mut W { |
| @@ -698,7 +672,7 @@ impl RegsExt for Regs { | |||
| 698 | let dr = self.dr(); | 672 | let dr = self.dr(); |
| 699 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 673 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 700 | let dr = self.rxdr(); | 674 | let dr = self.rxdr(); |
| 701 | dr.ptr() as *mut W | 675 | dr.as_ptr() as *mut W |
| 702 | } | 676 | } |
| 703 | } | 677 | } |
| 704 | 678 | ||
| @@ -731,7 +705,7 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> { | |||
| 731 | 705 | ||
| 732 | fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { | 706 | fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { |
| 733 | loop { | 707 | loop { |
| 734 | let sr = unsafe { regs.sr().read() }; | 708 | let sr = regs.sr().read(); |
| 735 | 709 | ||
| 736 | check_error_flags(sr)?; | 710 | check_error_flags(sr)?; |
| 737 | 711 | ||
| @@ -748,7 +722,7 @@ fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { | |||
| 748 | 722 | ||
| 749 | fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { | 723 | fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { |
| 750 | loop { | 724 | loop { |
| 751 | let sr = unsafe { regs.sr().read() }; | 725 | let sr = regs.sr().read(); |
| 752 | 726 | ||
| 753 | check_error_flags(sr)?; | 727 | check_error_flags(sr)?; |
| 754 | 728 | ||
| @@ -764,72 +738,64 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { | |||
| 764 | } | 738 | } |
| 765 | 739 | ||
| 766 | fn flush_rx_fifo(regs: Regs) { | 740 | fn flush_rx_fifo(regs: Regs) { |
| 767 | unsafe { | 741 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] |
| 768 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 742 | while regs.sr().read().rxne() { |
| 769 | while regs.sr().read().rxne() { | 743 | let _ = regs.dr().read(); |
| 770 | let _ = regs.dr().read(); | 744 | } |
| 771 | } | 745 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 772 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 746 | while regs.sr().read().rxp() { |
| 773 | while regs.sr().read().rxp() { | 747 | let _ = regs.rxdr().read(); |
| 774 | let _ = regs.rxdr().read(); | ||
| 775 | } | ||
| 776 | } | 748 | } |
| 777 | } | 749 | } |
| 778 | 750 | ||
| 779 | fn set_txdmaen(regs: Regs, val: bool) { | 751 | fn set_txdmaen(regs: Regs, val: bool) { |
| 780 | unsafe { | 752 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] |
| 781 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 753 | regs.cr2().modify(|reg| { |
| 782 | regs.cr2().modify(|reg| { | 754 | reg.set_txdmaen(val); |
| 783 | reg.set_txdmaen(val); | 755 | }); |
| 784 | }); | 756 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 785 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 757 | regs.cfg1().modify(|reg| { |
| 786 | regs.cfg1().modify(|reg| { | 758 | reg.set_txdmaen(val); |
| 787 | reg.set_txdmaen(val); | 759 | }); |
| 788 | }); | ||
| 789 | } | ||
| 790 | } | 760 | } |
| 791 | 761 | ||
| 792 | fn set_rxdmaen(regs: Regs, val: bool) { | 762 | fn set_rxdmaen(regs: Regs, val: bool) { |
| 793 | unsafe { | 763 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] |
| 794 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 764 | regs.cr2().modify(|reg| { |
| 795 | regs.cr2().modify(|reg| { | 765 | reg.set_rxdmaen(val); |
| 796 | reg.set_rxdmaen(val); | 766 | }); |
| 797 | }); | 767 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 798 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 768 | regs.cfg1().modify(|reg| { |
| 799 | regs.cfg1().modify(|reg| { | 769 | reg.set_rxdmaen(val); |
| 800 | reg.set_rxdmaen(val); | 770 | }); |
| 801 | }); | ||
| 802 | } | ||
| 803 | } | 771 | } |
| 804 | 772 | ||
| 805 | fn finish_dma(regs: Regs) { | 773 | fn finish_dma(regs: Regs) { |
| 806 | unsafe { | 774 | #[cfg(spi_v2)] |
| 807 | #[cfg(spi_v2)] | 775 | while regs.sr().read().ftlvl() > 0 {} |
| 808 | while regs.sr().read().ftlvl() > 0 {} | ||
| 809 | 776 | ||
| 810 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 777 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 811 | while !regs.sr().read().txc() {} | 778 | while !regs.sr().read().txc() {} |
| 812 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 779 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] |
| 813 | while regs.sr().read().bsy() {} | 780 | while regs.sr().read().bsy() {} |
| 814 | 781 | ||
| 815 | // Disable the spi peripheral | 782 | // Disable the spi peripheral |
| 816 | regs.cr1().modify(|w| { | 783 | regs.cr1().modify(|w| { |
| 817 | w.set_spe(false); | 784 | w.set_spe(false); |
| 818 | }); | 785 | }); |
| 819 | 786 | ||
| 820 | // The peripheral automatically disables the DMA stream on completion without error, | 787 | // The peripheral automatically disables the DMA stream on completion without error, |
| 821 | // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. | 788 | // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. |
| 822 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] | 789 | #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] |
| 823 | regs.cr2().modify(|reg| { | 790 | regs.cr2().modify(|reg| { |
| 824 | reg.set_txdmaen(false); | 791 | reg.set_txdmaen(false); |
| 825 | reg.set_rxdmaen(false); | 792 | reg.set_rxdmaen(false); |
| 826 | }); | 793 | }); |
| 827 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 794 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 828 | regs.cfg1().modify(|reg| { | 795 | regs.cfg1().modify(|reg| { |
| 829 | reg.set_txdmaen(false); | 796 | reg.set_txdmaen(false); |
| 830 | reg.set_rxdmaen(false); | 797 | reg.set_rxdmaen(false); |
| 831 | }); | 798 | }); |
| 832 | } | ||
| 833 | } | 799 | } |
| 834 | 800 | ||
| 835 | fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> { | 801 | fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> { |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 2236fde28..2622442f4 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -11,7 +11,7 @@ use embassy_time::driver::{AlarmHandle, Driver}; | |||
| 11 | use embassy_time::TICK_HZ; | 11 | use embassy_time::TICK_HZ; |
| 12 | use stm32_metapac::timer::regs; | 12 | use stm32_metapac::timer::regs; |
| 13 | 13 | ||
| 14 | use crate::interrupt::InterruptExt; | 14 | use crate::interrupt::typelevel::Interrupt; |
| 15 | use crate::pac::timer::vals; | 15 | use crate::pac::timer::vals; |
| 16 | use crate::rcc::sealed::RccPeripheral; | 16 | use crate::rcc::sealed::RccPeripheral; |
| 17 | use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; | 17 | use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; |
| @@ -40,6 +40,7 @@ type T = peripherals::TIM15; | |||
| 40 | foreach_interrupt! { | 40 | foreach_interrupt! { |
| 41 | (TIM2, timer, $block:ident, UP, $irq:ident) => { | 41 | (TIM2, timer, $block:ident, UP, $irq:ident) => { |
| 42 | #[cfg(time_driver_tim2)] | 42 | #[cfg(time_driver_tim2)] |
| 43 | #[cfg(feature = "rt")] | ||
| 43 | #[interrupt] | 44 | #[interrupt] |
| 44 | fn $irq() { | 45 | fn $irq() { |
| 45 | DRIVER.on_interrupt() | 46 | DRIVER.on_interrupt() |
| @@ -47,6 +48,7 @@ foreach_interrupt! { | |||
| 47 | }; | 48 | }; |
| 48 | (TIM3, timer, $block:ident, UP, $irq:ident) => { | 49 | (TIM3, timer, $block:ident, UP, $irq:ident) => { |
| 49 | #[cfg(time_driver_tim3)] | 50 | #[cfg(time_driver_tim3)] |
| 51 | #[cfg(feature = "rt")] | ||
| 50 | #[interrupt] | 52 | #[interrupt] |
| 51 | fn $irq() { | 53 | fn $irq() { |
| 52 | DRIVER.on_interrupt() | 54 | DRIVER.on_interrupt() |
| @@ -54,6 +56,7 @@ foreach_interrupt! { | |||
| 54 | }; | 56 | }; |
| 55 | (TIM4, timer, $block:ident, UP, $irq:ident) => { | 57 | (TIM4, timer, $block:ident, UP, $irq:ident) => { |
| 56 | #[cfg(time_driver_tim4)] | 58 | #[cfg(time_driver_tim4)] |
| 59 | #[cfg(feature = "rt")] | ||
| 57 | #[interrupt] | 60 | #[interrupt] |
| 58 | fn $irq() { | 61 | fn $irq() { |
| 59 | DRIVER.on_interrupt() | 62 | DRIVER.on_interrupt() |
| @@ -61,6 +64,7 @@ foreach_interrupt! { | |||
| 61 | }; | 64 | }; |
| 62 | (TIM5, timer, $block:ident, UP, $irq:ident) => { | 65 | (TIM5, timer, $block:ident, UP, $irq:ident) => { |
| 63 | #[cfg(time_driver_tim5)] | 66 | #[cfg(time_driver_tim5)] |
| 67 | #[cfg(feature = "rt")] | ||
| 64 | #[interrupt] | 68 | #[interrupt] |
| 65 | fn $irq() { | 69 | fn $irq() { |
| 66 | DRIVER.on_interrupt() | 70 | DRIVER.on_interrupt() |
| @@ -68,6 +72,7 @@ foreach_interrupt! { | |||
| 68 | }; | 72 | }; |
| 69 | (TIM12, timer, $block:ident, UP, $irq:ident) => { | 73 | (TIM12, timer, $block:ident, UP, $irq:ident) => { |
| 70 | #[cfg(time_driver_tim12)] | 74 | #[cfg(time_driver_tim12)] |
| 75 | #[cfg(feature = "rt")] | ||
| 71 | #[interrupt] | 76 | #[interrupt] |
| 72 | fn $irq() { | 77 | fn $irq() { |
| 73 | DRIVER.on_interrupt() | 78 | DRIVER.on_interrupt() |
| @@ -75,6 +80,7 @@ foreach_interrupt! { | |||
| 75 | }; | 80 | }; |
| 76 | (TIM15, timer, $block:ident, UP, $irq:ident) => { | 81 | (TIM15, timer, $block:ident, UP, $irq:ident) => { |
| 77 | #[cfg(time_driver_tim15)] | 82 | #[cfg(time_driver_tim15)] |
| 83 | #[cfg(feature = "rt")] | ||
| 78 | #[interrupt] | 84 | #[interrupt] |
| 79 | fn $irq() { | 85 | fn $irq() { |
| 80 | DRIVER.on_interrupt() | 86 | DRIVER.on_interrupt() |
| @@ -149,8 +155,7 @@ impl RtcDriver { | |||
| 149 | 155 | ||
| 150 | let timer_freq = T::frequency(); | 156 | let timer_freq = T::frequency(); |
| 151 | 157 | ||
| 152 | // NOTE(unsafe) Critical section to use the unsafe methods | 158 | critical_section::with(|_| { |
| 153 | critical_section::with(|_| unsafe { | ||
| 154 | r.cr1().modify(|w| w.set_cen(false)); | 159 | r.cr1().modify(|w| w.set_cen(false)); |
| 155 | r.cnt().write(|w| w.set_cnt(0)); | 160 | r.cnt().write(|w| w.set_cnt(0)); |
| 156 | 161 | ||
| @@ -177,9 +182,8 @@ impl RtcDriver { | |||
| 177 | w.set_ccie(0, true); | 182 | w.set_ccie(0, true); |
| 178 | }); | 183 | }); |
| 179 | 184 | ||
| 180 | let irq: <T as BasicInstance>::Interrupt = core::mem::transmute(()); | 185 | <T as BasicInstance>::Interrupt::unpend(); |
| 181 | irq.unpend(); | 186 | unsafe { <T as BasicInstance>::Interrupt::enable() }; |
| 182 | irq.enable(); | ||
| 183 | 187 | ||
| 184 | r.cr1().modify(|w| w.set_cen(true)); | 188 | r.cr1().modify(|w| w.set_cen(true)); |
| 185 | }) | 189 | }) |
| @@ -188,9 +192,8 @@ impl RtcDriver { | |||
| 188 | fn on_interrupt(&self) { | 192 | fn on_interrupt(&self) { |
| 189 | let r = T::regs_gp16(); | 193 | let r = T::regs_gp16(); |
| 190 | 194 | ||
| 191 | // NOTE(unsafe) Use critical section to access the methods | ||
| 192 | // XXX: reduce the size of this critical section ? | 195 | // XXX: reduce the size of this critical section ? |
| 193 | critical_section::with(|cs| unsafe { | 196 | critical_section::with(|cs| { |
| 194 | let sr = r.sr().read(); | 197 | let sr = r.sr().read(); |
| 195 | let dier = r.dier().read(); | 198 | let dier = r.dier().read(); |
| 196 | 199 | ||
| @@ -223,7 +226,7 @@ impl RtcDriver { | |||
| 223 | let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; | 226 | let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; |
| 224 | let t = (period as u64) << 15; | 227 | let t = (period as u64) << 15; |
| 225 | 228 | ||
| 226 | critical_section::with(move |cs| unsafe { | 229 | critical_section::with(move |cs| { |
| 227 | r.dier().modify(move |w| { | 230 | r.dier().modify(move |w| { |
| 228 | for n in 0..ALARM_COUNT { | 231 | for n in 0..ALARM_COUNT { |
| 229 | let alarm = &self.alarms.borrow(cs)[n]; | 232 | let alarm = &self.alarms.borrow(cs)[n]; |
| @@ -264,8 +267,7 @@ impl Driver for RtcDriver { | |||
| 264 | 267 | ||
| 265 | let period = self.period.load(Ordering::Relaxed); | 268 | let period = self.period.load(Ordering::Relaxed); |
| 266 | compiler_fence(Ordering::Acquire); | 269 | compiler_fence(Ordering::Acquire); |
| 267 | // NOTE(unsafe) Atomic read with no side-effects | 270 | let counter = r.cnt().read().cnt(); |
| 268 | let counter = unsafe { r.cnt().read().cnt() }; | ||
| 269 | calc_now(period, counter) | 271 | calc_now(period, counter) |
| 270 | } | 272 | } |
| 271 | 273 | ||
| @@ -305,7 +307,7 @@ impl Driver for RtcDriver { | |||
| 305 | if timestamp <= t { | 307 | if timestamp <= t { |
| 306 | // If alarm timestamp has passed the alarm will not fire. | 308 | // If alarm timestamp has passed the alarm will not fire. |
| 307 | // Disarm the alarm and return `false` to indicate that. | 309 | // Disarm the alarm and return `false` to indicate that. |
| 308 | unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) }; | 310 | r.dier().modify(|w| w.set_ccie(n + 1, false)); |
| 309 | 311 | ||
| 310 | alarm.timestamp.set(u64::MAX); | 312 | alarm.timestamp.set(u64::MAX); |
| 311 | 313 | ||
| @@ -316,12 +318,11 @@ impl Driver for RtcDriver { | |||
| 316 | 318 | ||
| 317 | // Write the CCR value regardless of whether we're going to enable it now or not. | 319 | // Write the CCR value regardless of whether we're going to enable it now or not. |
| 318 | // This way, when we enable it later, the right value is already set. | 320 | // This way, when we enable it later, the right value is already set. |
| 319 | unsafe { r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)) }; | 321 | r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)); |
| 320 | 322 | ||
| 321 | // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. | 323 | // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. |
| 322 | let diff = timestamp - t; | 324 | let diff = timestamp - t; |
| 323 | // NOTE(unsafe) We're in a critical section | 325 | r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); |
| 324 | unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) }; | ||
| 325 | 326 | ||
| 326 | true | 327 | true |
| 327 | }) | 328 | }) |
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 772c67686..09b7a3776 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | use stm32_metapac::timer::vals; | 1 | use stm32_metapac::timer::vals; |
| 2 | 2 | ||
| 3 | use crate::interrupt::Interrupt; | 3 | use crate::interrupt; |
| 4 | use crate::rcc::sealed::RccPeripheral as __RccPeri; | 4 | use crate::rcc::sealed::RccPeripheral as __RccPeri; |
| 5 | use crate::rcc::RccPeripheral; | 5 | use crate::rcc::RccPeripheral; |
| 6 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| @@ -13,7 +13,7 @@ pub mod low_level { | |||
| 13 | pub(crate) mod sealed { | 13 | pub(crate) mod sealed { |
| 14 | use super::*; | 14 | use super::*; |
| 15 | pub trait Basic16bitInstance: RccPeripheral { | 15 | pub trait Basic16bitInstance: RccPeripheral { |
| 16 | type Interrupt: Interrupt; | 16 | type Interrupt: interrupt::typelevel::Interrupt; |
| 17 | 17 | ||
| 18 | fn regs() -> crate::pac::timer::TimBasic; | 18 | fn regs() -> crate::pac::timer::TimBasic; |
| 19 | 19 | ||
| @@ -57,28 +57,22 @@ pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} | |||
| 57 | macro_rules! impl_basic_16bit_timer { | 57 | macro_rules! impl_basic_16bit_timer { |
| 58 | ($inst:ident, $irq:ident) => { | 58 | ($inst:ident, $irq:ident) => { |
| 59 | impl sealed::Basic16bitInstance for crate::peripherals::$inst { | 59 | impl sealed::Basic16bitInstance for crate::peripherals::$inst { |
| 60 | type Interrupt = crate::interrupt::$irq; | 60 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 61 | 61 | ||
| 62 | fn regs() -> crate::pac::timer::TimBasic { | 62 | fn regs() -> crate::pac::timer::TimBasic { |
| 63 | crate::pac::timer::TimBasic(crate::pac::$inst.0) | 63 | unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) } |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | fn start(&mut self) { | 66 | fn start(&mut self) { |
| 67 | unsafe { | 67 | Self::regs().cr1().modify(|r| r.set_cen(true)); |
| 68 | Self::regs().cr1().modify(|r| r.set_cen(true)); | ||
| 69 | } | ||
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | fn stop(&mut self) { | 70 | fn stop(&mut self) { |
| 73 | unsafe { | 71 | Self::regs().cr1().modify(|r| r.set_cen(false)); |
| 74 | Self::regs().cr1().modify(|r| r.set_cen(false)); | ||
| 75 | } | ||
| 76 | } | 72 | } |
| 77 | 73 | ||
| 78 | fn reset(&mut self) { | 74 | fn reset(&mut self) { |
| 79 | unsafe { | 75 | Self::regs().cnt().write(|r| r.set_cnt(0)); |
| 80 | Self::regs().cnt().write(|r| r.set_cnt(0)); | ||
| 81 | } | ||
| 82 | } | 76 | } |
| 83 | 77 | ||
| 84 | fn set_frequency(&mut self, frequency: Hertz) { | 78 | fn set_frequency(&mut self, frequency: Hertz) { |
| @@ -90,35 +84,29 @@ macro_rules! impl_basic_16bit_timer { | |||
| 90 | let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); | 84 | let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); |
| 91 | 85 | ||
| 92 | let regs = Self::regs(); | 86 | let regs = Self::regs(); |
| 93 | unsafe { | 87 | regs.psc().write(|r| r.set_psc(psc)); |
| 94 | regs.psc().write(|r| r.set_psc(psc)); | 88 | regs.arr().write(|r| r.set_arr(arr)); |
| 95 | regs.arr().write(|r| r.set_arr(arr)); | ||
| 96 | 89 | ||
| 97 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | 90 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); |
| 98 | regs.egr().write(|r| r.set_ug(true)); | 91 | regs.egr().write(|r| r.set_ug(true)); |
| 99 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | 92 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); |
| 100 | } | ||
| 101 | } | 93 | } |
| 102 | 94 | ||
| 103 | fn clear_update_interrupt(&mut self) -> bool { | 95 | fn clear_update_interrupt(&mut self) -> bool { |
| 104 | let regs = Self::regs(); | 96 | let regs = Self::regs(); |
| 105 | unsafe { | 97 | let sr = regs.sr().read(); |
| 106 | let sr = regs.sr().read(); | 98 | if sr.uif() { |
| 107 | if sr.uif() { | 99 | regs.sr().modify(|r| { |
| 108 | regs.sr().modify(|r| { | 100 | r.set_uif(false); |
| 109 | r.set_uif(false); | 101 | }); |
| 110 | }); | 102 | true |
| 111 | true | 103 | } else { |
| 112 | } else { | 104 | false |
| 113 | false | ||
| 114 | } | ||
| 115 | } | 105 | } |
| 116 | } | 106 | } |
| 117 | 107 | ||
| 118 | fn enable_update_interrupt(&mut self, enable: bool) { | 108 | fn enable_update_interrupt(&mut self, enable: bool) { |
| 119 | unsafe { | 109 | Self::regs().dier().write(|r| r.set_uie(enable)); |
| 120 | Self::regs().dier().write(|r| r.set_uie(enable)); | ||
| 121 | } | ||
| 122 | } | 110 | } |
| 123 | } | 111 | } |
| 124 | }; | 112 | }; |
| @@ -141,14 +129,12 @@ macro_rules! impl_32bit_timer { | |||
| 141 | let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into())); | 129 | let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into())); |
| 142 | 130 | ||
| 143 | let regs = Self::regs_gp32(); | 131 | let regs = Self::regs_gp32(); |
| 144 | unsafe { | 132 | regs.psc().write(|r| r.set_psc(psc)); |
| 145 | regs.psc().write(|r| r.set_psc(psc)); | 133 | regs.arr().write(|r| r.set_arr(arr)); |
| 146 | regs.arr().write(|r| r.set_arr(arr)); | ||
| 147 | 134 | ||
| 148 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); | 135 | regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); |
| 149 | regs.egr().write(|r| r.set_ug(true)); | 136 | regs.egr().write(|r| r.set_ug(true)); |
| 150 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | 137 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); |
| 151 | } | ||
| 152 | } | 138 | } |
| 153 | } | 139 | } |
| 154 | }; | 140 | }; |
| @@ -185,7 +171,7 @@ foreach_interrupt! { | |||
| 185 | 171 | ||
| 186 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { | 172 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { |
| 187 | fn regs_gp16() -> crate::pac::timer::TimGp16 { | 173 | fn regs_gp16() -> crate::pac::timer::TimGp16 { |
| 188 | crate::pac::timer::TimGp16(crate::pac::$inst.0) | 174 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } |
| 189 | } | 175 | } |
| 190 | } | 176 | } |
| 191 | 177 | ||
| @@ -206,7 +192,7 @@ foreach_interrupt! { | |||
| 206 | 192 | ||
| 207 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { | 193 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { |
| 208 | fn regs_gp16() -> crate::pac::timer::TimGp16 { | 194 | fn regs_gp16() -> crate::pac::timer::TimGp16 { |
| 209 | crate::pac::timer::TimGp16(crate::pac::$inst.0) | 195 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } |
| 210 | } | 196 | } |
| 211 | } | 197 | } |
| 212 | 198 | ||
diff --git a/embassy-stm32/src/tl_mbox/ble.rs b/embassy-stm32/src/tl_mbox/ble.rs deleted file mode 100644 index 062377999..000000000 --- a/embassy-stm32/src/tl_mbox/ble.rs +++ /dev/null | |||
| @@ -1,64 +0,0 @@ | |||
| 1 | use embassy_futures::block_on; | ||
| 2 | |||
| 3 | use super::cmd::CmdSerial; | ||
| 4 | use super::consts::TlPacketType; | ||
| 5 | use super::evt::EvtBox; | ||
| 6 | use super::unsafe_linked_list::LinkedListNode; | ||
| 7 | use super::{ | ||
| 8 | channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_CHANNEL, | ||
| 9 | TL_REF_TABLE, | ||
| 10 | }; | ||
| 11 | use crate::tl_mbox::cmd::CmdPacket; | ||
| 12 | use crate::tl_mbox::ipcc::Ipcc; | ||
| 13 | |||
| 14 | pub struct Ble; | ||
| 15 | |||
| 16 | impl Ble { | ||
| 17 | pub fn enable() { | ||
| 18 | unsafe { | ||
| 19 | LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); | ||
| 20 | |||
| 21 | TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable { | ||
| 22 | pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(), | ||
| 23 | pcs_buffer: CS_BUFFER.as_mut_ptr().cast(), | ||
| 24 | pevt_queue: EVT_QUEUE.as_ptr().cast(), | ||
| 25 | phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(), | ||
| 26 | }); | ||
| 27 | } | ||
| 28 | |||
| 29 | Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true); | ||
| 30 | } | ||
| 31 | |||
| 32 | pub fn evt_handler() { | ||
| 33 | unsafe { | ||
| 34 | let mut node_ptr = core::ptr::null_mut(); | ||
| 35 | let node_ptr_ptr: *mut _ = &mut node_ptr; | ||
| 36 | |||
| 37 | while !LinkedListNode::is_empty(EVT_QUEUE.as_mut_ptr()) { | ||
| 38 | LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr(), node_ptr_ptr); | ||
| 39 | |||
| 40 | let event = node_ptr.cast(); | ||
| 41 | let event = EvtBox::new(event); | ||
| 42 | |||
| 43 | block_on(TL_CHANNEL.send(event)); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL); | ||
| 48 | } | ||
| 49 | |||
| 50 | pub fn send_cmd(buf: &[u8]) { | ||
| 51 | unsafe { | ||
| 52 | let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer; | ||
| 53 | let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmd_serial; | ||
| 54 | let pcmd_serial_buf: *mut u8 = pcmd_serial.cast(); | ||
| 55 | |||
| 56 | core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len()); | ||
| 57 | |||
| 58 | let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer; | ||
| 59 | cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8; | ||
| 60 | } | ||
| 61 | |||
| 62 | Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL); | ||
| 63 | } | ||
| 64 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/cmd.rs b/embassy-stm32/src/tl_mbox/cmd.rs deleted file mode 100644 index 3507c3231..000000000 --- a/embassy-stm32/src/tl_mbox/cmd.rs +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | use super::PacketHeader; | ||
| 2 | |||
| 3 | #[repr(C, packed)] | ||
| 4 | #[derive(Copy, Clone)] | ||
| 5 | pub struct Cmd { | ||
| 6 | pub cmd_code: u16, | ||
| 7 | pub payload_len: u8, | ||
| 8 | pub payload: [u8; 255], | ||
| 9 | } | ||
| 10 | |||
| 11 | impl Default for Cmd { | ||
| 12 | fn default() -> Self { | ||
| 13 | Self { | ||
| 14 | cmd_code: 0, | ||
| 15 | payload_len: 0, | ||
| 16 | payload: [0u8; 255], | ||
| 17 | } | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | #[repr(C, packed)] | ||
| 22 | #[derive(Copy, Clone, Default)] | ||
| 23 | pub struct CmdSerial { | ||
| 24 | pub ty: u8, | ||
| 25 | pub cmd: Cmd, | ||
| 26 | } | ||
| 27 | |||
| 28 | #[repr(C, packed)] | ||
| 29 | #[derive(Copy, Clone, Default)] | ||
| 30 | pub struct CmdPacket { | ||
| 31 | pub header: PacketHeader, | ||
| 32 | pub cmd_serial: CmdSerial, | ||
| 33 | } | ||
| 34 | |||
| 35 | #[repr(C, packed)] | ||
| 36 | #[derive(Copy, Clone)] | ||
| 37 | pub struct AclDataSerial { | ||
| 38 | pub ty: u8, | ||
| 39 | pub handle: u16, | ||
| 40 | pub length: u16, | ||
| 41 | pub acl_data: [u8; 1], | ||
| 42 | } | ||
| 43 | |||
| 44 | #[repr(C, packed)] | ||
| 45 | #[derive(Copy, Clone)] | ||
| 46 | pub struct AclDataPacket { | ||
| 47 | pub header: PacketHeader, | ||
| 48 | pub acl_data_serial: AclDataSerial, | ||
| 49 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/evt.rs b/embassy-stm32/src/tl_mbox/evt.rs deleted file mode 100644 index 47a8b72fd..000000000 --- a/embassy-stm32/src/tl_mbox/evt.rs +++ /dev/null | |||
| @@ -1,136 +0,0 @@ | |||
| 1 | use core::mem::MaybeUninit; | ||
| 2 | |||
| 3 | use super::cmd::{AclDataPacket, AclDataSerial}; | ||
| 4 | use super::consts::TlPacketType; | ||
| 5 | use super::{PacketHeader, TL_EVT_HEADER_SIZE}; | ||
| 6 | use crate::tl_mbox::mm::MemoryManager; | ||
| 7 | |||
| 8 | /// the payload of [`Evt`] for a command status event | ||
| 9 | #[derive(Copy, Clone)] | ||
| 10 | #[repr(C, packed)] | ||
| 11 | pub struct CsEvt { | ||
| 12 | pub status: u8, | ||
| 13 | pub num_cmd: u8, | ||
| 14 | pub cmd_code: u16, | ||
| 15 | } | ||
| 16 | |||
| 17 | /// the payload of [`Evt`] for a command complete event | ||
| 18 | #[derive(Clone, Copy, Default)] | ||
| 19 | #[repr(C, packed)] | ||
| 20 | pub struct CcEvt { | ||
| 21 | pub num_cmd: u8, | ||
| 22 | pub cmd_code: u8, | ||
| 23 | pub payload: [u8; 1], | ||
| 24 | } | ||
| 25 | |||
| 26 | #[derive(Clone, Copy, Default)] | ||
| 27 | #[repr(C, packed)] | ||
| 28 | pub struct Evt { | ||
| 29 | pub evt_code: u8, | ||
| 30 | pub payload_len: u8, | ||
| 31 | pub payload: [u8; 1], | ||
| 32 | } | ||
| 33 | |||
| 34 | #[derive(Clone, Copy, Default)] | ||
| 35 | #[repr(C, packed)] | ||
| 36 | pub struct EvtSerial { | ||
| 37 | pub kind: u8, | ||
| 38 | pub evt: Evt, | ||
| 39 | } | ||
| 40 | |||
| 41 | /// This format shall be used for all events (asynchronous and command response) reported | ||
| 42 | /// by the CPU2 except for the command response of a system command where the header is not there | ||
| 43 | /// and the format to be used shall be `EvtSerial`. | ||
| 44 | /// | ||
| 45 | /// ### Note: | ||
| 46 | /// Be careful that the asynchronous events reported by the CPU2 on the system channel do | ||
| 47 | /// include the header and shall use `EvtPacket` format. Only the command response format on the | ||
| 48 | /// system channel is different. | ||
| 49 | #[derive(Clone, Copy, Default)] | ||
| 50 | #[repr(C, packed)] | ||
| 51 | pub struct EvtPacket { | ||
| 52 | pub header: PacketHeader, | ||
| 53 | pub evt_serial: EvtSerial, | ||
| 54 | } | ||
| 55 | |||
| 56 | /// Smart pointer to the [`EvtPacket`] that will dispose of it automatically on drop | ||
| 57 | pub struct EvtBox { | ||
| 58 | ptr: *mut EvtPacket, | ||
| 59 | } | ||
| 60 | |||
| 61 | unsafe impl Send for EvtBox {} | ||
| 62 | impl EvtBox { | ||
| 63 | pub(super) fn new(ptr: *mut EvtPacket) -> Self { | ||
| 64 | Self { ptr } | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Copies the event data from inner pointer and returns and event structure | ||
| 68 | pub fn evt(&self) -> EvtPacket { | ||
| 69 | let mut evt = MaybeUninit::uninit(); | ||
| 70 | unsafe { | ||
| 71 | self.ptr.copy_to(evt.as_mut_ptr(), 1); | ||
| 72 | evt.assume_init() | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | /// Returns the size of a buffer required to hold this event | ||
| 77 | pub fn size(&self) -> Result<usize, ()> { | ||
| 78 | unsafe { | ||
| 79 | let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?; | ||
| 80 | |||
| 81 | if evt_kind == TlPacketType::AclData { | ||
| 82 | let acl_data: *const AclDataPacket = self.ptr.cast(); | ||
| 83 | let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial; | ||
| 84 | |||
| 85 | Ok((*acl_serial).length as usize + 5) | ||
| 86 | } else { | ||
| 87 | let evt_data: *const EvtPacket = self.ptr.cast(); | ||
| 88 | let evt_serial: *const EvtSerial = &(*evt_data).evt_serial; | ||
| 89 | |||
| 90 | Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE) | ||
| 91 | } | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | /// writes an underlying [`EvtPacket`] into the provided buffer. Returns the number of bytes that were | ||
| 96 | /// written. Returns an error if event kind is unkown or if provided buffer size is not enough | ||
| 97 | pub fn copy_into_slice(&self, buf: &mut [u8]) -> Result<usize, ()> { | ||
| 98 | unsafe { | ||
| 99 | let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?; | ||
| 100 | |||
| 101 | let evt_data: *const EvtPacket = self.ptr.cast(); | ||
| 102 | let evt_serial: *const EvtSerial = &(*evt_data).evt_serial; | ||
| 103 | let evt_serial_buf: *const u8 = evt_serial.cast(); | ||
| 104 | |||
| 105 | let acl_data: *const AclDataPacket = self.ptr.cast(); | ||
| 106 | let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial; | ||
| 107 | let acl_serial_buf: *const u8 = acl_serial.cast(); | ||
| 108 | |||
| 109 | if let TlPacketType::AclData = evt_kind { | ||
| 110 | let len = (*acl_serial).length as usize + 5; | ||
| 111 | if len > buf.len() { | ||
| 112 | return Err(()); | ||
| 113 | } | ||
| 114 | |||
| 115 | core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len); | ||
| 116 | |||
| 117 | Ok(len) | ||
| 118 | } else { | ||
| 119 | let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE; | ||
| 120 | if len > buf.len() { | ||
| 121 | return Err(()); | ||
| 122 | } | ||
| 123 | |||
| 124 | core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len); | ||
| 125 | |||
| 126 | Ok(len) | ||
| 127 | } | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | impl Drop for EvtBox { | ||
| 133 | fn drop(&mut self) { | ||
| 134 | MemoryManager::evt_drop(self.ptr); | ||
| 135 | } | ||
| 136 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/ipcc.rs b/embassy-stm32/src/tl_mbox/ipcc.rs deleted file mode 100644 index d1ac731ed..000000000 --- a/embassy-stm32/src/tl_mbox/ipcc.rs +++ /dev/null | |||
| @@ -1,174 +0,0 @@ | |||
| 1 | use self::sealed::Instance; | ||
| 2 | use crate::peripherals::IPCC; | ||
| 3 | use crate::rcc::sealed::RccPeripheral; | ||
| 4 | |||
| 5 | #[non_exhaustive] | ||
| 6 | #[derive(Clone, Copy, Default)] | ||
| 7 | pub struct Config { | ||
| 8 | // TODO: add IPCC peripheral configuration, if any, here | ||
| 9 | // reserved for future use | ||
| 10 | } | ||
| 11 | |||
| 12 | #[derive(Debug, Clone, Copy)] | ||
| 13 | #[repr(C)] | ||
| 14 | pub enum IpccChannel { | ||
| 15 | Channel1 = 0, | ||
| 16 | Channel2 = 1, | ||
| 17 | Channel3 = 2, | ||
| 18 | Channel4 = 3, | ||
| 19 | Channel5 = 4, | ||
| 20 | Channel6 = 5, | ||
| 21 | } | ||
| 22 | |||
| 23 | pub mod sealed { | ||
| 24 | pub trait Instance: crate::rcc::RccPeripheral { | ||
| 25 | fn regs() -> crate::pac::ipcc::Ipcc; | ||
| 26 | fn set_cpu2(enabled: bool); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | pub struct Ipcc; | ||
| 31 | |||
| 32 | impl Ipcc { | ||
| 33 | pub fn enable(_config: Config) { | ||
| 34 | IPCC::enable(); | ||
| 35 | IPCC::reset(); | ||
| 36 | IPCC::set_cpu2(true); | ||
| 37 | |||
| 38 | unsafe { _configure_pwr() }; | ||
| 39 | |||
| 40 | let regs = IPCC::regs(); | ||
| 41 | |||
| 42 | unsafe { | ||
| 43 | regs.cpu(0).cr().modify(|w| { | ||
| 44 | w.set_rxoie(true); | ||
| 45 | w.set_txfie(true); | ||
| 46 | }) | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | pub fn c1_set_rx_channel(channel: IpccChannel, enabled: bool) { | ||
| 51 | let regs = IPCC::regs(); | ||
| 52 | |||
| 53 | // If bit is set to 1 then interrupt is disabled | ||
| 54 | unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, !enabled)) } | ||
| 55 | } | ||
| 56 | |||
| 57 | pub fn c1_get_rx_channel(channel: IpccChannel) -> bool { | ||
| 58 | let regs = IPCC::regs(); | ||
| 59 | |||
| 60 | // If bit is set to 1 then interrupt is disabled | ||
| 61 | unsafe { !regs.cpu(0).mr().read().chom(channel as usize) } | ||
| 62 | } | ||
| 63 | |||
| 64 | #[allow(dead_code)] | ||
| 65 | pub fn c2_set_rx_channel(channel: IpccChannel, enabled: bool) { | ||
| 66 | let regs = IPCC::regs(); | ||
| 67 | |||
| 68 | // If bit is set to 1 then interrupt is disabled | ||
| 69 | unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel as usize, !enabled)) } | ||
| 70 | } | ||
| 71 | |||
| 72 | #[allow(dead_code)] | ||
| 73 | pub fn c2_get_rx_channel(channel: IpccChannel) -> bool { | ||
| 74 | let regs = IPCC::regs(); | ||
| 75 | |||
| 76 | // If bit is set to 1 then interrupt is disabled | ||
| 77 | unsafe { !regs.cpu(1).mr().read().chom(channel as usize) } | ||
| 78 | } | ||
| 79 | |||
| 80 | pub fn c1_set_tx_channel(channel: IpccChannel, enabled: bool) { | ||
| 81 | let regs = IPCC::regs(); | ||
| 82 | |||
| 83 | // If bit is set to 1 then interrupt is disabled | ||
| 84 | unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) } | ||
| 85 | } | ||
| 86 | |||
| 87 | pub fn c1_get_tx_channel(channel: IpccChannel) -> bool { | ||
| 88 | let regs = IPCC::regs(); | ||
| 89 | |||
| 90 | // If bit is set to 1 then interrupt is disabled | ||
| 91 | unsafe { !regs.cpu(0).mr().read().chfm(channel as usize) } | ||
| 92 | } | ||
| 93 | |||
| 94 | #[allow(dead_code)] | ||
| 95 | pub fn c2_set_tx_channel(channel: IpccChannel, enabled: bool) { | ||
| 96 | let regs = IPCC::regs(); | ||
| 97 | |||
| 98 | // If bit is set to 1 then interrupt is disabled | ||
| 99 | unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) } | ||
| 100 | } | ||
| 101 | |||
| 102 | #[allow(dead_code)] | ||
| 103 | pub fn c2_get_tx_channel(channel: IpccChannel) -> bool { | ||
| 104 | let regs = IPCC::regs(); | ||
| 105 | |||
| 106 | // If bit is set to 1 then interrupt is disabled | ||
| 107 | unsafe { !regs.cpu(1).mr().read().chfm(channel as usize) } | ||
| 108 | } | ||
| 109 | |||
| 110 | /// clears IPCC receive channel status for CPU1 | ||
| 111 | pub fn c1_clear_flag_channel(channel: IpccChannel) { | ||
| 112 | let regs = IPCC::regs(); | ||
| 113 | |||
| 114 | unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) } | ||
| 115 | } | ||
| 116 | |||
| 117 | #[allow(dead_code)] | ||
| 118 | /// clears IPCC receive channel status for CPU2 | ||
| 119 | pub fn c2_clear_flag_channel(channel: IpccChannel) { | ||
| 120 | let regs = IPCC::regs(); | ||
| 121 | |||
| 122 | unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel as usize, true)) } | ||
| 123 | } | ||
| 124 | |||
| 125 | pub fn c1_set_flag_channel(channel: IpccChannel) { | ||
| 126 | let regs = IPCC::regs(); | ||
| 127 | |||
| 128 | unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) } | ||
| 129 | } | ||
| 130 | |||
| 131 | #[allow(dead_code)] | ||
| 132 | pub fn c2_set_flag_channel(channel: IpccChannel) { | ||
| 133 | let regs = IPCC::regs(); | ||
| 134 | |||
| 135 | unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel as usize, true)) } | ||
| 136 | } | ||
| 137 | |||
| 138 | pub fn c1_is_active_flag(channel: IpccChannel) -> bool { | ||
| 139 | let regs = IPCC::regs(); | ||
| 140 | |||
| 141 | unsafe { regs.cpu(0).sr().read().chf(channel as usize) } | ||
| 142 | } | ||
| 143 | |||
| 144 | pub fn c2_is_active_flag(channel: IpccChannel) -> bool { | ||
| 145 | let regs = IPCC::regs(); | ||
| 146 | |||
| 147 | unsafe { regs.cpu(1).sr().read().chf(channel as usize) } | ||
| 148 | } | ||
| 149 | |||
| 150 | pub fn is_tx_pending(channel: IpccChannel) -> bool { | ||
| 151 | !Self::c1_is_active_flag(channel) && Self::c1_get_tx_channel(channel) | ||
| 152 | } | ||
| 153 | |||
| 154 | pub fn is_rx_pending(channel: IpccChannel) -> bool { | ||
| 155 | Self::c2_is_active_flag(channel) && Self::c1_get_rx_channel(channel) | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | impl sealed::Instance for crate::peripherals::IPCC { | ||
| 160 | fn regs() -> crate::pac::ipcc::Ipcc { | ||
| 161 | crate::pac::IPCC | ||
| 162 | } | ||
| 163 | |||
| 164 | fn set_cpu2(enabled: bool) { | ||
| 165 | unsafe { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)) } | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | unsafe fn _configure_pwr() { | ||
| 170 | let rcc = crate::pac::RCC; | ||
| 171 | |||
| 172 | // set RF wake-up clock = LSE | ||
| 173 | rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); | ||
| 174 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/mm.rs b/embassy-stm32/src/tl_mbox/mm.rs deleted file mode 100644 index e28a6aa0c..000000000 --- a/embassy-stm32/src/tl_mbox/mm.rs +++ /dev/null | |||
| @@ -1,67 +0,0 @@ | |||
| 1 | use super::evt::EvtPacket; | ||
| 2 | use super::unsafe_linked_list::LinkedListNode; | ||
| 3 | use super::{ | ||
| 4 | channels, MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, | ||
| 5 | SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, TL_REF_TABLE, | ||
| 6 | }; | ||
| 7 | use crate::tl_mbox::ipcc::Ipcc; | ||
| 8 | |||
| 9 | pub struct MemoryManager; | ||
| 10 | |||
| 11 | impl MemoryManager { | ||
| 12 | pub fn enable() { | ||
| 13 | unsafe { | ||
| 14 | LinkedListNode::init_head(FREE_BUFF_QUEUE.as_mut_ptr()); | ||
| 15 | LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()); | ||
| 16 | |||
| 17 | TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable { | ||
| 18 | spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(), | ||
| 19 | spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(), | ||
| 20 | ble_pool: EVT_POOL.as_ptr().cast(), | ||
| 21 | ble_pool_size: POOL_SIZE as u32, | ||
| 22 | pevt_free_buffer_queue: FREE_BUFF_QUEUE.as_mut_ptr(), | ||
| 23 | traces_evt_pool: core::ptr::null(), | ||
| 24 | traces_pool_size: 0, | ||
| 25 | }); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | pub fn evt_handler() { | ||
| 30 | Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false); | ||
| 31 | Self::send_free_buf(); | ||
| 32 | Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); | ||
| 33 | } | ||
| 34 | |||
| 35 | pub fn evt_drop(evt: *mut EvtPacket) { | ||
| 36 | unsafe { | ||
| 37 | let list_node = evt.cast(); | ||
| 38 | |||
| 39 | LinkedListNode::remove_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node); | ||
| 40 | } | ||
| 41 | |||
| 42 | let channel_is_busy = Ipcc::c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); | ||
| 43 | |||
| 44 | // postpone event buffer freeing to IPCC interrupt handler | ||
| 45 | if channel_is_busy { | ||
| 46 | Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true); | ||
| 47 | } else { | ||
| 48 | Self::send_free_buf(); | ||
| 49 | Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | fn send_free_buf() { | ||
| 54 | unsafe { | ||
| 55 | let mut node_ptr = core::ptr::null_mut(); | ||
| 56 | let node_ptr_ptr: *mut _ = &mut node_ptr; | ||
| 57 | |||
| 58 | while !LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { | ||
| 59 | LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr); | ||
| 60 | LinkedListNode::insert_tail( | ||
| 61 | (*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue, | ||
| 62 | node_ptr, | ||
| 63 | ); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/mod.rs b/embassy-stm32/src/tl_mbox/mod.rs deleted file mode 100644 index 616f7dc56..000000000 --- a/embassy-stm32/src/tl_mbox/mod.rs +++ /dev/null | |||
| @@ -1,417 +0,0 @@ | |||
| 1 | use core::mem::MaybeUninit; | ||
| 2 | |||
| 3 | use atomic_polyfill::{compiler_fence, Ordering}; | ||
| 4 | use bit_field::BitField; | ||
| 5 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 6 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | ||
| 7 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 8 | use embassy_sync::channel::Channel; | ||
| 9 | |||
| 10 | use self::ble::Ble; | ||
| 11 | use self::cmd::{AclDataPacket, CmdPacket}; | ||
| 12 | use self::evt::{CsEvt, EvtBox}; | ||
| 13 | use self::mm::MemoryManager; | ||
| 14 | use self::shci::{shci_ble_init, ShciBleInitCmdParam}; | ||
| 15 | use self::sys::Sys; | ||
| 16 | use self::unsafe_linked_list::LinkedListNode; | ||
| 17 | use crate::interrupt; | ||
| 18 | use crate::peripherals::IPCC; | ||
| 19 | pub use crate::tl_mbox::ipcc::Config; | ||
| 20 | use crate::tl_mbox::ipcc::Ipcc; | ||
| 21 | |||
| 22 | mod ble; | ||
| 23 | mod channels; | ||
| 24 | mod cmd; | ||
| 25 | mod consts; | ||
| 26 | mod evt; | ||
| 27 | mod ipcc; | ||
| 28 | mod mm; | ||
| 29 | mod shci; | ||
| 30 | mod sys; | ||
| 31 | mod unsafe_linked_list; | ||
| 32 | |||
| 33 | pub type PacketHeader = LinkedListNode; | ||
| 34 | |||
| 35 | const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>(); | ||
| 36 | const TL_EVT_HEADER_SIZE: usize = 3; | ||
| 37 | const TL_CS_EVT_SIZE: usize = core::mem::size_of::<CsEvt>(); | ||
| 38 | |||
| 39 | const CFG_TL_BLE_EVT_QUEUE_LENGTH: usize = 5; | ||
| 40 | const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255; | ||
| 41 | const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE; | ||
| 42 | |||
| 43 | const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4); | ||
| 44 | |||
| 45 | const fn divc(x: usize, y: usize) -> usize { | ||
| 46 | (x + y - 1) / y | ||
| 47 | } | ||
| 48 | |||
| 49 | #[repr(C, packed)] | ||
| 50 | #[derive(Copy, Clone)] | ||
| 51 | pub struct SafeBootInfoTable { | ||
| 52 | version: u32, | ||
| 53 | } | ||
| 54 | |||
| 55 | #[repr(C, packed)] | ||
| 56 | #[derive(Copy, Clone)] | ||
| 57 | pub struct FusInfoTable { | ||
| 58 | version: u32, | ||
| 59 | memory_size: u32, | ||
| 60 | fus_info: u32, | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Interrupt handler. | ||
| 64 | pub struct ReceiveInterruptHandler {} | ||
| 65 | |||
| 66 | impl interrupt::Handler<interrupt::IPCC_C1_RX> for ReceiveInterruptHandler { | ||
| 67 | unsafe fn on_interrupt() { | ||
| 68 | // info!("ipcc rx interrupt"); | ||
| 69 | |||
| 70 | if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) { | ||
| 71 | sys::Sys::evt_handler(); | ||
| 72 | } else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) { | ||
| 73 | ble::Ble::evt_handler(); | ||
| 74 | } else { | ||
| 75 | todo!() | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | pub struct TransmitInterruptHandler {} | ||
| 81 | |||
| 82 | impl interrupt::Handler<interrupt::IPCC_C1_TX> for TransmitInterruptHandler { | ||
| 83 | unsafe fn on_interrupt() { | ||
| 84 | // info!("ipcc tx interrupt"); | ||
| 85 | |||
| 86 | if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) { | ||
| 87 | // TODO: handle this case | ||
| 88 | let _ = sys::Sys::cmd_evt_handler(); | ||
| 89 | } else if Ipcc::is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) { | ||
| 90 | mm::MemoryManager::evt_handler(); | ||
| 91 | } else { | ||
| 92 | todo!() | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | /// # Version | ||
| 98 | /// - 0 -> 3 = Build - 0: Untracked - 15:Released - x: Tracked version | ||
| 99 | /// - 4 -> 7 = branch - 0: Mass Market - x: ... | ||
| 100 | /// - 8 -> 15 = Subversion | ||
| 101 | /// - 16 -> 23 = Version minor | ||
| 102 | /// - 24 -> 31 = Version major | ||
| 103 | /// # Memory Size | ||
| 104 | /// - 0 -> 7 = Flash ( Number of 4k sector) | ||
| 105 | /// - 8 -> 15 = Reserved ( Shall be set to 0 - may be used as flash extension ) | ||
| 106 | /// - 16 -> 23 = SRAM2b ( Number of 1k sector) | ||
| 107 | /// - 24 -> 31 = SRAM2a ( Number of 1k sector) | ||
| 108 | #[repr(C, packed)] | ||
| 109 | #[derive(Copy, Clone)] | ||
| 110 | pub struct WirelessFwInfoTable { | ||
| 111 | version: u32, | ||
| 112 | memory_size: u32, | ||
| 113 | info_stack: u32, | ||
| 114 | reserved: u32, | ||
| 115 | } | ||
| 116 | |||
| 117 | impl WirelessFwInfoTable { | ||
| 118 | pub fn version_major(&self) -> u8 { | ||
| 119 | let version = self.version; | ||
| 120 | (version.get_bits(24..31) & 0xff) as u8 | ||
| 121 | } | ||
| 122 | |||
| 123 | pub fn version_minor(&self) -> u8 { | ||
| 124 | let version = self.version; | ||
| 125 | (version.get_bits(16..23) & 0xff) as u8 | ||
| 126 | } | ||
| 127 | |||
| 128 | pub fn subversion(&self) -> u8 { | ||
| 129 | let version = self.version; | ||
| 130 | (version.get_bits(8..15) & 0xff) as u8 | ||
| 131 | } | ||
| 132 | |||
| 133 | /// size of FLASH, expressed in number of 4K sectors | ||
| 134 | pub fn flash_size(&self) -> u8 { | ||
| 135 | let memory_size = self.memory_size; | ||
| 136 | (memory_size.get_bits(0..7) & 0xff) as u8 | ||
| 137 | } | ||
| 138 | |||
| 139 | /// size for SRAM2a, expressed in number of 1K sectors | ||
| 140 | pub fn sram2a_size(&self) -> u8 { | ||
| 141 | let memory_size = self.memory_size; | ||
| 142 | (memory_size.get_bits(24..31) & 0xff) as u8 | ||
| 143 | } | ||
| 144 | |||
| 145 | /// size of SRAM2b, expressed in number of 1K sectors | ||
| 146 | pub fn sram2b_size(&self) -> u8 { | ||
| 147 | let memory_size = self.memory_size; | ||
| 148 | (memory_size.get_bits(16..23) & 0xff) as u8 | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | #[repr(C, packed)] | ||
| 153 | #[derive(Copy, Clone)] | ||
| 154 | pub struct DeviceInfoTable { | ||
| 155 | pub safe_boot_info_table: SafeBootInfoTable, | ||
| 156 | pub fus_info_table: FusInfoTable, | ||
| 157 | pub wireless_fw_info_table: WirelessFwInfoTable, | ||
| 158 | } | ||
| 159 | |||
| 160 | #[repr(C, packed)] | ||
| 161 | struct BleTable { | ||
| 162 | pcmd_buffer: *mut CmdPacket, | ||
| 163 | pcs_buffer: *const u8, | ||
| 164 | pevt_queue: *const u8, | ||
| 165 | phci_acl_data_buffer: *mut AclDataPacket, | ||
| 166 | } | ||
| 167 | |||
| 168 | #[repr(C, packed)] | ||
| 169 | struct ThreadTable { | ||
| 170 | no_stack_buffer: *const u8, | ||
| 171 | cli_cmd_rsp_buffer: *const u8, | ||
| 172 | ot_cmd_rsp_buffer: *const u8, | ||
| 173 | } | ||
| 174 | |||
| 175 | #[repr(C, packed)] | ||
| 176 | struct SysTable { | ||
| 177 | pcmd_buffer: *mut CmdPacket, | ||
| 178 | sys_queue: *const LinkedListNode, | ||
| 179 | } | ||
| 180 | |||
| 181 | #[allow(dead_code)] // Not used currently but reserved | ||
| 182 | #[repr(C, packed)] | ||
| 183 | struct LldTestTable { | ||
| 184 | cli_cmd_rsp_buffer: *const u8, | ||
| 185 | m0_cmd_buffer: *const u8, | ||
| 186 | } | ||
| 187 | |||
| 188 | #[allow(dead_code)] // Not used currently but reserved | ||
| 189 | #[repr(C, packed)] | ||
| 190 | struct BleLldTable { | ||
| 191 | cmd_rsp_buffer: *const u8, | ||
| 192 | m0_cmd_buffer: *const u8, | ||
| 193 | } | ||
| 194 | |||
| 195 | #[allow(dead_code)] // Not used currently but reserved | ||
| 196 | #[repr(C, packed)] | ||
| 197 | struct ZigbeeTable { | ||
| 198 | notif_m0_to_m4_buffer: *const u8, | ||
| 199 | appli_cmd_m4_to_m0_buffer: *const u8, | ||
| 200 | request_m0_to_m4_buffer: *const u8, | ||
| 201 | } | ||
| 202 | |||
| 203 | #[repr(C, packed)] | ||
| 204 | struct MemManagerTable { | ||
| 205 | spare_ble_buffer: *const u8, | ||
| 206 | spare_sys_buffer: *const u8, | ||
| 207 | |||
| 208 | ble_pool: *const u8, | ||
| 209 | ble_pool_size: u32, | ||
| 210 | |||
| 211 | pevt_free_buffer_queue: *mut LinkedListNode, | ||
| 212 | |||
| 213 | traces_evt_pool: *const u8, | ||
| 214 | traces_pool_size: u32, | ||
| 215 | } | ||
| 216 | |||
| 217 | #[repr(C, packed)] | ||
| 218 | struct TracesTable { | ||
| 219 | traces_queue: *const u8, | ||
| 220 | } | ||
| 221 | |||
| 222 | #[repr(C, packed)] | ||
| 223 | struct Mac802_15_4Table { | ||
| 224 | pcmd_rsp_buffer: *const u8, | ||
| 225 | pnotack_buffer: *const u8, | ||
| 226 | evt_queue: *const u8, | ||
| 227 | } | ||
| 228 | |||
| 229 | /// reference table. Contains pointers to all other tables | ||
| 230 | #[repr(C, packed)] | ||
| 231 | #[derive(Copy, Clone)] | ||
| 232 | pub struct RefTable { | ||
| 233 | pub device_info_table: *const DeviceInfoTable, | ||
| 234 | ble_table: *const BleTable, | ||
| 235 | thread_table: *const ThreadTable, | ||
| 236 | sys_table: *const SysTable, | ||
| 237 | mem_manager_table: *const MemManagerTable, | ||
| 238 | traces_table: *const TracesTable, | ||
| 239 | mac_802_15_4_table: *const Mac802_15_4Table, | ||
| 240 | zigbee_table: *const ZigbeeTable, | ||
| 241 | lld_tests_table: *const LldTestTable, | ||
| 242 | ble_lld_table: *const BleLldTable, | ||
| 243 | } | ||
| 244 | |||
| 245 | #[link_section = "TL_REF_TABLE"] | ||
| 246 | pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit(); | ||
| 247 | |||
| 248 | #[link_section = "MB_MEM1"] | ||
| 249 | static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit(); | ||
| 250 | |||
| 251 | #[link_section = "MB_MEM1"] | ||
| 252 | static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit(); | ||
| 253 | |||
| 254 | #[link_section = "MB_MEM1"] | ||
| 255 | static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit(); | ||
| 256 | |||
| 257 | #[link_section = "MB_MEM1"] | ||
| 258 | static mut TL_LLD_TESTS_TABLE: MaybeUninit<LldTestTable> = MaybeUninit::uninit(); | ||
| 259 | |||
| 260 | #[link_section = "MB_MEM1"] | ||
| 261 | static mut TL_BLE_LLD_TABLE: MaybeUninit<BleLldTable> = MaybeUninit::uninit(); | ||
| 262 | |||
| 263 | #[link_section = "MB_MEM1"] | ||
| 264 | static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit(); | ||
| 265 | |||
| 266 | #[link_section = "MB_MEM1"] | ||
| 267 | static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit(); | ||
| 268 | |||
| 269 | #[link_section = "MB_MEM1"] | ||
| 270 | static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit(); | ||
| 271 | |||
| 272 | #[link_section = "MB_MEM1"] | ||
| 273 | static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit(); | ||
| 274 | |||
| 275 | #[link_section = "MB_MEM1"] | ||
| 276 | static mut TL_ZIGBEE_TABLE: MaybeUninit<ZigbeeTable> = MaybeUninit::uninit(); | ||
| 277 | |||
| 278 | #[allow(dead_code)] // Not used currently but reserved | ||
| 279 | #[link_section = "MB_MEM1"] | ||
| 280 | static mut FREE_BUFF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 281 | |||
| 282 | // not in shared RAM | ||
| 283 | static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 284 | |||
| 285 | #[link_section = "MB_MEM2"] | ||
| 286 | static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> = | ||
| 287 | MaybeUninit::uninit(); | ||
| 288 | |||
| 289 | #[link_section = "MB_MEM2"] | ||
| 290 | static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 291 | |||
| 292 | #[link_section = "MB_MEM2"] | ||
| 293 | static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit(); | ||
| 294 | |||
| 295 | #[link_section = "MB_MEM2"] | ||
| 296 | static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit(); | ||
| 297 | |||
| 298 | #[link_section = "MB_MEM2"] | ||
| 299 | static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); | ||
| 300 | |||
| 301 | #[link_section = "MB_MEM2"] | ||
| 302 | static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = | ||
| 303 | MaybeUninit::uninit(); | ||
| 304 | |||
| 305 | #[link_section = "MB_MEM2"] | ||
| 306 | static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = | ||
| 307 | MaybeUninit::uninit(); | ||
| 308 | |||
| 309 | #[link_section = "MB_MEM2"] | ||
| 310 | static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit(); | ||
| 311 | |||
| 312 | #[link_section = "MB_MEM2"] | ||
| 313 | // "magic" numbers from ST ---v---v | ||
| 314 | static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit(); | ||
| 315 | |||
| 316 | // TODO: get a better size, this is a placeholder | ||
| 317 | pub(crate) static TL_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 5> = Channel::new(); | ||
| 318 | |||
| 319 | pub struct TlMbox<'d> { | ||
| 320 | _ipcc: PeripheralRef<'d, IPCC>, | ||
| 321 | } | ||
| 322 | |||
| 323 | impl<'d> TlMbox<'d> { | ||
| 324 | /// initializes low-level transport between CPU1 and BLE stack on CPU2 | ||
| 325 | pub fn new( | ||
| 326 | ipcc: impl Peripheral<P = IPCC> + 'd, | ||
| 327 | _irqs: impl interrupt::Binding<interrupt::IPCC_C1_RX, ReceiveInterruptHandler> | ||
| 328 | + interrupt::Binding<interrupt::IPCC_C1_TX, TransmitInterruptHandler>, | ||
| 329 | config: Config, | ||
| 330 | ) -> Self { | ||
| 331 | into_ref!(ipcc); | ||
| 332 | |||
| 333 | unsafe { | ||
| 334 | compiler_fence(Ordering::AcqRel); | ||
| 335 | |||
| 336 | TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable { | ||
| 337 | device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), | ||
| 338 | ble_table: TL_BLE_TABLE.as_ptr(), | ||
| 339 | thread_table: TL_THREAD_TABLE.as_ptr(), | ||
| 340 | sys_table: TL_SYS_TABLE.as_ptr(), | ||
| 341 | mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(), | ||
| 342 | traces_table: TL_TRACES_TABLE.as_ptr(), | ||
| 343 | mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(), | ||
| 344 | zigbee_table: TL_ZIGBEE_TABLE.as_ptr(), | ||
| 345 | lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(), | ||
| 346 | ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(), | ||
| 347 | }); | ||
| 348 | |||
| 349 | // info!("TL_REF_TABLE addr: {:x}", TL_REF_TABLE.as_ptr() as usize); | ||
| 350 | |||
| 351 | compiler_fence(Ordering::AcqRel); | ||
| 352 | |||
| 353 | TL_SYS_TABLE = MaybeUninit::zeroed(); | ||
| 354 | TL_DEVICE_INFO_TABLE = MaybeUninit::zeroed(); | ||
| 355 | TL_BLE_TABLE = MaybeUninit::zeroed(); | ||
| 356 | TL_THREAD_TABLE = MaybeUninit::zeroed(); | ||
| 357 | TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed(); | ||
| 358 | TL_TRACES_TABLE = MaybeUninit::zeroed(); | ||
| 359 | TL_MAC_802_15_4_TABLE = MaybeUninit::zeroed(); | ||
| 360 | TL_ZIGBEE_TABLE = MaybeUninit::zeroed(); | ||
| 361 | TL_LLD_TESTS_TABLE = MaybeUninit::zeroed(); | ||
| 362 | TL_BLE_LLD_TABLE = MaybeUninit::zeroed(); | ||
| 363 | |||
| 364 | EVT_POOL = MaybeUninit::zeroed(); | ||
| 365 | SYS_SPARE_EVT_BUF = MaybeUninit::zeroed(); | ||
| 366 | BLE_SPARE_EVT_BUF = MaybeUninit::zeroed(); | ||
| 367 | |||
| 368 | CS_BUFFER = MaybeUninit::zeroed(); | ||
| 369 | BLE_CMD_BUFFER = MaybeUninit::zeroed(); | ||
| 370 | HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed(); | ||
| 371 | |||
| 372 | compiler_fence(Ordering::AcqRel); | ||
| 373 | } | ||
| 374 | |||
| 375 | Ipcc::enable(config); | ||
| 376 | |||
| 377 | Sys::enable(); | ||
| 378 | Ble::enable(); | ||
| 379 | MemoryManager::enable(); | ||
| 380 | |||
| 381 | // enable interrupts | ||
| 382 | unsafe { crate::interrupt::IPCC_C1_RX::steal() }.unpend(); | ||
| 383 | unsafe { crate::interrupt::IPCC_C1_TX::steal() }.unpend(); | ||
| 384 | |||
| 385 | unsafe { crate::interrupt::IPCC_C1_RX::steal() }.enable(); | ||
| 386 | unsafe { crate::interrupt::IPCC_C1_TX::steal() }.enable(); | ||
| 387 | |||
| 388 | Self { _ipcc: ipcc } | ||
| 389 | } | ||
| 390 | |||
| 391 | pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> { | ||
| 392 | let info = unsafe { &(*(*TL_REF_TABLE.as_ptr()).device_info_table).wireless_fw_info_table }; | ||
| 393 | |||
| 394 | // zero version indicates that CPU2 wasn't active and didn't fill the information table | ||
| 395 | if info.version != 0 { | ||
| 396 | Some(*info) | ||
| 397 | } else { | ||
| 398 | None | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | pub fn shci_ble_init(&self, param: ShciBleInitCmdParam) { | ||
| 403 | shci_ble_init(param); | ||
| 404 | } | ||
| 405 | |||
| 406 | pub fn send_ble_cmd(&self, buf: &[u8]) { | ||
| 407 | ble::Ble::send_cmd(buf); | ||
| 408 | } | ||
| 409 | |||
| 410 | // pub fn send_sys_cmd(&self, buf: &[u8]) { | ||
| 411 | // sys::Sys::send_cmd(buf); | ||
| 412 | // } | ||
| 413 | |||
| 414 | pub async fn read(&self) -> EvtBox { | ||
| 415 | TL_CHANNEL.recv().await | ||
| 416 | } | ||
| 417 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/sys.rs b/embassy-stm32/src/tl_mbox/sys.rs deleted file mode 100644 index 9685fb920..000000000 --- a/embassy-stm32/src/tl_mbox/sys.rs +++ /dev/null | |||
| @@ -1,83 +0,0 @@ | |||
| 1 | use embassy_futures::block_on; | ||
| 2 | |||
| 3 | use super::cmd::{CmdPacket, CmdSerial}; | ||
| 4 | use super::consts::TlPacketType; | ||
| 5 | use super::evt::{CcEvt, EvtBox, EvtSerial}; | ||
| 6 | use super::unsafe_linked_list::LinkedListNode; | ||
| 7 | use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_CHANNEL, TL_REF_TABLE, TL_SYS_TABLE}; | ||
| 8 | use crate::tl_mbox::ipcc::Ipcc; | ||
| 9 | |||
| 10 | pub struct Sys; | ||
| 11 | |||
| 12 | impl Sys { | ||
| 13 | pub fn enable() { | ||
| 14 | unsafe { | ||
| 15 | LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr()); | ||
| 16 | |||
| 17 | TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable { | ||
| 18 | pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(), | ||
| 19 | sys_queue: SYSTEM_EVT_QUEUE.as_ptr(), | ||
| 20 | }); | ||
| 21 | } | ||
| 22 | |||
| 23 | Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true); | ||
| 24 | } | ||
| 25 | |||
| 26 | pub fn evt_handler() { | ||
| 27 | unsafe { | ||
| 28 | let mut node_ptr = core::ptr::null_mut(); | ||
| 29 | let node_ptr_ptr: *mut _ = &mut node_ptr; | ||
| 30 | |||
| 31 | while !LinkedListNode::is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) { | ||
| 32 | LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr(), node_ptr_ptr); | ||
| 33 | |||
| 34 | let event = node_ptr.cast(); | ||
| 35 | let event = EvtBox::new(event); | ||
| 36 | |||
| 37 | // TODO: not really happy about this | ||
| 38 | block_on(TL_CHANNEL.send(event)); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL); | ||
| 43 | } | ||
| 44 | |||
| 45 | pub fn cmd_evt_handler() -> CcEvt { | ||
| 46 | Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false); | ||
| 47 | |||
| 48 | // ST's command response data structure is really convoluted. | ||
| 49 | // | ||
| 50 | // for command response events on SYS channel, the header is missing | ||
| 51 | // and one should: | ||
| 52 | // 1. interpret the content of CMD_BUFFER as CmdPacket | ||
| 53 | // 2. Access CmdPacket's cmdserial field and interpret its content as EvtSerial | ||
| 54 | // 3. Access EvtSerial's evt field (as Evt) and interpret its payload as CcEvt | ||
| 55 | // 4. CcEvt type is the actual SHCI response | ||
| 56 | // 5. profit | ||
| 57 | unsafe { | ||
| 58 | let cmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer; | ||
| 59 | let cmd_serial: *const CmdSerial = &(*cmd).cmd_serial; | ||
| 60 | let evt_serial: *const EvtSerial = cmd_serial.cast(); | ||
| 61 | let cc = (*evt_serial).evt.payload.as_ptr().cast(); | ||
| 62 | *cc | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | #[allow(dead_code)] | ||
| 67 | pub fn send_cmd(buf: &[u8]) { | ||
| 68 | unsafe { | ||
| 69 | // TODO: check this | ||
| 70 | let cmd_buffer = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer; | ||
| 71 | let cmd_serial: *mut CmdSerial = &mut cmd_buffer.cmd_serial; | ||
| 72 | let cmd_serial_buf = cmd_serial.cast(); | ||
| 73 | |||
| 74 | core::ptr::copy(buf.as_ptr(), cmd_serial_buf, buf.len()); | ||
| 75 | |||
| 76 | let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer; | ||
| 77 | cmd_packet.cmd_serial.ty = TlPacketType::SysCmd as u8; | ||
| 78 | |||
| 79 | Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL); | ||
| 80 | Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
diff --git a/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs b/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs deleted file mode 100644 index 482e2bf5a..000000000 --- a/embassy-stm32/src/tl_mbox/unsafe_linked_list.rs +++ /dev/null | |||
| @@ -1,125 +0,0 @@ | |||
| 1 | //! Unsafe linked list. | ||
| 2 | //! Translated from ST's C by `c2rust` tool. | ||
| 3 | |||
| 4 | #![allow( | ||
| 5 | dead_code, | ||
| 6 | mutable_transmutes, | ||
| 7 | non_camel_case_types, | ||
| 8 | non_snake_case, | ||
| 9 | non_upper_case_globals, | ||
| 10 | unused_assignments, | ||
| 11 | unused_mut | ||
| 12 | )] | ||
| 13 | |||
| 14 | use cortex_m::interrupt; | ||
| 15 | |||
| 16 | #[derive(Copy, Clone)] | ||
| 17 | #[repr(C, packed(4))] | ||
| 18 | pub struct LinkedListNode { | ||
| 19 | pub next: *mut LinkedListNode, | ||
| 20 | pub prev: *mut LinkedListNode, | ||
| 21 | } | ||
| 22 | |||
| 23 | impl Default for LinkedListNode { | ||
| 24 | fn default() -> Self { | ||
| 25 | LinkedListNode { | ||
| 26 | next: core::ptr::null_mut(), | ||
| 27 | prev: core::ptr::null_mut(), | ||
| 28 | } | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | impl LinkedListNode { | ||
| 33 | pub unsafe fn init_head(mut list_head: *mut LinkedListNode) { | ||
| 34 | (*list_head).next = list_head; | ||
| 35 | (*list_head).prev = list_head; | ||
| 36 | } | ||
| 37 | |||
| 38 | pub unsafe fn is_empty(mut list_head: *mut LinkedListNode) -> bool { | ||
| 39 | interrupt::free(|_| ((*list_head).next) == list_head) | ||
| 40 | } | ||
| 41 | |||
| 42 | pub unsafe fn insert_head(mut list_head: *mut LinkedListNode, mut node: *mut LinkedListNode) { | ||
| 43 | interrupt::free(|_| { | ||
| 44 | (*node).next = (*list_head).next; | ||
| 45 | (*node).prev = list_head; | ||
| 46 | (*list_head).next = node; | ||
| 47 | (*(*node).next).prev = node; | ||
| 48 | }); | ||
| 49 | } | ||
| 50 | |||
| 51 | pub unsafe fn insert_tail(mut list_head: *mut LinkedListNode, mut node: *mut LinkedListNode) { | ||
| 52 | interrupt::free(|_| { | ||
| 53 | (*node).next = list_head; | ||
| 54 | (*node).prev = (*list_head).prev; | ||
| 55 | (*list_head).prev = node; | ||
| 56 | (*(*node).prev).next = node; | ||
| 57 | }); | ||
| 58 | } | ||
| 59 | |||
| 60 | pub unsafe fn remove_node(mut node: *mut LinkedListNode) { | ||
| 61 | interrupt::free(|_| { | ||
| 62 | (*(*node).prev).next = (*node).next; | ||
| 63 | (*(*node).next).prev = (*node).prev; | ||
| 64 | }); | ||
| 65 | } | ||
| 66 | |||
| 67 | pub unsafe fn remove_head(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) { | ||
| 68 | interrupt::free(|_| { | ||
| 69 | *node = (*list_head).next; | ||
| 70 | Self::remove_node((*list_head).next); | ||
| 71 | }); | ||
| 72 | } | ||
| 73 | |||
| 74 | pub unsafe fn remove_tail(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) { | ||
| 75 | interrupt::free(|_| { | ||
| 76 | *node = (*list_head).prev; | ||
| 77 | Self::remove_node((*list_head).prev); | ||
| 78 | }); | ||
| 79 | } | ||
| 80 | |||
| 81 | pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) { | ||
| 82 | interrupt::free(|_| { | ||
| 83 | (*node).next = (*ref_node).next; | ||
| 84 | (*node).prev = ref_node; | ||
| 85 | (*ref_node).next = node; | ||
| 86 | (*(*node).next).prev = node; | ||
| 87 | }); | ||
| 88 | } | ||
| 89 | |||
| 90 | pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) { | ||
| 91 | interrupt::free(|_| { | ||
| 92 | (*node).next = ref_node; | ||
| 93 | (*node).prev = (*ref_node).prev; | ||
| 94 | (*ref_node).prev = node; | ||
| 95 | (*(*node).prev).next = node; | ||
| 96 | }); | ||
| 97 | } | ||
| 98 | |||
| 99 | pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize { | ||
| 100 | interrupt::free(|_| { | ||
| 101 | let mut size = 0; | ||
| 102 | let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>(); | ||
| 103 | |||
| 104 | temp = (*list_head).next; | ||
| 105 | while temp != list_head { | ||
| 106 | size += 1; | ||
| 107 | temp = (*temp).next | ||
| 108 | } | ||
| 109 | |||
| 110 | size | ||
| 111 | }) | ||
| 112 | } | ||
| 113 | |||
| 114 | pub unsafe fn get_next_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) { | ||
| 115 | interrupt::free(|_| { | ||
| 116 | *node = (*ref_node).next; | ||
| 117 | }); | ||
| 118 | } | ||
| 119 | |||
| 120 | pub unsafe fn get_prev_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) { | ||
| 121 | interrupt::free(|_| { | ||
| 122 | *node = (*ref_node).prev; | ||
| 123 | }); | ||
| 124 | } | ||
| 125 | } | ||
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 9f1da3583..433ad299c 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -2,79 +2,81 @@ use core::future::poll_fn; | |||
| 2 | use core::slice; | 2 | use core::slice; |
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 6 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; | 5 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 6 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | 7 | ||
| 9 | use super::*; | 8 | use super::*; |
| 9 | use crate::interrupt::typelevel::Interrupt; | ||
| 10 | 10 | ||
| 11 | /// Interrupt handler. | 11 | /// Interrupt handler. |
| 12 | pub struct InterruptHandler<T: BasicInstance> { | 12 | pub struct InterruptHandler<T: BasicInstance> { |
| 13 | _phantom: PhantomData<T>, | 13 | _phantom: PhantomData<T>, |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 16 | impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 17 | unsafe fn on_interrupt() { | 17 | unsafe fn on_interrupt() { |
| 18 | let r = T::regs(); | 18 | let r = T::regs(); |
| 19 | let state = T::buffered_state(); | 19 | let state = T::buffered_state(); |
| 20 | 20 | ||
| 21 | // RX | 21 | // RX |
| 22 | unsafe { | 22 | let sr_val = sr(r).read(); |
| 23 | let sr = sr(r).read(); | 23 | // On v1 & v2, reading DR clears the rxne, error and idle interrupt |
| 24 | clear_interrupt_flags(r, sr); | 24 | // flags. Keep this close to the SR read to reduce the chance of a |
| 25 | 25 | // flag being set in-between. | |
| 26 | if sr.rxne() { | 26 | let dr = if sr_val.rxne() || cfg!(any(usart_v1, usart_v2)) && (sr_val.ore() || sr_val.idle()) { |
| 27 | if sr.pe() { | 27 | Some(rdr(r).read_volatile()) |
| 28 | warn!("Parity error"); | 28 | } else { |
| 29 | } | 29 | None |
| 30 | if sr.fe() { | 30 | }; |
| 31 | warn!("Framing error"); | 31 | clear_interrupt_flags(r, sr_val); |
| 32 | } | 32 | |
| 33 | if sr.ne() { | 33 | if sr_val.pe() { |
| 34 | warn!("Noise error"); | 34 | warn!("Parity error"); |
| 35 | } | 35 | } |
| 36 | if sr.ore() { | 36 | if sr_val.fe() { |
| 37 | warn!("Overrun error"); | 37 | warn!("Framing error"); |
| 38 | } | 38 | } |
| 39 | 39 | if sr_val.ne() { | |
| 40 | let mut rx_writer = state.rx_buf.writer(); | 40 | warn!("Noise error"); |
| 41 | let buf = rx_writer.push_slice(); | 41 | } |
| 42 | if !buf.is_empty() { | 42 | if sr_val.ore() { |
| 43 | // This read also clears the error and idle interrupt flags on v1. | 43 | warn!("Overrun error"); |
| 44 | buf[0] = rdr(r).read_volatile(); | 44 | } |
| 45 | rx_writer.push_done(1); | 45 | if sr_val.rxne() { |
| 46 | } else { | 46 | let mut rx_writer = state.rx_buf.writer(); |
| 47 | // FIXME: Should we disable any further RX interrupts when the buffer becomes full. | 47 | let buf = rx_writer.push_slice(); |
| 48 | } | 48 | if !buf.is_empty() { |
| 49 | 49 | buf[0] = dr.unwrap(); | |
| 50 | if state.rx_buf.is_full() { | 50 | rx_writer.push_done(1); |
| 51 | state.rx_waker.wake(); | 51 | } else { |
| 52 | } | 52 | // FIXME: Should we disable any further RX interrupts when the buffer becomes full. |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | if sr.idle() { | 55 | if state.rx_buf.is_full() { |
| 56 | state.rx_waker.wake(); | 56 | state.rx_waker.wake(); |
| 57 | }; | 57 | } |
| 58 | } | ||
| 59 | |||
| 60 | if sr_val.idle() { | ||
| 61 | state.rx_waker.wake(); | ||
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | // TX | 64 | // TX |
| 61 | unsafe { | 65 | if sr(r).read().txe() { |
| 62 | if sr(r).read().txe() { | 66 | let mut tx_reader = state.tx_buf.reader(); |
| 63 | let mut tx_reader = state.tx_buf.reader(); | 67 | let buf = tx_reader.pop_slice(); |
| 64 | let buf = tx_reader.pop_slice(); | 68 | if !buf.is_empty() { |
| 65 | if !buf.is_empty() { | 69 | r.cr1().modify(|w| { |
| 66 | r.cr1().modify(|w| { | 70 | w.set_txeie(true); |
| 67 | w.set_txeie(true); | 71 | }); |
| 68 | }); | 72 | tdr(r).write_volatile(buf[0].into()); |
| 69 | tdr(r).write_volatile(buf[0].into()); | 73 | tx_reader.pop_done(1); |
| 70 | tx_reader.pop_done(1); | 74 | state.tx_waker.wake(); |
| 71 | state.tx_waker.wake(); | 75 | } else { |
| 72 | } else { | 76 | // Disable interrupt until we have something to transmit again |
| 73 | // Disable interrupt until we have something to transmit again | 77 | r.cr1().modify(|w| { |
| 74 | r.cr1().modify(|w| { | 78 | w.set_txeie(false); |
| 75 | w.set_txeie(false); | 79 | }); |
| 76 | }); | ||
| 77 | } | ||
| 78 | } | 80 | } |
| 79 | } | 81 | } |
| 80 | } | 82 | } |
| @@ -115,7 +117,7 @@ pub struct BufferedUartRx<'d, T: BasicInstance> { | |||
| 115 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { | 117 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { |
| 116 | pub fn new( | 118 | pub fn new( |
| 117 | peri: impl Peripheral<P = T> + 'd, | 119 | peri: impl Peripheral<P = T> + 'd, |
| 118 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 120 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 119 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 121 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 120 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 122 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 121 | tx_buffer: &'d mut [u8], | 123 | tx_buffer: &'d mut [u8], |
| @@ -130,7 +132,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 130 | 132 | ||
| 131 | pub fn new_with_rtscts( | 133 | pub fn new_with_rtscts( |
| 132 | peri: impl Peripheral<P = T> + 'd, | 134 | peri: impl Peripheral<P = T> + 'd, |
| 133 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 135 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 134 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 136 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 135 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 137 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 136 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | 138 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, |
| @@ -144,14 +146,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 144 | T::enable(); | 146 | T::enable(); |
| 145 | T::reset(); | 147 | T::reset(); |
| 146 | 148 | ||
| 147 | unsafe { | 149 | rts.set_as_af(rts.af_num(), AFType::OutputPushPull); |
| 148 | rts.set_as_af(rts.af_num(), AFType::OutputPushPull); | 150 | cts.set_as_af(cts.af_num(), AFType::Input); |
| 149 | cts.set_as_af(cts.af_num(), AFType::Input); | 151 | T::regs().cr3().write(|w| { |
| 150 | T::regs().cr3().write(|w| { | 152 | w.set_rtse(true); |
| 151 | w.set_rtse(true); | 153 | w.set_ctse(true); |
| 152 | w.set_ctse(true); | 154 | }); |
| 153 | }); | ||
| 154 | } | ||
| 155 | 155 | ||
| 156 | Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) | 156 | Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) |
| 157 | } | 157 | } |
| @@ -159,7 +159,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 159 | #[cfg(not(any(usart_v1, usart_v2)))] | 159 | #[cfg(not(any(usart_v1, usart_v2)))] |
| 160 | pub fn new_with_de( | 160 | pub fn new_with_de( |
| 161 | peri: impl Peripheral<P = T> + 'd, | 161 | peri: impl Peripheral<P = T> + 'd, |
| 162 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 162 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 163 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 163 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 164 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 164 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 165 | de: impl Peripheral<P = impl DePin<T>> + 'd, | 165 | de: impl Peripheral<P = impl DePin<T>> + 'd, |
| @@ -172,12 +172,10 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 172 | T::enable(); | 172 | T::enable(); |
| 173 | T::reset(); | 173 | T::reset(); |
| 174 | 174 | ||
| 175 | unsafe { | 175 | de.set_as_af(de.af_num(), AFType::OutputPushPull); |
| 176 | de.set_as_af(de.af_num(), AFType::OutputPushPull); | 176 | T::regs().cr3().write(|w| { |
| 177 | T::regs().cr3().write(|w| { | 177 | w.set_dem(true); |
| 178 | w.set_dem(true); | 178 | }); |
| 179 | }); | ||
| 180 | } | ||
| 181 | 179 | ||
| 182 | Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) | 180 | Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) |
| 183 | } | 181 | } |
| @@ -199,25 +197,21 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 199 | unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; | 197 | unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; |
| 200 | 198 | ||
| 201 | let r = T::regs(); | 199 | let r = T::regs(); |
| 202 | unsafe { | 200 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 203 | rx.set_as_af(rx.af_num(), AFType::Input); | 201 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 204 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 205 | } | ||
| 206 | 202 | ||
| 207 | configure(r, &config, T::frequency(), T::KIND, true, true); | 203 | configure(r, &config, T::frequency(), T::KIND, true, true); |
| 208 | 204 | ||
| 209 | unsafe { | 205 | r.cr1().modify(|w| { |
| 210 | r.cr1().modify(|w| { | 206 | #[cfg(lpuart_v2)] |
| 211 | #[cfg(lpuart_v2)] | 207 | w.set_fifoen(true); |
| 212 | w.set_fifoen(true); | ||
| 213 | 208 | ||
| 214 | w.set_rxneie(true); | 209 | w.set_rxneie(true); |
| 215 | w.set_idleie(true); | 210 | w.set_idleie(true); |
| 216 | }); | 211 | }); |
| 217 | } | ||
| 218 | 212 | ||
| 219 | unsafe { T::Interrupt::steal() }.unpend(); | 213 | T::Interrupt::unpend(); |
| 220 | unsafe { T::Interrupt::steal() }.enable(); | 214 | unsafe { T::Interrupt::enable() }; |
| 221 | 215 | ||
| 222 | Self { | 216 | Self { |
| 223 | rx: BufferedUartRx { phantom: PhantomData }, | 217 | rx: BufferedUartRx { phantom: PhantomData }, |
| @@ -245,7 +239,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { | |||
| 245 | rx_reader.pop_done(len); | 239 | rx_reader.pop_done(len); |
| 246 | 240 | ||
| 247 | if do_pend { | 241 | if do_pend { |
| 248 | unsafe { T::Interrupt::steal().pend() }; | 242 | T::Interrupt::pend(); |
| 249 | } | 243 | } |
| 250 | 244 | ||
| 251 | return Poll::Ready(Ok(len)); | 245 | return Poll::Ready(Ok(len)); |
| @@ -271,7 +265,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { | |||
| 271 | rx_reader.pop_done(len); | 265 | rx_reader.pop_done(len); |
| 272 | 266 | ||
| 273 | if do_pend { | 267 | if do_pend { |
| 274 | unsafe { T::Interrupt::steal().pend() }; | 268 | T::Interrupt::pend(); |
| 275 | } | 269 | } |
| 276 | 270 | ||
| 277 | return Ok(len); | 271 | return Ok(len); |
| @@ -301,7 +295,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { | |||
| 301 | let full = state.rx_buf.is_full(); | 295 | let full = state.rx_buf.is_full(); |
| 302 | rx_reader.pop_done(amt); | 296 | rx_reader.pop_done(amt); |
| 303 | if full { | 297 | if full { |
| 304 | unsafe { T::Interrupt::steal().pend() }; | 298 | T::Interrupt::pend(); |
| 305 | } | 299 | } |
| 306 | } | 300 | } |
| 307 | } | 301 | } |
| @@ -324,7 +318,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | |||
| 324 | tx_writer.push_done(n); | 318 | tx_writer.push_done(n); |
| 325 | 319 | ||
| 326 | if empty { | 320 | if empty { |
| 327 | unsafe { T::Interrupt::steal() }.pend(); | 321 | T::Interrupt::pend(); |
| 328 | } | 322 | } |
| 329 | 323 | ||
| 330 | Poll::Ready(Ok(n)) | 324 | Poll::Ready(Ok(n)) |
| @@ -358,7 +352,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | |||
| 358 | tx_writer.push_done(n); | 352 | tx_writer.push_done(n); |
| 359 | 353 | ||
| 360 | if empty { | 354 | if empty { |
| 361 | unsafe { T::Interrupt::steal() }.pend(); | 355 | T::Interrupt::pend(); |
| 362 | } | 356 | } |
| 363 | 357 | ||
| 364 | return Ok(n); | 358 | return Ok(n); |
| @@ -385,7 +379,7 @@ impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> { | |||
| 385 | // TX is inactive if the the buffer is not available. | 379 | // TX is inactive if the the buffer is not available. |
| 386 | // We can now unregister the interrupt handler | 380 | // We can now unregister the interrupt handler |
| 387 | if state.tx_buf.len() == 0 { | 381 | if state.tx_buf.len() == 0 { |
| 388 | T::Interrupt::steal().disable(); | 382 | T::Interrupt::disable(); |
| 389 | } | 383 | } |
| 390 | } | 384 | } |
| 391 | } | 385 | } |
| @@ -400,7 +394,7 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> { | |||
| 400 | // RX is inactive if the the buffer is not available. | 394 | // RX is inactive if the the buffer is not available. |
| 401 | // We can now unregister the interrupt handler | 395 | // We can now unregister the interrupt handler |
| 402 | if state.rx_buf.len() == 0 { | 396 | if state.rx_buf.len() == 0 { |
| 403 | T::Interrupt::steal().disable(); | 397 | T::Interrupt::disable(); |
| 404 | } | 398 | } |
| 405 | } | 399 | } |
| 406 | } | 400 | } |
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 05ccb8749..47a79c187 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -5,13 +5,13 @@ use core::marker::PhantomData; | |||
| 5 | use core::sync::atomic::{compiler_fence, Ordering}; | 5 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 6 | use core::task::Poll; | 6 | use core::task::Poll; |
| 7 | 7 | ||
| 8 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | ||
| 9 | use embassy_hal_common::drop::OnDrop; | 8 | use embassy_hal_common::drop::OnDrop; |
| 10 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 11 | use futures::future::{select, Either}; | 10 | use futures::future::{select, Either}; |
| 12 | 11 | ||
| 13 | use crate::dma::{NoDma, Transfer}; | 12 | use crate::dma::{NoDma, Transfer}; |
| 14 | use crate::gpio::sealed::AFType; | 13 | use crate::gpio::sealed::AFType; |
| 14 | use crate::interrupt::typelevel::Interrupt; | ||
| 15 | #[cfg(not(any(usart_v1, usart_v2)))] | 15 | #[cfg(not(any(usart_v1, usart_v2)))] |
| 16 | #[allow(unused_imports)] | 16 | #[allow(unused_imports)] |
| 17 | use crate::pac::usart::regs::Isr as Sr; | 17 | use crate::pac::usart::regs::Isr as Sr; |
| @@ -31,40 +31,36 @@ pub struct InterruptHandler<T: BasicInstance> { | |||
| 31 | _phantom: PhantomData<T>, | 31 | _phantom: PhantomData<T>, |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 34 | impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 35 | unsafe fn on_interrupt() { | 35 | unsafe fn on_interrupt() { |
| 36 | let r = T::regs(); | 36 | let r = T::regs(); |
| 37 | let s = T::state(); | 37 | let s = T::state(); |
| 38 | 38 | ||
| 39 | let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; | 39 | let (sr, cr1, cr3) = (sr(r).read(), r.cr1().read(), r.cr3().read()); |
| 40 | 40 | ||
| 41 | let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); | 41 | let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); |
| 42 | if has_errors { | 42 | if has_errors { |
| 43 | // clear all interrupts and DMA Rx Request | 43 | // clear all interrupts and DMA Rx Request |
| 44 | unsafe { | 44 | r.cr1().modify(|w| { |
| 45 | r.cr1().modify(|w| { | 45 | // disable RXNE interrupt |
| 46 | // disable RXNE interrupt | 46 | w.set_rxneie(false); |
| 47 | w.set_rxneie(false); | 47 | // disable parity interrupt |
| 48 | // disable parity interrupt | 48 | w.set_peie(false); |
| 49 | w.set_peie(false); | 49 | // disable idle line interrupt |
| 50 | // disable idle line interrupt | 50 | w.set_idleie(false); |
| 51 | w.set_idleie(false); | 51 | }); |
| 52 | }); | 52 | r.cr3().modify(|w| { |
| 53 | r.cr3().modify(|w| { | 53 | // disable Error Interrupt: (Frame error, Noise error, Overrun error) |
| 54 | // disable Error Interrupt: (Frame error, Noise error, Overrun error) | 54 | w.set_eie(false); |
| 55 | w.set_eie(false); | 55 | // disable DMA Rx Request |
| 56 | // disable DMA Rx Request | 56 | w.set_dmar(false); |
| 57 | w.set_dmar(false); | 57 | }); |
| 58 | }); | ||
| 59 | } | ||
| 60 | } else if cr1.idleie() && sr.idle() { | 58 | } else if cr1.idleie() && sr.idle() { |
| 61 | // IDLE detected: no more data will come | 59 | // IDLE detected: no more data will come |
| 62 | unsafe { | 60 | r.cr1().modify(|w| { |
| 63 | r.cr1().modify(|w| { | 61 | // disable idle line detection |
| 64 | // disable idle line detection | 62 | w.set_idleie(false); |
| 65 | w.set_idleie(false); | 63 | }); |
| 66 | }); | ||
| 67 | } | ||
| 68 | } else if cr1.rxneie() { | 64 | } else if cr1.rxneie() { |
| 69 | // We cannot check the RXNE flag as it is auto-cleared by the DMA controller | 65 | // We cannot check the RXNE flag as it is auto-cleared by the DMA controller |
| 70 | 66 | ||
| @@ -205,12 +201,10 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 205 | T::enable(); | 201 | T::enable(); |
| 206 | T::reset(); | 202 | T::reset(); |
| 207 | 203 | ||
| 208 | unsafe { | 204 | cts.set_as_af(cts.af_num(), AFType::Input); |
| 209 | cts.set_as_af(cts.af_num(), AFType::Input); | 205 | T::regs().cr3().write(|w| { |
| 210 | T::regs().cr3().write(|w| { | 206 | w.set_ctse(true); |
| 211 | w.set_ctse(true); | 207 | }); |
| 212 | }); | ||
| 213 | } | ||
| 214 | Self::new_inner(peri, tx, tx_dma, config) | 208 | Self::new_inner(peri, tx, tx_dma, config) |
| 215 | } | 209 | } |
| 216 | 210 | ||
| @@ -224,9 +218,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 224 | 218 | ||
| 225 | let r = T::regs(); | 219 | let r = T::regs(); |
| 226 | 220 | ||
| 227 | unsafe { | 221 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 228 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 229 | } | ||
| 230 | 222 | ||
| 231 | configure(r, &config, T::frequency(), T::KIND, false, true); | 223 | configure(r, &config, T::frequency(), T::KIND, false, true); |
| 232 | 224 | ||
| @@ -245,11 +237,9 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 245 | { | 237 | { |
| 246 | let ch = &mut self.tx_dma; | 238 | let ch = &mut self.tx_dma; |
| 247 | let request = ch.request(); | 239 | let request = ch.request(); |
| 248 | unsafe { | 240 | T::regs().cr3().modify(|reg| { |
| 249 | T::regs().cr3().modify(|reg| { | 241 | reg.set_dmat(true); |
| 250 | reg.set_dmat(true); | 242 | }); |
| 251 | }); | ||
| 252 | } | ||
| 253 | // If we don't assign future to a variable, the data register pointer | 243 | // If we don't assign future to a variable, the data register pointer |
| 254 | // is held across an await and makes the future non-Send. | 244 | // is held across an await and makes the future non-Send. |
| 255 | let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) }; | 245 | let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) }; |
| @@ -258,21 +248,17 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 258 | } | 248 | } |
| 259 | 249 | ||
| 260 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 250 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 261 | unsafe { | 251 | let r = T::regs(); |
| 262 | let r = T::regs(); | 252 | for &b in buffer { |
| 263 | for &b in buffer { | 253 | while !sr(r).read().txe() {} |
| 264 | while !sr(r).read().txe() {} | 254 | unsafe { tdr(r).write_volatile(b) }; |
| 265 | tdr(r).write_volatile(b); | ||
| 266 | } | ||
| 267 | } | 255 | } |
| 268 | Ok(()) | 256 | Ok(()) |
| 269 | } | 257 | } |
| 270 | 258 | ||
| 271 | pub fn blocking_flush(&mut self) -> Result<(), Error> { | 259 | pub fn blocking_flush(&mut self) -> Result<(), Error> { |
| 272 | unsafe { | 260 | let r = T::regs(); |
| 273 | let r = T::regs(); | 261 | while !sr(r).read().tc() {} |
| 274 | while !sr(r).read().tc() {} | ||
| 275 | } | ||
| 276 | Ok(()) | 262 | Ok(()) |
| 277 | } | 263 | } |
| 278 | } | 264 | } |
| @@ -281,7 +267,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 281 | /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. | 267 | /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. |
| 282 | pub fn new( | 268 | pub fn new( |
| 283 | peri: impl Peripheral<P = T> + 'd, | 269 | peri: impl Peripheral<P = T> + 'd, |
| 284 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 270 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 285 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 271 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 286 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 272 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 287 | config: Config, | 273 | config: Config, |
| @@ -294,7 +280,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 294 | 280 | ||
| 295 | pub fn new_with_rts( | 281 | pub fn new_with_rts( |
| 296 | peri: impl Peripheral<P = T> + 'd, | 282 | peri: impl Peripheral<P = T> + 'd, |
| 297 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 283 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 298 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 284 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 299 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | 285 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, |
| 300 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 286 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| @@ -305,12 +291,10 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 305 | T::enable(); | 291 | T::enable(); |
| 306 | T::reset(); | 292 | T::reset(); |
| 307 | 293 | ||
| 308 | unsafe { | 294 | rts.set_as_af(rts.af_num(), AFType::OutputPushPull); |
| 309 | rts.set_as_af(rts.af_num(), AFType::OutputPushPull); | 295 | T::regs().cr3().write(|w| { |
| 310 | T::regs().cr3().write(|w| { | 296 | w.set_rtse(true); |
| 311 | w.set_rtse(true); | 297 | }); |
| 312 | }); | ||
| 313 | } | ||
| 314 | 298 | ||
| 315 | Self::new_inner(peri, rx, rx_dma, config) | 299 | Self::new_inner(peri, rx, rx_dma, config) |
| 316 | } | 300 | } |
| @@ -325,14 +309,12 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 325 | 309 | ||
| 326 | let r = T::regs(); | 310 | let r = T::regs(); |
| 327 | 311 | ||
| 328 | unsafe { | 312 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 329 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 330 | } | ||
| 331 | 313 | ||
| 332 | configure(r, &config, T::frequency(), T::KIND, true, false); | 314 | configure(r, &config, T::frequency(), T::KIND, true, false); |
| 333 | 315 | ||
| 334 | unsafe { T::Interrupt::steal() }.unpend(); | 316 | T::Interrupt::unpend(); |
| 335 | unsafe { T::Interrupt::steal() }.enable(); | 317 | unsafe { T::Interrupt::enable() }; |
| 336 | 318 | ||
| 337 | // create state once! | 319 | // create state once! |
| 338 | let _s = T::state(); | 320 | let _s = T::state(); |
| @@ -347,7 +329,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 347 | } | 329 | } |
| 348 | 330 | ||
| 349 | #[cfg(any(usart_v1, usart_v2))] | 331 | #[cfg(any(usart_v1, usart_v2))] |
| 350 | unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> { | 332 | fn check_rx_flags(&mut self) -> Result<bool, Error> { |
| 351 | let r = T::regs(); | 333 | let r = T::regs(); |
| 352 | loop { | 334 | loop { |
| 353 | // Handle all buffered error flags. | 335 | // Handle all buffered error flags. |
| @@ -380,7 +362,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 380 | } | 362 | } |
| 381 | 363 | ||
| 382 | #[cfg(any(usart_v3, usart_v4))] | 364 | #[cfg(any(usart_v3, usart_v4))] |
| 383 | unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> { | 365 | fn check_rx_flags(&mut self) -> Result<bool, Error> { |
| 384 | let r = T::regs(); | 366 | let r = T::regs(); |
| 385 | let sr = r.isr().read(); | 367 | let sr = r.isr().read(); |
| 386 | if sr.pe() { | 368 | if sr.pe() { |
| @@ -410,22 +392,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 410 | 392 | ||
| 411 | pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { | 393 | pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { |
| 412 | let r = T::regs(); | 394 | let r = T::regs(); |
| 413 | unsafe { | 395 | if self.check_rx_flags()? { |
| 414 | if self.check_rx_flags()? { | 396 | Ok(unsafe { rdr(r).read_volatile() }) |
| 415 | Ok(rdr(r).read_volatile()) | 397 | } else { |
| 416 | } else { | 398 | Err(nb::Error::WouldBlock) |
| 417 | Err(nb::Error::WouldBlock) | ||
| 418 | } | ||
| 419 | } | 399 | } |
| 420 | } | 400 | } |
| 421 | 401 | ||
| 422 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 402 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 423 | unsafe { | 403 | let r = T::regs(); |
| 424 | let r = T::regs(); | 404 | for b in buffer { |
| 425 | for b in buffer { | 405 | while !self.check_rx_flags()? {} |
| 426 | while !self.check_rx_flags()? {} | 406 | unsafe { *b = rdr(r).read_volatile() } |
| 427 | *b = rdr(r).read_volatile(); | ||
| 428 | } | ||
| 429 | } | 407 | } |
| 430 | Ok(()) | 408 | Ok(()) |
| 431 | } | 409 | } |
| @@ -451,23 +429,20 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 451 | let on_drop = OnDrop::new(move || { | 429 | let on_drop = OnDrop::new(move || { |
| 452 | // defmt::trace!("Clear all USART interrupts and DMA Read Request"); | 430 | // defmt::trace!("Clear all USART interrupts and DMA Read Request"); |
| 453 | // clear all interrupts and DMA Rx Request | 431 | // clear all interrupts and DMA Rx Request |
| 454 | // SAFETY: only clears Rx related flags | 432 | r.cr1().modify(|w| { |
| 455 | unsafe { | 433 | // disable RXNE interrupt |
| 456 | r.cr1().modify(|w| { | 434 | w.set_rxneie(false); |
| 457 | // disable RXNE interrupt | 435 | // disable parity interrupt |
| 458 | w.set_rxneie(false); | 436 | w.set_peie(false); |
| 459 | // disable parity interrupt | 437 | // disable idle line interrupt |
| 460 | w.set_peie(false); | 438 | w.set_idleie(false); |
| 461 | // disable idle line interrupt | 439 | }); |
| 462 | w.set_idleie(false); | 440 | r.cr3().modify(|w| { |
| 463 | }); | 441 | // disable Error Interrupt: (Frame error, Noise error, Overrun error) |
| 464 | r.cr3().modify(|w| { | 442 | w.set_eie(false); |
| 465 | // disable Error Interrupt: (Frame error, Noise error, Overrun error) | 443 | // disable DMA Rx Request |
| 466 | w.set_eie(false); | 444 | w.set_dmar(false); |
| 467 | // disable DMA Rx Request | 445 | }); |
| 468 | w.set_dmar(false); | ||
| 469 | }); | ||
| 470 | } | ||
| 471 | }); | 446 | }); |
| 472 | 447 | ||
| 473 | let ch = &mut self.rx_dma; | 448 | let ch = &mut self.rx_dma; |
| @@ -480,78 +455,74 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 480 | // future which will complete when DMA Read request completes | 455 | // future which will complete when DMA Read request completes |
| 481 | let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) }; | 456 | let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) }; |
| 482 | 457 | ||
| 483 | // SAFETY: The only way we might have a problem is using split rx and tx | 458 | // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer |
| 484 | // here we only modify or read Rx related flags, interrupts and DMA channel | 459 | if !self.detect_previous_overrun { |
| 485 | unsafe { | 460 | let sr = sr(r).read(); |
| 486 | // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer | 461 | // This read also clears the error and idle interrupt flags on v1. |
| 487 | if !self.detect_previous_overrun { | 462 | unsafe { rdr(r).read_volatile() }; |
| 488 | let sr = sr(r).read(); | 463 | clear_interrupt_flags(r, sr); |
| 489 | // This read also clears the error and idle interrupt flags on v1. | 464 | } |
| 490 | rdr(r).read_volatile(); | ||
| 491 | clear_interrupt_flags(r, sr); | ||
| 492 | } | ||
| 493 | |||
| 494 | r.cr1().modify(|w| { | ||
| 495 | // disable RXNE interrupt | ||
| 496 | w.set_rxneie(false); | ||
| 497 | // enable parity interrupt if not ParityNone | ||
| 498 | w.set_peie(w.pce()); | ||
| 499 | }); | ||
| 500 | 465 | ||
| 501 | r.cr3().modify(|w| { | 466 | r.cr1().modify(|w| { |
| 502 | // enable Error Interrupt: (Frame error, Noise error, Overrun error) | 467 | // disable RXNE interrupt |
| 503 | w.set_eie(true); | 468 | w.set_rxneie(false); |
| 504 | // enable DMA Rx Request | 469 | // enable parity interrupt if not ParityNone |
| 505 | w.set_dmar(true); | 470 | w.set_peie(w.pce()); |
| 506 | }); | 471 | }); |
| 507 | 472 | ||
| 508 | compiler_fence(Ordering::SeqCst); | 473 | r.cr3().modify(|w| { |
| 474 | // enable Error Interrupt: (Frame error, Noise error, Overrun error) | ||
| 475 | w.set_eie(true); | ||
| 476 | // enable DMA Rx Request | ||
| 477 | w.set_dmar(true); | ||
| 478 | }); | ||
| 509 | 479 | ||
| 510 | // In case of errors already pending when reception started, interrupts may have already been raised | 480 | compiler_fence(Ordering::SeqCst); |
| 511 | // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts | ||
| 512 | // have been disabled in interrupt handler and DMA Rx Request has been disabled. | ||
| 513 | 481 | ||
| 514 | let cr3 = r.cr3().read(); | 482 | // In case of errors already pending when reception started, interrupts may have already been raised |
| 483 | // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts | ||
| 484 | // have been disabled in interrupt handler and DMA Rx Request has been disabled. | ||
| 515 | 485 | ||
| 516 | if !cr3.dmar() { | 486 | let cr3 = r.cr3().read(); |
| 517 | // something went wrong | ||
| 518 | // because the only way to get this flag cleared is to have an interrupt | ||
| 519 | 487 | ||
| 520 | // DMA will be stopped when transfer is dropped | 488 | if !cr3.dmar() { |
| 489 | // something went wrong | ||
| 490 | // because the only way to get this flag cleared is to have an interrupt | ||
| 521 | 491 | ||
| 522 | let sr = sr(r).read(); | 492 | // DMA will be stopped when transfer is dropped |
| 523 | // This read also clears the error and idle interrupt flags on v1. | ||
| 524 | rdr(r).read_volatile(); | ||
| 525 | clear_interrupt_flags(r, sr); | ||
| 526 | 493 | ||
| 527 | if sr.pe() { | 494 | let sr = sr(r).read(); |
| 528 | return Err(Error::Parity); | 495 | // This read also clears the error and idle interrupt flags on v1. |
| 529 | } | 496 | unsafe { rdr(r).read_volatile() }; |
| 530 | if sr.fe() { | 497 | clear_interrupt_flags(r, sr); |
| 531 | return Err(Error::Framing); | ||
| 532 | } | ||
| 533 | if sr.ne() { | ||
| 534 | return Err(Error::Noise); | ||
| 535 | } | ||
| 536 | if sr.ore() { | ||
| 537 | return Err(Error::Overrun); | ||
| 538 | } | ||
| 539 | 498 | ||
| 540 | unreachable!(); | 499 | if sr.pe() { |
| 500 | return Err(Error::Parity); | ||
| 541 | } | 501 | } |
| 542 | 502 | if sr.fe() { | |
| 543 | if enable_idle_line_detection { | 503 | return Err(Error::Framing); |
| 544 | // clear idle flag | ||
| 545 | let sr = sr(r).read(); | ||
| 546 | // This read also clears the error and idle interrupt flags on v1. | ||
| 547 | rdr(r).read_volatile(); | ||
| 548 | clear_interrupt_flags(r, sr); | ||
| 549 | |||
| 550 | // enable idle interrupt | ||
| 551 | r.cr1().modify(|w| { | ||
| 552 | w.set_idleie(true); | ||
| 553 | }); | ||
| 554 | } | 504 | } |
| 505 | if sr.ne() { | ||
| 506 | return Err(Error::Noise); | ||
| 507 | } | ||
| 508 | if sr.ore() { | ||
| 509 | return Err(Error::Overrun); | ||
| 510 | } | ||
| 511 | |||
| 512 | unreachable!(); | ||
| 513 | } | ||
| 514 | |||
| 515 | if enable_idle_line_detection { | ||
| 516 | // clear idle flag | ||
| 517 | let sr = sr(r).read(); | ||
| 518 | // This read also clears the error and idle interrupt flags on v1. | ||
| 519 | unsafe { rdr(r).read_volatile() }; | ||
| 520 | clear_interrupt_flags(r, sr); | ||
| 521 | |||
| 522 | // enable idle interrupt | ||
| 523 | r.cr1().modify(|w| { | ||
| 524 | w.set_idleie(true); | ||
| 525 | }); | ||
| 555 | } | 526 | } |
| 556 | 527 | ||
| 557 | compiler_fence(Ordering::SeqCst); | 528 | compiler_fence(Ordering::SeqCst); |
| @@ -562,15 +533,11 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 562 | 533 | ||
| 563 | s.rx_waker.register(cx.waker()); | 534 | s.rx_waker.register(cx.waker()); |
| 564 | 535 | ||
| 565 | // SAFETY: read only and we only use Rx related flags | 536 | let sr = sr(r).read(); |
| 566 | let sr = unsafe { sr(r).read() }; | ||
| 567 | 537 | ||
| 568 | // SAFETY: only clears Rx related flags | 538 | // This read also clears the error and idle interrupt flags on v1. |
| 569 | unsafe { | 539 | unsafe { rdr(r).read_volatile() }; |
| 570 | // This read also clears the error and idle interrupt flags on v1. | 540 | clear_interrupt_flags(r, sr); |
| 571 | rdr(r).read_volatile(); | ||
| 572 | clear_interrupt_flags(r, sr); | ||
| 573 | } | ||
| 574 | 541 | ||
| 575 | compiler_fence(Ordering::SeqCst); | 542 | compiler_fence(Ordering::SeqCst); |
| 576 | 543 | ||
| @@ -650,7 +617,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 650 | peri: impl Peripheral<P = T> + 'd, | 617 | peri: impl Peripheral<P = T> + 'd, |
| 651 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 618 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 652 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 619 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 653 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 620 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 654 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 621 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 655 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 622 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 656 | config: Config, | 623 | config: Config, |
| @@ -665,7 +632,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 665 | peri: impl Peripheral<P = T> + 'd, | 632 | peri: impl Peripheral<P = T> + 'd, |
| 666 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 633 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 667 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 634 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 668 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 635 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 669 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | 636 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, |
| 670 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, | 637 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, |
| 671 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 638 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| @@ -677,14 +644,12 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 677 | T::enable(); | 644 | T::enable(); |
| 678 | T::reset(); | 645 | T::reset(); |
| 679 | 646 | ||
| 680 | unsafe { | 647 | rts.set_as_af(rts.af_num(), AFType::OutputPushPull); |
| 681 | rts.set_as_af(rts.af_num(), AFType::OutputPushPull); | 648 | cts.set_as_af(cts.af_num(), AFType::Input); |
| 682 | cts.set_as_af(cts.af_num(), AFType::Input); | 649 | T::regs().cr3().write(|w| { |
| 683 | T::regs().cr3().write(|w| { | 650 | w.set_rtse(true); |
| 684 | w.set_rtse(true); | 651 | w.set_ctse(true); |
| 685 | w.set_ctse(true); | 652 | }); |
| 686 | }); | ||
| 687 | } | ||
| 688 | Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) | 653 | Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) |
| 689 | } | 654 | } |
| 690 | 655 | ||
| @@ -693,7 +658,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 693 | peri: impl Peripheral<P = T> + 'd, | 658 | peri: impl Peripheral<P = T> + 'd, |
| 694 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 659 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 695 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 660 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 696 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 661 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 697 | de: impl Peripheral<P = impl DePin<T>> + 'd, | 662 | de: impl Peripheral<P = impl DePin<T>> + 'd, |
| 698 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 663 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 699 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 664 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| @@ -704,12 +669,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 704 | T::enable(); | 669 | T::enable(); |
| 705 | T::reset(); | 670 | T::reset(); |
| 706 | 671 | ||
| 707 | unsafe { | 672 | de.set_as_af(de.af_num(), AFType::OutputPushPull); |
| 708 | de.set_as_af(de.af_num(), AFType::OutputPushPull); | 673 | T::regs().cr3().write(|w| { |
| 709 | T::regs().cr3().write(|w| { | 674 | w.set_dem(true); |
| 710 | w.set_dem(true); | 675 | }); |
| 711 | }); | ||
| 712 | } | ||
| 713 | Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) | 676 | Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) |
| 714 | } | 677 | } |
| 715 | 678 | ||
| @@ -725,15 +688,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 725 | 688 | ||
| 726 | let r = T::regs(); | 689 | let r = T::regs(); |
| 727 | 690 | ||
| 728 | unsafe { | 691 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 729 | rx.set_as_af(rx.af_num(), AFType::Input); | 692 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 730 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 731 | } | ||
| 732 | 693 | ||
| 733 | configure(r, &config, T::frequency(), T::KIND, true, true); | 694 | configure(r, &config, T::frequency(), T::KIND, true, true); |
| 734 | 695 | ||
| 735 | unsafe { T::Interrupt::steal() }.unpend(); | 696 | T::Interrupt::unpend(); |
| 736 | unsafe { T::Interrupt::steal() }.enable(); | 697 | unsafe { T::Interrupt::enable() }; |
| 737 | 698 | ||
| 738 | // create state once! | 699 | // create state once! |
| 739 | let _s = T::state(); | 700 | let _s = T::state(); |
| @@ -847,11 +808,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | |||
| 847 | if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { | 808 | if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { |
| 848 | over8 = true; | 809 | over8 = true; |
| 849 | let div = div as u32; | 810 | let div = div as u32; |
| 850 | unsafe { | 811 | r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07))); |
| 851 | r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07))); | 812 | #[cfg(usart_v4)] |
| 852 | #[cfg(usart_v4)] | 813 | r.presc().write(|w| w.set_prescaler(_presc_val)); |
| 853 | r.presc().write(|w| w.set_prescaler(_presc_val)); | ||
| 854 | } | ||
| 855 | found = Some(div); | 814 | found = Some(div); |
| 856 | break; | 815 | break; |
| 857 | } | 816 | } |
| @@ -860,11 +819,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | |||
| 860 | 819 | ||
| 861 | if div < brr_max { | 820 | if div < brr_max { |
| 862 | let div = div as u32; | 821 | let div = div as u32; |
| 863 | unsafe { | 822 | r.brr().write_value(regs::Brr(div)); |
| 864 | r.brr().write_value(regs::Brr(div)); | 823 | #[cfg(usart_v4)] |
| 865 | #[cfg(usart_v4)] | 824 | r.presc().write(|w| w.set_prescaler(_presc_val)); |
| 866 | r.presc().write(|w| w.set_prescaler(_presc_val)); | ||
| 867 | } | ||
| 868 | found = Some(div); | 825 | found = Some(div); |
| 869 | break; | 826 | break; |
| 870 | } | 827 | } |
| @@ -883,44 +840,42 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | |||
| 883 | pclk_freq.0 / div | 840 | pclk_freq.0 / div |
| 884 | ); | 841 | ); |
| 885 | 842 | ||
| 886 | unsafe { | 843 | r.cr2().write(|w| { |
| 887 | r.cr2().write(|w| { | 844 | w.set_stop(match config.stop_bits { |
| 888 | w.set_stop(match config.stop_bits { | 845 | StopBits::STOP0P5 => vals::Stop::STOP0P5, |
| 889 | StopBits::STOP0P5 => vals::Stop::STOP0P5, | 846 | StopBits::STOP1 => vals::Stop::STOP1, |
| 890 | StopBits::STOP1 => vals::Stop::STOP1, | 847 | StopBits::STOP1P5 => vals::Stop::STOP1P5, |
| 891 | StopBits::STOP1P5 => vals::Stop::STOP1P5, | 848 | StopBits::STOP2 => vals::Stop::STOP2, |
| 892 | StopBits::STOP2 => vals::Stop::STOP2, | ||
| 893 | }); | ||
| 894 | }); | 849 | }); |
| 895 | r.cr1().write(|w| { | 850 | }); |
| 896 | // enable uart | 851 | r.cr1().write(|w| { |
| 897 | w.set_ue(true); | 852 | // enable uart |
| 898 | // enable transceiver | 853 | w.set_ue(true); |
| 899 | w.set_te(enable_tx); | 854 | // enable transceiver |
| 900 | // enable receiver | 855 | w.set_te(enable_tx); |
| 901 | w.set_re(enable_rx); | 856 | // enable receiver |
| 902 | // configure word size | 857 | w.set_re(enable_rx); |
| 903 | w.set_m0(if config.parity != Parity::ParityNone { | 858 | // configure word size |
| 904 | vals::M0::BIT9 | 859 | w.set_m0(if config.parity != Parity::ParityNone { |
| 905 | } else { | 860 | vals::M0::BIT9 |
| 906 | vals::M0::BIT8 | 861 | } else { |
| 907 | }); | 862 | vals::M0::BIT8 |
| 908 | // configure parity | ||
| 909 | w.set_pce(config.parity != Parity::ParityNone); | ||
| 910 | w.set_ps(match config.parity { | ||
| 911 | Parity::ParityOdd => vals::Ps::ODD, | ||
| 912 | Parity::ParityEven => vals::Ps::EVEN, | ||
| 913 | _ => vals::Ps::EVEN, | ||
| 914 | }); | ||
| 915 | #[cfg(not(usart_v1))] | ||
| 916 | w.set_over8(vals::Over8(over8 as _)); | ||
| 917 | }); | 863 | }); |
| 918 | 864 | // configure parity | |
| 919 | #[cfg(not(usart_v1))] | 865 | w.set_pce(config.parity != Parity::ParityNone); |
| 920 | r.cr3().modify(|w| { | 866 | w.set_ps(match config.parity { |
| 921 | w.set_onebit(config.assume_noise_free); | 867 | Parity::ParityOdd => vals::Ps::ODD, |
| 868 | Parity::ParityEven => vals::Ps::EVEN, | ||
| 869 | _ => vals::Ps::EVEN, | ||
| 922 | }); | 870 | }); |
| 923 | } | 871 | #[cfg(not(usart_v1))] |
| 872 | w.set_over8(vals::Over8(over8 as _)); | ||
| 873 | }); | ||
| 874 | |||
| 875 | #[cfg(not(usart_v1))] | ||
| 876 | r.cr3().modify(|w| { | ||
| 877 | w.set_onebit(config.assume_noise_free); | ||
| 878 | }); | ||
| 924 | } | 879 | } |
| 925 | 880 | ||
| 926 | mod eh02 { | 881 | mod eh02 { |
| @@ -1111,12 +1066,12 @@ use self::sealed::Kind; | |||
| 1111 | 1066 | ||
| 1112 | #[cfg(any(usart_v1, usart_v2))] | 1067 | #[cfg(any(usart_v1, usart_v2))] |
| 1113 | fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { | 1068 | fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { |
| 1114 | r.dr().ptr() as _ | 1069 | r.dr().as_ptr() as _ |
| 1115 | } | 1070 | } |
| 1116 | 1071 | ||
| 1117 | #[cfg(any(usart_v1, usart_v2))] | 1072 | #[cfg(any(usart_v1, usart_v2))] |
| 1118 | fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { | 1073 | fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { |
| 1119 | r.dr().ptr() as _ | 1074 | r.dr().as_ptr() as _ |
| 1120 | } | 1075 | } |
| 1121 | 1076 | ||
| 1122 | #[cfg(any(usart_v1, usart_v2))] | 1077 | #[cfg(any(usart_v1, usart_v2))] |
| @@ -1126,18 +1081,18 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::p | |||
| 1126 | 1081 | ||
| 1127 | #[cfg(any(usart_v1, usart_v2))] | 1082 | #[cfg(any(usart_v1, usart_v2))] |
| 1128 | #[allow(unused)] | 1083 | #[allow(unused)] |
| 1129 | unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) { | 1084 | fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) { |
| 1130 | // On v1 the flags are cleared implicitly by reads and writes to DR. | 1085 | // On v1 the flags are cleared implicitly by reads and writes to DR. |
| 1131 | } | 1086 | } |
| 1132 | 1087 | ||
| 1133 | #[cfg(any(usart_v3, usart_v4))] | 1088 | #[cfg(any(usart_v3, usart_v4))] |
| 1134 | fn tdr(r: Regs) -> *mut u8 { | 1089 | fn tdr(r: Regs) -> *mut u8 { |
| 1135 | r.tdr().ptr() as _ | 1090 | r.tdr().as_ptr() as _ |
| 1136 | } | 1091 | } |
| 1137 | 1092 | ||
| 1138 | #[cfg(any(usart_v3, usart_v4))] | 1093 | #[cfg(any(usart_v3, usart_v4))] |
| 1139 | fn rdr(r: Regs) -> *mut u8 { | 1094 | fn rdr(r: Regs) -> *mut u8 { |
| 1140 | r.rdr().ptr() as _ | 1095 | r.rdr().as_ptr() as _ |
| 1141 | } | 1096 | } |
| 1142 | 1097 | ||
| 1143 | #[cfg(any(usart_v3, usart_v4))] | 1098 | #[cfg(any(usart_v3, usart_v4))] |
| @@ -1147,7 +1102,7 @@ fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> { | |||
| 1147 | 1102 | ||
| 1148 | #[cfg(any(usart_v3, usart_v4))] | 1103 | #[cfg(any(usart_v3, usart_v4))] |
| 1149 | #[allow(unused)] | 1104 | #[allow(unused)] |
| 1150 | unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { | 1105 | fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { |
| 1151 | r.icr().write(|w| *w = regs::Icr(sr.0)); | 1106 | r.icr().write(|w| *w = regs::Icr(sr.0)); |
| 1152 | } | 1107 | } |
| 1153 | 1108 | ||
| @@ -1179,7 +1134,7 @@ pub(crate) mod sealed { | |||
| 1179 | 1134 | ||
| 1180 | pub trait BasicInstance: crate::rcc::RccPeripheral { | 1135 | pub trait BasicInstance: crate::rcc::RccPeripheral { |
| 1181 | const KIND: Kind; | 1136 | const KIND: Kind; |
| 1182 | type Interrupt: crate::interrupt::Interrupt; | 1137 | type Interrupt: interrupt::typelevel::Interrupt; |
| 1183 | 1138 | ||
| 1184 | fn regs() -> Regs; | 1139 | fn regs() -> Regs; |
| 1185 | fn state() -> &'static State; | 1140 | fn state() -> &'static State; |
| @@ -1211,10 +1166,10 @@ macro_rules! impl_usart { | |||
| 1211 | ($inst:ident, $irq:ident, $kind:expr) => { | 1166 | ($inst:ident, $irq:ident, $kind:expr) => { |
| 1212 | impl sealed::BasicInstance for crate::peripherals::$inst { | 1167 | impl sealed::BasicInstance for crate::peripherals::$inst { |
| 1213 | const KIND: Kind = $kind; | 1168 | const KIND: Kind = $kind; |
| 1214 | type Interrupt = crate::interrupt::$irq; | 1169 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 1215 | 1170 | ||
| 1216 | fn regs() -> Regs { | 1171 | fn regs() -> Regs { |
| 1217 | Regs(crate::pac::$inst.0) | 1172 | unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) } |
| 1218 | } | 1173 | } |
| 1219 | 1174 | ||
| 1220 | fn state() -> &'static crate::usart::sealed::State { | 1175 | fn state() -> &'static crate::usart::sealed::State { |
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 511b71c7f..c74d7e092 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs | |||
| @@ -59,23 +59,20 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD | |||
| 59 | 59 | ||
| 60 | let r = T::regs(); | 60 | let r = T::regs(); |
| 61 | // clear all interrupts and DMA Rx Request | 61 | // clear all interrupts and DMA Rx Request |
| 62 | // SAFETY: only clears Rx related flags | 62 | r.cr1().modify(|w| { |
| 63 | unsafe { | 63 | // disable RXNE interrupt |
| 64 | r.cr1().modify(|w| { | 64 | w.set_rxneie(false); |
| 65 | // disable RXNE interrupt | 65 | // enable parity interrupt if not ParityNone |
| 66 | w.set_rxneie(false); | 66 | w.set_peie(w.pce()); |
| 67 | // enable parity interrupt if not ParityNone | 67 | // enable idle line interrupt |
| 68 | w.set_peie(w.pce()); | 68 | w.set_idleie(true); |
| 69 | // enable idle line interrupt | 69 | }); |
| 70 | w.set_idleie(true); | 70 | r.cr3().modify(|w| { |
| 71 | }); | 71 | // enable Error Interrupt: (Frame error, Noise error, Overrun error) |
| 72 | r.cr3().modify(|w| { | 72 | w.set_eie(true); |
| 73 | // enable Error Interrupt: (Frame error, Noise error, Overrun error) | 73 | // enable DMA Rx Request |
| 74 | w.set_eie(true); | 74 | w.set_dmar(true); |
| 75 | // enable DMA Rx Request | 75 | }); |
| 76 | w.set_dmar(true); | ||
| 77 | }); | ||
| 78 | } | ||
| 79 | } | 76 | } |
| 80 | 77 | ||
| 81 | /// Stop uart background receive | 78 | /// Stop uart background receive |
| @@ -84,23 +81,20 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD | |||
| 84 | 81 | ||
| 85 | let r = T::regs(); | 82 | let r = T::regs(); |
| 86 | // clear all interrupts and DMA Rx Request | 83 | // clear all interrupts and DMA Rx Request |
| 87 | // SAFETY: only clears Rx related flags | 84 | r.cr1().modify(|w| { |
| 88 | unsafe { | 85 | // disable RXNE interrupt |
| 89 | r.cr1().modify(|w| { | 86 | w.set_rxneie(false); |
| 90 | // disable RXNE interrupt | 87 | // disable parity interrupt |
| 91 | w.set_rxneie(false); | 88 | w.set_peie(false); |
| 92 | // disable parity interrupt | 89 | // disable idle line interrupt |
| 93 | w.set_peie(false); | 90 | w.set_idleie(false); |
| 94 | // disable idle line interrupt | 91 | }); |
| 95 | w.set_idleie(false); | 92 | r.cr3().modify(|w| { |
| 96 | }); | 93 | // disable Error Interrupt: (Frame error, Noise error, Overrun error) |
| 97 | r.cr3().modify(|w| { | 94 | w.set_eie(false); |
| 98 | // disable Error Interrupt: (Frame error, Noise error, Overrun error) | 95 | // disable DMA Rx Request |
| 99 | w.set_eie(false); | 96 | w.set_dmar(false); |
| 100 | // disable DMA Rx Request | 97 | }); |
| 101 | w.set_dmar(false); | ||
| 102 | }); | ||
| 103 | } | ||
| 104 | 98 | ||
| 105 | compiler_fence(Ordering::SeqCst); | 99 | compiler_fence(Ordering::SeqCst); |
| 106 | } | 100 | } |
| @@ -117,8 +111,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD | |||
| 117 | let r = T::regs(); | 111 | let r = T::regs(); |
| 118 | 112 | ||
| 119 | // Start background receive if it was not already started | 113 | // Start background receive if it was not already started |
| 120 | // SAFETY: read only | 114 | match r.cr3().read().dmar() { |
| 121 | match unsafe { r.cr3().read().dmar() } { | ||
| 122 | false => self.start()?, | 115 | false => self.start()?, |
| 123 | _ => {} | 116 | _ => {} |
| 124 | }; | 117 | }; |
| @@ -213,19 +206,17 @@ fn check_for_errors(s: Sr) -> Result<(), Error> { | |||
| 213 | 206 | ||
| 214 | /// Clear IDLE and return the Sr register | 207 | /// Clear IDLE and return the Sr register |
| 215 | fn clear_idle_flag(r: Regs) -> Sr { | 208 | fn clear_idle_flag(r: Regs) -> Sr { |
| 216 | unsafe { | 209 | // SAFETY: read only and we only use Rx related flags |
| 217 | // SAFETY: read only and we only use Rx related flags | ||
| 218 | 210 | ||
| 219 | let sr = sr(r).read(); | 211 | let sr = sr(r).read(); |
| 220 | 212 | ||
| 221 | // This read also clears the error and idle interrupt flags on v1. | 213 | // This read also clears the error and idle interrupt flags on v1. |
| 222 | rdr(r).read_volatile(); | 214 | unsafe { rdr(r).read_volatile() }; |
| 223 | clear_interrupt_flags(r, sr); | 215 | clear_interrupt_flags(r, sr); |
| 224 | 216 | ||
| 225 | r.cr1().modify(|w| w.set_idleie(true)); | 217 | r.cr1().modify(|w| w.set_idleie(true)); |
| 226 | 218 | ||
| 227 | sr | 219 | sr |
| 228 | } | ||
| 229 | } | 220 | } |
| 230 | 221 | ||
| 231 | #[cfg(all(feature = "unstable-traits", feature = "nightly"))] | 222 | #[cfg(all(feature = "unstable-traits", feature = "nightly"))] |
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index fbd1fa823..bee287fe6 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use crate::interrupt::Interrupt; | 1 | use crate::interrupt; |
| 2 | use crate::rcc::RccPeripheral; | 2 | use crate::rcc::RccPeripheral; |
| 3 | 3 | ||
| 4 | #[cfg(feature = "nightly")] | 4 | #[cfg(feature = "nightly")] |
| @@ -13,7 +13,7 @@ pub(crate) mod sealed { | |||
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | 15 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { |
| 16 | type Interrupt: Interrupt; | 16 | type Interrupt: interrupt::typelevel::Interrupt; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | // Internal PHY pins | 19 | // Internal PHY pins |
| @@ -29,7 +29,7 @@ foreach_interrupt!( | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | impl Instance for crate::peripherals::$inst { | 31 | impl Instance for crate::peripherals::$inst { |
| 32 | type Interrupt = crate::interrupt::$irq; | 32 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 33 | } | 33 | } |
| 34 | }; | 34 | }; |
| 35 | ); | 35 | ); |
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index a9ff284ae..2367127e8 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -14,7 +14,7 @@ use embassy_usb_driver::{ | |||
| 14 | 14 | ||
| 15 | use super::{DmPin, DpPin, Instance}; | 15 | use super::{DmPin, DpPin, Instance}; |
| 16 | use crate::gpio::sealed::AFType; | 16 | use crate::gpio::sealed::AFType; |
| 17 | use crate::interrupt::{Interrupt, InterruptExt}; | 17 | use crate::interrupt::typelevel::Interrupt; |
| 18 | use crate::pac::usb::regs; | 18 | use crate::pac::usb::regs; |
| 19 | use crate::pac::usb::vals::{EpType, Stat}; | 19 | use crate::pac::usb::vals::{EpType, Stat}; |
| 20 | use crate::pac::USBRAM; | 20 | use crate::pac::USBRAM; |
| @@ -26,84 +26,82 @@ pub struct InterruptHandler<T: Instance> { | |||
| 26 | _phantom: PhantomData<T>, | 26 | _phantom: PhantomData<T>, |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 29 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 30 | unsafe fn on_interrupt() { | 30 | unsafe fn on_interrupt() { |
| 31 | unsafe { | 31 | let regs = T::regs(); |
| 32 | let regs = T::regs(); | 32 | //let x = regs.istr().read().0; |
| 33 | //let x = regs.istr().read().0; | 33 | //trace!("USB IRQ: {:08x}", x); |
| 34 | //trace!("USB IRQ: {:08x}", x); | ||
| 35 | |||
| 36 | let istr = regs.istr().read(); | ||
| 37 | |||
| 38 | if istr.susp() { | ||
| 39 | //trace!("USB IRQ: susp"); | ||
| 40 | IRQ_SUSPEND.store(true, Ordering::Relaxed); | ||
| 41 | regs.cntr().modify(|w| { | ||
| 42 | w.set_fsusp(true); | ||
| 43 | w.set_lpmode(true); | ||
| 44 | }); | ||
| 45 | |||
| 46 | // Write 0 to clear. | ||
| 47 | let mut clear = regs::Istr(!0); | ||
| 48 | clear.set_susp(false); | ||
| 49 | regs.istr().write_value(clear); | ||
| 50 | |||
| 51 | // Wake main thread. | ||
| 52 | BUS_WAKER.wake(); | ||
| 53 | } | ||
| 54 | 34 | ||
| 55 | if istr.wkup() { | 35 | let istr = regs.istr().read(); |
| 56 | //trace!("USB IRQ: wkup"); | ||
| 57 | IRQ_RESUME.store(true, Ordering::Relaxed); | ||
| 58 | regs.cntr().modify(|w| { | ||
| 59 | w.set_fsusp(false); | ||
| 60 | w.set_lpmode(false); | ||
| 61 | }); | ||
| 62 | |||
| 63 | // Write 0 to clear. | ||
| 64 | let mut clear = regs::Istr(!0); | ||
| 65 | clear.set_wkup(false); | ||
| 66 | regs.istr().write_value(clear); | ||
| 67 | |||
| 68 | // Wake main thread. | ||
| 69 | BUS_WAKER.wake(); | ||
| 70 | } | ||
| 71 | 36 | ||
| 72 | if istr.reset() { | 37 | if istr.susp() { |
| 73 | //trace!("USB IRQ: reset"); | 38 | //trace!("USB IRQ: susp"); |
| 74 | IRQ_RESET.store(true, Ordering::Relaxed); | 39 | IRQ_SUSPEND.store(true, Ordering::Relaxed); |
| 40 | regs.cntr().modify(|w| { | ||
| 41 | w.set_fsusp(true); | ||
| 42 | w.set_lpmode(true); | ||
| 43 | }); | ||
| 75 | 44 | ||
| 76 | // Write 0 to clear. | 45 | // Write 0 to clear. |
| 77 | let mut clear = regs::Istr(!0); | 46 | let mut clear = regs::Istr(!0); |
| 78 | clear.set_reset(false); | 47 | clear.set_susp(false); |
| 79 | regs.istr().write_value(clear); | 48 | regs.istr().write_value(clear); |
| 80 | 49 | ||
| 81 | // Wake main thread. | 50 | // Wake main thread. |
| 82 | BUS_WAKER.wake(); | 51 | BUS_WAKER.wake(); |
| 83 | } | 52 | } |
| 84 | 53 | ||
| 85 | if istr.ctr() { | 54 | if istr.wkup() { |
| 86 | let index = istr.ep_id() as usize; | 55 | //trace!("USB IRQ: wkup"); |
| 87 | let mut epr = regs.epr(index).read(); | 56 | IRQ_RESUME.store(true, Ordering::Relaxed); |
| 88 | if epr.ctr_rx() { | 57 | regs.cntr().modify(|w| { |
| 89 | if index == 0 && epr.setup() { | 58 | w.set_fsusp(false); |
| 90 | EP0_SETUP.store(true, Ordering::Relaxed); | 59 | w.set_lpmode(false); |
| 91 | } | 60 | }); |
| 92 | //trace!("EP {} RX, setup={}", index, epr.setup()); | 61 | |
| 93 | EP_OUT_WAKERS[index].wake(); | 62 | // Write 0 to clear. |
| 94 | } | 63 | let mut clear = regs::Istr(!0); |
| 95 | if epr.ctr_tx() { | 64 | clear.set_wkup(false); |
| 96 | //trace!("EP {} TX", index); | 65 | regs.istr().write_value(clear); |
| 97 | EP_IN_WAKERS[index].wake(); | 66 | |
| 67 | // Wake main thread. | ||
| 68 | BUS_WAKER.wake(); | ||
| 69 | } | ||
| 70 | |||
| 71 | if istr.reset() { | ||
| 72 | //trace!("USB IRQ: reset"); | ||
| 73 | IRQ_RESET.store(true, Ordering::Relaxed); | ||
| 74 | |||
| 75 | // Write 0 to clear. | ||
| 76 | let mut clear = regs::Istr(!0); | ||
| 77 | clear.set_reset(false); | ||
| 78 | regs.istr().write_value(clear); | ||
| 79 | |||
| 80 | // Wake main thread. | ||
| 81 | BUS_WAKER.wake(); | ||
| 82 | } | ||
| 83 | |||
| 84 | if istr.ctr() { | ||
| 85 | let index = istr.ep_id() as usize; | ||
| 86 | let mut epr = regs.epr(index).read(); | ||
| 87 | if epr.ctr_rx() { | ||
| 88 | if index == 0 && epr.setup() { | ||
| 89 | EP0_SETUP.store(true, Ordering::Relaxed); | ||
| 98 | } | 90 | } |
| 99 | epr.set_dtog_rx(false); | 91 | //trace!("EP {} RX, setup={}", index, epr.setup()); |
| 100 | epr.set_dtog_tx(false); | 92 | EP_OUT_WAKERS[index].wake(); |
| 101 | epr.set_stat_rx(Stat(0)); | 93 | } |
| 102 | epr.set_stat_tx(Stat(0)); | 94 | if epr.ctr_tx() { |
| 103 | epr.set_ctr_rx(!epr.ctr_rx()); | 95 | //trace!("EP {} TX", index); |
| 104 | epr.set_ctr_tx(!epr.ctr_tx()); | 96 | EP_IN_WAKERS[index].wake(); |
| 105 | regs.epr(index).write_value(epr); | ||
| 106 | } | 97 | } |
| 98 | epr.set_dtog_rx(false); | ||
| 99 | epr.set_dtog_tx(false); | ||
| 100 | epr.set_stat_rx(Stat(0)); | ||
| 101 | epr.set_stat_tx(Stat(0)); | ||
| 102 | epr.set_ctr_rx(!epr.ctr_rx()); | ||
| 103 | epr.set_ctr_tx(!epr.ctr_tx()); | ||
| 104 | regs.epr(index).write_value(epr); | ||
| 107 | } | 105 | } |
| 108 | } | 106 | } |
| 109 | } | 107 | } |
| @@ -168,20 +166,20 @@ fn calc_out_len(len: u16) -> (u16, u16) { | |||
| 168 | mod btable { | 166 | mod btable { |
| 169 | use super::*; | 167 | use super::*; |
| 170 | 168 | ||
| 171 | pub(super) unsafe fn write_in<T: Instance>(index: usize, addr: u16) { | 169 | pub(super) fn write_in<T: Instance>(index: usize, addr: u16) { |
| 172 | USBRAM.mem(index * 4 + 0).write_value(addr); | 170 | USBRAM.mem(index * 4 + 0).write_value(addr); |
| 173 | } | 171 | } |
| 174 | 172 | ||
| 175 | pub(super) unsafe fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { | 173 | pub(super) fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { |
| 176 | USBRAM.mem(index * 4 + 1).write_value(len); | 174 | USBRAM.mem(index * 4 + 1).write_value(len); |
| 177 | } | 175 | } |
| 178 | 176 | ||
| 179 | pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { | 177 | pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { |
| 180 | USBRAM.mem(index * 4 + 2).write_value(addr); | 178 | USBRAM.mem(index * 4 + 2).write_value(addr); |
| 181 | USBRAM.mem(index * 4 + 3).write_value(max_len_bits); | 179 | USBRAM.mem(index * 4 + 3).write_value(max_len_bits); |
| 182 | } | 180 | } |
| 183 | 181 | ||
| 184 | pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { | 182 | pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 { |
| 185 | USBRAM.mem(index * 4 + 3).read() | 183 | USBRAM.mem(index * 4 + 3).read() |
| 186 | } | 184 | } |
| 187 | } | 185 | } |
| @@ -189,19 +187,19 @@ mod btable { | |||
| 189 | mod btable { | 187 | mod btable { |
| 190 | use super::*; | 188 | use super::*; |
| 191 | 189 | ||
| 192 | pub(super) unsafe fn write_in<T: Instance>(_index: usize, _addr: u16) {} | 190 | pub(super) fn write_in<T: Instance>(_index: usize, _addr: u16) {} |
| 193 | 191 | ||
| 194 | pub(super) unsafe fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) { | 192 | pub(super) fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) { |
| 195 | USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); | 193 | USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); |
| 196 | } | 194 | } |
| 197 | 195 | ||
| 198 | pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { | 196 | pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { |
| 199 | USBRAM | 197 | USBRAM |
| 200 | .mem(index * 2 + 1) | 198 | .mem(index * 2 + 1) |
| 201 | .write_value((addr as u32) | ((max_len_bits as u32) << 16)); | 199 | .write_value((addr as u32) | ((max_len_bits as u32) << 16)); |
| 202 | } | 200 | } |
| 203 | 201 | ||
| 204 | pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { | 202 | pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 { |
| 205 | (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 | 203 | (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 |
| 206 | } | 204 | } |
| 207 | } | 205 | } |
| @@ -216,7 +214,7 @@ impl<T: Instance> EndpointBuffer<T> { | |||
| 216 | fn read(&mut self, buf: &mut [u8]) { | 214 | fn read(&mut self, buf: &mut [u8]) { |
| 217 | assert!(buf.len() <= self.len as usize); | 215 | assert!(buf.len() <= self.len as usize); |
| 218 | for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { | 216 | for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { |
| 219 | let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() }; | 217 | let val = USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read(); |
| 220 | let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); | 218 | let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); |
| 221 | buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]); | 219 | buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]); |
| 222 | } | 220 | } |
| @@ -233,7 +231,7 @@ impl<T: Instance> EndpointBuffer<T> { | |||
| 233 | let val = u16::from_le_bytes(val); | 231 | let val = u16::from_le_bytes(val); |
| 234 | #[cfg(usbram_32_2048)] | 232 | #[cfg(usbram_32_2048)] |
| 235 | let val = u32::from_le_bytes(val); | 233 | let val = u32::from_le_bytes(val); |
| 236 | unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) }; | 234 | USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val); |
| 237 | } | 235 | } |
| 238 | } | 236 | } |
| 239 | } | 237 | } |
| @@ -255,47 +253,43 @@ pub struct Driver<'d, T: Instance> { | |||
| 255 | impl<'d, T: Instance> Driver<'d, T> { | 253 | impl<'d, T: Instance> Driver<'d, T> { |
| 256 | pub fn new( | 254 | pub fn new( |
| 257 | _usb: impl Peripheral<P = T> + 'd, | 255 | _usb: impl Peripheral<P = T> + 'd, |
| 258 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 256 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 259 | dp: impl Peripheral<P = impl DpPin<T>> + 'd, | 257 | dp: impl Peripheral<P = impl DpPin<T>> + 'd, |
| 260 | dm: impl Peripheral<P = impl DmPin<T>> + 'd, | 258 | dm: impl Peripheral<P = impl DmPin<T>> + 'd, |
| 261 | ) -> Self { | 259 | ) -> Self { |
| 262 | into_ref!(dp, dm); | 260 | into_ref!(dp, dm); |
| 263 | unsafe { T::Interrupt::steal() }.unpend(); | 261 | T::Interrupt::unpend(); |
| 264 | unsafe { T::Interrupt::steal() }.enable(); | 262 | unsafe { T::Interrupt::enable() }; |
| 265 | 263 | ||
| 266 | let regs = T::regs(); | 264 | let regs = T::regs(); |
| 267 | 265 | ||
| 268 | #[cfg(stm32l5)] | 266 | #[cfg(stm32l5)] |
| 269 | unsafe { | 267 | { |
| 270 | crate::peripherals::PWR::enable(); | 268 | crate::peripherals::PWR::enable(); |
| 271 | crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); | 269 | crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); |
| 272 | } | 270 | } |
| 273 | 271 | ||
| 274 | #[cfg(pwr_h5)] | 272 | #[cfg(pwr_h5)] |
| 275 | unsafe { | 273 | crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)); |
| 276 | crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)) | ||
| 277 | } | ||
| 278 | 274 | ||
| 279 | unsafe { | 275 | <T as RccPeripheral>::enable(); |
| 280 | <T as RccPeripheral>::enable(); | 276 | <T as RccPeripheral>::reset(); |
| 281 | <T as RccPeripheral>::reset(); | ||
| 282 | 277 | ||
| 283 | regs.cntr().write(|w| { | 278 | regs.cntr().write(|w| { |
| 284 | w.set_pdwn(false); | 279 | w.set_pdwn(false); |
| 285 | w.set_fres(true); | 280 | w.set_fres(true); |
| 286 | }); | 281 | }); |
| 287 | 282 | ||
| 288 | #[cfg(time)] | 283 | #[cfg(time)] |
| 289 | embassy_time::block_for(embassy_time::Duration::from_millis(100)); | 284 | embassy_time::block_for(embassy_time::Duration::from_millis(100)); |
| 290 | #[cfg(not(time))] | 285 | #[cfg(not(time))] |
| 291 | cortex_m::asm::delay(crate::rcc::get_freqs().sys.0 / 10); | 286 | cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.0 / 10); |
| 292 | 287 | ||
| 293 | #[cfg(not(usb_v4))] | 288 | #[cfg(not(usb_v4))] |
| 294 | regs.btable().write(|w| w.set_btable(0)); | 289 | regs.btable().write(|w| w.set_btable(0)); |
| 295 | 290 | ||
| 296 | dp.set_as_af(dp.af_num(), AFType::OutputPushPull); | 291 | dp.set_as_af(dp.af_num(), AFType::OutputPushPull); |
| 297 | dm.set_as_af(dm.af_num(), AFType::OutputPushPull); | 292 | dm.set_as_af(dm.af_num(), AFType::OutputPushPull); |
| 298 | } | ||
| 299 | 293 | ||
| 300 | // Initialize the bus so that it signals that power is available | 294 | // Initialize the bus so that it signals that power is available |
| 301 | BUS_WAKER.wake(); | 295 | BUS_WAKER.wake(); |
| @@ -363,7 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 363 | let addr = self.alloc_ep_mem(len); | 357 | let addr = self.alloc_ep_mem(len); |
| 364 | 358 | ||
| 365 | trace!(" len_bits = {:04x}", len_bits); | 359 | trace!(" len_bits = {:04x}", len_bits); |
| 366 | unsafe { btable::write_out::<T>(index, addr, len_bits) } | 360 | btable::write_out::<T>(index, addr, len_bits); |
| 367 | 361 | ||
| 368 | EndpointBuffer { | 362 | EndpointBuffer { |
| 369 | addr, | 363 | addr, |
| @@ -379,7 +373,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 379 | let addr = self.alloc_ep_mem(len); | 373 | let addr = self.alloc_ep_mem(len); |
| 380 | 374 | ||
| 381 | // ep_in_len is written when actually TXing packets. | 375 | // ep_in_len is written when actually TXing packets. |
| 382 | unsafe { btable::write_in::<T>(index, addr) } | 376 | btable::write_in::<T>(index, addr); |
| 383 | 377 | ||
| 384 | EndpointBuffer { | 378 | EndpointBuffer { |
| 385 | addr, | 379 | addr, |
| @@ -440,19 +434,17 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 440 | 434 | ||
| 441 | let regs = T::regs(); | 435 | let regs = T::regs(); |
| 442 | 436 | ||
| 443 | unsafe { | 437 | regs.cntr().write(|w| { |
| 444 | regs.cntr().write(|w| { | 438 | w.set_pdwn(false); |
| 445 | w.set_pdwn(false); | 439 | w.set_fres(false); |
| 446 | w.set_fres(false); | 440 | w.set_resetm(true); |
| 447 | w.set_resetm(true); | 441 | w.set_suspm(true); |
| 448 | w.set_suspm(true); | 442 | w.set_wkupm(true); |
| 449 | w.set_wkupm(true); | 443 | w.set_ctrm(true); |
| 450 | w.set_ctrm(true); | 444 | }); |
| 451 | }); | ||
| 452 | 445 | ||
| 453 | #[cfg(any(usb_v3, usb_v4))] | 446 | #[cfg(any(usb_v3, usb_v4))] |
| 454 | regs.bcdr().write(|w| w.set_dppu(true)) | 447 | regs.bcdr().write(|w| w.set_dppu(true)); |
| 455 | } | ||
| 456 | 448 | ||
| 457 | trace!("enabled"); | 449 | trace!("enabled"); |
| 458 | 450 | ||
| @@ -485,7 +477,7 @@ pub struct Bus<'d, T: Instance> { | |||
| 485 | 477 | ||
| 486 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | 478 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { |
| 487 | async fn poll(&mut self) -> Event { | 479 | async fn poll(&mut self) -> Event { |
| 488 | poll_fn(move |cx| unsafe { | 480 | poll_fn(move |cx| { |
| 489 | BUS_WAKER.register(cx.waker()); | 481 | BUS_WAKER.register(cx.waker()); |
| 490 | 482 | ||
| 491 | if self.inited { | 483 | if self.inited { |
| @@ -548,7 +540,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 548 | match ep_addr.direction() { | 540 | match ep_addr.direction() { |
| 549 | Direction::In => { | 541 | Direction::In => { |
| 550 | loop { | 542 | loop { |
| 551 | let r = unsafe { reg.read() }; | 543 | let r = reg.read(); |
| 552 | match r.stat_tx() { | 544 | match r.stat_tx() { |
| 553 | Stat::DISABLED => break, // if disabled, stall does nothing. | 545 | Stat::DISABLED => break, // if disabled, stall does nothing. |
| 554 | Stat::STALL => break, // done! | 546 | Stat::STALL => break, // done! |
| @@ -559,7 +551,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 559 | }; | 551 | }; |
| 560 | let mut w = invariant(r); | 552 | let mut w = invariant(r); |
| 561 | w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); | 553 | w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); |
| 562 | unsafe { reg.write_value(w) }; | 554 | reg.write_value(w); |
| 563 | } | 555 | } |
| 564 | } | 556 | } |
| 565 | } | 557 | } |
| @@ -567,7 +559,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 567 | } | 559 | } |
| 568 | Direction::Out => { | 560 | Direction::Out => { |
| 569 | loop { | 561 | loop { |
| 570 | let r = unsafe { reg.read() }; | 562 | let r = reg.read(); |
| 571 | match r.stat_rx() { | 563 | match r.stat_rx() { |
| 572 | Stat::DISABLED => break, // if disabled, stall does nothing. | 564 | Stat::DISABLED => break, // if disabled, stall does nothing. |
| 573 | Stat::STALL => break, // done! | 565 | Stat::STALL => break, // done! |
| @@ -578,7 +570,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 578 | }; | 570 | }; |
| 579 | let mut w = invariant(r); | 571 | let mut w = invariant(r); |
| 580 | w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); | 572 | w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); |
| 581 | unsafe { reg.write_value(w) }; | 573 | reg.write_value(w); |
| 582 | } | 574 | } |
| 583 | } | 575 | } |
| 584 | } | 576 | } |
| @@ -589,7 +581,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 589 | 581 | ||
| 590 | fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool { | 582 | fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool { |
| 591 | let regs = T::regs(); | 583 | let regs = T::regs(); |
| 592 | let epr = unsafe { regs.epr(ep_addr.index() as _).read() }; | 584 | let epr = regs.epr(ep_addr.index() as _).read(); |
| 593 | match ep_addr.direction() { | 585 | match ep_addr.direction() { |
| 594 | Direction::In => epr.stat_tx() == Stat::STALL, | 586 | Direction::In => epr.stat_tx() == Stat::STALL, |
| 595 | Direction::Out => epr.stat_rx() == Stat::STALL, | 587 | Direction::Out => epr.stat_rx() == Stat::STALL, |
| @@ -600,7 +592,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 600 | trace!("set_enabled {:x} {}", ep_addr, enabled); | 592 | trace!("set_enabled {:x} {}", ep_addr, enabled); |
| 601 | // This can race, so do a retry loop. | 593 | // This can race, so do a retry loop. |
| 602 | let reg = T::regs().epr(ep_addr.index() as _); | 594 | let reg = T::regs().epr(ep_addr.index() as _); |
| 603 | trace!("EPR before: {:04x}", unsafe { reg.read() }.0); | 595 | trace!("EPR before: {:04x}", reg.read().0); |
| 604 | match ep_addr.direction() { | 596 | match ep_addr.direction() { |
| 605 | Direction::In => { | 597 | Direction::In => { |
| 606 | loop { | 598 | loop { |
| @@ -608,13 +600,13 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 608 | false => Stat::DISABLED, | 600 | false => Stat::DISABLED, |
| 609 | true => Stat::NAK, | 601 | true => Stat::NAK, |
| 610 | }; | 602 | }; |
| 611 | let r = unsafe { reg.read() }; | 603 | let r = reg.read(); |
| 612 | if r.stat_tx() == want_stat { | 604 | if r.stat_tx() == want_stat { |
| 613 | break; | 605 | break; |
| 614 | } | 606 | } |
| 615 | let mut w = invariant(r); | 607 | let mut w = invariant(r); |
| 616 | w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); | 608 | w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); |
| 617 | unsafe { reg.write_value(w) }; | 609 | reg.write_value(w); |
| 618 | } | 610 | } |
| 619 | EP_IN_WAKERS[ep_addr.index()].wake(); | 611 | EP_IN_WAKERS[ep_addr.index()].wake(); |
| 620 | } | 612 | } |
| @@ -624,18 +616,18 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 624 | false => Stat::DISABLED, | 616 | false => Stat::DISABLED, |
| 625 | true => Stat::VALID, | 617 | true => Stat::VALID, |
| 626 | }; | 618 | }; |
| 627 | let r = unsafe { reg.read() }; | 619 | let r = reg.read(); |
| 628 | if r.stat_rx() == want_stat { | 620 | if r.stat_rx() == want_stat { |
| 629 | break; | 621 | break; |
| 630 | } | 622 | } |
| 631 | let mut w = invariant(r); | 623 | let mut w = invariant(r); |
| 632 | w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); | 624 | w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); |
| 633 | unsafe { reg.write_value(w) }; | 625 | reg.write_value(w); |
| 634 | } | 626 | } |
| 635 | EP_OUT_WAKERS[ep_addr.index()].wake(); | 627 | EP_OUT_WAKERS[ep_addr.index()].wake(); |
| 636 | } | 628 | } |
| 637 | } | 629 | } |
| 638 | trace!("EPR after: {:04x}", unsafe { reg.read() }.0); | 630 | trace!("EPR after: {:04x}", reg.read().0); |
| 639 | } | 631 | } |
| 640 | 632 | ||
| 641 | async fn enable(&mut self) {} | 633 | async fn enable(&mut self) {} |
| @@ -685,12 +677,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> { | |||
| 685 | fn write_data(&mut self, buf: &[u8]) { | 677 | fn write_data(&mut self, buf: &[u8]) { |
| 686 | let index = self.info.addr.index(); | 678 | let index = self.info.addr.index(); |
| 687 | self.buf.write(buf); | 679 | self.buf.write(buf); |
| 688 | unsafe { btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _) } | 680 | btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _); |
| 689 | } | 681 | } |
| 690 | 682 | ||
| 691 | fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { | 683 | fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { |
| 692 | let index = self.info.addr.index(); | 684 | let index = self.info.addr.index(); |
| 693 | let rx_len = unsafe { btable::read_out_len::<T>(index) as usize } & 0x3FF; | 685 | let rx_len = btable::read_out_len::<T>(index) as usize & 0x3FF; |
| 694 | trace!("READ DONE, rx_len = {}", rx_len); | 686 | trace!("READ DONE, rx_len = {}", rx_len); |
| 695 | if rx_len > buf.len() { | 687 | if rx_len > buf.len() { |
| 696 | return Err(EndpointError::BufferOverflow); | 688 | return Err(EndpointError::BufferOverflow); |
| @@ -711,7 +703,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { | |||
| 711 | poll_fn(|cx| { | 703 | poll_fn(|cx| { |
| 712 | EP_OUT_WAKERS[index].register(cx.waker()); | 704 | EP_OUT_WAKERS[index].register(cx.waker()); |
| 713 | let regs = T::regs(); | 705 | let regs = T::regs(); |
| 714 | if unsafe { regs.epr(index).read() }.stat_tx() == Stat::DISABLED { | 706 | if regs.epr(index).read().stat_tx() == Stat::DISABLED { |
| 715 | Poll::Pending | 707 | Poll::Pending |
| 716 | } else { | 708 | } else { |
| 717 | Poll::Ready(()) | 709 | Poll::Ready(()) |
| @@ -733,7 +725,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> { | |||
| 733 | poll_fn(|cx| { | 725 | poll_fn(|cx| { |
| 734 | EP_OUT_WAKERS[index].register(cx.waker()); | 726 | EP_OUT_WAKERS[index].register(cx.waker()); |
| 735 | let regs = T::regs(); | 727 | let regs = T::regs(); |
| 736 | if unsafe { regs.epr(index).read() }.stat_rx() == Stat::DISABLED { | 728 | if regs.epr(index).read().stat_rx() == Stat::DISABLED { |
| 737 | Poll::Pending | 729 | Poll::Pending |
| 738 | } else { | 730 | } else { |
| 739 | Poll::Ready(()) | 731 | Poll::Ready(()) |
| @@ -751,7 +743,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 751 | let stat = poll_fn(|cx| { | 743 | let stat = poll_fn(|cx| { |
| 752 | EP_OUT_WAKERS[index].register(cx.waker()); | 744 | EP_OUT_WAKERS[index].register(cx.waker()); |
| 753 | let regs = T::regs(); | 745 | let regs = T::regs(); |
| 754 | let stat = unsafe { regs.epr(index).read() }.stat_rx(); | 746 | let stat = regs.epr(index).read().stat_rx(); |
| 755 | if matches!(stat, Stat::NAK | Stat::DISABLED) { | 747 | if matches!(stat, Stat::NAK | Stat::DISABLED) { |
| 756 | Poll::Ready(stat) | 748 | Poll::Ready(stat) |
| 757 | } else { | 749 | } else { |
| @@ -767,16 +759,14 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 767 | let rx_len = self.read_data(buf)?; | 759 | let rx_len = self.read_data(buf)?; |
| 768 | 760 | ||
| 769 | let regs = T::regs(); | 761 | let regs = T::regs(); |
| 770 | unsafe { | 762 | regs.epr(index).write(|w| { |
| 771 | regs.epr(index).write(|w| { | 763 | w.set_ep_type(convert_type(self.info.ep_type)); |
| 772 | w.set_ep_type(convert_type(self.info.ep_type)); | 764 | w.set_ea(self.info.addr.index() as _); |
| 773 | w.set_ea(self.info.addr.index() as _); | 765 | w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); |
| 774 | w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); | 766 | w.set_stat_tx(Stat(0)); |
| 775 | w.set_stat_tx(Stat(0)); | 767 | w.set_ctr_rx(true); // don't clear |
| 776 | w.set_ctr_rx(true); // don't clear | 768 | w.set_ctr_tx(true); // don't clear |
| 777 | w.set_ctr_tx(true); // don't clear | 769 | }); |
| 778 | }) | ||
| 779 | }; | ||
| 780 | trace!("READ OK, rx_len = {}", rx_len); | 770 | trace!("READ OK, rx_len = {}", rx_len); |
| 781 | 771 | ||
| 782 | Ok(rx_len) | 772 | Ok(rx_len) |
| @@ -795,7 +785,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 795 | let stat = poll_fn(|cx| { | 785 | let stat = poll_fn(|cx| { |
| 796 | EP_IN_WAKERS[index].register(cx.waker()); | 786 | EP_IN_WAKERS[index].register(cx.waker()); |
| 797 | let regs = T::regs(); | 787 | let regs = T::regs(); |
| 798 | let stat = unsafe { regs.epr(index).read() }.stat_tx(); | 788 | let stat = regs.epr(index).read().stat_tx(); |
| 799 | if matches!(stat, Stat::NAK | Stat::DISABLED) { | 789 | if matches!(stat, Stat::NAK | Stat::DISABLED) { |
| 800 | Poll::Ready(stat) | 790 | Poll::Ready(stat) |
| 801 | } else { | 791 | } else { |
| @@ -811,16 +801,14 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 811 | self.write_data(buf); | 801 | self.write_data(buf); |
| 812 | 802 | ||
| 813 | let regs = T::regs(); | 803 | let regs = T::regs(); |
| 814 | unsafe { | 804 | regs.epr(index).write(|w| { |
| 815 | regs.epr(index).write(|w| { | 805 | w.set_ep_type(convert_type(self.info.ep_type)); |
| 816 | w.set_ep_type(convert_type(self.info.ep_type)); | 806 | w.set_ea(self.info.addr.index() as _); |
| 817 | w.set_ea(self.info.addr.index() as _); | 807 | w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); |
| 818 | w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); | 808 | w.set_stat_rx(Stat(0)); |
| 819 | w.set_stat_rx(Stat(0)); | 809 | w.set_ctr_rx(true); // don't clear |
| 820 | w.set_ctr_rx(true); // don't clear | 810 | w.set_ctr_tx(true); // don't clear |
| 821 | w.set_ctr_tx(true); // don't clear | 811 | }); |
| 822 | }) | ||
| 823 | }; | ||
| 824 | 812 | ||
| 825 | trace!("WRITE OK"); | 813 | trace!("WRITE OK"); |
| 826 | 814 | ||
| @@ -889,22 +877,20 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 889 | } | 877 | } |
| 890 | // Note: if this is the first AND last transfer, the above effectively | 878 | // Note: if this is the first AND last transfer, the above effectively |
| 891 | // changes stat_tx like NAK -> NAK, so noop. | 879 | // changes stat_tx like NAK -> NAK, so noop. |
| 892 | unsafe { | 880 | regs.epr(0).write(|w| { |
| 893 | regs.epr(0).write(|w| { | 881 | w.set_ep_type(EpType::CONTROL); |
| 894 | w.set_ep_type(EpType::CONTROL); | 882 | w.set_stat_rx(Stat(stat_rx)); |
| 895 | w.set_stat_rx(Stat(stat_rx)); | 883 | w.set_stat_tx(Stat(stat_tx)); |
| 896 | w.set_stat_tx(Stat(stat_tx)); | 884 | w.set_ctr_rx(true); // don't clear |
| 897 | w.set_ctr_rx(true); // don't clear | 885 | w.set_ctr_tx(true); // don't clear |
| 898 | w.set_ctr_tx(true); // don't clear | 886 | }); |
| 899 | }) | ||
| 900 | } | ||
| 901 | } | 887 | } |
| 902 | 888 | ||
| 903 | trace!("data_out WAITING, buf.len() = {}", buf.len()); | 889 | trace!("data_out WAITING, buf.len() = {}", buf.len()); |
| 904 | poll_fn(|cx| { | 890 | poll_fn(|cx| { |
| 905 | EP_OUT_WAKERS[0].register(cx.waker()); | 891 | EP_OUT_WAKERS[0].register(cx.waker()); |
| 906 | let regs = T::regs(); | 892 | let regs = T::regs(); |
| 907 | if unsafe { regs.epr(0).read() }.stat_rx() == Stat::NAK { | 893 | if regs.epr(0).read().stat_rx() == Stat::NAK { |
| 908 | Poll::Ready(()) | 894 | Poll::Ready(()) |
| 909 | } else { | 895 | } else { |
| 910 | Poll::Pending | 896 | Poll::Pending |
| @@ -919,19 +905,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 919 | 905 | ||
| 920 | let rx_len = self.ep_out.read_data(buf)?; | 906 | let rx_len = self.ep_out.read_data(buf)?; |
| 921 | 907 | ||
| 922 | unsafe { | 908 | regs.epr(0).write(|w| { |
| 923 | regs.epr(0).write(|w| { | 909 | w.set_ep_type(EpType::CONTROL); |
| 924 | w.set_ep_type(EpType::CONTROL); | 910 | w.set_stat_rx(Stat(match last { |
| 925 | w.set_stat_rx(Stat(match last { | 911 | // If last, set STAT_RX=STALL. |
| 926 | // If last, set STAT_RX=STALL. | 912 | true => Stat::NAK.0 ^ Stat::STALL.0, |
| 927 | true => Stat::NAK.0 ^ Stat::STALL.0, | 913 | // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet. |
| 928 | // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet. | 914 | false => Stat::NAK.0 ^ Stat::VALID.0, |
| 929 | false => Stat::NAK.0 ^ Stat::VALID.0, | 915 | })); |
| 930 | })); | 916 | w.set_ctr_rx(true); // don't clear |
| 931 | w.set_ctr_rx(true); // don't clear | 917 | w.set_ctr_tx(true); // don't clear |
| 932 | w.set_ctr_tx(true); // don't clear | 918 | }); |
| 933 | }) | ||
| 934 | }; | ||
| 935 | 919 | ||
| 936 | Ok(rx_len) | 920 | Ok(rx_len) |
| 937 | } | 921 | } |
| @@ -960,15 +944,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 960 | } | 944 | } |
| 961 | // Note: if this is the first AND last transfer, the above effectively | 945 | // Note: if this is the first AND last transfer, the above effectively |
| 962 | // does a change of NAK -> VALID. | 946 | // does a change of NAK -> VALID. |
| 963 | unsafe { | 947 | regs.epr(0).write(|w| { |
| 964 | regs.epr(0).write(|w| { | 948 | w.set_ep_type(EpType::CONTROL); |
| 965 | w.set_ep_type(EpType::CONTROL); | 949 | w.set_stat_rx(Stat(stat_rx)); |
| 966 | w.set_stat_rx(Stat(stat_rx)); | 950 | w.set_ep_kind(last); // set OUT_STATUS if last. |
| 967 | w.set_ep_kind(last); // set OUT_STATUS if last. | 951 | w.set_ctr_rx(true); // don't clear |
| 968 | w.set_ctr_rx(true); // don't clear | 952 | w.set_ctr_tx(true); // don't clear |
| 969 | w.set_ctr_tx(true); // don't clear | 953 | }); |
| 970 | }) | ||
| 971 | } | ||
| 972 | } | 954 | } |
| 973 | 955 | ||
| 974 | trace!("WRITE WAITING"); | 956 | trace!("WRITE WAITING"); |
| @@ -976,7 +958,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 976 | EP_IN_WAKERS[0].register(cx.waker()); | 958 | EP_IN_WAKERS[0].register(cx.waker()); |
| 977 | EP_OUT_WAKERS[0].register(cx.waker()); | 959 | EP_OUT_WAKERS[0].register(cx.waker()); |
| 978 | let regs = T::regs(); | 960 | let regs = T::regs(); |
| 979 | if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK { | 961 | if regs.epr(0).read().stat_tx() == Stat::NAK { |
| 980 | Poll::Ready(()) | 962 | Poll::Ready(()) |
| 981 | } else { | 963 | } else { |
| 982 | Poll::Pending | 964 | Poll::Pending |
| @@ -992,15 +974,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 992 | self.ep_in.write_data(data); | 974 | self.ep_in.write_data(data); |
| 993 | 975 | ||
| 994 | let regs = T::regs(); | 976 | let regs = T::regs(); |
| 995 | unsafe { | 977 | regs.epr(0).write(|w| { |
| 996 | regs.epr(0).write(|w| { | 978 | w.set_ep_type(EpType::CONTROL); |
| 997 | w.set_ep_type(EpType::CONTROL); | 979 | w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); |
| 998 | w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); | 980 | w.set_ep_kind(last); // set OUT_STATUS if last. |
| 999 | w.set_ep_kind(last); // set OUT_STATUS if last. | 981 | w.set_ctr_rx(true); // don't clear |
| 1000 | w.set_ctr_rx(true); // don't clear | 982 | w.set_ctr_tx(true); // don't clear |
| 1001 | w.set_ctr_tx(true); // don't clear | 983 | }); |
| 1002 | }) | ||
| 1003 | }; | ||
| 1004 | 984 | ||
| 1005 | trace!("WRITE OK"); | 985 | trace!("WRITE OK"); |
| 1006 | 986 | ||
| @@ -1014,16 +994,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 1014 | self.ep_in.write_data(&[]); | 994 | self.ep_in.write_data(&[]); |
| 1015 | 995 | ||
| 1016 | // Set OUT=stall, IN=accept | 996 | // Set OUT=stall, IN=accept |
| 1017 | unsafe { | 997 | let epr = regs.epr(0).read(); |
| 1018 | let epr = regs.epr(0).read(); | 998 | regs.epr(0).write(|w| { |
| 1019 | regs.epr(0).write(|w| { | 999 | w.set_ep_type(EpType::CONTROL); |
| 1020 | w.set_ep_type(EpType::CONTROL); | 1000 | w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); |
| 1021 | w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); | 1001 | w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0)); |
| 1022 | w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0)); | 1002 | w.set_ctr_rx(true); // don't clear |
| 1023 | w.set_ctr_rx(true); // don't clear | 1003 | w.set_ctr_tx(true); // don't clear |
| 1024 | w.set_ctr_tx(true); // don't clear | 1004 | }); |
| 1025 | }); | ||
| 1026 | } | ||
| 1027 | trace!("control: accept WAITING"); | 1005 | trace!("control: accept WAITING"); |
| 1028 | 1006 | ||
| 1029 | // Wait is needed, so that we don't set the address too soon, breaking the status stage. | 1007 | // Wait is needed, so that we don't set the address too soon, breaking the status stage. |
| @@ -1031,7 +1009,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 1031 | poll_fn(|cx| { | 1009 | poll_fn(|cx| { |
| 1032 | EP_IN_WAKERS[0].register(cx.waker()); | 1010 | EP_IN_WAKERS[0].register(cx.waker()); |
| 1033 | let regs = T::regs(); | 1011 | let regs = T::regs(); |
| 1034 | if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK { | 1012 | if regs.epr(0).read().stat_tx() == Stat::NAK { |
| 1035 | Poll::Ready(()) | 1013 | Poll::Ready(()) |
| 1036 | } else { | 1014 | } else { |
| 1037 | Poll::Pending | 1015 | Poll::Pending |
| @@ -1047,16 +1025,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 1047 | trace!("control: reject"); | 1025 | trace!("control: reject"); |
| 1048 | 1026 | ||
| 1049 | // Set IN+OUT to stall | 1027 | // Set IN+OUT to stall |
| 1050 | unsafe { | 1028 | let epr = regs.epr(0).read(); |
| 1051 | let epr = regs.epr(0).read(); | 1029 | regs.epr(0).write(|w| { |
| 1052 | regs.epr(0).write(|w| { | 1030 | w.set_ep_type(EpType::CONTROL); |
| 1053 | w.set_ep_type(EpType::CONTROL); | 1031 | w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); |
| 1054 | w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); | 1032 | w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0)); |
| 1055 | w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0)); | 1033 | w.set_ctr_rx(true); // don't clear |
| 1056 | w.set_ctr_rx(true); // don't clear | 1034 | w.set_ctr_tx(true); // don't clear |
| 1057 | w.set_ctr_tx(true); // don't clear | 1035 | }); |
| 1058 | }); | ||
| 1059 | } | ||
| 1060 | } | 1036 | } |
| 1061 | 1037 | ||
| 1062 | async fn accept_set_address(&mut self, addr: u8) { | 1038 | async fn accept_set_address(&mut self, addr: u8) { |
| @@ -1064,11 +1040,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 1064 | 1040 | ||
| 1065 | let regs = T::regs(); | 1041 | let regs = T::regs(); |
| 1066 | trace!("setting addr: {}", addr); | 1042 | trace!("setting addr: {}", addr); |
| 1067 | unsafe { | 1043 | regs.daddr().write(|w| { |
| 1068 | regs.daddr().write(|w| { | 1044 | w.set_ef(true); |
| 1069 | w.set_ef(true); | 1045 | w.set_add(addr); |
| 1070 | w.set_add(addr); | 1046 | }); |
| 1071 | }) | ||
| 1072 | } | ||
| 1073 | } | 1047 | } |
| 1074 | } | 1048 | } |
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs index 193e0df0d..12e5f0e60 100644 --- a/embassy-stm32/src/usb_otg/mod.rs +++ b/embassy-stm32/src/usb_otg/mod.rs | |||
| @@ -1,7 +1,5 @@ | |||
| 1 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 2 | |||
| 3 | use crate::peripherals; | ||
| 4 | use crate::rcc::RccPeripheral; | 1 | use crate::rcc::RccPeripheral; |
| 2 | use crate::{interrupt, peripherals}; | ||
| 5 | 3 | ||
| 6 | #[cfg(feature = "nightly")] | 4 | #[cfg(feature = "nightly")] |
| 7 | mod usb; | 5 | mod usb; |
| @@ -25,7 +23,7 @@ pub(crate) mod sealed { | |||
| 25 | } | 23 | } |
| 26 | 24 | ||
| 27 | pub trait Instance: sealed::Instance + RccPeripheral { | 25 | pub trait Instance: sealed::Instance + RccPeripheral { |
| 28 | type Interrupt: Interrupt; | 26 | type Interrupt: interrupt::typelevel::Interrupt; |
| 29 | } | 27 | } |
| 30 | 28 | ||
| 31 | // Internal PHY pins | 29 | // Internal PHY pins |
| @@ -109,7 +107,7 @@ foreach_interrupt!( | |||
| 109 | } | 107 | } |
| 110 | 108 | ||
| 111 | impl Instance for peripherals::USB_OTG_FS { | 109 | impl Instance for peripherals::USB_OTG_FS { |
| 112 | type Interrupt = crate::interrupt::$irq; | 110 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 113 | } | 111 | } |
| 114 | }; | 112 | }; |
| 115 | 113 | ||
| @@ -150,7 +148,7 @@ foreach_interrupt!( | |||
| 150 | 148 | ||
| 151 | fn regs() -> crate::pac::otg::Otg { | 149 | fn regs() -> crate::pac::otg::Otg { |
| 152 | // OTG HS registers are a superset of FS registers | 150 | // OTG HS registers are a superset of FS registers |
| 153 | crate::pac::otg::Otg(crate::pac::USB_OTG_HS.0) | 151 | unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) } |
| 154 | } | 152 | } |
| 155 | 153 | ||
| 156 | #[cfg(feature = "nightly")] | 154 | #[cfg(feature = "nightly")] |
| @@ -161,7 +159,7 @@ foreach_interrupt!( | |||
| 161 | } | 159 | } |
| 162 | 160 | ||
| 163 | impl Instance for peripherals::USB_OTG_HS { | 161 | impl Instance for peripherals::USB_OTG_HS { |
| 164 | type Interrupt = crate::interrupt::$irq; | 162 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 165 | } | 163 | } |
| 166 | }; | 164 | }; |
| 167 | ); | 165 | ); |
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 921a73c8b..8af5c7bd5 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs | |||
| @@ -3,7 +3,6 @@ use core::marker::PhantomData; | |||
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use atomic_polyfill::{AtomicBool, AtomicU16, Ordering}; | 5 | use atomic_polyfill::{AtomicBool, AtomicU16, Ordering}; |
| 6 | use embassy_cortex_m::interrupt::InterruptExt; | ||
| 7 | use embassy_hal_common::{into_ref, Peripheral}; | 6 | use embassy_hal_common::{into_ref, Peripheral}; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 9 | use embassy_usb_driver::{ | 8 | use embassy_usb_driver::{ |
| @@ -15,6 +14,7 @@ use futures::future::poll_fn; | |||
| 15 | use super::*; | 14 | use super::*; |
| 16 | use crate::gpio::sealed::AFType; | 15 | use crate::gpio::sealed::AFType; |
| 17 | use crate::interrupt; | 16 | use crate::interrupt; |
| 17 | use crate::interrupt::typelevel::Interrupt; | ||
| 18 | use crate::pac::otg::{regs, vals}; | 18 | use crate::pac::otg::{regs, vals}; |
| 19 | use crate::rcc::sealed::RccPeripheral; | 19 | use crate::rcc::sealed::RccPeripheral; |
| 20 | use crate::time::Hertz; | 20 | use crate::time::Hertz; |
| @@ -24,25 +24,22 @@ pub struct InterruptHandler<T: Instance> { | |||
| 24 | _phantom: PhantomData<T>, | 24 | _phantom: PhantomData<T>, |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | 27 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 28 | unsafe fn on_interrupt() { | 28 | unsafe fn on_interrupt() { |
| 29 | trace!("irq"); | 29 | trace!("irq"); |
| 30 | let r = T::regs(); | 30 | let r = T::regs(); |
| 31 | let state = T::state(); | 31 | let state = T::state(); |
| 32 | 32 | ||
| 33 | // SAFETY: atomic read/write | 33 | let ints = r.gintsts().read(); |
| 34 | let ints = unsafe { r.gintsts().read() }; | ||
| 35 | if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() { | 34 | if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() { |
| 36 | // Mask interrupts and notify `Bus` to process them | 35 | // Mask interrupts and notify `Bus` to process them |
| 37 | unsafe { r.gintmsk().write(|_| {}) }; | 36 | r.gintmsk().write(|_| {}); |
| 38 | T::state().bus_waker.wake(); | 37 | T::state().bus_waker.wake(); |
| 39 | } | 38 | } |
| 40 | 39 | ||
| 41 | // Handle RX | 40 | // Handle RX |
| 42 | // SAFETY: atomic read with no side effects | 41 | while r.gintsts().read().rxflvl() { |
| 43 | while unsafe { r.gintsts().read().rxflvl() } { | 42 | let status = r.grxstsp().read(); |
| 44 | // SAFETY: atomic "pop" register | ||
| 45 | let status = unsafe { r.grxstsp().read() }; | ||
| 46 | let ep_num = status.epnum() as usize; | 43 | let ep_num = status.epnum() as usize; |
| 47 | let len = status.bcnt() as usize; | 44 | let len = status.bcnt() as usize; |
| 48 | 45 | ||
| @@ -57,21 +54,15 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | |||
| 57 | if state.ep0_setup_ready.load(Ordering::Relaxed) == false { | 54 | if state.ep0_setup_ready.load(Ordering::Relaxed) == false { |
| 58 | // SAFETY: exclusive access ensured by atomic bool | 55 | // SAFETY: exclusive access ensured by atomic bool |
| 59 | let data = unsafe { &mut *state.ep0_setup_data.get() }; | 56 | let data = unsafe { &mut *state.ep0_setup_data.get() }; |
| 60 | // SAFETY: FIFO reads are exclusive to this IRQ | 57 | data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); |
| 61 | unsafe { | 58 | data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); |
| 62 | data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); | ||
| 63 | data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); | ||
| 64 | } | ||
| 65 | state.ep0_setup_ready.store(true, Ordering::Release); | 59 | state.ep0_setup_ready.store(true, Ordering::Release); |
| 66 | state.ep_out_wakers[0].wake(); | 60 | state.ep_out_wakers[0].wake(); |
| 67 | } else { | 61 | } else { |
| 68 | error!("received SETUP before previous finished processing"); | 62 | error!("received SETUP before previous finished processing"); |
| 69 | // discard FIFO | 63 | // discard FIFO |
| 70 | // SAFETY: FIFO reads are exclusive to IRQ | 64 | r.fifo(0).read(); |
| 71 | unsafe { | 65 | r.fifo(0).read(); |
| 72 | r.fifo(0).read(); | ||
| 73 | r.fifo(0).read(); | ||
| 74 | } | ||
| 75 | } | 66 | } |
| 76 | } | 67 | } |
| 77 | vals::Pktstsd::OUT_DATA_RX => { | 68 | vals::Pktstsd::OUT_DATA_RX => { |
| @@ -84,8 +75,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | |||
| 84 | 75 | ||
| 85 | for chunk in buf.chunks_mut(4) { | 76 | for chunk in buf.chunks_mut(4) { |
| 86 | // RX FIFO is shared so always read from fifo(0) | 77 | // RX FIFO is shared so always read from fifo(0) |
| 87 | // SAFETY: FIFO reads are exclusive to IRQ | 78 | let data = r.fifo(0).read().0; |
| 88 | let data = unsafe { r.fifo(0).read().0 }; | ||
| 89 | chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]); | 79 | chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]); |
| 90 | } | 80 | } |
| 91 | 81 | ||
| @@ -97,8 +87,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | |||
| 97 | // discard FIFO data | 87 | // discard FIFO data |
| 98 | let len_words = (len + 3) / 4; | 88 | let len_words = (len + 3) / 4; |
| 99 | for _ in 0..len_words { | 89 | for _ in 0..len_words { |
| 100 | // SAFETY: FIFO reads are exclusive to IRQ | 90 | r.fifo(0).read().data(); |
| 101 | unsafe { r.fifo(0).read().data() }; | ||
| 102 | } | 91 | } |
| 103 | } | 92 | } |
| 104 | } | 93 | } |
| @@ -114,24 +103,20 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | |||
| 114 | 103 | ||
| 115 | // IN endpoint interrupt | 104 | // IN endpoint interrupt |
| 116 | if ints.iepint() { | 105 | if ints.iepint() { |
| 117 | // SAFETY: atomic read with no side effects | 106 | let mut ep_mask = r.daint().read().iepint(); |
| 118 | let mut ep_mask = unsafe { r.daint().read().iepint() }; | ||
| 119 | let mut ep_num = 0; | 107 | let mut ep_num = 0; |
| 120 | 108 | ||
| 121 | // Iterate over endpoints while there are non-zero bits in the mask | 109 | // Iterate over endpoints while there are non-zero bits in the mask |
| 122 | while ep_mask != 0 { | 110 | while ep_mask != 0 { |
| 123 | if ep_mask & 1 != 0 { | 111 | if ep_mask & 1 != 0 { |
| 124 | // SAFETY: atomic read with no side effects | 112 | let ep_ints = r.diepint(ep_num).read(); |
| 125 | let ep_ints = unsafe { r.diepint(ep_num).read() }; | ||
| 126 | 113 | ||
| 127 | // clear all | 114 | // clear all |
| 128 | // SAFETY: DIEPINT is exclusive to IRQ | 115 | r.diepint(ep_num).write_value(ep_ints); |
| 129 | unsafe { r.diepint(ep_num).write_value(ep_ints) }; | ||
| 130 | 116 | ||
| 131 | // TXFE is cleared in DIEPEMPMSK | 117 | // TXFE is cleared in DIEPEMPMSK |
| 132 | if ep_ints.txfe() { | 118 | if ep_ints.txfe() { |
| 133 | // SAFETY: DIEPEMPMSK is shared with `Endpoint` so critical section is needed for RMW | 119 | critical_section::with(|_| { |
| 134 | critical_section::with(|_| unsafe { | ||
| 135 | r.diepempmsk().modify(|w| { | 120 | r.diepempmsk().modify(|w| { |
| 136 | w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num)); | 121 | w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num)); |
| 137 | }); | 122 | }); |
| @@ -172,8 +157,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | |||
| 172 | macro_rules! config_ulpi_pins { | 157 | macro_rules! config_ulpi_pins { |
| 173 | ($($pin:ident),*) => { | 158 | ($($pin:ident),*) => { |
| 174 | into_ref!($($pin),*); | 159 | into_ref!($($pin),*); |
| 175 | // NOTE(unsafe) Exclusive access to the registers | 160 | critical_section::with(|_| { |
| 176 | critical_section::with(|_| unsafe { | ||
| 177 | $( | 161 | $( |
| 178 | $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); | 162 | $pin.set_as_af($pin.af_num(), AFType::OutputPushPull); |
| 179 | #[cfg(gpio_v2)] | 163 | #[cfg(gpio_v2)] |
| @@ -291,17 +275,15 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 291 | /// Endpoint allocation will fail if it is too small. | 275 | /// Endpoint allocation will fail if it is too small. |
| 292 | pub fn new_fs( | 276 | pub fn new_fs( |
| 293 | _peri: impl Peripheral<P = T> + 'd, | 277 | _peri: impl Peripheral<P = T> + 'd, |
| 294 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 278 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 295 | dp: impl Peripheral<P = impl DpPin<T>> + 'd, | 279 | dp: impl Peripheral<P = impl DpPin<T>> + 'd, |
| 296 | dm: impl Peripheral<P = impl DmPin<T>> + 'd, | 280 | dm: impl Peripheral<P = impl DmPin<T>> + 'd, |
| 297 | ep_out_buffer: &'d mut [u8], | 281 | ep_out_buffer: &'d mut [u8], |
| 298 | ) -> Self { | 282 | ) -> Self { |
| 299 | into_ref!(dp, dm); | 283 | into_ref!(dp, dm); |
| 300 | 284 | ||
| 301 | unsafe { | 285 | dp.set_as_af(dp.af_num(), AFType::OutputPushPull); |
| 302 | dp.set_as_af(dp.af_num(), AFType::OutputPushPull); | 286 | dm.set_as_af(dm.af_num(), AFType::OutputPushPull); |
| 303 | dm.set_as_af(dm.af_num(), AFType::OutputPushPull); | ||
| 304 | } | ||
| 305 | 287 | ||
| 306 | Self { | 288 | Self { |
| 307 | phantom: PhantomData, | 289 | phantom: PhantomData, |
| @@ -322,7 +304,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 322 | /// Endpoint allocation will fail if it is too small. | 304 | /// Endpoint allocation will fail if it is too small. |
| 323 | pub fn new_hs_ulpi( | 305 | pub fn new_hs_ulpi( |
| 324 | _peri: impl Peripheral<P = T> + 'd, | 306 | _peri: impl Peripheral<P = T> + 'd, |
| 325 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 307 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 326 | ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd, | 308 | ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd, |
| 327 | ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd, | 309 | ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd, |
| 328 | ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd, | 310 | ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd, |
| @@ -508,18 +490,15 @@ pub struct Bus<'d, T: Instance> { | |||
| 508 | 490 | ||
| 509 | impl<'d, T: Instance> Bus<'d, T> { | 491 | impl<'d, T: Instance> Bus<'d, T> { |
| 510 | fn restore_irqs() { | 492 | fn restore_irqs() { |
| 511 | // SAFETY: atomic write | 493 | T::regs().gintmsk().write(|w| { |
| 512 | unsafe { | 494 | w.set_usbrst(true); |
| 513 | T::regs().gintmsk().write(|w| { | 495 | w.set_enumdnem(true); |
| 514 | w.set_usbrst(true); | 496 | w.set_usbsuspm(true); |
| 515 | w.set_enumdnem(true); | 497 | w.set_wuim(true); |
| 516 | w.set_usbsuspm(true); | 498 | w.set_iepint(true); |
| 517 | w.set_wuim(true); | 499 | w.set_oepint(true); |
| 518 | w.set_iepint(true); | 500 | w.set_rxflvlm(true); |
| 519 | w.set_oepint(true); | 501 | }); |
| 520 | w.set_rxflvlm(true); | ||
| 521 | }); | ||
| 522 | } | ||
| 523 | } | 502 | } |
| 524 | } | 503 | } |
| 525 | 504 | ||
| @@ -533,8 +512,7 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 533 | let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); | 512 | let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); |
| 534 | trace!("configuring rx fifo size={}", rx_fifo_size_words); | 513 | trace!("configuring rx fifo size={}", rx_fifo_size_words); |
| 535 | 514 | ||
| 536 | // SAFETY: register is exclusive to `Bus` with `&mut self` | 515 | r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)); |
| 537 | unsafe { r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)) }; | ||
| 538 | 516 | ||
| 539 | // Configure TX (USB in direction) fifo size for each endpoint | 517 | // Configure TX (USB in direction) fifo size for each endpoint |
| 540 | let mut fifo_top = rx_fifo_size_words; | 518 | let mut fifo_top = rx_fifo_size_words; |
| @@ -549,13 +527,10 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 549 | 527 | ||
| 550 | let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; | 528 | let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; |
| 551 | 529 | ||
| 552 | // SAFETY: register is exclusive to `Bus` with `&mut self` | 530 | dieptxf.write(|w| { |
| 553 | unsafe { | 531 | w.set_fd(ep.fifo_size_words); |
| 554 | dieptxf.write(|w| { | 532 | w.set_sa(fifo_top); |
| 555 | w.set_fd(ep.fifo_size_words); | 533 | }); |
| 556 | w.set_sa(fifo_top); | ||
| 557 | }); | ||
| 558 | } | ||
| 559 | 534 | ||
| 560 | fifo_top += ep.fifo_size_words; | 535 | fifo_top += ep.fifo_size_words; |
| 561 | } | 536 | } |
| @@ -575,8 +550,7 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 575 | // Configure IN endpoints | 550 | // Configure IN endpoints |
| 576 | for (index, ep) in self.ep_in.iter().enumerate() { | 551 | for (index, ep) in self.ep_in.iter().enumerate() { |
| 577 | if let Some(ep) = ep { | 552 | if let Some(ep) = ep { |
| 578 | // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW | 553 | critical_section::with(|_| { |
| 579 | critical_section::with(|_| unsafe { | ||
| 580 | r.diepctl(index).write(|w| { | 554 | r.diepctl(index).write(|w| { |
| 581 | if index == 0 { | 555 | if index == 0 { |
| 582 | w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); | 556 | w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); |
| @@ -593,8 +567,7 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 593 | // Configure OUT endpoints | 567 | // Configure OUT endpoints |
| 594 | for (index, ep) in self.ep_out.iter().enumerate() { | 568 | for (index, ep) in self.ep_out.iter().enumerate() { |
| 595 | if let Some(ep) = ep { | 569 | if let Some(ep) = ep { |
| 596 | // SAFETY: DOEPCTL/DOEPTSIZ is shared with `Endpoint` so critical section is needed for RMW | 570 | critical_section::with(|_| { |
| 597 | critical_section::with(|_| unsafe { | ||
| 598 | r.doepctl(index).write(|w| { | 571 | r.doepctl(index).write(|w| { |
| 599 | if index == 0 { | 572 | if index == 0 { |
| 600 | w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); | 573 | w.set_mpsiz(ep0_mpsiz(ep.max_packet_size)); |
| @@ -618,26 +591,21 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 618 | } | 591 | } |
| 619 | 592 | ||
| 620 | // Enable IRQs for allocated endpoints | 593 | // Enable IRQs for allocated endpoints |
| 621 | // SAFETY: register is exclusive to `Bus` with `&mut self` | 594 | r.daintmsk().modify(|w| { |
| 622 | unsafe { | 595 | w.set_iepm(ep_irq_mask(&self.ep_in)); |
| 623 | r.daintmsk().modify(|w| { | 596 | // OUT interrupts not used, handled in RXFLVL |
| 624 | w.set_iepm(ep_irq_mask(&self.ep_in)); | 597 | // w.set_oepm(ep_irq_mask(&self.ep_out)); |
| 625 | // OUT interrupts not used, handled in RXFLVL | 598 | }); |
| 626 | // w.set_oepm(ep_irq_mask(&self.ep_out)); | ||
| 627 | }); | ||
| 628 | } | ||
| 629 | } | 599 | } |
| 630 | 600 | ||
| 631 | fn disable(&mut self) { | 601 | fn disable(&mut self) { |
| 632 | unsafe { T::Interrupt::steal() }.disable(); | 602 | T::Interrupt::disable(); |
| 633 | 603 | ||
| 634 | <T as RccPeripheral>::disable(); | 604 | <T as RccPeripheral>::disable(); |
| 635 | 605 | ||
| 636 | #[cfg(stm32l4)] | 606 | #[cfg(stm32l4)] |
| 637 | unsafe { | 607 | crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); |
| 638 | crate::pac::PWR.cr2().modify(|w| w.set_usv(false)); | 608 | // Cannot disable PWR, because other peripherals might be using it |
| 639 | // Cannot disable PWR, because other peripherals might be using it | ||
| 640 | } | ||
| 641 | } | 609 | } |
| 642 | } | 610 | } |
| 643 | 611 | ||
| @@ -653,7 +621,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 653 | 621 | ||
| 654 | T::state().bus_waker.register(cx.waker()); | 622 | T::state().bus_waker.register(cx.waker()); |
| 655 | 623 | ||
| 656 | let ints = unsafe { r.gintsts().read() }; | 624 | let ints = r.gintsts().read(); |
| 657 | if ints.usbrst() { | 625 | if ints.usbrst() { |
| 658 | trace!("reset"); | 626 | trace!("reset"); |
| 659 | 627 | ||
| @@ -661,34 +629,27 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 661 | self.configure_endpoints(); | 629 | self.configure_endpoints(); |
| 662 | 630 | ||
| 663 | // Reset address | 631 | // Reset address |
| 664 | // SAFETY: DCFG is shared with `ControlPipe` so critical section is needed for RMW | 632 | critical_section::with(|_| { |
| 665 | critical_section::with(|_| unsafe { | ||
| 666 | r.dcfg().modify(|w| { | 633 | r.dcfg().modify(|w| { |
| 667 | w.set_dad(0); | 634 | w.set_dad(0); |
| 668 | }); | 635 | }); |
| 669 | }); | 636 | }); |
| 670 | 637 | ||
| 671 | // SAFETY: atomic clear on rc_w1 register | 638 | r.gintsts().write(|w| w.set_usbrst(true)); // clear |
| 672 | unsafe { r.gintsts().write(|w| w.set_usbrst(true)) }; // clear | ||
| 673 | Self::restore_irqs(); | 639 | Self::restore_irqs(); |
| 674 | } | 640 | } |
| 675 | 641 | ||
| 676 | if ints.enumdne() { | 642 | if ints.enumdne() { |
| 677 | trace!("enumdne"); | 643 | trace!("enumdne"); |
| 678 | 644 | ||
| 679 | // SAFETY: atomic read with no side effects | 645 | let speed = r.dsts().read().enumspd(); |
| 680 | let speed = unsafe { r.dsts().read().enumspd() }; | ||
| 681 | trace!(" speed={}", speed.0); | 646 | trace!(" speed={}", speed.0); |
| 682 | 647 | ||
| 683 | // SAFETY: register is only accessed by `Bus` under `&mut self` | 648 | r.gusbcfg().modify(|w| { |
| 684 | unsafe { | 649 | w.set_trdt(calculate_trdt(speed, T::frequency())); |
| 685 | r.gusbcfg().modify(|w| { | 650 | }); |
| 686 | w.set_trdt(calculate_trdt(speed, T::frequency())); | ||
| 687 | }) | ||
| 688 | }; | ||
| 689 | 651 | ||
| 690 | // SAFETY: atomic clear on rc_w1 register | 652 | r.gintsts().write(|w| w.set_enumdne(true)); // clear |
| 691 | unsafe { r.gintsts().write(|w| w.set_enumdne(true)) }; // clear | ||
| 692 | Self::restore_irqs(); | 653 | Self::restore_irqs(); |
| 693 | 654 | ||
| 694 | return Poll::Ready(Event::Reset); | 655 | return Poll::Ready(Event::Reset); |
| @@ -696,16 +657,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 696 | 657 | ||
| 697 | if ints.usbsusp() { | 658 | if ints.usbsusp() { |
| 698 | trace!("suspend"); | 659 | trace!("suspend"); |
| 699 | // SAFETY: atomic clear on rc_w1 register | 660 | r.gintsts().write(|w| w.set_usbsusp(true)); // clear |
| 700 | unsafe { r.gintsts().write(|w| w.set_usbsusp(true)) }; // clear | ||
| 701 | Self::restore_irqs(); | 661 | Self::restore_irqs(); |
| 702 | return Poll::Ready(Event::Suspend); | 662 | return Poll::Ready(Event::Suspend); |
| 703 | } | 663 | } |
| 704 | 664 | ||
| 705 | if ints.wkupint() { | 665 | if ints.wkupint() { |
| 706 | trace!("resume"); | 666 | trace!("resume"); |
| 707 | // SAFETY: atomic clear on rc_w1 register | 667 | r.gintsts().write(|w| w.set_wkupint(true)); // clear |
| 708 | unsafe { r.gintsts().write(|w| w.set_wkupint(true)) }; // clear | ||
| 709 | Self::restore_irqs(); | 668 | Self::restore_irqs(); |
| 710 | return Poll::Ready(Event::Resume); | 669 | return Poll::Ready(Event::Resume); |
| 711 | } | 670 | } |
| @@ -727,8 +686,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 727 | let regs = T::regs(); | 686 | let regs = T::regs(); |
| 728 | match ep_addr.direction() { | 687 | match ep_addr.direction() { |
| 729 | Direction::Out => { | 688 | Direction::Out => { |
| 730 | // SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW | 689 | critical_section::with(|_| { |
| 731 | critical_section::with(|_| unsafe { | ||
| 732 | regs.doepctl(ep_addr.index()).modify(|w| { | 690 | regs.doepctl(ep_addr.index()).modify(|w| { |
| 733 | w.set_stall(stalled); | 691 | w.set_stall(stalled); |
| 734 | }); | 692 | }); |
| @@ -737,8 +695,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 737 | T::state().ep_out_wakers[ep_addr.index()].wake(); | 695 | T::state().ep_out_wakers[ep_addr.index()].wake(); |
| 738 | } | 696 | } |
| 739 | Direction::In => { | 697 | Direction::In => { |
| 740 | // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW | 698 | critical_section::with(|_| { |
| 741 | critical_section::with(|_| unsafe { | ||
| 742 | regs.diepctl(ep_addr.index()).modify(|w| { | 699 | regs.diepctl(ep_addr.index()).modify(|w| { |
| 743 | w.set_stall(stalled); | 700 | w.set_stall(stalled); |
| 744 | }); | 701 | }); |
| @@ -758,10 +715,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 758 | 715 | ||
| 759 | let regs = T::regs(); | 716 | let regs = T::regs(); |
| 760 | 717 | ||
| 761 | // SAFETY: atomic read with no side effects | ||
| 762 | match ep_addr.direction() { | 718 | match ep_addr.direction() { |
| 763 | Direction::Out => unsafe { regs.doepctl(ep_addr.index()).read().stall() }, | 719 | Direction::Out => regs.doepctl(ep_addr.index()).read().stall(), |
| 764 | Direction::In => unsafe { regs.diepctl(ep_addr.index()).read().stall() }, | 720 | Direction::In => regs.diepctl(ep_addr.index()).read().stall(), |
| 765 | } | 721 | } |
| 766 | } | 722 | } |
| 767 | 723 | ||
| @@ -777,8 +733,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 777 | let r = T::regs(); | 733 | let r = T::regs(); |
| 778 | match ep_addr.direction() { | 734 | match ep_addr.direction() { |
| 779 | Direction::Out => { | 735 | Direction::Out => { |
| 780 | // SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW | 736 | critical_section::with(|_| { |
| 781 | critical_section::with(|_| unsafe { | ||
| 782 | // cancel transfer if active | 737 | // cancel transfer if active |
| 783 | if !enabled && r.doepctl(ep_addr.index()).read().epena() { | 738 | if !enabled && r.doepctl(ep_addr.index()).read().epena() { |
| 784 | r.doepctl(ep_addr.index()).modify(|w| { | 739 | r.doepctl(ep_addr.index()).modify(|w| { |
| @@ -796,8 +751,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 796 | T::state().ep_out_wakers[ep_addr.index()].wake(); | 751 | T::state().ep_out_wakers[ep_addr.index()].wake(); |
| 797 | } | 752 | } |
| 798 | Direction::In => { | 753 | Direction::In => { |
| 799 | // SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW | 754 | critical_section::with(|_| { |
| 800 | critical_section::with(|_| unsafe { | ||
| 801 | // cancel transfer if active | 755 | // cancel transfer if active |
| 802 | if !enabled && r.diepctl(ep_addr.index()).read().epena() { | 756 | if !enabled && r.diepctl(ep_addr.index()).read().epena() { |
| 803 | r.diepctl(ep_addr.index()).modify(|w| { | 757 | r.diepctl(ep_addr.index()).modify(|w| { |
| @@ -820,171 +774,192 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 820 | async fn enable(&mut self) { | 774 | async fn enable(&mut self) { |
| 821 | trace!("enable"); | 775 | trace!("enable"); |
| 822 | 776 | ||
| 823 | // SAFETY: registers are only accessed by `Bus` under `&mut self` | 777 | #[cfg(stm32l4)] |
| 824 | unsafe { | 778 | { |
| 825 | #[cfg(stm32l4)] | 779 | crate::peripherals::PWR::enable(); |
| 826 | { | 780 | critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); |
| 827 | crate::peripherals::PWR::enable(); | 781 | } |
| 828 | critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); | ||
| 829 | } | ||
| 830 | 782 | ||
| 831 | #[cfg(stm32h7)] | 783 | #[cfg(stm32f7)] |
| 832 | { | 784 | { |
| 833 | // If true, VDD33USB is generated by internal regulator from VDD50USB | 785 | // Enable ULPI clock if external PHY is used |
| 834 | // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) | 786 | let ulpien = !self.phy_type.internal(); |
| 835 | // TODO: unhardcode | 787 | critical_section::with(|_| { |
| 836 | let internal_regulator = false; | 788 | crate::pac::RCC.ahb1enr().modify(|w| { |
| 789 | if T::HIGH_SPEED { | ||
| 790 | w.set_usb_otg_hsulpien(ulpien); | ||
| 791 | } else { | ||
| 792 | w.set_usb_otg_hsen(ulpien); | ||
| 793 | } | ||
| 794 | }); | ||
| 837 | 795 | ||
| 838 | // Enable USB power | 796 | // Low power mode |
| 839 | critical_section::with(|_| { | 797 | crate::pac::RCC.ahb1lpenr().modify(|w| { |
| 840 | crate::pac::PWR.cr3().modify(|w| { | 798 | if T::HIGH_SPEED { |
| 841 | w.set_usb33den(true); | 799 | w.set_usb_otg_hsulpilpen(ulpien); |
| 842 | w.set_usbregen(internal_regulator); | 800 | } else { |
| 843 | }) | 801 | w.set_usb_otg_hslpen(ulpien); |
| 802 | } | ||
| 844 | }); | 803 | }); |
| 804 | }); | ||
| 805 | } | ||
| 845 | 806 | ||
| 846 | // Wait for USB power to stabilize | 807 | #[cfg(stm32h7)] |
| 847 | while !crate::pac::PWR.cr3().read().usb33rdy() {} | 808 | { |
| 809 | // If true, VDD33USB is generated by internal regulator from VDD50USB | ||
| 810 | // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) | ||
| 811 | // TODO: unhardcode | ||
| 812 | let internal_regulator = false; | ||
| 813 | |||
| 814 | // Enable USB power | ||
| 815 | critical_section::with(|_| { | ||
| 816 | crate::pac::PWR.cr3().modify(|w| { | ||
| 817 | w.set_usb33den(true); | ||
| 818 | w.set_usbregen(internal_regulator); | ||
| 819 | }) | ||
| 820 | }); | ||
| 848 | 821 | ||
| 849 | // Use internal 48MHz HSI clock. Should be enabled in RCC by default. | 822 | // Wait for USB power to stabilize |
| 850 | critical_section::with(|_| { | 823 | while !crate::pac::PWR.cr3().read().usb33rdy() {} |
| 851 | crate::pac::RCC | ||
| 852 | .d2ccip2r() | ||
| 853 | .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) | ||
| 854 | }); | ||
| 855 | 824 | ||
| 856 | // Enable ULPI clock if external PHY is used | 825 | // Use internal 48MHz HSI clock. Should be enabled in RCC by default. |
| 857 | let ulpien = !self.phy_type.internal(); | 826 | critical_section::with(|_| { |
| 858 | critical_section::with(|_| { | 827 | crate::pac::RCC |
| 859 | crate::pac::RCC.ahb1enr().modify(|w| { | 828 | .d2ccip2r() |
| 860 | if T::HIGH_SPEED { | 829 | .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) |
| 861 | w.set_usb_otg_hs_ulpien(ulpien); | 830 | }); |
| 862 | } else { | 831 | |
| 863 | w.set_usb_otg_fs_ulpien(ulpien); | 832 | // Enable ULPI clock if external PHY is used |
| 864 | } | 833 | let ulpien = !self.phy_type.internal(); |
| 865 | }); | 834 | critical_section::with(|_| { |
| 866 | crate::pac::RCC.ahb1lpenr().modify(|w| { | 835 | crate::pac::RCC.ahb1enr().modify(|w| { |
| 867 | if T::HIGH_SPEED { | 836 | if T::HIGH_SPEED { |
| 868 | w.set_usb_otg_hs_ulpilpen(ulpien); | 837 | w.set_usb_otg_hs_ulpien(ulpien); |
| 869 | } else { | 838 | } else { |
| 870 | w.set_usb_otg_fs_ulpilpen(ulpien); | 839 | w.set_usb_otg_fs_ulpien(ulpien); |
| 871 | } | 840 | } |
| 872 | }); | ||
| 873 | }); | 841 | }); |
| 874 | } | 842 | crate::pac::RCC.ahb1lpenr().modify(|w| { |
| 843 | if T::HIGH_SPEED { | ||
| 844 | w.set_usb_otg_hs_ulpilpen(ulpien); | ||
| 845 | } else { | ||
| 846 | w.set_usb_otg_fs_ulpilpen(ulpien); | ||
| 847 | } | ||
| 848 | }); | ||
| 849 | }); | ||
| 850 | } | ||
| 875 | 851 | ||
| 876 | #[cfg(stm32u5)] | 852 | #[cfg(stm32u5)] |
| 877 | { | 853 | { |
| 878 | // Enable USB power | 854 | // Enable USB power |
| 879 | critical_section::with(|_| { | 855 | critical_section::with(|_| { |
| 880 | crate::pac::RCC.ahb3enr().modify(|w| { | 856 | crate::pac::RCC.ahb3enr().modify(|w| { |
| 881 | w.set_pwren(true); | 857 | w.set_pwren(true); |
| 882 | }); | 858 | }); |
| 883 | cortex_m::asm::delay(2); | 859 | cortex_m::asm::delay(2); |
| 884 | 860 | ||
| 885 | crate::pac::PWR.svmcr().modify(|w| { | 861 | crate::pac::PWR.svmcr().modify(|w| { |
| 886 | w.set_usv(true); | 862 | w.set_usv(true); |
| 887 | w.set_uvmen(true); | 863 | w.set_uvmen(true); |
| 888 | }); | ||
| 889 | }); | 864 | }); |
| 865 | }); | ||
| 890 | 866 | ||
| 891 | // Wait for USB power to stabilize | 867 | // Wait for USB power to stabilize |
| 892 | while !crate::pac::PWR.svmsr().read().vddusbrdy() {} | 868 | while !crate::pac::PWR.svmsr().read().vddusbrdy() {} |
| 893 | 869 | ||
| 894 | // Select HSI48 as USB clock source. | 870 | // Select HSI48 as USB clock source. |
| 895 | critical_section::with(|_| { | 871 | critical_section::with(|_| { |
| 896 | crate::pac::RCC.ccipr1().modify(|w| { | 872 | crate::pac::RCC.ccipr1().modify(|w| { |
| 897 | w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); | 873 | w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); |
| 898 | }) | 874 | }) |
| 899 | }); | 875 | }); |
| 900 | } | 876 | } |
| 901 | 877 | ||
| 902 | <T as RccPeripheral>::enable(); | 878 | <T as RccPeripheral>::enable(); |
| 903 | <T as RccPeripheral>::reset(); | 879 | <T as RccPeripheral>::reset(); |
| 904 | 880 | ||
| 905 | T::Interrupt::steal().unpend(); | 881 | T::Interrupt::unpend(); |
| 906 | T::Interrupt::steal().enable(); | 882 | unsafe { T::Interrupt::enable() }; |
| 907 | 883 | ||
| 908 | let r = T::regs(); | 884 | let r = T::regs(); |
| 909 | let core_id = r.cid().read().0; | 885 | let core_id = r.cid().read().0; |
| 910 | info!("Core id {:08x}", core_id); | 886 | info!("Core id {:08x}", core_id); |
| 911 | 887 | ||
| 912 | // Wait for AHB ready. | 888 | // Wait for AHB ready. |
| 913 | while !r.grstctl().read().ahbidl() {} | 889 | while !r.grstctl().read().ahbidl() {} |
| 914 | 890 | ||
| 915 | // Configure as device. | 891 | // Configure as device. |
| 916 | r.gusbcfg().write(|w| { | 892 | r.gusbcfg().write(|w| { |
| 917 | // Force device mode | 893 | // Force device mode |
| 918 | w.set_fdmod(true); | 894 | w.set_fdmod(true); |
| 919 | // Enable internal full-speed PHY | 895 | // Enable internal full-speed PHY |
| 920 | w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); | 896 | w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); |
| 921 | }); | 897 | }); |
| 922 | 898 | ||
| 923 | // Configuring Vbus sense and SOF output | 899 | // Configuring Vbus sense and SOF output |
| 924 | match core_id { | 900 | match core_id { |
| 925 | 0x0000_1200 | 0x0000_1100 => { | 901 | 0x0000_1200 | 0x0000_1100 => { |
| 926 | assert!(self.phy_type != PhyType::InternalHighSpeed); | 902 | assert!(self.phy_type != PhyType::InternalHighSpeed); |
| 927 | 903 | ||
| 928 | r.gccfg_v1().modify(|w| { | 904 | r.gccfg_v1().modify(|w| { |
| 929 | // Enable internal full-speed PHY, logic is inverted | 905 | // Enable internal full-speed PHY, logic is inverted |
| 930 | w.set_pwrdwn(self.phy_type.internal()); | 906 | w.set_pwrdwn(self.phy_type.internal()); |
| 931 | }); | 907 | }); |
| 932 | 908 | ||
| 933 | // F429-like chips have the GCCFG.NOVBUSSENS bit | 909 | // F429-like chips have the GCCFG.NOVBUSSENS bit |
| 934 | r.gccfg_v1().modify(|w| { | 910 | r.gccfg_v1().modify(|w| { |
| 935 | w.set_novbussens(true); | 911 | w.set_novbussens(true); |
| 936 | w.set_vbusasen(false); | 912 | w.set_vbusasen(false); |
| 937 | w.set_vbusbsen(false); | 913 | w.set_vbusbsen(false); |
| 938 | w.set_sofouten(false); | 914 | w.set_sofouten(false); |
| 939 | }); | 915 | }); |
| 940 | } | 916 | } |
| 941 | 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { | 917 | 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { |
| 942 | // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning | 918 | // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning |
| 943 | r.gccfg_v2().modify(|w| { | 919 | r.gccfg_v2().modify(|w| { |
| 944 | // Enable internal full-speed PHY, logic is inverted | 920 | // Enable internal full-speed PHY, logic is inverted |
| 945 | w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); | 921 | w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); |
| 946 | w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); | 922 | w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); |
| 947 | }); | 923 | }); |
| 948 | 924 | ||
| 949 | r.gccfg_v2().modify(|w| { | 925 | r.gccfg_v2().modify(|w| { |
| 950 | w.set_vbden(false); | 926 | w.set_vbden(false); |
| 951 | }); | 927 | }); |
| 952 | 928 | ||
| 953 | // Force B-peripheral session | 929 | // Force B-peripheral session |
| 954 | r.gotgctl().modify(|w| { | 930 | r.gotgctl().modify(|w| { |
| 955 | w.set_bvaloen(true); | 931 | w.set_bvaloen(true); |
| 956 | w.set_bvaloval(true); | 932 | w.set_bvaloval(true); |
| 957 | }); | 933 | }); |
| 958 | } | ||
| 959 | _ => unimplemented!("Unknown USB core id {:X}", core_id), | ||
| 960 | } | 934 | } |
| 935 | _ => unimplemented!("Unknown USB core id {:X}", core_id), | ||
| 936 | } | ||
| 961 | 937 | ||
| 962 | // Soft disconnect. | 938 | // Soft disconnect. |
| 963 | r.dctl().write(|w| w.set_sdis(true)); | 939 | r.dctl().write(|w| w.set_sdis(true)); |
| 964 | 940 | ||
| 965 | // Set speed. | 941 | // Set speed. |
| 966 | r.dcfg().write(|w| { | 942 | r.dcfg().write(|w| { |
| 967 | w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); | 943 | w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); |
| 968 | w.set_dspd(self.phy_type.to_dspd()); | 944 | w.set_dspd(self.phy_type.to_dspd()); |
| 969 | }); | 945 | }); |
| 970 | 946 | ||
| 971 | // Unmask transfer complete EP interrupt | 947 | // Unmask transfer complete EP interrupt |
| 972 | r.diepmsk().write(|w| { | 948 | r.diepmsk().write(|w| { |
| 973 | w.set_xfrcm(true); | 949 | w.set_xfrcm(true); |
| 974 | }); | 950 | }); |
| 975 | 951 | ||
| 976 | // Unmask and clear core interrupts | 952 | // Unmask and clear core interrupts |
| 977 | Bus::<T>::restore_irqs(); | 953 | Bus::<T>::restore_irqs(); |
| 978 | r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); | 954 | r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); |
| 979 | 955 | ||
| 980 | // Unmask global interrupt | 956 | // Unmask global interrupt |
| 981 | r.gahbcfg().write(|w| { | 957 | r.gahbcfg().write(|w| { |
| 982 | w.set_gint(true); // unmask global interrupt | 958 | w.set_gint(true); // unmask global interrupt |
| 983 | }); | 959 | }); |
| 984 | 960 | ||
| 985 | // Connect | 961 | // Connect |
| 986 | r.dctl().write(|w| w.set_sdis(false)); | 962 | r.dctl().write(|w| w.set_sdis(false)); |
| 987 | } | ||
| 988 | 963 | ||
| 989 | self.enabled = true; | 964 | self.enabled = true; |
| 990 | } | 965 | } |
| @@ -1042,8 +1017,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, In> { | |||
| 1042 | 1017 | ||
| 1043 | T::state().ep_in_wakers[ep_index].register(cx.waker()); | 1018 | T::state().ep_in_wakers[ep_index].register(cx.waker()); |
| 1044 | 1019 | ||
| 1045 | // SAFETY: atomic read without side effects | 1020 | if T::regs().diepctl(ep_index).read().usbaep() { |
| 1046 | if unsafe { T::regs().diepctl(ep_index).read().usbaep() } { | ||
| 1047 | Poll::Ready(()) | 1021 | Poll::Ready(()) |
| 1048 | } else { | 1022 | } else { |
| 1049 | Poll::Pending | 1023 | Poll::Pending |
| @@ -1064,8 +1038,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, Out> { | |||
| 1064 | 1038 | ||
| 1065 | T::state().ep_out_wakers[ep_index].register(cx.waker()); | 1039 | T::state().ep_out_wakers[ep_index].register(cx.waker()); |
| 1066 | 1040 | ||
| 1067 | // SAFETY: atomic read without side effects | 1041 | if T::regs().doepctl(ep_index).read().usbaep() { |
| 1068 | if unsafe { T::regs().doepctl(ep_index).read().usbaep() } { | ||
| 1069 | Poll::Ready(()) | 1042 | Poll::Ready(()) |
| 1070 | } else { | 1043 | } else { |
| 1071 | Poll::Pending | 1044 | Poll::Pending |
| @@ -1100,8 +1073,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 1100 | // Release buffer | 1073 | // Release buffer |
| 1101 | state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release); | 1074 | state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release); |
| 1102 | 1075 | ||
| 1103 | // SAFETY: DOEPCTL/DOEPTSIZ is shared with `Bus` so a critical section is needed for RMW | 1076 | critical_section::with(|_| { |
| 1104 | critical_section::with(|_| unsafe { | ||
| 1105 | // Receive 1 packet | 1077 | // Receive 1 packet |
| 1106 | T::regs().doeptsiz(index).modify(|w| { | 1078 | T::regs().doeptsiz(index).modify(|w| { |
| 1107 | w.set_xfrsiz(self.info.max_packet_size as _); | 1079 | w.set_xfrsiz(self.info.max_packet_size as _); |
| @@ -1139,8 +1111,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 1139 | poll_fn(|cx| { | 1111 | poll_fn(|cx| { |
| 1140 | state.ep_in_wakers[index].register(cx.waker()); | 1112 | state.ep_in_wakers[index].register(cx.waker()); |
| 1141 | 1113 | ||
| 1142 | // SAFETY: atomic read with no side effects | 1114 | let diepctl = r.diepctl(index).read(); |
| 1143 | let diepctl = unsafe { r.diepctl(index).read() }; | ||
| 1144 | if !diepctl.usbaep() { | 1115 | if !diepctl.usbaep() { |
| 1145 | Poll::Ready(Err(EndpointError::Disabled)) | 1116 | Poll::Ready(Err(EndpointError::Disabled)) |
| 1146 | } else if !diepctl.epena() { | 1117 | } else if !diepctl.epena() { |
| @@ -1157,12 +1128,10 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 1157 | 1128 | ||
| 1158 | let size_words = (buf.len() + 3) / 4; | 1129 | let size_words = (buf.len() + 3) / 4; |
| 1159 | 1130 | ||
| 1160 | // SAFETY: atomic read with no side effects | 1131 | let fifo_space = r.dtxfsts(index).read().ineptfsav() as usize; |
| 1161 | let fifo_space = unsafe { r.dtxfsts(index).read().ineptfsav() as usize }; | ||
| 1162 | if size_words > fifo_space { | 1132 | if size_words > fifo_space { |
| 1163 | // Not enough space in fifo, enable tx fifo empty interrupt | 1133 | // Not enough space in fifo, enable tx fifo empty interrupt |
| 1164 | // SAFETY: DIEPEMPMSK is shared with IRQ so critical section is needed for RMW | 1134 | critical_section::with(|_| { |
| 1165 | critical_section::with(|_| unsafe { | ||
| 1166 | r.diepempmsk().modify(|w| { | 1135 | r.diepempmsk().modify(|w| { |
| 1167 | w.set_ineptxfem(w.ineptxfem() | (1 << index)); | 1136 | w.set_ineptxfem(w.ineptxfem() | (1 << index)); |
| 1168 | }); | 1137 | }); |
| @@ -1178,18 +1147,14 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 1178 | .await | 1147 | .await |
| 1179 | } | 1148 | } |
| 1180 | 1149 | ||
| 1181 | // SAFETY: DIEPTSIZ is exclusive to this endpoint under `&mut self` | 1150 | // Setup transfer size |
| 1182 | unsafe { | 1151 | r.dieptsiz(index).write(|w| { |
| 1183 | // Setup transfer size | 1152 | w.set_mcnt(1); |
| 1184 | r.dieptsiz(index).write(|w| { | 1153 | w.set_pktcnt(1); |
| 1185 | w.set_mcnt(1); | 1154 | w.set_xfrsiz(buf.len() as _); |
| 1186 | w.set_pktcnt(1); | 1155 | }); |
| 1187 | w.set_xfrsiz(buf.len() as _); | ||
| 1188 | }); | ||
| 1189 | } | ||
| 1190 | 1156 | ||
| 1191 | // SAFETY: DIEPCTL is shared with `Bus` so a critical section is needed for RMW | 1157 | critical_section::with(|_| { |
| 1192 | critical_section::with(|_| unsafe { | ||
| 1193 | // Enable endpoint | 1158 | // Enable endpoint |
| 1194 | r.diepctl(index).modify(|w| { | 1159 | r.diepctl(index).modify(|w| { |
| 1195 | w.set_cnak(true); | 1160 | w.set_cnak(true); |
| @@ -1201,8 +1166,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 1201 | for chunk in buf.chunks(4) { | 1166 | for chunk in buf.chunks(4) { |
| 1202 | let mut tmp = [0u8; 4]; | 1167 | let mut tmp = [0u8; 4]; |
| 1203 | tmp[0..chunk.len()].copy_from_slice(chunk); | 1168 | tmp[0..chunk.len()].copy_from_slice(chunk); |
| 1204 | // SAFETY: FIFO is exclusive to this endpoint under `&mut self` | 1169 | r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))); |
| 1205 | unsafe { r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))) }; | ||
| 1206 | } | 1170 | } |
| 1207 | 1171 | ||
| 1208 | trace!("write done ep={:?}", self.info.addr); | 1172 | trace!("write done ep={:?}", self.info.addr); |
| @@ -1234,17 +1198,15 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> { | |||
| 1234 | state.ep0_setup_ready.store(false, Ordering::Release); | 1198 | state.ep0_setup_ready.store(false, Ordering::Release); |
| 1235 | 1199 | ||
| 1236 | // EP0 should not be controlled by `Bus` so this RMW does not need a critical section | 1200 | // EP0 should not be controlled by `Bus` so this RMW does not need a critical section |
| 1237 | unsafe { | 1201 | // Receive 1 SETUP packet |
| 1238 | // Receive 1 SETUP packet | 1202 | T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| { |
| 1239 | T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| { | 1203 | w.set_rxdpid_stupcnt(1); |
| 1240 | w.set_rxdpid_stupcnt(1); | 1204 | }); |
| 1241 | }); | ||
| 1242 | 1205 | ||
| 1243 | // Clear NAK to indicate we are ready to receive more data | 1206 | // Clear NAK to indicate we are ready to receive more data |
| 1244 | T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| { | 1207 | T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| { |
| 1245 | w.set_cnak(true); | 1208 | w.set_cnak(true); |
| 1246 | }); | 1209 | }); |
| 1247 | } | ||
| 1248 | 1210 | ||
| 1249 | trace!("SETUP received: {:?}", data); | 1211 | trace!("SETUP received: {:?}", data); |
| 1250 | Poll::Ready(data) | 1212 | Poll::Ready(data) |
| @@ -1289,20 +1251,18 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> { | |||
| 1289 | trace!("control: reject"); | 1251 | trace!("control: reject"); |
| 1290 | 1252 | ||
| 1291 | // EP0 should not be controlled by `Bus` so this RMW does not need a critical section | 1253 | // EP0 should not be controlled by `Bus` so this RMW does not need a critical section |
| 1292 | unsafe { | 1254 | let regs = T::regs(); |
| 1293 | let regs = T::regs(); | 1255 | regs.diepctl(self.ep_in.info.addr.index()).modify(|w| { |
| 1294 | regs.diepctl(self.ep_in.info.addr.index()).modify(|w| { | 1256 | w.set_stall(true); |
| 1295 | w.set_stall(true); | 1257 | }); |
| 1296 | }); | 1258 | regs.doepctl(self.ep_out.info.addr.index()).modify(|w| { |
| 1297 | regs.doepctl(self.ep_out.info.addr.index()).modify(|w| { | 1259 | w.set_stall(true); |
| 1298 | w.set_stall(true); | 1260 | }); |
| 1299 | }); | ||
| 1300 | } | ||
| 1301 | } | 1261 | } |
| 1302 | 1262 | ||
| 1303 | async fn accept_set_address(&mut self, addr: u8) { | 1263 | async fn accept_set_address(&mut self, addr: u8) { |
| 1304 | trace!("setting addr: {}", addr); | 1264 | trace!("setting addr: {}", addr); |
| 1305 | critical_section::with(|_| unsafe { | 1265 | critical_section::with(|_| { |
| 1306 | T::regs().dcfg().modify(|w| { | 1266 | T::regs().dcfg().modify(|w| { |
| 1307 | w.set_dad(addr); | 1267 | w.set_dad(addr); |
| 1308 | }); | 1268 | }); |
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index 18ebf97d8..5907a4e54 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs | |||
| @@ -48,11 +48,9 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { | |||
| 48 | let rl = reload_value(psc, timeout_us); | 48 | let rl = reload_value(psc, timeout_us); |
| 49 | 49 | ||
| 50 | let wdg = T::regs(); | 50 | let wdg = T::regs(); |
| 51 | unsafe { | 51 | wdg.kr().write(|w| w.set_key(Key::ENABLE)); |
| 52 | wdg.kr().write(|w| w.set_key(Key::ENABLE)); | 52 | wdg.pr().write(|w| w.set_pr(Pr(pr))); |
| 53 | wdg.pr().write(|w| w.set_pr(Pr(pr))); | 53 | wdg.rlr().write(|w| w.set_rl(rl)); |
| 54 | wdg.rlr().write(|w| w.set_rl(rl)); | ||
| 55 | } | ||
| 56 | 54 | ||
| 57 | trace!( | 55 | trace!( |
| 58 | "Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})", | 56 | "Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})", |
| @@ -67,11 +65,11 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { | |||
| 67 | } | 65 | } |
| 68 | } | 66 | } |
| 69 | 67 | ||
| 70 | pub unsafe fn unleash(&mut self) { | 68 | pub fn unleash(&mut self) { |
| 71 | T::regs().kr().write(|w| w.set_key(Key::START)); | 69 | T::regs().kr().write(|w| w.set_key(Key::START)); |
| 72 | } | 70 | } |
| 73 | 71 | ||
| 74 | pub unsafe fn pet(&mut self) { | 72 | pub fn pet(&mut self) { |
| 75 | T::regs().kr().write(|w| w.set_key(Key::RESET)); | 73 | T::regs().kr().write(|w| w.set_key(Key::RESET)); |
| 76 | } | 74 | } |
| 77 | } | 75 | } |
diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index bc06b92cd..340724eab 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml | |||
| @@ -45,4 +45,4 @@ futures-util = { version = "0.3.17", features = [ "channel" ] } | |||
| 45 | 45 | ||
| 46 | # Enable critical-section implementation for std, for tests | 46 | # Enable critical-section implementation for std, for tests |
| 47 | critical-section = { version = "1.1", features = ["std"] } | 47 | critical-section = { version = "1.1", features = ["std"] } |
| 48 | static_cell = "1.0" | 48 | static_cell = "1.1" |
diff --git a/embassy-sync/src/fmt.rs b/embassy-sync/src/fmt.rs index f8bb0a035..066970813 100644 --- a/embassy-sync/src/fmt.rs +++ b/embassy-sync/src/fmt.rs | |||
| @@ -195,9 +195,6 @@ macro_rules! unwrap { | |||
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | #[cfg(feature = "defmt-timestamp-uptime")] | ||
| 199 | defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() } | ||
| 200 | |||
| 201 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 202 | pub struct NoneError; | 199 | pub struct NoneError; |
| 203 | 200 | ||
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs index ee27cdec8..db6ebb08b 100644 --- a/embassy-sync/src/pipe.rs +++ b/embassy-sync/src/pipe.rs | |||
| @@ -294,6 +294,16 @@ where | |||
| 294 | WriteFuture { pipe: self, buf } | 294 | WriteFuture { pipe: self, buf } |
| 295 | } | 295 | } |
| 296 | 296 | ||
| 297 | /// Write all bytes to the pipe. | ||
| 298 | /// | ||
| 299 | /// This method writes all bytes from `buf` into the pipe | ||
| 300 | pub async fn write_all(&self, mut buf: &[u8]) { | ||
| 301 | while !buf.is_empty() { | ||
| 302 | let n = self.write(buf).await; | ||
| 303 | buf = &buf[n..]; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 297 | /// Attempt to immediately write some bytes to the pipe. | 307 | /// Attempt to immediately write some bytes to the pipe. |
| 298 | /// | 308 | /// |
| 299 | /// This method will either write a nonzero amount of bytes to the pipe immediately, | 309 | /// This method will either write a nonzero amount of bytes to the pipe immediately, |
diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 1d8dd13ce..6e50c40ba 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs | |||
| @@ -138,7 +138,7 @@ macro_rules! run { | |||
| 138 | ( $x:expr, $l:expr, $p:ident ) => { | 138 | ( $x:expr, $l:expr, $p:ident ) => { |
| 139 | static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); | 139 | static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); |
| 140 | unsafe { | 140 | unsafe { |
| 141 | let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level($l)); | 141 | let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); |
| 142 | } | 142 | } |
| 143 | let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await; | 143 | let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await; |
| 144 | }; | 144 | }; |
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index 8d60f18be..c1dc99eec 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml | |||
| @@ -30,3 +30,4 @@ debug = ["defmt-rtt", "defmt"] | |||
| 30 | 30 | ||
| 31 | [profile.release] | 31 | [profile.release] |
| 32 | debug = true | 32 | debug = true |
| 33 | opt-level = 's' | ||
diff --git a/examples/nrf52840-rtic/.cargo/config.toml b/examples/nrf52840-rtic/.cargo/config.toml new file mode 100644 index 000000000..3872e7189 --- /dev/null +++ b/examples/nrf52840-rtic/.cargo/config.toml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` | ||
| 3 | runner = "probe-rs-cli run --chip nRF52840_xxAA" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv7em-none-eabi" | ||
| 7 | |||
| 8 | [env] | ||
| 9 | DEFMT_LOG = "trace" | ||
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml new file mode 100644 index 000000000..0f9048b0f --- /dev/null +++ b/examples/nrf52840-rtic/Cargo.toml | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-nrf52840-rtic-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | rtic = { version = "2", features = ["thumbv7-backend"] } | ||
| 9 | |||
| 10 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 11 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | ||
| 12 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] } | ||
| 13 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nightly", "unstable-traits", "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | ||
| 14 | |||
| 15 | defmt = "0.3" | ||
| 16 | defmt-rtt = "0.4" | ||
| 17 | |||
| 18 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 19 | cortex-m-rt = "0.7.0" | ||
| 20 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 21 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||
diff --git a/examples/nrf52840-rtic/build.rs b/examples/nrf52840-rtic/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/nrf52840-rtic/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/nrf52840-rtic/memory.x b/examples/nrf52840-rtic/memory.x new file mode 100644 index 000000000..9b04edec0 --- /dev/null +++ b/examples/nrf52840-rtic/memory.x | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | /* NOTE 1 K = 1 KiBi = 1024 bytes */ | ||
| 4 | /* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */ | ||
| 5 | FLASH : ORIGIN = 0x00000000, LENGTH = 1024K | ||
| 6 | RAM : ORIGIN = 0x20000000, LENGTH = 256K | ||
| 7 | } | ||
diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs new file mode 100644 index 000000000..a682c1932 --- /dev/null +++ b/examples/nrf52840-rtic/src/bin/blinky.rs | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use {defmt_rtt as _, panic_probe as _}; | ||
| 6 | |||
| 7 | #[rtic::app(device = embassy_nrf, peripherals = false, dispatchers = [SWI0_EGU0, SWI1_EGU1])] | ||
| 8 | mod app { | ||
| 9 | use defmt::info; | ||
| 10 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 11 | use embassy_nrf::peripherals; | ||
| 12 | use embassy_time::{Duration, Timer}; | ||
| 13 | |||
| 14 | #[shared] | ||
| 15 | struct Shared {} | ||
| 16 | |||
| 17 | #[local] | ||
| 18 | struct Local {} | ||
| 19 | |||
| 20 | #[init] | ||
| 21 | fn init(_: init::Context) -> (Shared, Local) { | ||
| 22 | info!("Hello World!"); | ||
| 23 | |||
| 24 | let p = embassy_nrf::init(Default::default()); | ||
| 25 | blink::spawn(p.P0_13).map_err(|_| ()).unwrap(); | ||
| 26 | |||
| 27 | (Shared {}, Local {}) | ||
| 28 | } | ||
| 29 | |||
| 30 | #[task(priority = 1)] | ||
| 31 | async fn blink(_cx: blink::Context, pin: peripherals::P0_13) { | ||
| 32 | let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); | ||
| 33 | |||
| 34 | loop { | ||
| 35 | info!("off!"); | ||
| 36 | led.set_high(); | ||
| 37 | Timer::after(Duration::from_millis(300)).await; | ||
| 38 | info!("on!"); | ||
| 39 | led.set_low(); | ||
| 40 | Timer::after(Duration::from_millis(300)).await; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | } | ||
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 0f75b3ab7..6627b7861 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [features] | 7 | [features] |
| 8 | default = ["nightly"] | 8 | default = ["nightly"] |
| 9 | nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-time/nightly", "embassy-time/unstable-traits", | 9 | nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-time/nightly", "embassy-time/unstable-traits", "static_cell/nightly", |
| 10 | "embassy-usb", "embedded-io/async", "embassy-net", "embassy-lora", "lora-phy", "lorawan-device", "lorawan"] | 10 | "embassy-usb", "embedded-io/async", "embassy-net", "embassy-lora", "lora-phy", "lorawan-device", "lorawan"] |
| 11 | 11 | ||
| 12 | [dependencies] | 12 | [dependencies] |
| @@ -26,7 +26,7 @@ lorawan = { version = "0.7.3", default-features = false, features = ["default-cr | |||
| 26 | defmt = "0.3" | 26 | defmt = "0.3" |
| 27 | defmt-rtt = "0.4" | 27 | defmt-rtt = "0.4" |
| 28 | 28 | ||
| 29 | static_cell = "1.0" | 29 | static_cell = "1.1" |
| 30 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 30 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 31 | cortex-m-rt = "0.7.0" | 31 | cortex-m-rt = "0.7.0" |
| 32 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 32 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs index 851e189ea..aab819117 100644 --- a/examples/nrf52840/src/bin/multiprio.rs +++ b/examples/nrf52840/src/bin/multiprio.rs | |||
| @@ -57,14 +57,11 @@ | |||
| 57 | #![no_main] | 57 | #![no_main] |
| 58 | #![feature(type_alias_impl_trait)] | 58 | #![feature(type_alias_impl_trait)] |
| 59 | 59 | ||
| 60 | use core::mem; | ||
| 61 | |||
| 62 | use cortex_m::peripheral::NVIC; | ||
| 63 | use cortex_m_rt::entry; | 60 | use cortex_m_rt::entry; |
| 64 | use defmt::{info, unwrap}; | 61 | use defmt::{info, unwrap}; |
| 65 | use embassy_nrf::executor::{Executor, InterruptExecutor}; | 62 | use embassy_executor::{Executor, InterruptExecutor}; |
| 66 | use embassy_nrf::interrupt; | 63 | use embassy_nrf::interrupt; |
| 67 | use embassy_nrf::pac::Interrupt; | 64 | use embassy_nrf::interrupt::{InterruptExt, Priority}; |
| 68 | use embassy_time::{Duration, Instant, Timer}; | 65 | use embassy_time::{Duration, Instant, Timer}; |
| 69 | use static_cell::StaticCell; | 66 | use static_cell::StaticCell; |
| 70 | use {defmt_rtt as _, panic_probe as _}; | 67 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -130,16 +127,15 @@ fn main() -> ! { | |||
| 130 | info!("Hello World!"); | 127 | info!("Hello World!"); |
| 131 | 128 | ||
| 132 | let _p = embassy_nrf::init(Default::default()); | 129 | let _p = embassy_nrf::init(Default::default()); |
| 133 | let mut nvic: NVIC = unsafe { mem::transmute(()) }; | ||
| 134 | 130 | ||
| 135 | // High-priority executor: SWI1_EGU1, priority level 6 | 131 | // High-priority executor: SWI1_EGU1, priority level 6 |
| 136 | unsafe { nvic.set_priority(Interrupt::SWI1_EGU1, 6 << 5) }; | 132 | interrupt::SWI1_EGU1.set_priority(Priority::P6); |
| 137 | let spawner = EXECUTOR_HIGH.start(Interrupt::SWI1_EGU1); | 133 | let spawner = EXECUTOR_HIGH.start(interrupt::SWI1_EGU1); |
| 138 | unwrap!(spawner.spawn(run_high())); | 134 | unwrap!(spawner.spawn(run_high())); |
| 139 | 135 | ||
| 140 | // Medium-priority executor: SWI0_EGU0, priority level 7 | 136 | // Medium-priority executor: SWI0_EGU0, priority level 7 |
| 141 | unsafe { nvic.set_priority(Interrupt::SWI0_EGU0, 7 << 5) }; | 137 | interrupt::SWI0_EGU0.set_priority(Priority::P7); |
| 142 | let spawner = EXECUTOR_MED.start(Interrupt::SWI0_EGU0); | 138 | let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0); |
| 143 | unwrap!(spawner.spawn(run_med())); | 139 | unwrap!(spawner.spawn(run_med())); |
| 144 | 140 | ||
| 145 | // Low priority executor: runs in thread mode, using WFE/SEV | 141 | // Low priority executor: runs in thread mode, using WFE/SEV |
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index 786025c43..f527c0d7f 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs | |||
| @@ -16,7 +16,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState | |||
| 16 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | 16 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; |
| 17 | use embassy_usb::{Builder, Config, UsbDevice}; | 17 | use embassy_usb::{Builder, Config, UsbDevice}; |
| 18 | use embedded_io::asynch::Write; | 18 | use embedded_io::asynch::Write; |
| 19 | use static_cell::StaticCell; | 19 | use static_cell::make_static; |
| 20 | use {defmt_rtt as _, panic_probe as _}; | 20 | use {defmt_rtt as _, panic_probe as _}; |
| 21 | 21 | ||
| 22 | bind_interrupts!(struct Irqs { | 22 | bind_interrupts!(struct Irqs { |
| @@ -27,15 +27,6 @@ bind_interrupts!(struct Irqs { | |||
| 27 | 27 | ||
| 28 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; | 28 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; |
| 29 | 29 | ||
| 30 | macro_rules! singleton { | ||
| 31 | ($val:expr) => {{ | ||
| 32 | type T = impl Sized; | ||
| 33 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 34 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 35 | x | ||
| 36 | }}; | ||
| 37 | } | ||
| 38 | |||
| 39 | const MTU: usize = 1514; | 30 | const MTU: usize = 1514; |
| 40 | 31 | ||
| 41 | #[embassy_executor::task] | 32 | #[embassy_executor::task] |
| @@ -83,11 +74,11 @@ async fn main(spawner: Spawner) { | |||
| 83 | let mut builder = Builder::new( | 74 | let mut builder = Builder::new( |
| 84 | driver, | 75 | driver, |
| 85 | config, | 76 | config, |
| 86 | &mut singleton!([0; 256])[..], | 77 | &mut make_static!([0; 256])[..], |
| 87 | &mut singleton!([0; 256])[..], | 78 | &mut make_static!([0; 256])[..], |
| 88 | &mut singleton!([0; 256])[..], | 79 | &mut make_static!([0; 256])[..], |
| 89 | &mut singleton!([0; 128])[..], | 80 | &mut make_static!([0; 128])[..], |
| 90 | &mut singleton!([0; 128])[..], | 81 | &mut make_static!([0; 128])[..], |
| 91 | ); | 82 | ); |
| 92 | 83 | ||
| 93 | // Our MAC addr. | 84 | // Our MAC addr. |
| @@ -96,22 +87,22 @@ async fn main(spawner: Spawner) { | |||
| 96 | let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; | 87 | let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; |
| 97 | 88 | ||
| 98 | // Create classes on the builder. | 89 | // Create classes on the builder. |
| 99 | let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); | 90 | let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); |
| 100 | 91 | ||
| 101 | // Build the builder. | 92 | // Build the builder. |
| 102 | let usb = builder.build(); | 93 | let usb = builder.build(); |
| 103 | 94 | ||
| 104 | unwrap!(spawner.spawn(usb_task(usb))); | 95 | unwrap!(spawner.spawn(usb_task(usb))); |
| 105 | 96 | ||
| 106 | let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); | 97 | let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); |
| 107 | unwrap!(spawner.spawn(usb_ncm_task(runner))); | 98 | unwrap!(spawner.spawn(usb_ncm_task(runner))); |
| 108 | 99 | ||
| 109 | let config = embassy_net::Config::Dhcp(Default::default()); | 100 | let config = embassy_net::Config::dhcpv4(Default::default()); |
| 110 | //let config = embassy_net::Config::Static(embassy_net::StaticConfig { | 101 | // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 111 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | 102 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), |
| 112 | // dns_servers: Vec::new(), | 103 | // dns_servers: Vec::new(), |
| 113 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | 104 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), |
| 114 | //}); | 105 | // }); |
| 115 | 106 | ||
| 116 | // Generate random seed | 107 | // Generate random seed |
| 117 | let mut rng = Rng::new(p.RNG, Irqs); | 108 | let mut rng = Rng::new(p.RNG, Irqs); |
| @@ -120,7 +111,12 @@ async fn main(spawner: Spawner) { | |||
| 120 | let seed = u64::from_le_bytes(seed); | 111 | let seed = u64::from_le_bytes(seed); |
| 121 | 112 | ||
| 122 | // Init network stack | 113 | // Init network stack |
| 123 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); | 114 | let stack = &*make_static!(Stack::new( |
| 115 | device, | ||
| 116 | config, | ||
| 117 | make_static!(StackResources::<2>::new()), | ||
| 118 | seed | ||
| 119 | )); | ||
| 124 | 120 | ||
| 125 | unwrap!(spawner.spawn(net_task(stack))); | 121 | unwrap!(spawner.spawn(net_task(stack))); |
| 126 | 122 | ||
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index ac22d9499..cd4392903 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs | |||
| @@ -12,7 +12,7 @@ use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | |||
| 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 13 | use embassy_usb::driver::EndpointError; | 13 | use embassy_usb::driver::EndpointError; |
| 14 | use embassy_usb::{Builder, Config, UsbDevice}; | 14 | use embassy_usb::{Builder, Config, UsbDevice}; |
| 15 | use static_cell::StaticCell; | 15 | use static_cell::make_static; |
| 16 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {defmt_rtt as _, panic_probe as _}; |
| 17 | 17 | ||
| 18 | bind_interrupts!(struct Irqs { | 18 | bind_interrupts!(struct Irqs { |
| @@ -20,15 +20,6 @@ bind_interrupts!(struct Irqs { | |||
| 20 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; | 20 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; |
| 21 | }); | 21 | }); |
| 22 | 22 | ||
| 23 | macro_rules! singleton { | ||
| 24 | ($val:expr) => {{ | ||
| 25 | type T = impl Sized; | ||
| 26 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 27 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 28 | x | ||
| 29 | }}; | ||
| 30 | } | ||
| 31 | |||
| 32 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; | 23 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; |
| 33 | 24 | ||
| 34 | #[embassy_executor::task] | 25 | #[embassy_executor::task] |
| @@ -73,17 +64,17 @@ async fn main(spawner: Spawner) { | |||
| 73 | config.device_protocol = 0x01; | 64 | config.device_protocol = 0x01; |
| 74 | config.composite_with_iads = true; | 65 | config.composite_with_iads = true; |
| 75 | 66 | ||
| 76 | let state = singleton!(State::new()); | 67 | let state = make_static!(State::new()); |
| 77 | 68 | ||
| 78 | // Create embassy-usb DeviceBuilder using the driver and config. | 69 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 79 | let mut builder = Builder::new( | 70 | let mut builder = Builder::new( |
| 80 | driver, | 71 | driver, |
| 81 | config, | 72 | config, |
| 82 | &mut singleton!([0; 256])[..], | 73 | &mut make_static!([0; 256])[..], |
| 83 | &mut singleton!([0; 256])[..], | 74 | &mut make_static!([0; 256])[..], |
| 84 | &mut singleton!([0; 256])[..], | 75 | &mut make_static!([0; 256])[..], |
| 85 | &mut singleton!([0; 128])[..], | 76 | &mut make_static!([0; 128])[..], |
| 86 | &mut singleton!([0; 128])[..], | 77 | &mut make_static!([0; 128])[..], |
| 87 | ); | 78 | ); |
| 88 | 79 | ||
| 89 | // Create classes on the builder. | 80 | // Create classes on the builder. |
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 40422e7df..efb66bae6 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml | |||
| @@ -42,7 +42,7 @@ embedded-io = { version = "0.4.0", features = [ "async" ]} | |||
| 42 | defmt = "0.3" | 42 | defmt = "0.3" |
| 43 | defmt-rtt = "0.4" | 43 | defmt-rtt = "0.4" |
| 44 | 44 | ||
| 45 | static_cell = "1.0" | 45 | static_cell = { version = "1.1", features = ["nightly"]} |
| 46 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 46 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 47 | cortex-m-rt = "0.7.0" | 47 | cortex-m-rt = "0.7.0" |
| 48 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 48 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 58b701915..48f3a26bb 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" | |||
| 8 | [dependencies] | 8 | [dependencies] |
| 9 | embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } | 9 | embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } |
| 10 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } | 12 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } | 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| @@ -45,7 +45,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" } | |||
| 45 | embedded-hal-async = "0.2.0-alpha.1" | 45 | embedded-hal-async = "0.2.0-alpha.1" |
| 46 | embedded-io = { version = "0.4.0", features = ["async", "defmt"] } | 46 | embedded-io = { version = "0.4.0", features = ["async", "defmt"] } |
| 47 | embedded-storage = { version = "0.3" } | 47 | embedded-storage = { version = "0.3" } |
| 48 | static_cell = "1.0.0" | 48 | static_cell = { version = "1.1", features = ["nightly"]} |
| 49 | log = "0.4" | 49 | log = "0.4" |
| 50 | pio-proc = "0.2" | 50 | pio-proc = "0.2" |
| 51 | pio = "0.2.1" | 51 | pio = "0.2.1" |
diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs index c5422c616..0d246c093 100644 --- a/examples/rp/src/bin/button.rs +++ b/examples/rp/src/bin/button.rs | |||
| @@ -9,9 +9,12 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 9 | #[embassy_executor::main] | 9 | #[embassy_executor::main] |
| 10 | async fn main(_spawner: Spawner) { | 10 | async fn main(_spawner: Spawner) { |
| 11 | let p = embassy_rp::init(Default::default()); | 11 | let p = embassy_rp::init(Default::default()); |
| 12 | let button = Input::new(p.PIN_28, Pull::Up); | ||
| 13 | let mut led = Output::new(p.PIN_25, Level::Low); | 12 | let mut led = Output::new(p.PIN_25, Level::Low); |
| 14 | 13 | ||
| 14 | // Use PIN_28, Pin34 on J0 for RP Pico, as a input. | ||
| 15 | // You need to add your own button. | ||
| 16 | let button = Input::new(p.PIN_28, Pull::Up); | ||
| 17 | |||
| 15 | loop { | 18 | loop { |
| 16 | if button.is_high() { | 19 | if button.is_high() { |
| 17 | led.set_high(); | 20 | led.set_high(); |
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index c8e6d46a6..82568254a 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs | |||
| @@ -19,18 +19,9 @@ use embassy_time::Duration; | |||
| 19 | use embedded_hal_async::spi::ExclusiveDevice; | 19 | use embedded_hal_async::spi::ExclusiveDevice; |
| 20 | use embedded_io::asynch::Write; | 20 | use embedded_io::asynch::Write; |
| 21 | use rand::RngCore; | 21 | use rand::RngCore; |
| 22 | use static_cell::StaticCell; | 22 | use static_cell::make_static; |
| 23 | use {defmt_rtt as _, panic_probe as _}; | 23 | use {defmt_rtt as _, panic_probe as _}; |
| 24 | 24 | ||
| 25 | macro_rules! singleton { | ||
| 26 | ($val:expr) => {{ | ||
| 27 | type T = impl Sized; | ||
| 28 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 29 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 30 | x | ||
| 31 | }}; | ||
| 32 | } | ||
| 33 | |||
| 34 | #[embassy_executor::task] | 25 | #[embassy_executor::task] |
| 35 | async fn ethernet_task( | 26 | async fn ethernet_task( |
| 36 | runner: Runner< | 27 | runner: Runner< |
| @@ -62,7 +53,7 @@ async fn main(spawner: Spawner) { | |||
| 62 | let w5500_reset = Output::new(p.PIN_20, Level::High); | 53 | let w5500_reset = Output::new(p.PIN_20, Level::High); |
| 63 | 54 | ||
| 64 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; | 55 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; |
| 65 | let state = singleton!(State::<8, 8>::new()); | 56 | let state = make_static!(State::<8, 8>::new()); |
| 66 | let (device, runner) = | 57 | let (device, runner) = |
| 67 | embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; | 58 | embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; |
| 68 | unwrap!(spawner.spawn(ethernet_task(runner))); | 59 | unwrap!(spawner.spawn(ethernet_task(runner))); |
| @@ -71,10 +62,10 @@ async fn main(spawner: Spawner) { | |||
| 71 | let seed = rng.next_u64(); | 62 | let seed = rng.next_u64(); |
| 72 | 63 | ||
| 73 | // Init network stack | 64 | // Init network stack |
| 74 | let stack = &*singleton!(Stack::new( | 65 | let stack = &*make_static!(Stack::new( |
| 75 | device, | 66 | device, |
| 76 | embassy_net::Config::Dhcp(Default::default()), | 67 | embassy_net::Config::dhcpv4(Default::default()), |
| 77 | singleton!(StackResources::<3>::new()), | 68 | make_static!(StackResources::<3>::new()), |
| 78 | seed | 69 | seed |
| 79 | )); | 70 | )); |
| 80 | 71 | ||
| @@ -129,9 +120,9 @@ async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16) | |||
| 129 | } | 120 | } |
| 130 | } | 121 | } |
| 131 | 122 | ||
| 132 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { | 123 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { |
| 133 | loop { | 124 | loop { |
| 134 | if let Some(config) = stack.config() { | 125 | if let Some(config) = stack.config_v4() { |
| 135 | return config.clone(); | 126 | return config.clone(); |
| 136 | } | 127 | } |
| 137 | yield_now().await; | 128 | yield_now().await; |
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index 9a7c3ad19..d562defad 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs | |||
| @@ -21,18 +21,9 @@ use embassy_time::{Duration, Timer}; | |||
| 21 | use embedded_hal_async::spi::ExclusiveDevice; | 21 | use embedded_hal_async::spi::ExclusiveDevice; |
| 22 | use embedded_io::asynch::Write; | 22 | use embedded_io::asynch::Write; |
| 23 | use rand::RngCore; | 23 | use rand::RngCore; |
| 24 | use static_cell::StaticCell; | 24 | use static_cell::make_static; |
| 25 | use {defmt_rtt as _, panic_probe as _}; | 25 | use {defmt_rtt as _, panic_probe as _}; |
| 26 | 26 | ||
| 27 | macro_rules! singleton { | ||
| 28 | ($val:expr) => {{ | ||
| 29 | type T = impl Sized; | ||
| 30 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 31 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 32 | x | ||
| 33 | }}; | ||
| 34 | } | ||
| 35 | |||
| 36 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| 37 | async fn ethernet_task( | 28 | async fn ethernet_task( |
| 38 | runner: Runner< | 29 | runner: Runner< |
| @@ -65,7 +56,7 @@ async fn main(spawner: Spawner) { | |||
| 65 | let w5500_reset = Output::new(p.PIN_20, Level::High); | 56 | let w5500_reset = Output::new(p.PIN_20, Level::High); |
| 66 | 57 | ||
| 67 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; | 58 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; |
| 68 | let state = singleton!(State::<8, 8>::new()); | 59 | let state = make_static!(State::<8, 8>::new()); |
| 69 | let (device, runner) = | 60 | let (device, runner) = |
| 70 | embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; | 61 | embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; |
| 71 | unwrap!(spawner.spawn(ethernet_task(runner))); | 62 | unwrap!(spawner.spawn(ethernet_task(runner))); |
| @@ -74,10 +65,10 @@ async fn main(spawner: Spawner) { | |||
| 74 | let seed = rng.next_u64(); | 65 | let seed = rng.next_u64(); |
| 75 | 66 | ||
| 76 | // Init network stack | 67 | // Init network stack |
| 77 | let stack = &*singleton!(Stack::new( | 68 | let stack = &*make_static!(Stack::new( |
| 78 | device, | 69 | device, |
| 79 | embassy_net::Config::Dhcp(Default::default()), | 70 | embassy_net::Config::dhcpv4(Default::default()), |
| 80 | singleton!(StackResources::<2>::new()), | 71 | make_static!(StackResources::<2>::new()), |
| 81 | seed | 72 | seed |
| 82 | )); | 73 | )); |
| 83 | 74 | ||
| @@ -117,9 +108,9 @@ async fn main(spawner: Spawner) { | |||
| 117 | } | 108 | } |
| 118 | } | 109 | } |
| 119 | 110 | ||
| 120 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { | 111 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { |
| 121 | loop { | 112 | loop { |
| 122 | if let Some(config) = stack.config() { | 113 | if let Some(config) = stack.config_v4() { |
| 123 | return config.clone(); | 114 | return config.clone(); |
| 124 | } | 115 | } |
| 125 | yield_now().await; | 116 | yield_now().await; |
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index f02543246..7f521cdb4 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs | |||
| @@ -20,18 +20,8 @@ use embassy_time::Duration; | |||
| 20 | use embedded_hal_async::spi::ExclusiveDevice; | 20 | use embedded_hal_async::spi::ExclusiveDevice; |
| 21 | use embedded_io::asynch::Write; | 21 | use embedded_io::asynch::Write; |
| 22 | use rand::RngCore; | 22 | use rand::RngCore; |
| 23 | use static_cell::StaticCell; | 23 | use static_cell::make_static; |
| 24 | use {defmt_rtt as _, panic_probe as _}; | 24 | use {defmt_rtt as _, panic_probe as _}; |
| 25 | |||
| 26 | macro_rules! singleton { | ||
| 27 | ($val:expr) => {{ | ||
| 28 | type T = impl Sized; | ||
| 29 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 30 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 31 | x | ||
| 32 | }}; | ||
| 33 | } | ||
| 34 | |||
| 35 | #[embassy_executor::task] | 25 | #[embassy_executor::task] |
| 36 | async fn ethernet_task( | 26 | async fn ethernet_task( |
| 37 | runner: Runner< | 27 | runner: Runner< |
| @@ -64,7 +54,7 @@ async fn main(spawner: Spawner) { | |||
| 64 | let w5500_reset = Output::new(p.PIN_20, Level::High); | 54 | let w5500_reset = Output::new(p.PIN_20, Level::High); |
| 65 | 55 | ||
| 66 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; | 56 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; |
| 67 | let state = singleton!(State::<8, 8>::new()); | 57 | let state = make_static!(State::<8, 8>::new()); |
| 68 | let (device, runner) = | 58 | let (device, runner) = |
| 69 | embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; | 59 | embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; |
| 70 | unwrap!(spawner.spawn(ethernet_task(runner))); | 60 | unwrap!(spawner.spawn(ethernet_task(runner))); |
| @@ -73,10 +63,10 @@ async fn main(spawner: Spawner) { | |||
| 73 | let seed = rng.next_u64(); | 63 | let seed = rng.next_u64(); |
| 74 | 64 | ||
| 75 | // Init network stack | 65 | // Init network stack |
| 76 | let stack = &*singleton!(Stack::new( | 66 | let stack = &*make_static!(Stack::new( |
| 77 | device, | 67 | device, |
| 78 | embassy_net::Config::Dhcp(Default::default()), | 68 | embassy_net::Config::dhcpv4(Default::default()), |
| 79 | singleton!(StackResources::<2>::new()), | 69 | make_static!(StackResources::<2>::new()), |
| 80 | seed | 70 | seed |
| 81 | )); | 71 | )); |
| 82 | 72 | ||
| @@ -126,9 +116,9 @@ async fn main(spawner: Spawner) { | |||
| 126 | } | 116 | } |
| 127 | } | 117 | } |
| 128 | 118 | ||
| 129 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { | 119 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { |
| 130 | loop { | 120 | loop { |
| 131 | if let Some(config) = stack.config() { | 121 | if let Some(config) = stack.config_v4() { |
| 132 | return config.clone(); | 122 | return config.clone(); |
| 133 | } | 123 | } |
| 134 | yield_now().await; | 124 | yield_now().await; |
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index 2c54f711e..ada86ae55 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs | |||
| @@ -18,18 +18,8 @@ use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; | |||
| 18 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; | 18 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; |
| 19 | use embedded_hal_async::spi::ExclusiveDevice; | 19 | use embedded_hal_async::spi::ExclusiveDevice; |
| 20 | use rand::RngCore; | 20 | use rand::RngCore; |
| 21 | use static_cell::StaticCell; | 21 | use static_cell::make_static; |
| 22 | use {defmt_rtt as _, panic_probe as _}; | 22 | use {defmt_rtt as _, panic_probe as _}; |
| 23 | |||
| 24 | macro_rules! singleton { | ||
| 25 | ($val:expr) => {{ | ||
| 26 | type T = impl Sized; | ||
| 27 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 28 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 29 | x | ||
| 30 | }}; | ||
| 31 | } | ||
| 32 | |||
| 33 | #[embassy_executor::task] | 23 | #[embassy_executor::task] |
| 34 | async fn ethernet_task( | 24 | async fn ethernet_task( |
| 35 | runner: Runner< | 25 | runner: Runner< |
| @@ -61,7 +51,7 @@ async fn main(spawner: Spawner) { | |||
| 61 | let w5500_reset = Output::new(p.PIN_20, Level::High); | 51 | let w5500_reset = Output::new(p.PIN_20, Level::High); |
| 62 | 52 | ||
| 63 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; | 53 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; |
| 64 | let state = singleton!(State::<8, 8>::new()); | 54 | let state = make_static!(State::<8, 8>::new()); |
| 65 | let (device, runner) = | 55 | let (device, runner) = |
| 66 | embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; | 56 | embassy_net_w5500::new(mac_addr, state, ExclusiveDevice::new(spi, cs), w5500_int, w5500_reset).await; |
| 67 | unwrap!(spawner.spawn(ethernet_task(runner))); | 57 | unwrap!(spawner.spawn(ethernet_task(runner))); |
| @@ -70,10 +60,10 @@ async fn main(spawner: Spawner) { | |||
| 70 | let seed = rng.next_u64(); | 60 | let seed = rng.next_u64(); |
| 71 | 61 | ||
| 72 | // Init network stack | 62 | // Init network stack |
| 73 | let stack = &*singleton!(Stack::new( | 63 | let stack = &*make_static!(Stack::new( |
| 74 | device, | 64 | device, |
| 75 | embassy_net::Config::Dhcp(Default::default()), | 65 | embassy_net::Config::dhcpv4(Default::default()), |
| 76 | singleton!(StackResources::<2>::new()), | 66 | make_static!(StackResources::<2>::new()), |
| 77 | seed | 67 | seed |
| 78 | )); | 68 | )); |
| 79 | 69 | ||
| @@ -105,9 +95,9 @@ async fn main(spawner: Spawner) { | |||
| 105 | } | 95 | } |
| 106 | } | 96 | } |
| 107 | 97 | ||
| 108 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfig { | 98 | async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 { |
| 109 | loop { | 99 | loop { |
| 110 | if let Some(config) = stack.config() { | 100 | if let Some(config) = stack.config_v4() { |
| 111 | return config.clone(); | 101 | return config.clone(); |
| 112 | } | 102 | } |
| 113 | yield_now().await; | 103 | yield_now().await; |
diff --git a/examples/rp/src/bin/lora_p2p_send_multicore.rs b/examples/rp/src/bin/lora_p2p_send_multicore.rs index 5585606d8..eef2f7a53 100644 --- a/examples/rp/src/bin/lora_p2p_send_multicore.rs +++ b/examples/rp/src/bin/lora_p2p_send_multicore.rs | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | 7 | ||
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Executor; | 9 | use embassy_executor::Executor; |
| 10 | use embassy_executor::_export::StaticCell; | ||
| 11 | use embassy_lora::iv::GenericSx126xInterfaceVariant; | 10 | use embassy_lora::iv::GenericSx126xInterfaceVariant; |
| 12 | use embassy_rp::gpio::{AnyPin, Input, Level, Output, Pin, Pull}; | 11 | use embassy_rp::gpio::{AnyPin, Input, Level, Output, Pin, Pull}; |
| 13 | use embassy_rp::multicore::{spawn_core1, Stack}; | 12 | use embassy_rp::multicore::{spawn_core1, Stack}; |
| @@ -19,6 +18,7 @@ use embassy_time::{Delay, Duration, Timer}; | |||
| 19 | use lora_phy::mod_params::*; | 18 | use lora_phy::mod_params::*; |
| 20 | use lora_phy::sx1261_2::SX1261_2; | 19 | use lora_phy::sx1261_2::SX1261_2; |
| 21 | use lora_phy::LoRa; | 20 | use lora_phy::LoRa; |
| 21 | use static_cell::StaticCell; | ||
| 22 | use {defmt_rtt as _, panic_probe as _}; | 22 | use {defmt_rtt as _, panic_probe as _}; |
| 23 | 23 | ||
| 24 | static mut CORE1_STACK: Stack<4096> = Stack::new(); | 24 | static mut CORE1_STACK: Stack<4096> = Stack::new(); |
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs index 376b2b61e..57278dd6c 100644 --- a/examples/rp/src/bin/multicore.rs +++ b/examples/rp/src/bin/multicore.rs | |||
| @@ -4,13 +4,13 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Executor; | 6 | use embassy_executor::Executor; |
| 7 | use embassy_executor::_export::StaticCell; | ||
| 8 | use embassy_rp::gpio::{Level, Output}; | 7 | use embassy_rp::gpio::{Level, Output}; |
| 9 | use embassy_rp::multicore::{spawn_core1, Stack}; | 8 | use embassy_rp::multicore::{spawn_core1, Stack}; |
| 10 | use embassy_rp::peripherals::PIN_25; | 9 | use embassy_rp::peripherals::PIN_25; |
| 11 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 10 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 12 | use embassy_sync::channel::Channel; | 11 | use embassy_sync::channel::Channel; |
| 13 | use embassy_time::{Duration, Timer}; | 12 | use embassy_time::{Duration, Timer}; |
| 13 | use static_cell::StaticCell; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | 14 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 15 | ||
| 16 | static mut CORE1_STACK: Stack<4096> = Stack::new(); | 16 | static mut CORE1_STACK: Stack<4096> = Stack::new(); |
diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs index 2f79ba49e..9ace4cd68 100644 --- a/examples/rp/src/bin/multiprio.rs +++ b/examples/rp/src/bin/multiprio.rs | |||
| @@ -57,14 +57,11 @@ | |||
| 57 | #![no_main] | 57 | #![no_main] |
| 58 | #![feature(type_alias_impl_trait)] | 58 | #![feature(type_alias_impl_trait)] |
| 59 | 59 | ||
| 60 | use core::mem; | ||
| 61 | |||
| 62 | use cortex_m::peripheral::NVIC; | ||
| 63 | use cortex_m_rt::entry; | 60 | use cortex_m_rt::entry; |
| 64 | use defmt::{info, unwrap}; | 61 | use defmt::{info, unwrap}; |
| 65 | use embassy_rp::executor::{Executor, InterruptExecutor}; | 62 | use embassy_executor::{Executor, InterruptExecutor}; |
| 66 | use embassy_rp::interrupt; | 63 | use embassy_rp::interrupt; |
| 67 | use embassy_rp::pac::Interrupt; | 64 | use embassy_rp::interrupt::{InterruptExt, Priority}; |
| 68 | use embassy_time::{Duration, Instant, Timer, TICK_HZ}; | 65 | use embassy_time::{Duration, Instant, Timer, TICK_HZ}; |
| 69 | use static_cell::StaticCell; | 66 | use static_cell::StaticCell; |
| 70 | use {defmt_rtt as _, panic_probe as _}; | 67 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -130,18 +127,15 @@ fn main() -> ! { | |||
| 130 | info!("Hello World!"); | 127 | info!("Hello World!"); |
| 131 | 128 | ||
| 132 | let _p = embassy_rp::init(Default::default()); | 129 | let _p = embassy_rp::init(Default::default()); |
| 133 | let mut nvic: NVIC = unsafe { mem::transmute(()) }; | ||
| 134 | 130 | ||
| 135 | // High-priority executor: SWI_IRQ_1, priority level 2 | 131 | // High-priority executor: SWI_IRQ_1, priority level 2 |
| 136 | unsafe { nvic.set_priority(Interrupt::SWI_IRQ_1, 2 << 6) }; | 132 | interrupt::SWI_IRQ_1.set_priority(Priority::P2); |
| 137 | info!("bla: {}", NVIC::get_priority(Interrupt::SWI_IRQ_1)); | 133 | let spawner = EXECUTOR_HIGH.start(interrupt::SWI_IRQ_1); |
| 138 | let spawner = EXECUTOR_HIGH.start(Interrupt::SWI_IRQ_1); | ||
| 139 | unwrap!(spawner.spawn(run_high())); | 134 | unwrap!(spawner.spawn(run_high())); |
| 140 | 135 | ||
| 141 | // Medium-priority executor: SWI_IRQ_0, priority level 3 | 136 | // Medium-priority executor: SWI_IRQ_0, priority level 3 |
| 142 | unsafe { nvic.set_priority(Interrupt::SWI_IRQ_0, 3 << 6) }; | 137 | interrupt::SWI_IRQ_0.set_priority(Priority::P3); |
| 143 | info!("bla: {}", NVIC::get_priority(Interrupt::SWI_IRQ_0)); | 138 | let spawner = EXECUTOR_MED.start(interrupt::SWI_IRQ_0); |
| 144 | let spawner = EXECUTOR_MED.start(Interrupt::SWI_IRQ_0); | ||
| 145 | unwrap!(spawner.spawn(run_med())); | 139 | unwrap!(spawner.spawn(run_med())); |
| 146 | 140 | ||
| 147 | // Low priority executor: runs in thread mode, using WFE/SEV | 141 | // Low priority executor: runs in thread mode, using WFE/SEV |
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs index d6f01b4de..9df99bd58 100644 --- a/examples/rp/src/bin/uart_buffered_split.rs +++ b/examples/rp/src/bin/uart_buffered_split.rs | |||
| @@ -4,34 +4,25 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_executor::_export::StaticCell; | ||
| 8 | use embassy_rp::bind_interrupts; | 7 | use embassy_rp::bind_interrupts; |
| 9 | use embassy_rp::peripherals::UART0; | 8 | use embassy_rp::peripherals::UART0; |
| 10 | use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config}; | 9 | use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config}; |
| 11 | use embassy_time::{Duration, Timer}; | 10 | use embassy_time::{Duration, Timer}; |
| 12 | use embedded_io::asynch::{Read, Write}; | 11 | use embedded_io::asynch::{Read, Write}; |
| 12 | use static_cell::make_static; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| 16 | UART0_IRQ => BufferedInterruptHandler<UART0>; | 16 | UART0_IRQ => BufferedInterruptHandler<UART0>; |
| 17 | }); | 17 | }); |
| 18 | 18 | ||
| 19 | macro_rules! singleton { | ||
| 20 | ($val:expr) => {{ | ||
| 21 | type T = impl Sized; | ||
| 22 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 23 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 24 | x | ||
| 25 | }}; | ||
| 26 | } | ||
| 27 | |||
| 28 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| 29 | async fn main(spawner: Spawner) { | 20 | async fn main(spawner: Spawner) { |
| 30 | let p = embassy_rp::init(Default::default()); | 21 | let p = embassy_rp::init(Default::default()); |
| 31 | let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0); | 22 | let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0); |
| 32 | 23 | ||
| 33 | let tx_buf = &mut singleton!([0u8; 16])[..]; | 24 | let tx_buf = &mut make_static!([0u8; 16])[..]; |
| 34 | let rx_buf = &mut singleton!([0u8; 16])[..]; | 25 | let rx_buf = &mut make_static!([0u8; 16])[..]; |
| 35 | let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); | 26 | let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); |
| 36 | let (rx, mut tx) = uart.split(); | 27 | let (rx, mut tx) = uart.split(); |
| 37 | 28 | ||
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 38ff1620d..91d1ec8e7 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs | |||
| @@ -13,7 +13,7 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState | |||
| 13 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | 13 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; |
| 14 | use embassy_usb::{Builder, Config, UsbDevice}; | 14 | use embassy_usb::{Builder, Config, UsbDevice}; |
| 15 | use embedded_io::asynch::Write; | 15 | use embedded_io::asynch::Write; |
| 16 | use static_cell::StaticCell; | 16 | use static_cell::make_static; |
| 17 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {defmt_rtt as _, panic_probe as _}; |
| 18 | 18 | ||
| 19 | bind_interrupts!(struct Irqs { | 19 | bind_interrupts!(struct Irqs { |
| @@ -22,15 +22,6 @@ bind_interrupts!(struct Irqs { | |||
| 22 | 22 | ||
| 23 | type MyDriver = Driver<'static, peripherals::USB>; | 23 | type MyDriver = Driver<'static, peripherals::USB>; |
| 24 | 24 | ||
| 25 | macro_rules! singleton { | ||
| 26 | ($val:expr) => {{ | ||
| 27 | type T = impl Sized; | ||
| 28 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 29 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 30 | x | ||
| 31 | }}; | ||
| 32 | } | ||
| 33 | |||
| 34 | const MTU: usize = 1514; | 25 | const MTU: usize = 1514; |
| 35 | 26 | ||
| 36 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| @@ -73,10 +64,10 @@ async fn main(spawner: Spawner) { | |||
| 73 | let mut builder = Builder::new( | 64 | let mut builder = Builder::new( |
| 74 | driver, | 65 | driver, |
| 75 | config, | 66 | config, |
| 76 | &mut singleton!([0; 256])[..], | 67 | &mut make_static!([0; 256])[..], |
| 77 | &mut singleton!([0; 256])[..], | 68 | &mut make_static!([0; 256])[..], |
| 78 | &mut singleton!([0; 256])[..], | 69 | &mut make_static!([0; 256])[..], |
| 79 | &mut singleton!([0; 128])[..], | 70 | &mut make_static!([0; 128])[..], |
| 80 | ); | 71 | ); |
| 81 | 72 | ||
| 82 | // Our MAC addr. | 73 | // Our MAC addr. |
| @@ -85,18 +76,18 @@ async fn main(spawner: Spawner) { | |||
| 85 | let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; | 76 | let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; |
| 86 | 77 | ||
| 87 | // Create classes on the builder. | 78 | // Create classes on the builder. |
| 88 | let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); | 79 | let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); |
| 89 | 80 | ||
| 90 | // Build the builder. | 81 | // Build the builder. |
| 91 | let usb = builder.build(); | 82 | let usb = builder.build(); |
| 92 | 83 | ||
| 93 | unwrap!(spawner.spawn(usb_task(usb))); | 84 | unwrap!(spawner.spawn(usb_task(usb))); |
| 94 | 85 | ||
| 95 | let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); | 86 | let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); |
| 96 | unwrap!(spawner.spawn(usb_ncm_task(runner))); | 87 | unwrap!(spawner.spawn(usb_ncm_task(runner))); |
| 97 | 88 | ||
| 98 | let config = embassy_net::Config::Dhcp(Default::default()); | 89 | let config = embassy_net::Config::dhcpv4(Default::default()); |
| 99 | //let config = embassy_net::Config::Static(embassy_net::StaticConfig { | 90 | //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 100 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | 91 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), |
| 101 | // dns_servers: Vec::new(), | 92 | // dns_servers: Vec::new(), |
| 102 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | 93 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), |
| @@ -106,7 +97,12 @@ async fn main(spawner: Spawner) { | |||
| 106 | let seed = 1234; // guaranteed random, chosen by a fair dice roll | 97 | let seed = 1234; // guaranteed random, chosen by a fair dice roll |
| 107 | 98 | ||
| 108 | // Init network stack | 99 | // Init network stack |
| 109 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); | 100 | let stack = &*make_static!(Stack::new( |
| 101 | device, | ||
| 102 | config, | ||
| 103 | make_static!(StackResources::<2>::new()), | ||
| 104 | seed | ||
| 105 | )); | ||
| 110 | 106 | ||
| 111 | unwrap!(spawner.spawn(net_task(stack))); | 107 | unwrap!(spawner.spawn(net_task(stack))); |
| 112 | 108 | ||
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 15264524e..e8197390c 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs | |||
| @@ -16,17 +16,9 @@ use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; | |||
| 16 | use embassy_rp::pio::Pio; | 16 | use embassy_rp::pio::Pio; |
| 17 | use embassy_time::Duration; | 17 | use embassy_time::Duration; |
| 18 | use embedded_io::asynch::Write; | 18 | use embedded_io::asynch::Write; |
| 19 | use static_cell::StaticCell; | 19 | use static_cell::make_static; |
| 20 | use {defmt_rtt as _, panic_probe as _}; | 20 | use {defmt_rtt as _, panic_probe as _}; |
| 21 | 21 | ||
| 22 | macro_rules! singleton { | ||
| 23 | ($val:expr) => {{ | ||
| 24 | type T = impl Sized; | ||
| 25 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 26 | STATIC_CELL.init_with(move || $val) | ||
| 27 | }}; | ||
| 28 | } | ||
| 29 | |||
| 30 | #[embassy_executor::task] | 22 | #[embassy_executor::task] |
| 31 | async fn wifi_task( | 23 | async fn wifi_task( |
| 32 | runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, | 24 | runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, |
| @@ -60,7 +52,7 @@ async fn main(spawner: Spawner) { | |||
| 60 | let mut pio = Pio::new(p.PIO0); | 52 | let mut pio = Pio::new(p.PIO0); |
| 61 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); | 53 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); |
| 62 | 54 | ||
| 63 | let state = singleton!(cyw43::State::new()); | 55 | let state = make_static!(cyw43::State::new()); |
| 64 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 56 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 65 | unwrap!(spawner.spawn(wifi_task(runner))); | 57 | unwrap!(spawner.spawn(wifi_task(runner))); |
| 66 | 58 | ||
| @@ -70,7 +62,7 @@ async fn main(spawner: Spawner) { | |||
| 70 | .await; | 62 | .await; |
| 71 | 63 | ||
| 72 | // Use a link-local address for communication without DHCP server | 64 | // Use a link-local address for communication without DHCP server |
| 73 | let config = Config::Static(embassy_net::StaticConfig { | 65 | let config = Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 74 | address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::new(169, 254, 1, 1), 16), | 66 | address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::new(169, 254, 1, 1), 16), |
| 75 | dns_servers: heapless::Vec::new(), | 67 | dns_servers: heapless::Vec::new(), |
| 76 | gateway: None, | 68 | gateway: None, |
| @@ -80,10 +72,10 @@ async fn main(spawner: Spawner) { | |||
| 80 | let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. | 72 | let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. |
| 81 | 73 | ||
| 82 | // Init network stack | 74 | // Init network stack |
| 83 | let stack = &*singleton!(Stack::new( | 75 | let stack = &*make_static!(Stack::new( |
| 84 | net_device, | 76 | net_device, |
| 85 | config, | 77 | config, |
| 86 | singleton!(StackResources::<2>::new()), | 78 | make_static!(StackResources::<2>::new()), |
| 87 | seed | 79 | seed |
| 88 | )); | 80 | )); |
| 89 | 81 | ||
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs new file mode 100644 index 000000000..be965807b --- /dev/null +++ b/examples/rp/src/bin/wifi_blinky.rs | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use cyw43_pio::PioSpi; | ||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::gpio::{Level, Output}; | ||
| 9 | use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; | ||
| 10 | use embassy_rp::pio::Pio; | ||
| 11 | use embassy_time::{Duration, Timer}; | ||
| 12 | use static_cell::make_static; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | #[embassy_executor::task] | ||
| 16 | async fn wifi_task( | ||
| 17 | runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, | ||
| 18 | ) -> ! { | ||
| 19 | runner.run().await | ||
| 20 | } | ||
| 21 | |||
| 22 | #[embassy_executor::main] | ||
| 23 | async fn main(spawner: Spawner) { | ||
| 24 | let p = embassy_rp::init(Default::default()); | ||
| 25 | let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); | ||
| 26 | let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); | ||
| 27 | |||
| 28 | // To make flashing faster for development, you may want to flash the firmwares independently | ||
| 29 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: | ||
| 30 | // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 | ||
| 31 | // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 | ||
| 32 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; | ||
| 33 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | ||
| 34 | |||
| 35 | let pwr = Output::new(p.PIN_23, Level::Low); | ||
| 36 | let cs = Output::new(p.PIN_25, Level::High); | ||
| 37 | let mut pio = Pio::new(p.PIO0); | ||
| 38 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); | ||
| 39 | |||
| 40 | let state = make_static!(cyw43::State::new()); | ||
| 41 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | ||
| 42 | unwrap!(spawner.spawn(wifi_task(runner))); | ||
| 43 | |||
| 44 | control.init(clm).await; | ||
| 45 | control | ||
| 46 | .set_power_management(cyw43::PowerManagementMode::PowerSave) | ||
| 47 | .await; | ||
| 48 | |||
| 49 | let delay = Duration::from_secs(1); | ||
| 50 | loop { | ||
| 51 | info!("led on!"); | ||
| 52 | control.gpio_set(0, true).await; | ||
| 53 | Timer::after(delay).await; | ||
| 54 | |||
| 55 | info!("led off!"); | ||
| 56 | control.gpio_set(0, false).await; | ||
| 57 | Timer::after(delay).await; | ||
| 58 | } | ||
| 59 | } | ||
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index aa5e5a399..79534f229 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs | |||
| @@ -13,17 +13,9 @@ use embassy_net::Stack; | |||
| 13 | use embassy_rp::gpio::{Level, Output}; | 13 | use embassy_rp::gpio::{Level, Output}; |
| 14 | use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; | 14 | use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; |
| 15 | use embassy_rp::pio::Pio; | 15 | use embassy_rp::pio::Pio; |
| 16 | use static_cell::StaticCell; | 16 | use static_cell::make_static; |
| 17 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {defmt_rtt as _, panic_probe as _}; |
| 18 | 18 | ||
| 19 | macro_rules! singleton { | ||
| 20 | ($val:expr) => {{ | ||
| 21 | type T = impl Sized; | ||
| 22 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 23 | STATIC_CELL.init_with(move || $val) | ||
| 24 | }}; | ||
| 25 | } | ||
| 26 | |||
| 27 | #[embassy_executor::task] | 19 | #[embassy_executor::task] |
| 28 | async fn wifi_task( | 20 | async fn wifi_task( |
| 29 | runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, | 21 | runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, |
| @@ -57,7 +49,7 @@ async fn main(spawner: Spawner) { | |||
| 57 | let mut pio = Pio::new(p.PIO0); | 49 | let mut pio = Pio::new(p.PIO0); |
| 58 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); | 50 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); |
| 59 | 51 | ||
| 60 | let state = singleton!(cyw43::State::new()); | 52 | let state = make_static!(cyw43::State::new()); |
| 61 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 53 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 62 | unwrap!(spawner.spawn(wifi_task(runner))); | 54 | unwrap!(spawner.spawn(wifi_task(runner))); |
| 63 | 55 | ||
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index eafa25f68..026e056fa 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs | |||
| @@ -16,17 +16,9 @@ use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; | |||
| 16 | use embassy_rp::pio::Pio; | 16 | use embassy_rp::pio::Pio; |
| 17 | use embassy_time::Duration; | 17 | use embassy_time::Duration; |
| 18 | use embedded_io::asynch::Write; | 18 | use embedded_io::asynch::Write; |
| 19 | use static_cell::StaticCell; | 19 | use static_cell::make_static; |
| 20 | use {defmt_rtt as _, panic_probe as _}; | 20 | use {defmt_rtt as _, panic_probe as _}; |
| 21 | 21 | ||
| 22 | macro_rules! singleton { | ||
| 23 | ($val:expr) => {{ | ||
| 24 | type T = impl Sized; | ||
| 25 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 26 | STATIC_CELL.init_with(move || $val) | ||
| 27 | }}; | ||
| 28 | } | ||
| 29 | |||
| 30 | #[embassy_executor::task] | 22 | #[embassy_executor::task] |
| 31 | async fn wifi_task( | 23 | async fn wifi_task( |
| 32 | runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, | 24 | runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, |
| @@ -60,7 +52,7 @@ async fn main(spawner: Spawner) { | |||
| 60 | let mut pio = Pio::new(p.PIO0); | 52 | let mut pio = Pio::new(p.PIO0); |
| 61 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); | 53 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); |
| 62 | 54 | ||
| 63 | let state = singleton!(cyw43::State::new()); | 55 | let state = make_static!(cyw43::State::new()); |
| 64 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 56 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 65 | unwrap!(spawner.spawn(wifi_task(runner))); | 57 | unwrap!(spawner.spawn(wifi_task(runner))); |
| 66 | 58 | ||
| @@ -69,8 +61,8 @@ async fn main(spawner: Spawner) { | |||
| 69 | .set_power_management(cyw43::PowerManagementMode::PowerSave) | 61 | .set_power_management(cyw43::PowerManagementMode::PowerSave) |
| 70 | .await; | 62 | .await; |
| 71 | 63 | ||
| 72 | let config = Config::Dhcp(Default::default()); | 64 | let config = Config::dhcpv4(Default::default()); |
| 73 | //let config = embassy_net::Config::Static(embassy_net::Config { | 65 | //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 74 | // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), | 66 | // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), |
| 75 | // dns_servers: Vec::new(), | 67 | // dns_servers: Vec::new(), |
| 76 | // gateway: Some(Ipv4Address::new(192, 168, 69, 1)), | 68 | // gateway: Some(Ipv4Address::new(192, 168, 69, 1)), |
| @@ -80,10 +72,10 @@ async fn main(spawner: Spawner) { | |||
| 80 | let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. | 72 | let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. |
| 81 | 73 | ||
| 82 | // Init network stack | 74 | // Init network stack |
| 83 | let stack = &*singleton!(Stack::new( | 75 | let stack = &*make_static!(Stack::new( |
| 84 | net_device, | 76 | net_device, |
| 85 | config, | 77 | config, |
| 86 | singleton!(StackResources::<2>::new()), | 78 | make_static!(StackResources::<2>::new()), |
| 87 | seed | 79 | seed |
| 88 | )); | 80 | )); |
| 89 | 81 | ||
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 36770ca9c..878ad8c5a 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml | |||
| @@ -22,4 +22,4 @@ libc = "0.2.101" | |||
| 22 | clap = { version = "3.0.0-beta.5", features = ["derive"] } | 22 | clap = { version = "3.0.0-beta.5", features = ["derive"] } |
| 23 | rand_core = { version = "0.6.3", features = ["std"] } | 23 | rand_core = { version = "0.6.3", features = ["std"] } |
| 24 | heapless = { version = "0.7.5", default-features = false } | 24 | heapless = { version = "0.7.5", default-features = false } |
| 25 | static_cell = "1.0" | 25 | static_cell = { version = "1.1", features = ["nightly"]} |
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index d93616254..3aadb029d 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs | |||
| @@ -11,21 +11,12 @@ use embedded_io::asynch::Write; | |||
| 11 | use heapless::Vec; | 11 | use heapless::Vec; |
| 12 | use log::*; | 12 | use log::*; |
| 13 | use rand_core::{OsRng, RngCore}; | 13 | use rand_core::{OsRng, RngCore}; |
| 14 | use static_cell::StaticCell; | 14 | use static_cell::{make_static, StaticCell}; |
| 15 | 15 | ||
| 16 | #[path = "../tuntap.rs"] | 16 | #[path = "../tuntap.rs"] |
| 17 | mod tuntap; | 17 | mod tuntap; |
| 18 | 18 | ||
| 19 | use crate::tuntap::TunTapDevice; | 19 | use crate::tuntap::TunTapDevice; |
| 20 | |||
| 21 | macro_rules! singleton { | ||
| 22 | ($val:expr) => {{ | ||
| 23 | type T = impl Sized; | ||
| 24 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 25 | STATIC_CELL.init_with(move || $val) | ||
| 26 | }}; | ||
| 27 | } | ||
| 28 | |||
| 29 | #[derive(Parser)] | 20 | #[derive(Parser)] |
| 30 | #[clap(version = "1.0")] | 21 | #[clap(version = "1.0")] |
| 31 | struct Opts { | 22 | struct Opts { |
| @@ -51,13 +42,13 @@ async fn main_task(spawner: Spawner) { | |||
| 51 | 42 | ||
| 52 | // Choose between dhcp or static ip | 43 | // Choose between dhcp or static ip |
| 53 | let config = if opts.static_ip { | 44 | let config = if opts.static_ip { |
| 54 | Config::Static(embassy_net::StaticConfig { | 45 | Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 55 | address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), | 46 | address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), |
| 56 | dns_servers: Vec::new(), | 47 | dns_servers: Vec::new(), |
| 57 | gateway: Some(Ipv4Address::new(192, 168, 69, 1)), | 48 | gateway: Some(Ipv4Address::new(192, 168, 69, 1)), |
| 58 | }) | 49 | }) |
| 59 | } else { | 50 | } else { |
| 60 | Config::Dhcp(Default::default()) | 51 | Config::dhcpv4(Default::default()) |
| 61 | }; | 52 | }; |
| 62 | 53 | ||
| 63 | // Generate random seed | 54 | // Generate random seed |
| @@ -66,7 +57,12 @@ async fn main_task(spawner: Spawner) { | |||
| 66 | let seed = u64::from_le_bytes(seed); | 57 | let seed = u64::from_le_bytes(seed); |
| 67 | 58 | ||
| 68 | // Init network stack | 59 | // Init network stack |
| 69 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed)); | 60 | let stack = &*make_static!(Stack::new( |
| 61 | device, | ||
| 62 | config, | ||
| 63 | make_static!(StackResources::<3>::new()), | ||
| 64 | seed | ||
| 65 | )); | ||
| 70 | 66 | ||
| 71 | // Launch network task | 67 | // Launch network task |
| 72 | spawner.spawn(net_task(stack)).unwrap(); | 68 | spawner.spawn(net_task(stack)).unwrap(); |
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs index d1e1f8212..65b5a2cd9 100644 --- a/examples/std/src/bin/net_dns.rs +++ b/examples/std/src/bin/net_dns.rs | |||
| @@ -9,21 +9,12 @@ use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | |||
| 9 | use heapless::Vec; | 9 | use heapless::Vec; |
| 10 | use log::*; | 10 | use log::*; |
| 11 | use rand_core::{OsRng, RngCore}; | 11 | use rand_core::{OsRng, RngCore}; |
| 12 | use static_cell::StaticCell; | 12 | use static_cell::{make_static, StaticCell}; |
| 13 | 13 | ||
| 14 | #[path = "../tuntap.rs"] | 14 | #[path = "../tuntap.rs"] |
| 15 | mod tuntap; | 15 | mod tuntap; |
| 16 | 16 | ||
| 17 | use crate::tuntap::TunTapDevice; | 17 | use crate::tuntap::TunTapDevice; |
| 18 | |||
| 19 | macro_rules! singleton { | ||
| 20 | ($val:expr) => {{ | ||
| 21 | type T = impl Sized; | ||
| 22 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 23 | STATIC_CELL.init_with(move || $val) | ||
| 24 | }}; | ||
| 25 | } | ||
| 26 | |||
| 27 | #[derive(Parser)] | 18 | #[derive(Parser)] |
| 28 | #[clap(version = "1.0")] | 19 | #[clap(version = "1.0")] |
| 29 | struct Opts { | 20 | struct Opts { |
| @@ -49,14 +40,14 @@ async fn main_task(spawner: Spawner) { | |||
| 49 | 40 | ||
| 50 | // Choose between dhcp or static ip | 41 | // Choose between dhcp or static ip |
| 51 | let config = if opts.static_ip { | 42 | let config = if opts.static_ip { |
| 52 | Config::Static(embassy_net::StaticConfig { | 43 | Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 53 | address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24), | 44 | address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24), |
| 54 | dns_servers: Vec::from_slice(&[Ipv4Address::new(8, 8, 4, 4).into(), Ipv4Address::new(8, 8, 8, 8).into()]) | 45 | dns_servers: Vec::from_slice(&[Ipv4Address::new(8, 8, 4, 4).into(), Ipv4Address::new(8, 8, 8, 8).into()]) |
| 55 | .unwrap(), | 46 | .unwrap(), |
| 56 | gateway: Some(Ipv4Address::new(192, 168, 69, 100)), | 47 | gateway: Some(Ipv4Address::new(192, 168, 69, 100)), |
| 57 | }) | 48 | }) |
| 58 | } else { | 49 | } else { |
| 59 | Config::Dhcp(Default::default()) | 50 | Config::dhcpv4(Default::default()) |
| 60 | }; | 51 | }; |
| 61 | 52 | ||
| 62 | // Generate random seed | 53 | // Generate random seed |
| @@ -65,7 +56,12 @@ async fn main_task(spawner: Spawner) { | |||
| 65 | let seed = u64::from_le_bytes(seed); | 56 | let seed = u64::from_le_bytes(seed); |
| 66 | 57 | ||
| 67 | // Init network stack | 58 | // Init network stack |
| 68 | let stack: &Stack<_> = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed)); | 59 | let stack: &Stack<_> = &*make_static!(Stack::new( |
| 60 | device, | ||
| 61 | config, | ||
| 62 | make_static!(StackResources::<3>::new()), | ||
| 63 | seed | ||
| 64 | )); | ||
| 69 | 65 | ||
| 70 | // Launch network task | 66 | // Launch network task |
| 71 | spawner.spawn(net_task(stack)).unwrap(); | 67 | spawner.spawn(net_task(stack)).unwrap(); |
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs index 4df23edf6..3fc46156c 100644 --- a/examples/std/src/bin/net_udp.rs +++ b/examples/std/src/bin/net_udp.rs | |||
| @@ -7,21 +7,12 @@ use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; | |||
| 7 | use heapless::Vec; | 7 | use heapless::Vec; |
| 8 | use log::*; | 8 | use log::*; |
| 9 | use rand_core::{OsRng, RngCore}; | 9 | use rand_core::{OsRng, RngCore}; |
| 10 | use static_cell::StaticCell; | 10 | use static_cell::{make_static, StaticCell}; |
| 11 | 11 | ||
| 12 | #[path = "../tuntap.rs"] | 12 | #[path = "../tuntap.rs"] |
| 13 | mod tuntap; | 13 | mod tuntap; |
| 14 | 14 | ||
| 15 | use crate::tuntap::TunTapDevice; | 15 | use crate::tuntap::TunTapDevice; |
| 16 | |||
| 17 | macro_rules! singleton { | ||
| 18 | ($val:expr) => {{ | ||
| 19 | type T = impl Sized; | ||
| 20 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 21 | STATIC_CELL.init_with(move || $val) | ||
| 22 | }}; | ||
| 23 | } | ||
| 24 | |||
| 25 | #[derive(Parser)] | 16 | #[derive(Parser)] |
| 26 | #[clap(version = "1.0")] | 17 | #[clap(version = "1.0")] |
| 27 | struct Opts { | 18 | struct Opts { |
| @@ -47,13 +38,13 @@ async fn main_task(spawner: Spawner) { | |||
| 47 | 38 | ||
| 48 | // Choose between dhcp or static ip | 39 | // Choose between dhcp or static ip |
| 49 | let config = if opts.static_ip { | 40 | let config = if opts.static_ip { |
| 50 | Config::Static(embassy_net::StaticConfig { | 41 | Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 51 | address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), | 42 | address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), |
| 52 | dns_servers: Vec::new(), | 43 | dns_servers: Vec::new(), |
| 53 | gateway: Some(Ipv4Address::new(192, 168, 69, 1)), | 44 | gateway: Some(Ipv4Address::new(192, 168, 69, 1)), |
| 54 | }) | 45 | }) |
| 55 | } else { | 46 | } else { |
| 56 | Config::Dhcp(Default::default()) | 47 | Config::dhcpv4(Default::default()) |
| 57 | }; | 48 | }; |
| 58 | 49 | ||
| 59 | // Generate random seed | 50 | // Generate random seed |
| @@ -62,7 +53,12 @@ async fn main_task(spawner: Spawner) { | |||
| 62 | let seed = u64::from_le_bytes(seed); | 53 | let seed = u64::from_le_bytes(seed); |
| 63 | 54 | ||
| 64 | // Init network stack | 55 | // Init network stack |
| 65 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed)); | 56 | let stack = &*make_static!(Stack::new( |
| 57 | device, | ||
| 58 | config, | ||
| 59 | make_static!(StackResources::<3>::new()), | ||
| 60 | seed | ||
| 61 | )); | ||
| 66 | 62 | ||
| 67 | // Launch network task | 63 | // Launch network task |
| 68 | spawner.spawn(net_task(stack)).unwrap(); | 64 | spawner.spawn(net_task(stack)).unwrap(); |
diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs index 97ce77f42..df09986ac 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs | |||
| @@ -12,21 +12,12 @@ use embedded_io::asynch::Write as _; | |||
| 12 | use heapless::Vec; | 12 | use heapless::Vec; |
| 13 | use log::*; | 13 | use log::*; |
| 14 | use rand_core::{OsRng, RngCore}; | 14 | use rand_core::{OsRng, RngCore}; |
| 15 | use static_cell::StaticCell; | 15 | use static_cell::{make_static, StaticCell}; |
| 16 | 16 | ||
| 17 | #[path = "../tuntap.rs"] | 17 | #[path = "../tuntap.rs"] |
| 18 | mod tuntap; | 18 | mod tuntap; |
| 19 | 19 | ||
| 20 | use crate::tuntap::TunTapDevice; | 20 | use crate::tuntap::TunTapDevice; |
| 21 | |||
| 22 | macro_rules! singleton { | ||
| 23 | ($val:expr) => {{ | ||
| 24 | type T = impl Sized; | ||
| 25 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 26 | STATIC_CELL.init_with(move || $val) | ||
| 27 | }}; | ||
| 28 | } | ||
| 29 | |||
| 30 | #[derive(Parser)] | 21 | #[derive(Parser)] |
| 31 | #[clap(version = "1.0")] | 22 | #[clap(version = "1.0")] |
| 32 | struct Opts { | 23 | struct Opts { |
| @@ -62,13 +53,13 @@ async fn main_task(spawner: Spawner) { | |||
| 62 | 53 | ||
| 63 | // Choose between dhcp or static ip | 54 | // Choose between dhcp or static ip |
| 64 | let config = if opts.static_ip { | 55 | let config = if opts.static_ip { |
| 65 | Config::Static(embassy_net::StaticConfig { | 56 | Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 66 | address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), | 57 | address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), |
| 67 | dns_servers: Vec::new(), | 58 | dns_servers: Vec::new(), |
| 68 | gateway: Some(Ipv4Address::new(192, 168, 69, 1)), | 59 | gateway: Some(Ipv4Address::new(192, 168, 69, 1)), |
| 69 | }) | 60 | }) |
| 70 | } else { | 61 | } else { |
| 71 | Config::Dhcp(Default::default()) | 62 | Config::dhcpv4(Default::default()) |
| 72 | }; | 63 | }; |
| 73 | 64 | ||
| 74 | // Generate random seed | 65 | // Generate random seed |
| @@ -77,7 +68,12 @@ async fn main_task(spawner: Spawner) { | |||
| 77 | let seed = u64::from_le_bytes(seed); | 68 | let seed = u64::from_le_bytes(seed); |
| 78 | 69 | ||
| 79 | // Init network stack | 70 | // Init network stack |
| 80 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed)); | 71 | let stack = &*make_static!(Stack::new( |
| 72 | device, | ||
| 73 | config, | ||
| 74 | make_static!(StackResources::<3>::new()), | ||
| 75 | seed | ||
| 76 | )); | ||
| 81 | 77 | ||
| 82 | // Launch network task | 78 | // Launch network task |
| 83 | spawner.spawn(net_task(stack)).unwrap(); | 79 | spawner.spawn(net_task(stack)).unwrap(); |
| @@ -112,7 +108,7 @@ async fn main_task(spawner: Spawner) { | |||
| 112 | info!("Closing the connection"); | 108 | info!("Closing the connection"); |
| 113 | socket.abort(); | 109 | socket.abort(); |
| 114 | info!("Flushing the RST out..."); | 110 | info!("Flushing the RST out..."); |
| 115 | socket.flush().await; | 111 | _ = socket.flush().await; |
| 116 | info!("Finished with the socket"); | 112 | info!("Finished with the socket"); |
| 117 | } | 113 | } |
| 118 | } | 114 | } |
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index ad11fbd1c..43f432520 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } |
| 12 | 12 | ||
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 9c59c45c6..8d2248ed0 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml | |||
| @@ -13,7 +13,7 @@ defmt = "0.3" | |||
| 13 | defmt-rtt = "0.4" | 13 | defmt-rtt = "0.4" |
| 14 | panic-probe = "0.3" | 14 | panic-probe = "0.3" |
| 15 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 15 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 16 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 16 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 17 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 17 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 18 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } | 18 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } |
| 19 | static_cell = "1.0" | 19 | static_cell = { version = "1.1", features = ["nightly"]} |
diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs index 430a805fc..988ffeef1 100644 --- a/examples/stm32f0/src/bin/multiprio.rs +++ b/examples/stm32f0/src/bin/multiprio.rs | |||
| @@ -57,14 +57,11 @@ | |||
| 57 | #![no_main] | 57 | #![no_main] |
| 58 | #![feature(type_alias_impl_trait)] | 58 | #![feature(type_alias_impl_trait)] |
| 59 | 59 | ||
| 60 | use core::mem; | ||
| 61 | |||
| 62 | use cortex_m::peripheral::NVIC; | ||
| 63 | use cortex_m_rt::entry; | 60 | use cortex_m_rt::entry; |
| 64 | use defmt::*; | 61 | use defmt::*; |
| 65 | use embassy_executor::{Executor, InterruptExecutor}; | 62 | use embassy_executor::{Executor, InterruptExecutor}; |
| 66 | use embassy_stm32::interrupt; | 63 | use embassy_stm32::interrupt; |
| 67 | use embassy_stm32::pac::Interrupt; | 64 | use embassy_stm32::interrupt::{InterruptExt, Priority}; |
| 68 | use embassy_time::{Duration, Instant, Timer}; | 65 | use embassy_time::{Duration, Instant, Timer}; |
| 69 | use static_cell::StaticCell; | 66 | use static_cell::StaticCell; |
| 70 | use {defmt_rtt as _, panic_probe as _}; | 67 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -129,16 +126,15 @@ unsafe fn USART2() { | |||
| 129 | fn main() -> ! { | 126 | fn main() -> ! { |
| 130 | // Initialize and create handle for devicer peripherals | 127 | // Initialize and create handle for devicer peripherals |
| 131 | let _p = embassy_stm32::init(Default::default()); | 128 | let _p = embassy_stm32::init(Default::default()); |
| 132 | let mut nvic: NVIC = unsafe { mem::transmute(()) }; | ||
| 133 | 129 | ||
| 134 | // High-priority executor: USART1, priority level 6 | 130 | // High-priority executor: USART1, priority level 6 |
| 135 | unsafe { nvic.set_priority(Interrupt::USART1, 6 << 4) }; | 131 | interrupt::USART1.set_priority(Priority::P6); |
| 136 | let spawner = EXECUTOR_HIGH.start(Interrupt::USART1); | 132 | let spawner = EXECUTOR_HIGH.start(interrupt::USART1); |
| 137 | unwrap!(spawner.spawn(run_high())); | 133 | unwrap!(spawner.spawn(run_high())); |
| 138 | 134 | ||
| 139 | // Medium-priority executor: USART2, priority level 7 | 135 | // Medium-priority executor: USART2, priority level 7 |
| 140 | unsafe { nvic.set_priority(Interrupt::USART2, 7 << 4) }; | 136 | interrupt::USART2.set_priority(Priority::P7); |
| 141 | let spawner = EXECUTOR_MED.start(Interrupt::USART2); | 137 | let spawner = EXECUTOR_MED.start(interrupt::USART2); |
| 142 | unwrap!(spawner.spawn(run_med())); | 138 | unwrap!(spawner.spawn(run_med())); |
| 143 | 139 | ||
| 144 | // Low priority executor: runs in thread mode, using WFE/SEV | 140 | // Low priority executor: runs in thread mode, using WFE/SEV |
diff --git a/examples/stm32f0/src/bin/wdg.rs b/examples/stm32f0/src/bin/wdg.rs index 80e76f901..a44b17528 100644 --- a/examples/stm32f0/src/bin/wdg.rs +++ b/examples/stm32f0/src/bin/wdg.rs | |||
| @@ -16,10 +16,10 @@ async fn main(_spawner: Spawner) { | |||
| 16 | let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00); | 16 | let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00); |
| 17 | 17 | ||
| 18 | info!("Watchdog start"); | 18 | info!("Watchdog start"); |
| 19 | unsafe { wdg.unleash() }; | 19 | wdg.unleash(); |
| 20 | 20 | ||
| 21 | loop { | 21 | loop { |
| 22 | Timer::after(Duration::from_secs(1)).await; | 22 | Timer::after(Duration::from_secs(1)).await; |
| 23 | unsafe { wdg.pet() }; | 23 | wdg.pet(); |
| 24 | } | 24 | } |
| 25 | } | 25 | } |
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 345e948a6..d34fd439a 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] } |
| 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index e4f97a589..5e3e0d0f7 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 12 | 12 | ||
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 3d314e6c5..29ab2009c 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| @@ -23,4 +23,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa | |||
| 23 | heapless = { version = "0.7.5", default-features = false } | 23 | heapless = { version = "0.7.5", default-features = false } |
| 24 | nb = "1.0.0" | 24 | nb = "1.0.0" |
| 25 | embedded-storage = "0.3.0" | 25 | embedded-storage = "0.3.0" |
| 26 | static_cell = "1.0" | 26 | static_cell = { version = "1.1", features = ["nightly"]} |
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs index 5d010f799..80bf59deb 100644 --- a/examples/stm32f3/src/bin/multiprio.rs +++ b/examples/stm32f3/src/bin/multiprio.rs | |||
| @@ -57,14 +57,11 @@ | |||
| 57 | #![no_main] | 57 | #![no_main] |
| 58 | #![feature(type_alias_impl_trait)] | 58 | #![feature(type_alias_impl_trait)] |
| 59 | 59 | ||
| 60 | use core::mem; | ||
| 61 | |||
| 62 | use cortex_m::peripheral::NVIC; | ||
| 63 | use cortex_m_rt::entry; | 60 | use cortex_m_rt::entry; |
| 64 | use defmt::*; | 61 | use defmt::*; |
| 65 | use embassy_executor::{Executor, InterruptExecutor}; | 62 | use embassy_executor::{Executor, InterruptExecutor}; |
| 66 | use embassy_stm32::interrupt; | 63 | use embassy_stm32::interrupt; |
| 67 | use embassy_stm32::pac::Interrupt; | 64 | use embassy_stm32::interrupt::{InterruptExt, Priority}; |
| 68 | use embassy_time::{Duration, Instant, Timer}; | 65 | use embassy_time::{Duration, Instant, Timer}; |
| 69 | use static_cell::StaticCell; | 66 | use static_cell::StaticCell; |
| 70 | use {defmt_rtt as _, panic_probe as _}; | 67 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -130,16 +127,15 @@ fn main() -> ! { | |||
| 130 | info!("Hello World!"); | 127 | info!("Hello World!"); |
| 131 | 128 | ||
| 132 | let _p = embassy_stm32::init(Default::default()); | 129 | let _p = embassy_stm32::init(Default::default()); |
| 133 | let mut nvic: NVIC = unsafe { mem::transmute(()) }; | ||
| 134 | 130 | ||
| 135 | // High-priority executor: UART4, priority level 6 | 131 | // High-priority executor: UART4, priority level 6 |
| 136 | unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) }; | 132 | interrupt::UART4.set_priority(Priority::P6); |
| 137 | let spawner = EXECUTOR_HIGH.start(Interrupt::UART4); | 133 | let spawner = EXECUTOR_HIGH.start(interrupt::UART4); |
| 138 | unwrap!(spawner.spawn(run_high())); | 134 | unwrap!(spawner.spawn(run_high())); |
| 139 | 135 | ||
| 140 | // Medium-priority executor: UART5, priority level 7 | 136 | // Medium-priority executor: UART5, priority level 7 |
| 141 | unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) }; | 137 | interrupt::UART5.set_priority(Priority::P7); |
| 142 | let spawner = EXECUTOR_MED.start(Interrupt::UART5); | 138 | let spawner = EXECUTOR_MED.start(interrupt::UART5); |
| 143 | unwrap!(spawner.spawn(run_med())); | 139 | unwrap!(spawner.spawn(run_med())); |
| 144 | 140 | ||
| 145 | // Low priority executor: runs in thread mode, using WFE/SEV | 141 | // Low priority executor: runs in thread mode, using WFE/SEV |
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index f5f8b632d..7ecb64fce 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers", "arch-cortex-m", "executor-thread", "executor-interrupt"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers", "arch-cortex-m", "executor-thread", "executor-interrupt"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] } |
| 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| @@ -25,7 +25,7 @@ heapless = { version = "0.7.5", default-features = false } | |||
| 25 | nb = "1.0.0" | 25 | nb = "1.0.0" |
| 26 | embedded-storage = "0.3.0" | 26 | embedded-storage = "0.3.0" |
| 27 | micromath = "2.0.0" | 27 | micromath = "2.0.0" |
| 28 | static_cell = "1.0" | 28 | static_cell = { version = "1.1", features = ["nightly"]} |
| 29 | chrono = { version = "^0.4", default-features = false} | 29 | chrono = { version = "^0.4", default-features = false} |
| 30 | 30 | ||
| 31 | [profile.release] | 31 | [profile.release] |
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs index 5d010f799..80bf59deb 100644 --- a/examples/stm32f4/src/bin/multiprio.rs +++ b/examples/stm32f4/src/bin/multiprio.rs | |||
| @@ -57,14 +57,11 @@ | |||
| 57 | #![no_main] | 57 | #![no_main] |
| 58 | #![feature(type_alias_impl_trait)] | 58 | #![feature(type_alias_impl_trait)] |
| 59 | 59 | ||
| 60 | use core::mem; | ||
| 61 | |||
| 62 | use cortex_m::peripheral::NVIC; | ||
| 63 | use cortex_m_rt::entry; | 60 | use cortex_m_rt::entry; |
| 64 | use defmt::*; | 61 | use defmt::*; |
| 65 | use embassy_executor::{Executor, InterruptExecutor}; | 62 | use embassy_executor::{Executor, InterruptExecutor}; |
| 66 | use embassy_stm32::interrupt; | 63 | use embassy_stm32::interrupt; |
| 67 | use embassy_stm32::pac::Interrupt; | 64 | use embassy_stm32::interrupt::{InterruptExt, Priority}; |
| 68 | use embassy_time::{Duration, Instant, Timer}; | 65 | use embassy_time::{Duration, Instant, Timer}; |
| 69 | use static_cell::StaticCell; | 66 | use static_cell::StaticCell; |
| 70 | use {defmt_rtt as _, panic_probe as _}; | 67 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -130,16 +127,15 @@ fn main() -> ! { | |||
| 130 | info!("Hello World!"); | 127 | info!("Hello World!"); |
| 131 | 128 | ||
| 132 | let _p = embassy_stm32::init(Default::default()); | 129 | let _p = embassy_stm32::init(Default::default()); |
| 133 | let mut nvic: NVIC = unsafe { mem::transmute(()) }; | ||
| 134 | 130 | ||
| 135 | // High-priority executor: UART4, priority level 6 | 131 | // High-priority executor: UART4, priority level 6 |
| 136 | unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) }; | 132 | interrupt::UART4.set_priority(Priority::P6); |
| 137 | let spawner = EXECUTOR_HIGH.start(Interrupt::UART4); | 133 | let spawner = EXECUTOR_HIGH.start(interrupt::UART4); |
| 138 | unwrap!(spawner.spawn(run_high())); | 134 | unwrap!(spawner.spawn(run_high())); |
| 139 | 135 | ||
| 140 | // Medium-priority executor: UART5, priority level 7 | 136 | // Medium-priority executor: UART5, priority level 7 |
| 141 | unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) }; | 137 | interrupt::UART5.set_priority(Priority::P7); |
| 142 | let spawner = EXECUTOR_MED.start(Interrupt::UART5); | 138 | let spawner = EXECUTOR_MED.start(interrupt::UART5); |
| 143 | unwrap!(spawner.spawn(run_med())); | 139 | unwrap!(spawner.spawn(run_med())); |
| 144 | 140 | ||
| 145 | // Low priority executor: runs in thread mode, using WFE/SEV | 141 | // Low priority executor: runs in thread mode, using WFE/SEV |
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index c4e395f0f..953d99a45 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs | |||
| @@ -14,20 +14,11 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState | |||
| 14 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | 14 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; |
| 15 | use embassy_usb::{Builder, UsbDevice}; | 15 | use embassy_usb::{Builder, UsbDevice}; |
| 16 | use embedded_io::asynch::Write; | 16 | use embedded_io::asynch::Write; |
| 17 | use static_cell::StaticCell; | 17 | use static_cell::make_static; |
| 18 | use {defmt_rtt as _, panic_probe as _}; | 18 | use {defmt_rtt as _, panic_probe as _}; |
| 19 | 19 | ||
| 20 | type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>; | 20 | type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>; |
| 21 | 21 | ||
| 22 | macro_rules! singleton { | ||
| 23 | ($val:expr) => {{ | ||
| 24 | type T = impl Sized; | ||
| 25 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 26 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 27 | x | ||
| 28 | }}; | ||
| 29 | } | ||
| 30 | |||
| 31 | const MTU: usize = 1514; | 22 | const MTU: usize = 1514; |
| 32 | 23 | ||
| 33 | #[embassy_executor::task] | 24 | #[embassy_executor::task] |
| @@ -60,7 +51,7 @@ async fn main(spawner: Spawner) { | |||
| 60 | let p = embassy_stm32::init(config); | 51 | let p = embassy_stm32::init(config); |
| 61 | 52 | ||
| 62 | // Create the driver, from the HAL. | 53 | // Create the driver, from the HAL. |
| 63 | let ep_out_buffer = &mut singleton!([0; 256])[..]; | 54 | let ep_out_buffer = &mut make_static!([0; 256])[..]; |
| 64 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer); | 55 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer); |
| 65 | 56 | ||
| 66 | // Create embassy-usb Config | 57 | // Create embassy-usb Config |
| @@ -81,10 +72,10 @@ async fn main(spawner: Spawner) { | |||
| 81 | let mut builder = Builder::new( | 72 | let mut builder = Builder::new( |
| 82 | driver, | 73 | driver, |
| 83 | config, | 74 | config, |
| 84 | &mut singleton!([0; 256])[..], | 75 | &mut make_static!([0; 256])[..], |
| 85 | &mut singleton!([0; 256])[..], | 76 | &mut make_static!([0; 256])[..], |
| 86 | &mut singleton!([0; 256])[..], | 77 | &mut make_static!([0; 256])[..], |
| 87 | &mut singleton!([0; 128])[..], | 78 | &mut make_static!([0; 128])[..], |
| 88 | ); | 79 | ); |
| 89 | 80 | ||
| 90 | // Our MAC addr. | 81 | // Our MAC addr. |
| @@ -93,18 +84,18 @@ async fn main(spawner: Spawner) { | |||
| 93 | let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; | 84 | let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; |
| 94 | 85 | ||
| 95 | // Create classes on the builder. | 86 | // Create classes on the builder. |
| 96 | let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); | 87 | let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); |
| 97 | 88 | ||
| 98 | // Build the builder. | 89 | // Build the builder. |
| 99 | let usb = builder.build(); | 90 | let usb = builder.build(); |
| 100 | 91 | ||
| 101 | unwrap!(spawner.spawn(usb_task(usb))); | 92 | unwrap!(spawner.spawn(usb_task(usb))); |
| 102 | 93 | ||
| 103 | let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); | 94 | let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); |
| 104 | unwrap!(spawner.spawn(usb_ncm_task(runner))); | 95 | unwrap!(spawner.spawn(usb_ncm_task(runner))); |
| 105 | 96 | ||
| 106 | let config = embassy_net::Config::Dhcp(Default::default()); | 97 | let config = embassy_net::Config::dhcpv4(Default::default()); |
| 107 | //let config = embassy_net::Config::Static(embassy_net::StaticConfig { | 98 | //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 108 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | 99 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), |
| 109 | // dns_servers: Vec::new(), | 100 | // dns_servers: Vec::new(), |
| 110 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | 101 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), |
| @@ -117,7 +108,12 @@ async fn main(spawner: Spawner) { | |||
| 117 | let seed = u64::from_le_bytes(seed); | 108 | let seed = u64::from_le_bytes(seed); |
| 118 | 109 | ||
| 119 | // Init network stack | 110 | // Init network stack |
| 120 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); | 111 | let stack = &*make_static!(Stack::new( |
| 112 | device, | ||
| 113 | config, | ||
| 114 | make_static!(StackResources::<2>::new()), | ||
| 115 | seed | ||
| 116 | )); | ||
| 121 | 117 | ||
| 122 | unwrap!(spawner.spawn(net_task(stack))); | 118 | unwrap!(spawner.spawn(net_task(stack))); |
| 123 | 119 | ||
diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs index b2c587fa1..e5d122af7 100644 --- a/examples/stm32f4/src/bin/wdt.rs +++ b/examples/stm32f4/src/bin/wdt.rs | |||
| @@ -17,9 +17,7 @@ async fn main(_spawner: Spawner) { | |||
| 17 | let mut led = Output::new(p.PB7, Level::High, Speed::Low); | 17 | let mut led = Output::new(p.PB7, Level::High, Speed::Low); |
| 18 | 18 | ||
| 19 | let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); | 19 | let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); |
| 20 | unsafe { | 20 | wdt.unleash(); |
| 21 | wdt.unleash(); | ||
| 22 | } | ||
| 23 | 21 | ||
| 24 | let mut i = 0; | 22 | let mut i = 0; |
| 25 | 23 | ||
| @@ -36,9 +34,7 @@ async fn main(_spawner: Spawner) { | |||
| 36 | // MCU should restart in 1 second after the last pet. | 34 | // MCU should restart in 1 second after the last pet. |
| 37 | if i < 5 { | 35 | if i < 5 { |
| 38 | info!("Petting watchdog"); | 36 | info!("Petting watchdog"); |
| 39 | unsafe { | 37 | wdt.pet(); |
| 40 | wdt.pet(); | ||
| 41 | } | ||
| 42 | } | 38 | } |
| 43 | 39 | ||
| 44 | i += 1; | 40 | i += 1; |
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 6ddb7186e..657251c50 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } |
| 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } | 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } |
| @@ -26,4 +26,4 @@ nb = "1.0.0" | |||
| 26 | rand_core = "0.6.3" | 26 | rand_core = "0.6.3" |
| 27 | critical-section = "1.1" | 27 | critical-section = "1.1" |
| 28 | embedded-storage = "0.3.0" | 28 | embedded-storage = "0.3.0" |
| 29 | static_cell = "1.0" | 29 | static_cell = { version = "1.1", features = ["nightly"]} |
diff --git a/examples/stm32f7/build.rs b/examples/stm32f7/build.rs index c4e15f19c..2b5d412a9 100644 --- a/examples/stm32f7/build.rs +++ b/examples/stm32f7/build.rs | |||
| @@ -1,9 +1,8 @@ | |||
| 1 | //! adapted from https://github.com/stm32-rs/stm32f7xx-hal/blob/master/build.rs | 1 | //! adapted from https://github.com/stm32-rs/stm32f7xx-hal/blob/master/build.rs |
| 2 | use std::env; | ||
| 3 | use std::fs::File; | 2 | use std::fs::File; |
| 4 | use std::io::prelude::*; | 3 | use std::io::prelude::*; |
| 5 | use std::io::{self}; | ||
| 6 | use std::path::PathBuf; | 4 | use std::path::PathBuf; |
| 5 | use std::{env, io}; | ||
| 7 | 6 | ||
| 8 | #[derive(Debug)] | 7 | #[derive(Debug)] |
| 9 | enum Error { | 8 | enum Error { |
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 6d286c368..fde6a7576 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs | |||
| @@ -15,18 +15,8 @@ use embassy_stm32::{bind_interrupts, eth, Config}; | |||
| 15 | use embassy_time::{Duration, Timer}; | 15 | use embassy_time::{Duration, Timer}; |
| 16 | use embedded_io::asynch::Write; | 16 | use embedded_io::asynch::Write; |
| 17 | use rand_core::RngCore; | 17 | use rand_core::RngCore; |
| 18 | use static_cell::StaticCell; | 18 | use static_cell::make_static; |
| 19 | use {defmt_rtt as _, panic_probe as _}; | 19 | use {defmt_rtt as _, panic_probe as _}; |
| 20 | |||
| 21 | macro_rules! singleton { | ||
| 22 | ($val:expr) => {{ | ||
| 23 | type T = impl Sized; | ||
| 24 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 25 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 26 | x | ||
| 27 | }}; | ||
| 28 | } | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | 20 | bind_interrupts!(struct Irqs { |
| 31 | ETH => eth::InterruptHandler; | 21 | ETH => eth::InterruptHandler; |
| 32 | }); | 22 | }); |
| @@ -55,7 +45,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 55 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 45 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 56 | 46 | ||
| 57 | let device = Ethernet::new( | 47 | let device = Ethernet::new( |
| 58 | singleton!(PacketQueue::<16, 16>::new()), | 48 | make_static!(PacketQueue::<16, 16>::new()), |
| 59 | p.ETH, | 49 | p.ETH, |
| 60 | Irqs, | 50 | Irqs, |
| 61 | p.PA1, | 51 | p.PA1, |
| @@ -72,15 +62,20 @@ async fn main(spawner: Spawner) -> ! { | |||
| 72 | 0, | 62 | 0, |
| 73 | ); | 63 | ); |
| 74 | 64 | ||
| 75 | let config = embassy_net::Config::Dhcp(Default::default()); | 65 | let config = embassy_net::Config::dhcpv4(Default::default()); |
| 76 | //let config = embassy_net::Config::Static(embassy_net::StaticConfig { | 66 | //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 77 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | 67 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), |
| 78 | // dns_servers: Vec::new(), | 68 | // dns_servers: Vec::new(), |
| 79 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | 69 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), |
| 80 | //}); | 70 | //}); |
| 81 | 71 | ||
| 82 | // Init network stack | 72 | // Init network stack |
| 83 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); | 73 | let stack = &*make_static!(Stack::new( |
| 74 | device, | ||
| 75 | config, | ||
| 76 | make_static!(StackResources::<2>::new()), | ||
| 77 | seed | ||
| 78 | )); | ||
| 84 | 79 | ||
| 85 | // Launch network task | 80 | // Launch network task |
| 86 | unwrap!(spawner.spawn(net_task(&stack))); | 81 | unwrap!(spawner.spawn(net_task(&stack))); |
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 4d7fc4548..c5245757b 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } |
| 12 | 12 | ||
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 00e2dae4c..fbfbc6408 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml | |||
| @@ -6,10 +6,11 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } |
| 12 | embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } | 12 | embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } |
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | ||
| 13 | 14 | ||
| 14 | defmt = "0.3" | 15 | defmt = "0.3" |
| 15 | defmt-rtt = "0.4" | 16 | defmt-rtt = "0.4" |
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs new file mode 100644 index 000000000..ef7d4800c --- /dev/null +++ b/examples/stm32g4/src/bin/pll.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllR, PllSrc}; | ||
| 8 | use embassy_stm32::Config; | ||
| 9 | use embassy_time::{Duration, Timer}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let mut config = Config::default(); | ||
| 15 | |||
| 16 | config.rcc.pll = Some(Pll { | ||
| 17 | source: PllSrc::HSI16, | ||
| 18 | prediv_m: PllM::Div4, | ||
| 19 | mul_n: PllN::Mul85, | ||
| 20 | div_p: None, | ||
| 21 | div_q: None, | ||
| 22 | // Main system clock at 170 MHz | ||
| 23 | div_r: Some(PllR::Div2), | ||
| 24 | }); | ||
| 25 | |||
| 26 | config.rcc.mux = ClockSrc::PLL; | ||
| 27 | |||
| 28 | let _p = embassy_stm32::init(config); | ||
| 29 | info!("Hello World!"); | ||
| 30 | |||
| 31 | loop { | ||
| 32 | Timer::after(Duration::from_millis(1000)).await; | ||
| 33 | info!("1s elapsed"); | ||
| 34 | } | ||
| 35 | } | ||
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs new file mode 100644 index 000000000..c111a9787 --- /dev/null +++ b/examples/stm32g4/src/bin/usb_serial.rs | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::{panic, *}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllQ, PllR, PllSrc}; | ||
| 8 | use embassy_stm32::time::Hertz; | ||
| 9 | use embassy_stm32::usb::{self, Driver, Instance}; | ||
| 10 | use embassy_stm32::{bind_interrupts, pac, peripherals, Config}; | ||
| 11 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 12 | use embassy_usb::driver::EndpointError; | ||
| 13 | use embassy_usb::Builder; | ||
| 14 | use futures::future::join; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | bind_interrupts!(struct Irqs { | ||
| 18 | USB_LP => usb::InterruptHandler<peripherals::USB>; | ||
| 19 | }); | ||
| 20 | |||
| 21 | #[embassy_executor::main] | ||
| 22 | async fn main(_spawner: Spawner) { | ||
| 23 | let mut config = Config::default(); | ||
| 24 | |||
| 25 | config.rcc.pll = Some(Pll { | ||
| 26 | source: PllSrc::HSE(Hertz(8000000)), | ||
| 27 | prediv_m: PllM::Div2, | ||
| 28 | mul_n: PllN::Mul72, | ||
| 29 | div_p: None, | ||
| 30 | // USB and CAN at 48 MHz | ||
| 31 | div_q: Some(PllQ::Div6), | ||
| 32 | // Main system clock at 144 MHz | ||
| 33 | div_r: Some(PllR::Div2), | ||
| 34 | }); | ||
| 35 | |||
| 36 | config.rcc.mux = ClockSrc::PLL; | ||
| 37 | |||
| 38 | let p = embassy_stm32::init(config); | ||
| 39 | info!("Hello World!"); | ||
| 40 | |||
| 41 | pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10)); | ||
| 42 | |||
| 43 | let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); | ||
| 44 | |||
| 45 | let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||
| 46 | config.manufacturer = Some("Embassy"); | ||
| 47 | config.product = Some("USB-Serial Example"); | ||
| 48 | config.serial_number = Some("123456"); | ||
| 49 | |||
| 50 | config.device_class = 0xEF; | ||
| 51 | config.device_sub_class = 0x02; | ||
| 52 | config.device_protocol = 0x01; | ||
| 53 | config.composite_with_iads = true; | ||
| 54 | |||
| 55 | let mut device_descriptor = [0; 256]; | ||
| 56 | let mut config_descriptor = [0; 256]; | ||
| 57 | let mut bos_descriptor = [0; 256]; | ||
| 58 | let mut control_buf = [0; 64]; | ||
| 59 | |||
| 60 | let mut state = State::new(); | ||
| 61 | |||
| 62 | let mut builder = Builder::new( | ||
| 63 | driver, | ||
| 64 | config, | ||
| 65 | &mut device_descriptor, | ||
| 66 | &mut config_descriptor, | ||
| 67 | &mut bos_descriptor, | ||
| 68 | &mut control_buf, | ||
| 69 | ); | ||
| 70 | |||
| 71 | let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); | ||
| 72 | |||
| 73 | let mut usb = builder.build(); | ||
| 74 | |||
| 75 | let usb_fut = usb.run(); | ||
| 76 | |||
| 77 | let echo_fut = async { | ||
| 78 | loop { | ||
| 79 | class.wait_connection().await; | ||
| 80 | info!("Connected"); | ||
| 81 | let _ = echo(&mut class).await; | ||
| 82 | info!("Disconnected"); | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | |||
| 86 | join(usb_fut, echo_fut).await; | ||
| 87 | } | ||
| 88 | |||
| 89 | struct Disconnected {} | ||
| 90 | |||
| 91 | impl From<EndpointError> for Disconnected { | ||
| 92 | fn from(val: EndpointError) -> Self { | ||
| 93 | match val { | ||
| 94 | EndpointError::BufferOverflow => panic!("Buffer overflow"), | ||
| 95 | EndpointError::Disabled => Disconnected {}, | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { | ||
| 101 | let mut buf = [0; 64]; | ||
| 102 | loop { | ||
| 103 | let n = class.read_packet(&mut buf).await?; | ||
| 104 | let data = &buf[..n]; | ||
| 105 | info!("data: {:x}", data); | ||
| 106 | class.write_packet(data).await?; | ||
| 107 | } | ||
| 108 | } | ||
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index b9204fba8..ebe511347 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } |
| 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } | 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } |
| @@ -30,7 +30,7 @@ critical-section = "1.1" | |||
| 30 | micromath = "2.0.0" | 30 | micromath = "2.0.0" |
| 31 | stm32-fmc = "0.2.4" | 31 | stm32-fmc = "0.2.4" |
| 32 | embedded-storage = "0.3.0" | 32 | embedded-storage = "0.3.0" |
| 33 | static_cell = "1.0" | 33 | static_cell = { version = "1.1", features = ["nightly"]} |
| 34 | 34 | ||
| 35 | # cargo build/run | 35 | # cargo build/run |
| 36 | [profile.dev] | 36 | [profile.dev] |
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index fa1f225fe..78c8282a6 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs | |||
| @@ -16,18 +16,8 @@ use embassy_stm32::{bind_interrupts, eth, Config}; | |||
| 16 | use embassy_time::{Duration, Timer}; | 16 | use embassy_time::{Duration, Timer}; |
| 17 | use embedded_io::asynch::Write; | 17 | use embedded_io::asynch::Write; |
| 18 | use rand_core::RngCore; | 18 | use rand_core::RngCore; |
| 19 | use static_cell::StaticCell; | 19 | use static_cell::make_static; |
| 20 | use {defmt_rtt as _, panic_probe as _}; | 20 | use {defmt_rtt as _, panic_probe as _}; |
| 21 | |||
| 22 | macro_rules! singleton { | ||
| 23 | ($val:expr) => {{ | ||
| 24 | type T = impl Sized; | ||
| 25 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 26 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 27 | x | ||
| 28 | }}; | ||
| 29 | } | ||
| 30 | |||
| 31 | bind_interrupts!(struct Irqs { | 21 | bind_interrupts!(struct Irqs { |
| 32 | ETH => eth::InterruptHandler; | 22 | ETH => eth::InterruptHandler; |
| 33 | }); | 23 | }); |
| @@ -74,7 +64,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 74 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 64 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 75 | 65 | ||
| 76 | let device = Ethernet::new( | 66 | let device = Ethernet::new( |
| 77 | singleton!(PacketQueue::<4, 4>::new()), | 67 | make_static!(PacketQueue::<4, 4>::new()), |
| 78 | p.ETH, | 68 | p.ETH, |
| 79 | Irqs, | 69 | Irqs, |
| 80 | p.PA1, | 70 | p.PA1, |
| @@ -91,15 +81,20 @@ async fn main(spawner: Spawner) -> ! { | |||
| 91 | 0, | 81 | 0, |
| 92 | ); | 82 | ); |
| 93 | 83 | ||
| 94 | let config = embassy_net::Config::Dhcp(Default::default()); | 84 | let config = embassy_net::Config::dhcpv4(Default::default()); |
| 95 | //let config = embassy_net::Config::Static(embassy_net::StaticConfig { | 85 | //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 96 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | 86 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), |
| 97 | // dns_servers: Vec::new(), | 87 | // dns_servers: Vec::new(), |
| 98 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | 88 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), |
| 99 | //}); | 89 | //}); |
| 100 | 90 | ||
| 101 | // Init network stack | 91 | // Init network stack |
| 102 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); | 92 | let stack = &*make_static!(Stack::new( |
| 93 | device, | ||
| 94 | config, | ||
| 95 | make_static!(StackResources::<2>::new()), | ||
| 96 | seed | ||
| 97 | )); | ||
| 103 | 98 | ||
| 104 | // Launch network task | 99 | // Launch network task |
| 105 | unwrap!(spawner.spawn(net_task(&stack))); | 100 | unwrap!(spawner.spawn(net_task(&stack))); |
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 3912327e2..336eed644 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs | |||
| @@ -45,11 +45,9 @@ async fn main(_spawner: Spawner) { | |||
| 45 | 45 | ||
| 46 | info!("Hello World!"); | 46 | info!("Hello World!"); |
| 47 | 47 | ||
| 48 | unsafe { | 48 | pac::RCC.ccipr4().write(|w| { |
| 49 | pac::RCC.ccipr4().write(|w| { | 49 | w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); |
| 50 | w.set_usbsel(pac::rcc::vals::Usbsel::HSI48); | 50 | }); |
| 51 | }); | ||
| 52 | } | ||
| 53 | 51 | ||
| 54 | // Create the driver, from the HAL. | 52 | // Create the driver, from the HAL. |
| 55 | let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); | 53 | let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); |
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 8b534ca05..62ef5e9e4 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } |
| 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } | 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] } |
| @@ -30,7 +30,7 @@ critical-section = "1.1" | |||
| 30 | micromath = "2.0.0" | 30 | micromath = "2.0.0" |
| 31 | stm32-fmc = "0.2.4" | 31 | stm32-fmc = "0.2.4" |
| 32 | embedded-storage = "0.3.0" | 32 | embedded-storage = "0.3.0" |
| 33 | static_cell = "1.0" | 33 | static_cell = { version = "1.1", features = ["nightly"]} |
| 34 | 34 | ||
| 35 | # cargo build/run | 35 | # cargo build/run |
| 36 | [profile.dev] | 36 | [profile.dev] |
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index dbfc90cf4..12d37f7a4 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs | |||
| @@ -15,18 +15,8 @@ use embassy_stm32::{bind_interrupts, eth, Config}; | |||
| 15 | use embassy_time::{Duration, Timer}; | 15 | use embassy_time::{Duration, Timer}; |
| 16 | use embedded_io::asynch::Write; | 16 | use embedded_io::asynch::Write; |
| 17 | use rand_core::RngCore; | 17 | use rand_core::RngCore; |
| 18 | use static_cell::StaticCell; | 18 | use static_cell::make_static; |
| 19 | use {defmt_rtt as _, panic_probe as _}; | 19 | use {defmt_rtt as _, panic_probe as _}; |
| 20 | |||
| 21 | macro_rules! singleton { | ||
| 22 | ($val:expr) => {{ | ||
| 23 | type T = impl Sized; | ||
| 24 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 25 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 26 | x | ||
| 27 | }}; | ||
| 28 | } | ||
| 29 | |||
| 30 | bind_interrupts!(struct Irqs { | 20 | bind_interrupts!(struct Irqs { |
| 31 | ETH => eth::InterruptHandler; | 21 | ETH => eth::InterruptHandler; |
| 32 | }); | 22 | }); |
| @@ -56,7 +46,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 56 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 46 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 57 | 47 | ||
| 58 | let device = Ethernet::new( | 48 | let device = Ethernet::new( |
| 59 | singleton!(PacketQueue::<16, 16>::new()), | 49 | make_static!(PacketQueue::<16, 16>::new()), |
| 60 | p.ETH, | 50 | p.ETH, |
| 61 | Irqs, | 51 | Irqs, |
| 62 | p.PA1, | 52 | p.PA1, |
| @@ -73,15 +63,20 @@ async fn main(spawner: Spawner) -> ! { | |||
| 73 | 0, | 63 | 0, |
| 74 | ); | 64 | ); |
| 75 | 65 | ||
| 76 | let config = embassy_net::Config::Dhcp(Default::default()); | 66 | let config = embassy_net::Config::dhcpv4(Default::default()); |
| 77 | //let config = embassy_net::Config::Static(embassy_net::StaticConfig { | 67 | //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 78 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | 68 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), |
| 79 | // dns_servers: Vec::new(), | 69 | // dns_servers: Vec::new(), |
| 80 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | 70 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), |
| 81 | //}); | 71 | //}); |
| 82 | 72 | ||
| 83 | // Init network stack | 73 | // Init network stack |
| 84 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); | 74 | let stack = &*make_static!(Stack::new( |
| 75 | device, | ||
| 76 | config, | ||
| 77 | make_static!(StackResources::<2>::new()), | ||
| 78 | seed | ||
| 79 | )); | ||
| 85 | 80 | ||
| 86 | // Launch network task | 81 | // Launch network task |
| 87 | unwrap!(spawner.spawn(net_task(&stack))); | 82 | unwrap!(spawner.spawn(net_task(&stack))); |
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 14e6b7914..6078fc3fe 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs | |||
| @@ -16,18 +16,8 @@ use embassy_time::{Duration, Timer}; | |||
| 16 | use embedded_io::asynch::Write; | 16 | use embedded_io::asynch::Write; |
| 17 | use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; | 17 | use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; |
| 18 | use rand_core::RngCore; | 18 | use rand_core::RngCore; |
| 19 | use static_cell::StaticCell; | 19 | use static_cell::make_static; |
| 20 | use {defmt_rtt as _, panic_probe as _}; | 20 | use {defmt_rtt as _, panic_probe as _}; |
| 21 | |||
| 22 | macro_rules! singleton { | ||
| 23 | ($val:expr) => {{ | ||
| 24 | type T = impl Sized; | ||
| 25 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 26 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 27 | x | ||
| 28 | }}; | ||
| 29 | } | ||
| 30 | |||
| 31 | bind_interrupts!(struct Irqs { | 21 | bind_interrupts!(struct Irqs { |
| 32 | ETH => eth::InterruptHandler; | 22 | ETH => eth::InterruptHandler; |
| 33 | }); | 23 | }); |
| @@ -57,7 +47,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 57 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 47 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 58 | 48 | ||
| 59 | let device = Ethernet::new( | 49 | let device = Ethernet::new( |
| 60 | singleton!(PacketQueue::<16, 16>::new()), | 50 | make_static!(PacketQueue::<16, 16>::new()), |
| 61 | p.ETH, | 51 | p.ETH, |
| 62 | Irqs, | 52 | Irqs, |
| 63 | p.PA1, | 53 | p.PA1, |
| @@ -74,15 +64,20 @@ async fn main(spawner: Spawner) -> ! { | |||
| 74 | 0, | 64 | 0, |
| 75 | ); | 65 | ); |
| 76 | 66 | ||
| 77 | let config = embassy_net::Config::Dhcp(Default::default()); | 67 | let config = embassy_net::Config::dhcpv4(Default::default()); |
| 78 | //let config = embassy_net::Config::StaticConfig(embassy_net::Config { | 68 | //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 79 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | 69 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), |
| 80 | // dns_servers: Vec::new(), | 70 | // dns_servers: Vec::new(), |
| 81 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | 71 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), |
| 82 | //}); | 72 | //}); |
| 83 | 73 | ||
| 84 | // Init network stack | 74 | // Init network stack |
| 85 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); | 75 | let stack = &*make_static!(Stack::new( |
| 76 | device, | ||
| 77 | config, | ||
| 78 | make_static!(StackResources::<2>::new()), | ||
| 79 | seed | ||
| 80 | )); | ||
| 86 | 81 | ||
| 87 | // Launch network task | 82 | // Launch network task |
| 88 | unwrap!(spawner.spawn(net_task(&stack))); | 83 | unwrap!(spawner.spawn(net_task(&stack))); |
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 1972f8ff2..d360df085 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs | |||
| @@ -62,49 +62,39 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 62 | T::enable(); | 62 | T::enable(); |
| 63 | <T as embassy_stm32::rcc::low_level::RccPeripheral>::reset(); | 63 | <T as embassy_stm32::rcc::low_level::RccPeripheral>::reset(); |
| 64 | 64 | ||
| 65 | unsafe { | 65 | ch1.set_speed(Speed::VeryHigh); |
| 66 | ch1.set_speed(Speed::VeryHigh); | 66 | ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); |
| 67 | ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 67 | ch2.set_speed(Speed::VeryHigh); |
| 68 | ch2.set_speed(Speed::VeryHigh); | 68 | ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); |
| 69 | ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 69 | ch3.set_speed(Speed::VeryHigh); |
| 70 | ch3.set_speed(Speed::VeryHigh); | 70 | ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); |
| 71 | ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); | 71 | ch4.set_speed(Speed::VeryHigh); |
| 72 | ch4.set_speed(Speed::VeryHigh); | 72 | ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); |
| 73 | ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); | ||
| 74 | } | ||
| 75 | 73 | ||
| 76 | let mut this = Self { inner: tim }; | 74 | let mut this = Self { inner: tim }; |
| 77 | 75 | ||
| 78 | this.set_freq(freq); | 76 | this.set_freq(freq); |
| 79 | this.inner.start(); | 77 | this.inner.start(); |
| 80 | 78 | ||
| 81 | unsafe { | 79 | let r = T::regs_gp32(); |
| 82 | T::regs_gp32() | 80 | r.ccmr_output(0) |
| 83 | .ccmr_output(0) | 81 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); |
| 84 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | 82 | r.ccmr_output(0) |
| 85 | T::regs_gp32() | 83 | .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); |
| 86 | .ccmr_output(0) | 84 | r.ccmr_output(1) |
| 87 | .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); | 85 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); |
| 88 | T::regs_gp32() | 86 | r.ccmr_output(1) |
| 89 | .ccmr_output(1) | 87 | .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); |
| 90 | .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); | 88 | |
| 91 | T::regs_gp32() | ||
| 92 | .ccmr_output(1) | ||
| 93 | .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); | ||
| 94 | } | ||
| 95 | this | 89 | this |
| 96 | } | 90 | } |
| 97 | 91 | ||
| 98 | pub fn enable(&mut self, channel: Channel) { | 92 | pub fn enable(&mut self, channel: Channel) { |
| 99 | unsafe { | 93 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true)); |
| 100 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true)); | ||
| 101 | } | ||
| 102 | } | 94 | } |
| 103 | 95 | ||
| 104 | pub fn disable(&mut self, channel: Channel) { | 96 | pub fn disable(&mut self, channel: Channel) { |
| 105 | unsafe { | 97 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false)); |
| 106 | T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false)); | ||
| 107 | } | ||
| 108 | } | 98 | } |
| 109 | 99 | ||
| 110 | pub fn set_freq(&mut self, freq: Hertz) { | 100 | pub fn set_freq(&mut self, freq: Hertz) { |
| @@ -112,11 +102,11 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { | |||
| 112 | } | 102 | } |
| 113 | 103 | ||
| 114 | pub fn get_max_duty(&self) -> u32 { | 104 | pub fn get_max_duty(&self) -> u32 { |
| 115 | unsafe { T::regs_gp32().arr().read().arr() } | 105 | T::regs_gp32().arr().read().arr() |
| 116 | } | 106 | } |
| 117 | 107 | ||
| 118 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { | 108 | pub fn set_duty(&mut self, channel: Channel, duty: u32) { |
| 119 | defmt::assert!(duty < self.get_max_duty()); | 109 | defmt::assert!(duty < self.get_max_duty()); |
| 120 | unsafe { T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) } | 110 | T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) |
| 121 | } | 111 | } |
| 122 | } | 112 | } |
diff --git a/examples/stm32h7/src/bin/wdg.rs b/examples/stm32h7/src/bin/wdg.rs index 2b0301aad..9181dfd67 100644 --- a/examples/stm32h7/src/bin/wdg.rs +++ b/examples/stm32h7/src/bin/wdg.rs | |||
| @@ -15,10 +15,10 @@ async fn main(_spawner: Spawner) { | |||
| 15 | 15 | ||
| 16 | let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000); | 16 | let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000); |
| 17 | 17 | ||
| 18 | unsafe { wdg.unleash() }; | 18 | wdg.unleash(); |
| 19 | 19 | ||
| 20 | loop { | 20 | loop { |
| 21 | Timer::after(Duration::from_secs(1)).await; | 21 | Timer::after(Duration::from_secs(1)).await; |
| 22 | unsafe { wdg.pet() }; | 22 | wdg.pet(); |
| 23 | } | 23 | } |
| 24 | } | 24 | } |
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index ffb6cdb43..2ead714e4 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [features] | 7 | [features] |
| 8 | default = ["nightly"] | 8 | default = ["nightly"] |
| 9 | nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstable-traits", | 9 | nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstable-traits", "embassy-executor/nightly", |
| 10 | "embassy-lora", "lora-phy", "lorawan-device", "lorawan", "embedded-io/async"] | 10 | "embassy-lora", "lora-phy", "lorawan-device", "lorawan", "embedded-io/async"] |
| 11 | 11 | ||
| 12 | [dependencies] | 12 | [dependencies] |
| @@ -31,4 +31,4 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } | |||
| 31 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 31 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 32 | heapless = { version = "0.7.5", default-features = false } | 32 | heapless = { version = "0.7.5", default-features = false } |
| 33 | embedded-hal = "0.2.6" | 33 | embedded-hal = "0.2.6" |
| 34 | static_cell = "1.0" | 34 | static_cell = "1.1" |
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 8b6508c87..93d48abeb 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } |
| 12 | 12 | ||
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 29d091f94..3bb473ef5 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } | 11 | embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } |
| 12 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } | 12 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } |
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index 281346e5f..1771e5202 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs | |||
| @@ -12,12 +12,10 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 12 | fn main() -> ! { | 12 | fn main() -> ! { |
| 13 | info!("Hello World!"); | 13 | info!("Hello World!"); |
| 14 | 14 | ||
| 15 | unsafe { | 15 | pac::RCC.ccipr().modify(|w| { |
| 16 | pac::RCC.ccipr().modify(|w| { | 16 | w.set_adcsel(0b11); |
| 17 | w.set_adcsel(0b11); | 17 | }); |
| 18 | }); | 18 | pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); |
| 19 | pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); | ||
| 20 | } | ||
| 21 | 19 | ||
| 22 | let p = embassy_stm32::init(Default::default()); | 20 | let p = embassy_stm32::init(Default::default()); |
| 23 | 21 | ||
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs index d6e744aa6..a36ed5d90 100644 --- a/examples/stm32l4/src/bin/dac.rs +++ b/examples/stm32l4/src/bin/dac.rs | |||
| @@ -11,11 +11,9 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 11 | fn main() -> ! { | 11 | fn main() -> ! { |
| 12 | info!("Hello World!"); | 12 | info!("Hello World!"); |
| 13 | 13 | ||
| 14 | unsafe { | 14 | pac::RCC.apb1enr1().modify(|w| { |
| 15 | pac::RCC.apb1enr1().modify(|w| { | 15 | w.set_dac1en(true); |
| 16 | w.set_dac1en(true); | 16 | }); |
| 17 | }); | ||
| 18 | } | ||
| 19 | 17 | ||
| 20 | let p = embassy_stm32::init(Default::default()); | 18 | let p = embassy_stm32::init(Default::default()); |
| 21 | 19 | ||
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index acb48c765..6035c291f 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } |
| 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| @@ -25,4 +25,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa | |||
| 25 | heapless = { version = "0.7.5", default-features = false } | 25 | heapless = { version = "0.7.5", default-features = false } |
| 26 | rand_core = { version = "0.6.3", default-features = false } | 26 | rand_core = { version = "0.6.3", default-features = false } |
| 27 | embedded-io = { version = "0.4.0", features = ["async"] } | 27 | embedded-io = { version = "0.4.0", features = ["async"] } |
| 28 | static_cell = "1.0" | 28 | static_cell = { version = "1.1", features = ["nightly"]} |
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index b84e53d3a..32eba4277 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs | |||
| @@ -15,20 +15,11 @@ use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | |||
| 15 | use embassy_usb::{Builder, UsbDevice}; | 15 | use embassy_usb::{Builder, UsbDevice}; |
| 16 | use embedded_io::asynch::Write; | 16 | use embedded_io::asynch::Write; |
| 17 | use rand_core::RngCore; | 17 | use rand_core::RngCore; |
| 18 | use static_cell::StaticCell; | 18 | use static_cell::make_static; |
| 19 | use {defmt_rtt as _, panic_probe as _}; | 19 | use {defmt_rtt as _, panic_probe as _}; |
| 20 | 20 | ||
| 21 | type MyDriver = Driver<'static, embassy_stm32::peripherals::USB>; | 21 | type MyDriver = Driver<'static, embassy_stm32::peripherals::USB>; |
| 22 | 22 | ||
| 23 | macro_rules! singleton { | ||
| 24 | ($val:expr) => {{ | ||
| 25 | type T = impl Sized; | ||
| 26 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 27 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 28 | x | ||
| 29 | }}; | ||
| 30 | } | ||
| 31 | |||
| 32 | const MTU: usize = 1514; | 23 | const MTU: usize = 1514; |
| 33 | 24 | ||
| 34 | bind_interrupts!(struct Irqs { | 25 | bind_interrupts!(struct Irqs { |
| @@ -78,10 +69,10 @@ async fn main(spawner: Spawner) { | |||
| 78 | let mut builder = Builder::new( | 69 | let mut builder = Builder::new( |
| 79 | driver, | 70 | driver, |
| 80 | config, | 71 | config, |
| 81 | &mut singleton!([0; 256])[..], | 72 | &mut make_static!([0; 256])[..], |
| 82 | &mut singleton!([0; 256])[..], | 73 | &mut make_static!([0; 256])[..], |
| 83 | &mut singleton!([0; 256])[..], | 74 | &mut make_static!([0; 256])[..], |
| 84 | &mut singleton!([0; 128])[..], | 75 | &mut make_static!([0; 128])[..], |
| 85 | ); | 76 | ); |
| 86 | 77 | ||
| 87 | // Our MAC addr. | 78 | // Our MAC addr. |
| @@ -90,18 +81,18 @@ async fn main(spawner: Spawner) { | |||
| 90 | let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; | 81 | let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; |
| 91 | 82 | ||
| 92 | // Create classes on the builder. | 83 | // Create classes on the builder. |
| 93 | let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); | 84 | let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64); |
| 94 | 85 | ||
| 95 | // Build the builder. | 86 | // Build the builder. |
| 96 | let usb = builder.build(); | 87 | let usb = builder.build(); |
| 97 | 88 | ||
| 98 | unwrap!(spawner.spawn(usb_task(usb))); | 89 | unwrap!(spawner.spawn(usb_task(usb))); |
| 99 | 90 | ||
| 100 | let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); | 91 | let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr); |
| 101 | unwrap!(spawner.spawn(usb_ncm_task(runner))); | 92 | unwrap!(spawner.spawn(usb_ncm_task(runner))); |
| 102 | 93 | ||
| 103 | let config = embassy_net::Config::Dhcp(Default::default()); | 94 | let config = embassy_net::Config::dhcpv4(Default::default()); |
| 104 | //let config = embassy_net::Config::Static(embassy_net::StaticConfig { | 95 | //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { |
| 105 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | 96 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), |
| 106 | // dns_servers: Vec::new(), | 97 | // dns_servers: Vec::new(), |
| 107 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | 98 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), |
| @@ -112,7 +103,12 @@ async fn main(spawner: Spawner) { | |||
| 112 | let seed = rng.next_u64(); | 103 | let seed = rng.next_u64(); |
| 113 | 104 | ||
| 114 | // Init network stack | 105 | // Init network stack |
| 115 | let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed)); | 106 | let stack = &*make_static!(Stack::new( |
| 107 | device, | ||
| 108 | config, | ||
| 109 | make_static!(StackResources::<2>::new()), | ||
| 110 | seed | ||
| 111 | )); | ||
| 116 | 112 | ||
| 117 | unwrap!(spawner.spawn(net_task(stack))); | 113 | unwrap!(spawner.spawn(net_task(stack))); |
| 118 | 114 | ||
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index be205f880..e2318c3d6 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } |
| 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 8cfac772a..83a443754 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml | |||
| @@ -6,9 +6,10 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } |
| 12 | embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } | ||
| 12 | 13 | ||
| 13 | defmt = "0.3" | 14 | defmt = "0.3" |
| 14 | defmt-rtt = "0.4" | 15 | defmt-rtt = "0.4" |
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs index 8f4e70af0..9fc4b8aac 100644 --- a/examples/stm32wb/src/bin/tl_mbox.rs +++ b/examples/stm32wb/src/bin/tl_mbox.rs | |||
| @@ -4,14 +4,15 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::tl_mbox::{Config, TlMbox}; | 7 | use embassy_stm32::bind_interrupts; |
| 8 | use embassy_stm32::{bind_interrupts, tl_mbox}; | 8 | use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; |
| 9 | use embassy_stm32_wpan::TlMbox; | ||
| 9 | use embassy_time::{Duration, Timer}; | 10 | use embassy_time::{Duration, Timer}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 12 | ||
| 12 | bind_interrupts!(struct Irqs{ | 13 | bind_interrupts!(struct Irqs{ |
| 13 | IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; | 14 | IPCC_C1_RX => ReceiveInterruptHandler; |
| 14 | IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; | 15 | IPCC_C1_TX => TransmitInterruptHandler; |
| 15 | }); | 16 | }); |
| 16 | 17 | ||
| 17 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| @@ -44,10 +45,10 @@ async fn main(_spawner: Spawner) { | |||
| 44 | info!("Hello World!"); | 45 | info!("Hello World!"); |
| 45 | 46 | ||
| 46 | let config = Config::default(); | 47 | let config = Config::default(); |
| 47 | let mbox = TlMbox::new(p.IPCC, Irqs, config); | 48 | let mbox = TlMbox::init(p.IPCC, Irqs, config); |
| 48 | 49 | ||
| 49 | loop { | 50 | loop { |
| 50 | let wireless_fw_info = mbox.wireless_fw_info(); | 51 | let wireless_fw_info = mbox.sys_subsystem.wireless_fw_info(); |
| 51 | match wireless_fw_info { | 52 | match wireless_fw_info { |
| 52 | None => info!("not yet initialized"), | 53 | None => info!("not yet initialized"), |
| 53 | Some(fw_info) => { | 54 | Some(fw_info) => { |
diff --git a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs index 1724d946f..439bd01ac 100644 --- a/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs +++ b/examples/stm32wb/src/bin/tl_mbox_tx_rx.rs | |||
| @@ -4,13 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::tl_mbox::{Config, TlMbox}; | 7 | use embassy_stm32::bind_interrupts; |
| 8 | use embassy_stm32::{bind_interrupts, tl_mbox}; | 8 | use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; |
| 9 | use embassy_stm32_wpan::TlMbox; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 11 | ||
| 11 | bind_interrupts!(struct Irqs{ | 12 | bind_interrupts!(struct Irqs{ |
| 12 | IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; | 13 | IPCC_C1_RX => ReceiveInterruptHandler; |
| 13 | IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; | 14 | IPCC_C1_TX => TransmitInterruptHandler; |
| 14 | }); | 15 | }); |
| 15 | 16 | ||
| 16 | #[embassy_executor::main] | 17 | #[embassy_executor::main] |
| @@ -43,55 +44,20 @@ async fn main(_spawner: Spawner) { | |||
| 43 | info!("Hello World!"); | 44 | info!("Hello World!"); |
| 44 | 45 | ||
| 45 | let config = Config::default(); | 46 | let config = Config::default(); |
| 46 | let mbox = TlMbox::new(p.IPCC, Irqs, config); | 47 | let mbox = TlMbox::init(p.IPCC, Irqs, config); |
| 47 | 48 | ||
| 48 | info!("waiting for coprocessor to boot"); | 49 | let sys_event = mbox.sys_subsystem.read().await; |
| 49 | let event_box = mbox.read().await; | 50 | info!("sys event: {}", sys_event.payload()); |
| 50 | 51 | ||
| 51 | let mut payload = [0u8; 6]; | 52 | mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; |
| 52 | event_box.copy_into_slice(&mut payload).unwrap(); | ||
| 53 | 53 | ||
| 54 | let event_packet = event_box.evt(); | 54 | info!("starting ble..."); |
| 55 | let kind = event_packet.evt_serial.kind; | 55 | mbox.ble_subsystem.write(0x0c, &[]).await; |
| 56 | 56 | ||
| 57 | // means recieved SYS event, which indicates in this case that the coprocessor is ready | 57 | info!("waiting for ble..."); |
| 58 | if kind == 0x12 { | 58 | let ble_event = mbox.ble_subsystem.read().await; |
| 59 | let code = event_packet.evt_serial.evt.evt_code; | ||
| 60 | let payload_len = event_packet.evt_serial.evt.payload_len; | ||
| 61 | 59 | ||
| 62 | info!( | 60 | info!("ble event: {}", ble_event.payload()); |
| 63 | "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}", | ||
| 64 | kind, | ||
| 65 | code, | ||
| 66 | payload_len, | ||
| 67 | payload[3..] | ||
| 68 | ); | ||
| 69 | } | ||
| 70 | |||
| 71 | // initialize ble stack, does not return a response | ||
| 72 | mbox.shci_ble_init(Default::default()); | ||
| 73 | |||
| 74 | info!("resetting BLE"); | ||
| 75 | mbox.send_ble_cmd(&[0x01, 0x03, 0x0c, 0x00, 0x00]); | ||
| 76 | |||
| 77 | let event_box = mbox.read().await; | ||
| 78 | |||
| 79 | let mut payload = [0u8; 7]; | ||
| 80 | event_box.copy_into_slice(&mut payload).unwrap(); | ||
| 81 | |||
| 82 | let event_packet = event_box.evt(); | ||
| 83 | let kind = event_packet.evt_serial.kind; | ||
| 84 | |||
| 85 | let code = event_packet.evt_serial.evt.evt_code; | ||
| 86 | let payload_len = event_packet.evt_serial.evt.payload_len; | ||
| 87 | |||
| 88 | info!( | ||
| 89 | "==> kind: {:#04x}, code: {:#04x}, payload_length: {}, payload: {:#04x}", | ||
| 90 | kind, | ||
| 91 | code, | ||
| 92 | payload_len, | ||
| 93 | payload[3..] | ||
| 94 | ); | ||
| 95 | 61 | ||
| 96 | info!("Test OK"); | 62 | info!("Test OK"); |
| 97 | cortex_m::asm::bkpt(); | 63 | cortex_m::asm::bkpt(); |
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 6191d01e9..260f9afa1 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml | |||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti"] } |
| 12 | embassy-embedded-hal = {version = "0.1.0", path = "../../embassy-embedded-hal" } | 12 | embassy-embedded-hal = {version = "0.1.0", path = "../../embassy-embedded-hal" } |
diff --git a/examples/stm32wl/src/bin/lora_lorawan.rs b/examples/stm32wl/src/bin/lora_lorawan.rs index e179c5ca1..805d21418 100644 --- a/examples/stm32wl/src/bin/lora_lorawan.rs +++ b/examples/stm32wl/src/bin/lora_lorawan.rs | |||
| @@ -35,7 +35,7 @@ async fn main(_spawner: Spawner) { | |||
| 35 | config.rcc.enable_lsi = true; // enable RNG | 35 | config.rcc.enable_lsi = true; // enable RNG |
| 36 | let p = embassy_stm32::init(config); | 36 | let p = embassy_stm32::init(config); |
| 37 | 37 | ||
| 38 | unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) } | 38 | pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)); |
| 39 | 39 | ||
| 40 | let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); | 40 | let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); |
| 41 | 41 | ||
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs index 182c607f9..d8562fca5 100644 --- a/examples/stm32wl/src/bin/random.rs +++ b/examples/stm32wl/src/bin/random.rs | |||
| @@ -15,11 +15,9 @@ async fn main(_spawner: Spawner) { | |||
| 15 | config.rcc.enable_lsi = true; //Needed for RNG to work | 15 | config.rcc.enable_lsi = true; //Needed for RNG to work |
| 16 | 16 | ||
| 17 | let p = embassy_stm32::init(config); | 17 | let p = embassy_stm32::init(config); |
| 18 | unsafe { | 18 | pac::RCC.ccipr().modify(|w| { |
| 19 | pac::RCC.ccipr().modify(|w| { | 19 | w.set_rngsel(0b01); |
| 20 | w.set_rngsel(0b01); | 20 | }); |
| 21 | }); | ||
| 22 | } | ||
| 23 | 21 | ||
| 24 | info!("Hello World!"); | 22 | info!("Hello World!"); |
| 25 | 23 | ||
diff --git a/tests/perf-server/Cargo.toml b/tests/perf-server/Cargo.toml new file mode 100644 index 000000000..532039050 --- /dev/null +++ b/tests/perf-server/Cargo.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [package] | ||
| 2 | name = "perf-server" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [dependencies] | ||
| 7 | log = "0.4.17" | ||
| 8 | pretty_env_logger = "0.4.0" | ||
diff --git a/tests/perf-server/deploy.sh b/tests/perf-server/deploy.sh new file mode 100755 index 000000000..032e99c30 --- /dev/null +++ b/tests/perf-server/deploy.sh | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | |||
| 3 | set -euxo pipefail | ||
| 4 | |||
| 5 | [email protected] | ||
| 6 | |||
| 7 | cargo build --release | ||
| 8 | ssh $HOST -- systemctl stop perf-server | ||
| 9 | scp target/release/perf-server $HOST:/root | ||
| 10 | scp perf-server.service $HOST:/etc/systemd/system/ | ||
| 11 | ssh $HOST -- 'systemctl daemon-reload; systemctl restart perf-server' \ No newline at end of file | ||
diff --git a/tests/perf-server/perf-server.service b/tests/perf-server/perf-server.service new file mode 100644 index 000000000..c14c5d16f --- /dev/null +++ b/tests/perf-server/perf-server.service | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | [Unit] | ||
| 2 | Description=perf-server | ||
| 3 | After=network.target | ||
| 4 | StartLimitIntervalSec=0 | ||
| 5 | |||
| 6 | [Service] | ||
| 7 | Type=simple | ||
| 8 | Restart=always | ||
| 9 | RestartSec=1 | ||
| 10 | User=root | ||
| 11 | ExecStart=/root/perf-server | ||
| 12 | Environment=RUST_BACKTRACE=1 | ||
| 13 | Environment=RUST_LOG=info | ||
| 14 | |||
| 15 | [Install] | ||
| 16 | WantedBy=multi-user.target | ||
diff --git a/tests/perf-server/src/main.rs b/tests/perf-server/src/main.rs new file mode 100644 index 000000000..f6e7efc59 --- /dev/null +++ b/tests/perf-server/src/main.rs | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | use std::io::{Read, Write}; | ||
| 2 | use std::net::{TcpListener, TcpStream}; | ||
| 3 | use std::thread::spawn; | ||
| 4 | use std::time::Duration; | ||
| 5 | |||
| 6 | use log::info; | ||
| 7 | |||
| 8 | fn main() { | ||
| 9 | pretty_env_logger::init(); | ||
| 10 | spawn(|| rx_listen()); | ||
| 11 | spawn(|| rxtx_listen()); | ||
| 12 | tx_listen(); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn tx_listen() { | ||
| 16 | info!("tx: listening on 0.0.0.0:4321"); | ||
| 17 | let listener = TcpListener::bind("0.0.0.0:4321").unwrap(); | ||
| 18 | loop { | ||
| 19 | let (socket, addr) = listener.accept().unwrap(); | ||
| 20 | info!("tx: received connection from: {}", addr); | ||
| 21 | spawn(|| tx_conn(socket)); | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | fn tx_conn(mut socket: TcpStream) { | ||
| 26 | socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap(); | ||
| 27 | socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap(); | ||
| 28 | |||
| 29 | let buf = [0; 1024]; | ||
| 30 | loop { | ||
| 31 | if let Err(e) = socket.write_all(&buf) { | ||
| 32 | info!("tx: failed to write to socket; err = {:?}", e); | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | fn rx_listen() { | ||
| 39 | info!("rx: listening on 0.0.0.0:4322"); | ||
| 40 | let listener = TcpListener::bind("0.0.0.0:4322").unwrap(); | ||
| 41 | loop { | ||
| 42 | let (socket, addr) = listener.accept().unwrap(); | ||
| 43 | info!("rx: received connection from: {}", addr); | ||
| 44 | spawn(|| rx_conn(socket)); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | fn rx_conn(mut socket: TcpStream) { | ||
| 49 | socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap(); | ||
| 50 | socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap(); | ||
| 51 | |||
| 52 | let mut buf = [0; 1024]; | ||
| 53 | loop { | ||
| 54 | if let Err(e) = socket.read_exact(&mut buf) { | ||
| 55 | info!("rx: failed to read from socket; err = {:?}", e); | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | fn rxtx_listen() { | ||
| 62 | info!("rxtx: listening on 0.0.0.0:4323"); | ||
| 63 | let listener = TcpListener::bind("0.0.0.0:4323").unwrap(); | ||
| 64 | loop { | ||
| 65 | let (socket, addr) = listener.accept().unwrap(); | ||
| 66 | info!("rxtx: received connection from: {}", addr); | ||
| 67 | spawn(|| rxtx_conn(socket)); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | fn rxtx_conn(mut socket: TcpStream) { | ||
| 72 | socket.set_read_timeout(Some(Duration::from_secs(30))).unwrap(); | ||
| 73 | socket.set_write_timeout(Some(Duration::from_secs(30))).unwrap(); | ||
| 74 | |||
| 75 | let mut buf = [0; 1024]; | ||
| 76 | loop { | ||
| 77 | match socket.read(&mut buf) { | ||
| 78 | Ok(n) => { | ||
| 79 | if let Err(e) = socket.write_all(&buf[..n]) { | ||
| 80 | info!("rxtx: failed to write to socket; err = {:?}", e); | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | Err(e) => { | ||
| 85 | info!("rxtx: failed to read from socket; err = {:?}", e); | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 1786baee3..180d0ebbe 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml | |||
| @@ -5,13 +5,16 @@ version = "0.1.0" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | teleprobe-meta = "1" | 8 | teleprobe-meta = "1.1" |
| 9 | 9 | ||
| 10 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } | 12 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } |
| 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics"] } | 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 15 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } | ||
| 16 | cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } | ||
| 17 | cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } | ||
| 15 | 18 | ||
| 16 | defmt = "0.3.0" | 19 | defmt = "0.3.0" |
| 17 | defmt-rtt = "0.4" | 20 | defmt-rtt = "0.4" |
| @@ -25,6 +28,7 @@ panic-probe = { version = "0.3.0", features = ["print-defmt"] } | |||
| 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 28 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 26 | embedded-io = { version = "0.4.0", features = ["async"] } | 29 | embedded-io = { version = "0.4.0", features = ["async"] } |
| 27 | embedded-storage = { version = "0.3" } | 30 | embedded-storage = { version = "0.3" } |
| 31 | static_cell = { version = "1.1", features = ["nightly"]} | ||
| 28 | 32 | ||
| 29 | [profile.dev] | 33 | [profile.dev] |
| 30 | debug = 2 | 34 | debug = 2 |
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs new file mode 100644 index 000000000..7a94ea191 --- /dev/null +++ b/tests/rp/src/bin/cyw43-perf.rs | |||
| @@ -0,0 +1,267 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #[path = "../common.rs"] | ||
| 5 | mod common; | ||
| 6 | |||
| 7 | use cyw43_pio::PioSpi; | ||
| 8 | use defmt::{assert, panic, *}; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_futures::join::join; | ||
| 11 | use embassy_net::tcp::TcpSocket; | ||
| 12 | use embassy_net::{Config, Ipv4Address, Stack, StackResources}; | ||
| 13 | use embassy_rp::gpio::{Level, Output}; | ||
| 14 | use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; | ||
| 15 | use embassy_rp::pio::Pio; | ||
| 16 | use embassy_rp::rom_data; | ||
| 17 | use embassy_time::{with_timeout, Duration, Timer}; | ||
| 18 | use static_cell::make_static; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | teleprobe_meta::timeout!(120); | ||
| 22 | |||
| 23 | #[embassy_executor::task] | ||
| 24 | async fn wifi_task( | ||
| 25 | runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, | ||
| 26 | ) -> ! { | ||
| 27 | runner.run().await | ||
| 28 | } | ||
| 29 | |||
| 30 | #[embassy_executor::task] | ||
| 31 | async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { | ||
| 32 | stack.run().await | ||
| 33 | } | ||
| 34 | |||
| 35 | #[embassy_executor::main] | ||
| 36 | async fn main(spawner: Spawner) { | ||
| 37 | info!("Hello World!"); | ||
| 38 | let p = embassy_rp::init(Default::default()); | ||
| 39 | |||
| 40 | // needed for reading the firmware from flash via XIP. | ||
| 41 | unsafe { | ||
| 42 | rom_data::flash_exit_xip(); | ||
| 43 | rom_data::flash_enter_cmd_xip(); | ||
| 44 | } | ||
| 45 | |||
| 46 | // cyw43 firmware needs to be flashed manually: | ||
| 47 | // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x101c0000 | ||
| 48 | // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x101f8000 | ||
| 49 | let fw = unsafe { core::slice::from_raw_parts(0x101c0000 as *const u8, 224190) }; | ||
| 50 | let clm = unsafe { core::slice::from_raw_parts(0x101f8000 as *const u8, 4752) }; | ||
| 51 | |||
| 52 | let pwr = Output::new(p.PIN_23, Level::Low); | ||
| 53 | let cs = Output::new(p.PIN_25, Level::High); | ||
| 54 | let mut pio = Pio::new(p.PIO0); | ||
| 55 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); | ||
| 56 | |||
| 57 | let state = make_static!(cyw43::State::new()); | ||
| 58 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | ||
| 59 | unwrap!(spawner.spawn(wifi_task(runner))); | ||
| 60 | |||
| 61 | control.init(clm).await; | ||
| 62 | control | ||
| 63 | .set_power_management(cyw43::PowerManagementMode::PowerSave) | ||
| 64 | .await; | ||
| 65 | |||
| 66 | let config = Config::dhcpv4(Default::default()); | ||
| 67 | //let config = embassy_net::Config::Static(embassy_net::Config { | ||
| 68 | // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), | ||
| 69 | // dns_servers: Vec::new(), | ||
| 70 | // gateway: Some(Ipv4Address::new(192, 168, 69, 1)), | ||
| 71 | //}); | ||
| 72 | |||
| 73 | // Generate random seed | ||
| 74 | let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. | ||
| 75 | |||
| 76 | // Init network stack | ||
| 77 | let stack = &*make_static!(Stack::new( | ||
| 78 | net_device, | ||
| 79 | config, | ||
| 80 | make_static!(StackResources::<2>::new()), | ||
| 81 | seed | ||
| 82 | )); | ||
| 83 | |||
| 84 | unwrap!(spawner.spawn(net_task(stack))); | ||
| 85 | |||
| 86 | loop { | ||
| 87 | match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { | ||
| 88 | Ok(_) => break, | ||
| 89 | Err(err) => { | ||
| 90 | panic!("join failed with status={}", err.status); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | info!("Waiting for DHCP up..."); | ||
| 96 | while stack.config_v4().is_none() { | ||
| 97 | Timer::after(Duration::from_millis(100)).await; | ||
| 98 | } | ||
| 99 | info!("IP addressing up!"); | ||
| 100 | |||
| 101 | let down = test_download(stack).await; | ||
| 102 | let up = test_upload(stack).await; | ||
| 103 | let updown = test_upload_download(stack).await; | ||
| 104 | |||
| 105 | assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS); | ||
| 106 | assert!(up > TEST_EXPECTED_UPLOAD_KBPS); | ||
| 107 | assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS); | ||
| 108 | |||
| 109 | info!("Test OK"); | ||
| 110 | cortex_m::asm::bkpt(); | ||
| 111 | } | ||
| 112 | |||
| 113 | // Test-only wifi network, no internet access! | ||
| 114 | const WIFI_NETWORK: &str = "EmbassyTest"; | ||
| 115 | const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; | ||
| 116 | |||
| 117 | const TEST_DURATION: usize = 10; | ||
| 118 | const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 300; | ||
| 119 | const TEST_EXPECTED_UPLOAD_KBPS: usize = 300; | ||
| 120 | const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 300; | ||
| 121 | const RX_BUFFER_SIZE: usize = 4096; | ||
| 122 | const TX_BUFFER_SIZE: usize = 4096; | ||
| 123 | const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); | ||
| 124 | const DOWNLOAD_PORT: u16 = 4321; | ||
| 125 | const UPLOAD_PORT: u16 = 4322; | ||
| 126 | const UPLOAD_DOWNLOAD_PORT: u16 = 4323; | ||
| 127 | |||
| 128 | async fn test_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize { | ||
| 129 | info!("Testing download..."); | ||
| 130 | |||
| 131 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 132 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 133 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 134 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 135 | |||
| 136 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); | ||
| 137 | if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { | ||
| 138 | error!("connect error: {:?}", e); | ||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | info!("connected, testing..."); | ||
| 142 | |||
| 143 | let mut rx_buf = [0; 4096]; | ||
| 144 | let mut total: usize = 0; | ||
| 145 | with_timeout(Duration::from_secs(TEST_DURATION as _), async { | ||
| 146 | loop { | ||
| 147 | match socket.read(&mut rx_buf).await { | ||
| 148 | Ok(0) => { | ||
| 149 | error!("read EOF"); | ||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | Ok(n) => total += n, | ||
| 153 | Err(e) => { | ||
| 154 | error!("read error: {:?}", e); | ||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | }) | ||
| 160 | .await | ||
| 161 | .ok(); | ||
| 162 | |||
| 163 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 164 | info!("download: {} kB/s", kbps); | ||
| 165 | kbps | ||
| 166 | } | ||
| 167 | |||
| 168 | async fn test_upload(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize { | ||
| 169 | info!("Testing upload..."); | ||
| 170 | |||
| 171 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 172 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 173 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 174 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 175 | |||
| 176 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); | ||
| 177 | if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { | ||
| 178 | error!("connect error: {:?}", e); | ||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | info!("connected, testing..."); | ||
| 182 | |||
| 183 | let buf = [0; 4096]; | ||
| 184 | let mut total: usize = 0; | ||
| 185 | with_timeout(Duration::from_secs(TEST_DURATION as _), async { | ||
| 186 | loop { | ||
| 187 | match socket.write(&buf).await { | ||
| 188 | Ok(0) => { | ||
| 189 | error!("write zero?!??!?!"); | ||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | Ok(n) => total += n, | ||
| 193 | Err(e) => { | ||
| 194 | error!("write error: {:?}", e); | ||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } | ||
| 199 | }) | ||
| 200 | .await | ||
| 201 | .ok(); | ||
| 202 | |||
| 203 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 204 | info!("upload: {} kB/s", kbps); | ||
| 205 | kbps | ||
| 206 | } | ||
| 207 | |||
| 208 | async fn test_upload_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize { | ||
| 209 | info!("Testing upload+download..."); | ||
| 210 | |||
| 211 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 212 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 213 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 214 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 215 | |||
| 216 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); | ||
| 217 | if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { | ||
| 218 | error!("connect error: {:?}", e); | ||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | info!("connected, testing..."); | ||
| 222 | |||
| 223 | let (mut reader, mut writer) = socket.split(); | ||
| 224 | |||
| 225 | let tx_buf = [0; 4096]; | ||
| 226 | let mut rx_buf = [0; 4096]; | ||
| 227 | let mut total: usize = 0; | ||
| 228 | let tx_fut = async { | ||
| 229 | loop { | ||
| 230 | match writer.write(&tx_buf).await { | ||
| 231 | Ok(0) => { | ||
| 232 | error!("write zero?!??!?!"); | ||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | Ok(_) => {} | ||
| 236 | Err(e) => { | ||
| 237 | error!("write error: {:?}", e); | ||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | } | ||
| 242 | }; | ||
| 243 | |||
| 244 | let rx_fut = async { | ||
| 245 | loop { | ||
| 246 | match reader.read(&mut rx_buf).await { | ||
| 247 | Ok(0) => { | ||
| 248 | error!("read EOF"); | ||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | Ok(n) => total += n, | ||
| 252 | Err(e) => { | ||
| 253 | error!("read error: {:?}", e); | ||
| 254 | return 0; | ||
| 255 | } | ||
| 256 | } | ||
| 257 | } | ||
| 258 | }; | ||
| 259 | |||
| 260 | with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) | ||
| 261 | .await | ||
| 262 | .ok(); | ||
| 263 | |||
| 264 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 265 | info!("upload+download: {} kB/s", kbps); | ||
| 266 | kbps | ||
| 267 | } | ||
diff --git a/tests/rp/src/bin/float.rs b/tests/rp/src/bin/float.rs index 6a982507a..0e0de85fa 100644 --- a/tests/rp/src/bin/float.rs +++ b/tests/rp/src/bin/float.rs | |||
| @@ -18,11 +18,9 @@ async fn main(_spawner: Spawner) { | |||
| 18 | const PI_F: f32 = 3.1415926535f32; | 18 | const PI_F: f32 = 3.1415926535f32; |
| 19 | const PI_D: f64 = 3.14159265358979323846f64; | 19 | const PI_D: f64 = 3.14159265358979323846f64; |
| 20 | 20 | ||
| 21 | unsafe { | 21 | pac::BUSCTRL |
| 22 | pac::BUSCTRL | 22 | .perfsel(0) |
| 23 | .perfsel(0) | 23 | .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM)); |
| 24 | .write(|r| r.set_perfsel(pac::busctrl::vals::Perfsel::ROM)); | ||
| 25 | } | ||
| 26 | 24 | ||
| 27 | for i in 0..=360 { | 25 | for i in 0..=360 { |
| 28 | let rad_f = (i as f32) * PI_F / 180.0; | 26 | let rad_f = (i as f32) * PI_F / 180.0; |
| @@ -46,7 +44,7 @@ async fn main(_spawner: Spawner) { | |||
| 46 | Timer::after(Duration::from_millis(10)).await; | 44 | Timer::after(Duration::from_millis(10)).await; |
| 47 | } | 45 | } |
| 48 | 46 | ||
| 49 | let rom_accesses = unsafe { pac::BUSCTRL.perfctr(0).read().perfctr() }; | 47 | let rom_accesses = pac::BUSCTRL.perfctr(0).read().perfctr(); |
| 50 | // every float operation used here uses at least 10 cycles | 48 | // every float operation used here uses at least 10 cycles |
| 51 | defmt::assert!(rom_accesses >= 360 * 12 * 10); | 49 | defmt::assert!(rom_accesses >= 360 * 12 * 10); |
| 52 | 50 | ||
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 0f96c4ca3..365f631b7 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -12,24 +12,25 @@ stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma"] # Nucleo | |||
| 12 | stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo | 12 | stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo |
| 13 | stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo | 13 | stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo |
| 14 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo | 14 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma"] # Nucleo |
| 15 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble"] # Nucleo | 15 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble" ] # Nucleo |
| 16 | stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo | 16 | stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo |
| 17 | stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board | 17 | stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board |
| 18 | 18 | ||
| 19 | sdmmc = [] | 19 | sdmmc = [] |
| 20 | chrono = ["embassy-stm32/chrono", "dep:chrono"] | 20 | chrono = ["embassy-stm32/chrono", "dep:chrono"] |
| 21 | ble = [] | ||
| 22 | can = [] | 21 | can = [] |
| 22 | ble = ["dep:embassy-stm32-wpan"] | ||
| 23 | not-gpdma = [] | 23 | not-gpdma = [] |
| 24 | 24 | ||
| 25 | [dependencies] | 25 | [dependencies] |
| 26 | teleprobe-meta = "1" | 26 | teleprobe-meta = "1" |
| 27 | 27 | ||
| 28 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 28 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 29 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 29 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 30 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } | 30 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } |
| 31 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } | 31 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } |
| 32 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 32 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 33 | embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg"] } | ||
| 33 | 34 | ||
| 34 | defmt = "0.3.0" | 35 | defmt = "0.3.0" |
| 35 | defmt-rtt = "0.4" | 36 | defmt-rtt = "0.4" |
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs index 32d35c42c..582df5753 100644 --- a/tests/stm32/src/bin/rtc.rs +++ b/tests/stm32/src/bin/rtc.rs | |||
| @@ -24,10 +24,8 @@ async fn main(_spawner: Spawner) { | |||
| 24 | 24 | ||
| 25 | info!("Starting LSI"); | 25 | info!("Starting LSI"); |
| 26 | 26 | ||
| 27 | unsafe { | 27 | pac::RCC.csr().modify(|w| w.set_lsion(true)); |
| 28 | pac::RCC.csr().modify(|w| w.set_lsion(true)); | 28 | while !pac::RCC.csr().read().lsirdy() {} |
| 29 | while !pac::RCC.csr().read().lsirdy() {} | ||
| 30 | } | ||
| 31 | 29 | ||
| 32 | info!("Started LSI"); | 30 | info!("Started LSI"); |
| 33 | 31 | ||
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs index fab9f0e1b..f6641ae31 100644 --- a/tests/stm32/src/bin/tl_mbox.rs +++ b/tests/stm32/src/bin/tl_mbox.rs | |||
| @@ -6,49 +6,70 @@ | |||
| 6 | #[path = "../common.rs"] | 6 | #[path = "../common.rs"] |
| 7 | mod common; | 7 | mod common; |
| 8 | 8 | ||
| 9 | use core::mem; | ||
| 10 | |||
| 9 | use common::*; | 11 | use common::*; |
| 10 | use embassy_executor::Spawner; | 12 | use embassy_executor::Spawner; |
| 11 | use embassy_stm32::tl_mbox::{Config, TlMbox}; | 13 | use embassy_futures::poll_once; |
| 12 | use embassy_stm32::{bind_interrupts, tl_mbox}; | 14 | use embassy_stm32::bind_interrupts; |
| 15 | use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; | ||
| 16 | use embassy_stm32_wpan::{mm, TlMbox}; | ||
| 13 | use embassy_time::{Duration, Timer}; | 17 | use embassy_time::{Duration, Timer}; |
| 14 | 18 | ||
| 15 | bind_interrupts!(struct Irqs{ | 19 | bind_interrupts!(struct Irqs{ |
| 16 | IPCC_C1_RX => tl_mbox::ReceiveInterruptHandler; | 20 | IPCC_C1_RX => ReceiveInterruptHandler; |
| 17 | IPCC_C1_TX => tl_mbox::TransmitInterruptHandler; | 21 | IPCC_C1_TX => TransmitInterruptHandler; |
| 18 | }); | 22 | }); |
| 19 | 23 | ||
| 24 | #[embassy_executor::task] | ||
| 25 | async fn run_mm_queue(memory_manager: mm::MemoryManager) { | ||
| 26 | memory_manager.run_queue().await; | ||
| 27 | } | ||
| 28 | |||
| 20 | #[embassy_executor::main] | 29 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 30 | async fn main(spawner: Spawner) { |
| 22 | let p = embassy_stm32::init(config()); | 31 | let p = embassy_stm32::init(config()); |
| 23 | info!("Hello World!"); | 32 | info!("Hello World!"); |
| 24 | 33 | ||
| 25 | let config = Config::default(); | 34 | let config = Config::default(); |
| 26 | let mbox = TlMbox::new(p.IPCC, Irqs, config); | 35 | let mbox = TlMbox::init(p.IPCC, Irqs, config); |
| 36 | |||
| 37 | spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap(); | ||
| 38 | |||
| 39 | let ready_event = mbox.sys_subsystem.read().await; | ||
| 40 | let _ = poll_once(mbox.sys_subsystem.read()); // clear rx not | ||
| 41 | |||
| 42 | info!("coprocessor ready {}", ready_event.payload()); | ||
| 43 | |||
| 44 | // test memory manager | ||
| 45 | mem::drop(ready_event); | ||
| 46 | |||
| 47 | let fw_info = mbox.sys_subsystem.wireless_fw_info().unwrap(); | ||
| 48 | let version_major = fw_info.version_major(); | ||
| 49 | let version_minor = fw_info.version_minor(); | ||
| 50 | let subversion = fw_info.subversion(); | ||
| 51 | |||
| 52 | let sram2a_size = fw_info.sram2a_size(); | ||
| 53 | let sram2b_size = fw_info.sram2b_size(); | ||
| 54 | |||
| 55 | info!( | ||
| 56 | "version {}.{}.{} - SRAM2a {} - SRAM2b {}", | ||
| 57 | version_major, version_minor, subversion, sram2a_size, sram2b_size | ||
| 58 | ); | ||
| 27 | 59 | ||
| 28 | loop { | 60 | Timer::after(Duration::from_millis(50)).await; |
| 29 | let wireless_fw_info = mbox.wireless_fw_info(); | ||
| 30 | match wireless_fw_info { | ||
| 31 | None => {} | ||
| 32 | Some(fw_info) => { | ||
| 33 | let version_major = fw_info.version_major(); | ||
| 34 | let version_minor = fw_info.version_minor(); | ||
| 35 | let subversion = fw_info.subversion(); | ||
| 36 | 61 | ||
| 37 | let sram2a_size = fw_info.sram2a_size(); | 62 | mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; |
| 38 | let sram2b_size = fw_info.sram2b_size(); | ||
| 39 | 63 | ||
| 40 | info!( | 64 | info!("starting ble..."); |
| 41 | "version {}.{}.{} - SRAM2a {} - SRAM2b {}", | 65 | mbox.ble_subsystem.write(0x0c, &[]).await; |
| 42 | version_major, version_minor, subversion, sram2a_size, sram2b_size | ||
| 43 | ); | ||
| 44 | 66 | ||
| 45 | break; | 67 | info!("waiting for ble..."); |
| 46 | } | 68 | let ble_event = mbox.ble_subsystem.read().await; |
| 47 | } | ||
| 48 | 69 | ||
| 49 | Timer::after(Duration::from_millis(50)).await; | 70 | info!("ble event: {}", ble_event.payload()); |
| 50 | } | ||
| 51 | 71 | ||
| 72 | Timer::after(Duration::from_millis(150)).await; | ||
| 52 | info!("Test OK"); | 73 | info!("Test OK"); |
| 53 | cortex_m::asm::bkpt(); | 74 | cortex_m::asm::bkpt(); |
| 54 | } | 75 | } |
