mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-27 04:10:25 +00:00
Merge remote-tracking branch 'upstream/main' into adc_v3-enums
This commit is contained in:
commit
42c21a24e5
3
.github/ci/build-nightly.sh
vendored
3
.github/ci/build-nightly.sh
vendored
@ -7,6 +7,7 @@ set -euo pipefail
|
||||
export RUSTUP_HOME=/ci/cache/rustup
|
||||
export CARGO_HOME=/ci/cache/cargo
|
||||
export CARGO_TARGET_DIR=/ci/cache/target
|
||||
export PATH=$CARGO_HOME/bin:$PATH
|
||||
mv rust-toolchain-nightly.toml rust-toolchain.toml
|
||||
|
||||
# needed for "dumb HTTP" transport support
|
||||
@ -22,6 +23,8 @@ fi
|
||||
hashtime restore /ci/cache/filetime.json || true
|
||||
hashtime save /ci/cache/filetime.json
|
||||
|
||||
cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe
|
||||
|
||||
./ci-nightly.sh
|
||||
|
||||
# Save lockfiles
|
||||
|
11
.github/ci/build-xtensa.sh
vendored
11
.github/ci/build-xtensa.sh
vendored
@ -7,13 +7,14 @@ set -euo pipefail
|
||||
export RUSTUP_HOME=/ci/cache/rustup
|
||||
export CARGO_HOME=/ci/cache/cargo
|
||||
export CARGO_TARGET_DIR=/ci/cache/target
|
||||
export PATH=$CARGO_HOME/bin:$PATH
|
||||
|
||||
# needed for "dumb HTTP" transport support
|
||||
# used when pointing stm32-metapac to a CI-built one.
|
||||
export CARGO_NET_GIT_FETCH_WITH_CLI=true
|
||||
|
||||
cargo install espup
|
||||
/ci/cache/cargo/bin/espup install --toolchain-version 1.84.0.0
|
||||
cargo install espup --locked
|
||||
espup install --toolchain-version 1.88.0.0
|
||||
|
||||
# Restore lockfiles
|
||||
if [ -f /ci/cache/lockfiles.tar ]; then
|
||||
@ -24,11 +25,7 @@ fi
|
||||
hashtime restore /ci/cache/filetime.json || true
|
||||
hashtime save /ci/cache/filetime.json
|
||||
|
||||
mkdir .cargo
|
||||
cat > .cargo/config.toml<< EOF
|
||||
[unstable]
|
||||
build-std = ["alloc", "core"]
|
||||
EOF
|
||||
cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe
|
||||
|
||||
./ci-xtensa.sh
|
||||
|
||||
|
3
.github/ci/build.sh
vendored
3
.github/ci/build.sh
vendored
@ -7,6 +7,7 @@ set -euo pipefail
|
||||
export RUSTUP_HOME=/ci/cache/rustup
|
||||
export CARGO_HOME=/ci/cache/cargo
|
||||
export CARGO_TARGET_DIR=/ci/cache/target
|
||||
export PATH=$CARGO_HOME/bin:$PATH
|
||||
if [ -f /ci/secrets/teleprobe-token.txt ]; then
|
||||
echo Got teleprobe token!
|
||||
export TELEPROBE_HOST=https://teleprobe.embassy.dev
|
||||
@ -27,6 +28,8 @@ fi
|
||||
hashtime restore /ci/cache/filetime.json || true
|
||||
hashtime save /ci/cache/filetime.json
|
||||
|
||||
cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe
|
||||
|
||||
./ci.sh
|
||||
|
||||
# Save lockfiles
|
||||
|
68
.github/ci/doc.sh
vendored
68
.github/ci/doc.sh
vendored
@ -19,42 +19,42 @@ mv rust-toolchain-nightly.toml rust-toolchain.toml
|
||||
# which makes rustup very sad
|
||||
rustc --version > /dev/null
|
||||
|
||||
docserver-builder -i ./embassy-boot -o webroot/crates/embassy-boot/git.zup
|
||||
docserver-builder -i ./embassy-boot-nrf -o webroot/crates/embassy-boot-nrf/git.zup
|
||||
docserver-builder -i ./embassy-boot-rp -o webroot/crates/embassy-boot-rp/git.zup
|
||||
docserver-builder -i ./embassy-boot-stm32 -o webroot/crates/embassy-boot-stm32/git.zup
|
||||
docserver-builder -i ./embassy-embedded-hal -o webroot/crates/embassy-embedded-hal/git.zup
|
||||
docserver-builder -i ./embassy-executor -o webroot/crates/embassy-executor/git.zup
|
||||
docserver-builder -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup
|
||||
docserver-builder -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup
|
||||
docserver-builder -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup
|
||||
docserver-builder -i ./embassy-mspm0 -o webroot/crates/embassy-mspm0/git.zup
|
||||
docserver-builder -i ./embassy-nxp -o webroot/crates/embassy-nxp/git.zup
|
||||
docserver-builder -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup
|
||||
docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup
|
||||
docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup
|
||||
docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static
|
||||
docserver build -i ./embassy-boot -o webroot/crates/embassy-boot/git.zup
|
||||
docserver build -i ./embassy-boot-nrf -o webroot/crates/embassy-boot-nrf/git.zup
|
||||
docserver build -i ./embassy-boot-rp -o webroot/crates/embassy-boot-rp/git.zup
|
||||
docserver build -i ./embassy-boot-stm32 -o webroot/crates/embassy-boot-stm32/git.zup
|
||||
docserver build -i ./embassy-embedded-hal -o webroot/crates/embassy-embedded-hal/git.zup
|
||||
docserver build -i ./embassy-executor -o webroot/crates/embassy-executor/git.zup
|
||||
docserver build -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup
|
||||
docserver build -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup
|
||||
docserver build -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup
|
||||
docserver build -i ./embassy-mspm0 -o webroot/crates/embassy-mspm0/git.zup
|
||||
docserver build -i ./embassy-nxp -o webroot/crates/embassy-nxp/git.zup
|
||||
docserver build -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup
|
||||
docserver build -i ./cyw43 -o webroot/crates/cyw43/git.zup
|
||||
docserver build -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup
|
||||
docserver build -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static
|
||||
|
||||
docserver-builder -i ./embassy-time -o webroot/crates/embassy-time/git.zup
|
||||
docserver-builder -i ./embassy-time-driver -o webroot/crates/embassy-time-driver/git.zup
|
||||
docserver-builder -i ./embassy-time-queue-utils -o webroot/crates/embassy-time-queue-utils/git.zup
|
||||
docserver build -i ./embassy-time -o webroot/crates/embassy-time/git.zup
|
||||
docserver build -i ./embassy-time-driver -o webroot/crates/embassy-time-driver/git.zup
|
||||
docserver build -i ./embassy-time-queue-utils -o webroot/crates/embassy-time-queue-utils/git.zup
|
||||
|
||||
docserver-builder -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup
|
||||
docserver-builder -i ./embassy-usb-dfu -o webroot/crates/embassy-usb-dfu/git.zup
|
||||
docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup
|
||||
docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup
|
||||
docserver-builder -i ./embassy-usb-synopsys-otg -o webroot/crates/embassy-usb-synopsys-otg/git.zup
|
||||
docserver build -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup
|
||||
docserver build -i ./embassy-usb-dfu -o webroot/crates/embassy-usb-dfu/git.zup
|
||||
docserver build -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup
|
||||
docserver build -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup
|
||||
docserver build -i ./embassy-usb-synopsys-otg -o webroot/crates/embassy-usb-synopsys-otg/git.zup
|
||||
|
||||
docserver-builder -i ./embassy-net -o webroot/crates/embassy-net/git.zup
|
||||
docserver-builder -i ./embassy-net-nrf91 -o webroot/crates/embassy-net-nrf91/git.zup
|
||||
docserver-builder -i ./embassy-net-driver -o webroot/crates/embassy-net-driver/git.zup
|
||||
docserver-builder -i ./embassy-net-driver-channel -o webroot/crates/embassy-net-driver-channel/git.zup
|
||||
docserver-builder -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/git.zup
|
||||
docserver-builder -i ./embassy-net-ppp -o webroot/crates/embassy-net-ppp/git.zup
|
||||
docserver-builder -i ./embassy-net-tuntap -o webroot/crates/embassy-net-tuntap/git.zup
|
||||
docserver-builder -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup
|
||||
docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup
|
||||
docserver-builder -i ./embassy-net-adin1110 -o webroot/crates/embassy-net-adin1110/git.zup
|
||||
docserver build -i ./embassy-net -o webroot/crates/embassy-net/git.zup
|
||||
docserver build -i ./embassy-net-nrf91 -o webroot/crates/embassy-net-nrf91/git.zup
|
||||
docserver build -i ./embassy-net-driver -o webroot/crates/embassy-net-driver/git.zup
|
||||
docserver build -i ./embassy-net-driver-channel -o webroot/crates/embassy-net-driver-channel/git.zup
|
||||
docserver build -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/git.zup
|
||||
docserver build -i ./embassy-net-ppp -o webroot/crates/embassy-net-ppp/git.zup
|
||||
docserver build -i ./embassy-net-tuntap -o webroot/crates/embassy-net-tuntap/git.zup
|
||||
docserver build -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup
|
||||
docserver build -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup
|
||||
docserver build -i ./embassy-net-adin1110 -o webroot/crates/embassy-net-adin1110/git.zup
|
||||
|
||||
export KUBECONFIG=/ci/secrets/kubeconfig.yml
|
||||
POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
|
||||
@ -65,6 +65,6 @@ kubectl cp webroot/static $POD:/data
|
||||
# so that it doesn't prevent other crates from getting docs updates when it breaks.
|
||||
|
||||
rm -rf webroot
|
||||
docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
|
||||
docserver build -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
|
||||
POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
|
||||
kubectl cp webroot/crates $POD:/data
|
||||
|
@ -8,19 +8,4 @@ if [[ -z "${CARGO_TARGET_DIR}" ]]; then
|
||||
export CARGO_TARGET_DIR=target_ci
|
||||
fi
|
||||
|
||||
cargo batch \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \
|
||||
--- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52840-rtic \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target armv7a-none-eabi --features nightly,arch-cortex-ar,executor-thread \
|
||||
|
||||
RUSTFLAGS="$RUSTFLAGS -C target-cpu=atmega328p" cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-none -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p
|
||||
cargo embassy-devtool build --group nightly
|
||||
|
28
ci-xtensa.sh
28
ci-xtensa.sh
@ -9,30 +9,4 @@ if [[ -z "${CARGO_TARGET_DIR}" ]]; then
|
||||
export CARGO_TARGET_DIR=target_ci
|
||||
fi
|
||||
|
||||
cargo batch \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features log \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features defmt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features defmt,arch-spin,executor-thread \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,arch-spin,executor-thread \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s3-none-elf --features defmt,arch-spin,executor-thread \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,rtos-trace \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread \
|
||||
--- build --release --manifest-path embassy-sync/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \
|
||||
--- build --release --manifest-path embassy-time/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,defmt-timestamp-uptime,mock-driver \
|
||||
--- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target xtensa-esp32s2-none-elf \
|
||||
--- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target xtensa-esp32s2-none-elf --features generic-queue-8 \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,dhcpv4-hostname \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \
|
||||
cargo embassy-devtool build --group xtensa
|
||||
|
352
ci.sh
352
ci.sh
@ -10,355 +10,21 @@ if ! command -v cargo-batch &> /dev/null; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v cargo-embassy-devtool &> /dev/null; then
|
||||
echo "cargo-embassy-devtool could not be found. Install it with the following command:"
|
||||
echo ""
|
||||
echo " cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export RUSTFLAGS=-Dwarnings
|
||||
export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
|
||||
if [[ -z "${CARGO_TARGET_DIR}" ]]; then
|
||||
export CARGO_TARGET_DIR=target_ci
|
||||
fi
|
||||
|
||||
TARGET=$(rustc -vV | sed -n 's|host: ||p')
|
||||
|
||||
BUILD_EXTRA=""
|
||||
if [ $TARGET = "x86_64-unknown-linux-gnu" ] || [ $TARGET = "aarch64-unknown-linux-gnu" ]; then
|
||||
BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --artifact-dir out/examples/std"
|
||||
fi
|
||||
|
||||
# CI intentionally does not use -eabihf on thumbv7em to minimize dep compile time.
|
||||
cargo batch \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,metadata-name \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,trace \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,rtos-trace \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,trace,rtos-trace \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target armv7a-none-eabi --features arch-cortex-ar,executor-thread \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabi --features arch-cortex-ar,executor-thread \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabihf --features arch-cortex-ar,executor-thread \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \
|
||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \
|
||||
--- build --release --manifest-path embassy-embedded-hal/Cargo.toml --target thumbv7em-none-eabi \
|
||||
--- build --release --manifest-path embassy-embedded-hal/Cargo.toml --target thumbv7em-none-eabi --features time \
|
||||
--- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \
|
||||
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,mock-driver \
|
||||
--- build --release --manifest-path embassy-time/Cargo.toml --features defmt,std \
|
||||
--- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target thumbv6m-none-eabi \
|
||||
--- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target thumbv6m-none-eabi --features generic-queue-8 \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,dhcpv4-hostname \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \
|
||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \
|
||||
--- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt633s,defmt,unstable-pac,time,time-driver-rtc \
|
||||
--- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt685s,defmt,unstable-pac,time,time-driver-rtc \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52820,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832,gpiote,time,time-driver-rtc1,reset-pin-as-gpio \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833,gpiote,time,time-driver-rtc1,nfc-pins-as-gpio \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-s,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-ns,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-s,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-ns,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-net,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf54l15-app-s,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf54l15-app-ns,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,log,time \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,log,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,log,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \
|
||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt,rp2040 \
|
||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log,rp2040 \
|
||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics,rp2040 \
|
||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio,rp2040 \
|
||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235xa \
|
||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235xa \
|
||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,rp235xa,binary-info \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,single-bank,defmt \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c071rb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c051f6,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c091gb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c092rc,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f038f6,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030c6,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f058t8,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030r8,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f031k6,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030rc,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f070f6,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f078vb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f042g4,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f072c8,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f401ve,defmt,exti,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f405zg,defmt,exti,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f407zg,defmt,exti,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f401ve,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f405zg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f407zg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f412zg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f413vh,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f415zg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f417zg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f423zh,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f427zi,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f437zi,log,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f439zi,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446ze,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f469zi,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f479zi,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f730i8,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h735zg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time,split-pc2,split-pc3 \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-tim1,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7r3z8,defmt,exti,time-driver-tim1,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7r7a8,defmt,exti,time-driver-tim1,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s3a8,defmt,exti,time-driver-tim1,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s7z8,defmt,exti,time-driver-tim1,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb15cc,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l041f6,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l051k8,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073cz,defmt,exti,time-driver-any,low-power,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303c8,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f398ve,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0b0ce,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0c1ve,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,low-power,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32wl54jc-cm0p,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wle5jb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g431kb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g474pe,dual-bank,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103re,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100c4,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h523cc,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h562ag,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba50ke,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba55ug,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba62cg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba65ri,defmt,exti,time-driver-any,low-power,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5f9zj,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5g9nj,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb35ce,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg,defmt,exti,time-driver-any,low-power,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u031r8,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf --features lpc55,defmt \
|
||||
--- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1011,rt,defmt,time-driver-pit \
|
||||
--- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1062,rt,defmt,time-driver-pit \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1104dgs20,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1106rgz,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507pm,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3519pz,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1306rhb,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l2228pn,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1345dgs28,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1106dgs28,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1228pm,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1107ycj,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3105rhb,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1505pt,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1519rhb,rt,defmt,time-driver-any \
|
||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
|
||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
|
||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
|
||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \
|
||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \
|
||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs,bluetooth' \
|
||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs,bluetooth' \
|
||||
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \
|
||||
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \
|
||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf5340-app-s \
|
||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
|
||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
|
||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \
|
||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \
|
||||
--- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi --features embassy-rp/rp2040 \
|
||||
--- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \
|
||||
--- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --no-default-features \
|
||||
--- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi \
|
||||
--- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features log \
|
||||
--- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features defmt \
|
||||
--- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features usbd-hid \
|
||||
--- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-interface-count-1 \
|
||||
--- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-interface-count-8 \
|
||||
--- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-handler-count-8 \
|
||||
--- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-handler-count-8 \
|
||||
--- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
|
||||
--- build --release --manifest-path docs/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
|
||||
--- build --release --manifest-path docs/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
|
||||
--- build --release --manifest-path docs/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
|
||||
--- build --release --manifest-path docs/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
|
||||
--- build --release --manifest-path examples/nrf52810/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52810 \
|
||||
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52840 \
|
||||
--- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf5340 \
|
||||
--- build --release --manifest-path examples/nrf54l15/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf54l15 \
|
||||
--- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf9160 \
|
||||
--- build --release --manifest-path examples/nrf9151/s/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf9151/s \
|
||||
--- build --release --manifest-path examples/nrf9151/ns/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf9151/ns \
|
||||
--- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/nrf51 \
|
||||
--- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/rp \
|
||||
--- build --release --manifest-path examples/rp235x/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/rp235x \
|
||||
--- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32f0 \
|
||||
--- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32f1 \
|
||||
--- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32f2 \
|
||||
--- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f3 \
|
||||
--- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f334 \
|
||||
--- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f4 \
|
||||
--- build --release --manifest-path examples/stm32f469/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f469 \
|
||||
--- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f7 \
|
||||
--- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32c0 \
|
||||
--- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32g0 \
|
||||
--- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32g4 \
|
||||
--- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32h5 \
|
||||
--- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h7 \
|
||||
--- build --release --manifest-path examples/stm32h7b0/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h7b0 \
|
||||
--- build --release --manifest-path examples/stm32h723/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h723 \
|
||||
--- build --release --manifest-path examples/stm32h735/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h735 \
|
||||
--- build --release --manifest-path examples/stm32h755cm4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h755cm4 \
|
||||
--- build --release --manifest-path examples/stm32h755cm7/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h755cm7 \
|
||||
--- build --release --manifest-path examples/stm32h7rs/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h7rs \
|
||||
--- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32l0 \
|
||||
--- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32l1 \
|
||||
--- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32l4 \
|
||||
--- build --release --manifest-path examples/stm32l432/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32l432 \
|
||||
--- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32l5 \
|
||||
--- build --release --manifest-path examples/stm32u0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32u0 \
|
||||
--- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32u5 \
|
||||
--- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wb \
|
||||
--- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \
|
||||
--- build --release --manifest-path examples/stm32wba6/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba6 \
|
||||
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \
|
||||
--- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \
|
||||
--- build --release --manifest-path examples/mimxrt1011/Cargo.toml --target thumbv7em-none-eabihf --artifact-dir out/examples/mimxrt1011 \
|
||||
--- build --release --manifest-path examples/mimxrt1062-evk/Cargo.toml --target thumbv7em-none-eabihf --artifact-dir out/examples/mimxrt1062-evk \
|
||||
--- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \
|
||||
--- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \
|
||||
--- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \
|
||||
--- build --release --manifest-path examples/mspm0l2228/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l2228 \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --artifact-dir out/examples/boot/nrf52840 \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --artifact-dir out/examples/boot/nrf9160 \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --artifact-dir out/examples/boot/nrf9120 \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns,skip-include --artifact-dir out/examples/boot/nrf9151 \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns,skip-include --artifact-dir out/examples/boot/nrf9161 \
|
||||
--- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --artifact-dir out/examples/boot/rp \
|
||||
--- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32f3 \
|
||||
--- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32f7 \
|
||||
--- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32h7 \
|
||||
--- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32l0 \
|
||||
--- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32l1 \
|
||||
--- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32l4 \
|
||||
--- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32wl \
|
||||
--- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/boot/stm32wb-dfu \
|
||||
--- build --release --manifest-path examples/boot/application/stm32wba-dfu/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/boot/stm32wba-dfu \
|
||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
|
||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
|
||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \
|
||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \
|
||||
--- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
|
||||
--- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \
|
||||
--- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \
|
||||
--- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg,verify \
|
||||
--- build --release --manifest-path examples/boot/bootloader/stm32wba-dfu/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-stm32/stm32wba65ri,verify \
|
||||
--- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h743zi \
|
||||
--- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --artifact-dir out/examples/wasm \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100rd --artifact-dir out/tests/stm32f100rd \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --artifact-dir out/tests/stm32f103c8 \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc --artifact-dir out/tests/stm32f107vc \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --artifact-dir out/tests/stm32f429zi \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446re --artifact-dir out/tests/stm32f446re \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --artifact-dir out/tests/stm32g491re \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --artifact-dir out/tests/stm32g071rb \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --artifact-dir out/tests/stm32c031c6 \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c071rb --artifact-dir out/tests/stm32c071rb \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --artifact-dir out/tests/stm32h755zi \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi --artifact-dir out/tests/stm32h753zi \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7a3zi --artifact-dir out/tests/stm32h7a3zi \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --artifact-dir out/tests/stm32wb55rg \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h563zi --artifact-dir out/tests/stm32h563zi \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u585ai --artifact-dir out/tests/stm32u585ai \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5a5zj --artifact-dir out/tests/stm32u5a5zj \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba52cg --artifact-dir out/tests/stm32wba52cg \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --artifact-dir out/tests/stm32l073rz \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --artifact-dir out/tests/stm32l152re \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --artifact-dir out/tests/stm32l4a6zg \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r5zi --artifact-dir out/tests/stm32l4r5zi \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze --artifact-dir out/tests/stm32l552ze \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f767zi --artifact-dir out/tests/stm32f767zi \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f207zg --artifact-dir out/tests/stm32f207zg \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --artifact-dir out/tests/stm32f303ze \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --artifact-dir out/tests/stm32l496zg \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --artifact-dir out/tests/stm32wl55jc \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s3l8 --artifact-dir out/tests/stm32h7s3l8 \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f091rc --artifact-dir out/tests/stm32f091rc \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb --artifact-dir out/tests/stm32h503rb \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc --artifact-dir out/tests/stm32u083rc \
|
||||
--- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --features rp2040 --artifact-dir out/tests/rpi-pico \
|
||||
--- build --release --manifest-path tests/rp/Cargo.toml --target thumbv8m.main-none-eabihf --features rp235xb --artifact-dir out/tests/pimoroni-pico-plus-2 \
|
||||
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51422 --artifact-dir out/tests/nrf51422-dk \
|
||||
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832 --artifact-dir out/tests/nrf52832-dk \
|
||||
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833 --artifact-dir out/tests/nrf52833-dk \
|
||||
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840 --artifact-dir out/tests/nrf52840-dk \
|
||||
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340 --artifact-dir out/tests/nrf5340-dk \
|
||||
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160 --artifact-dir out/tests/nrf9160-dk \
|
||||
--- build --release --manifest-path tests/mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507 --artifact-dir out/tests/mspm0g3507 \
|
||||
--- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
|
||||
$BUILD_EXTRA
|
||||
|
||||
|
||||
# MSPM0C1104 must be built seperately since cargo batch does not consider env vars set in `.cargo/config.toml`.
|
||||
# Since the target has 1KB of ram, we need to limit defmt's buffer size.
|
||||
DEFMT_RTT_BUFFER_SIZE="72" cargo batch \
|
||||
--- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 \
|
||||
cargo embassy-devtool build
|
||||
|
||||
# temporarily disabled, these boards are dead.
|
||||
rm -rf out/tests/stm32f103c8
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]!
|
||||
|
||||
_newer entries at the top_
|
||||
|
||||
* link:https://github.com/CarlKCarlK/clock[Embassy Clock: Layered, modular bare-metal clock with emulation]
|
||||
** A `no_std` Raspberry Pi Pico clock demonstrating layered Embassy tasks (Display->Blinker->Clock) for clean separation of multiplexing, blinking, and UI logic. Features single-button HH:MM/MM:SS time-set UI, heapless data structures, and a Renode emulator for hardware-free testing. See link:https://medium.com/@carlmkadie/how-rust-embassy-shine-on-embedded-devices-part-2-aad1adfccf72[this article] for details.
|
||||
* link:https://github.com/1-rafael-1/simple-robot[A simple tracked robot based on Raspberry Pi Pico 2]
|
||||
** A hobbyist project building a tracked robot with basic autonomous and manual drive mode.
|
||||
* link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock]
|
||||
|
@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Added new metadata API for tasks.
|
||||
- Main task automatically gets a name of `main` when the `metadata-name` feature is enabled.
|
||||
- Upgraded rtos-trace
|
||||
- Added optional "highest priority" scheduling
|
||||
- Added optional "earliest deadline first" EDF scheduling
|
||||
|
||||
## 0.9.1 - 2025-08-31
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-executor"
|
||||
version = "0.9.0"
|
||||
version = "0.9.1"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "async/await executor designed for embedded usage"
|
||||
@ -24,18 +24,49 @@ build = [
|
||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-thread"]},
|
||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt"]},
|
||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"]},
|
||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver"]},
|
||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-priority"]},
|
||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-priority", "scheduler-deadline"]},
|
||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-deadline"]},
|
||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-priority", "scheduler-deadline"]},
|
||||
{target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-deadline"]},
|
||||
{target = "armv7a-none-eabi", features = ["arch-cortex-ar", "executor-thread"]},
|
||||
{target = "armv7r-none-eabi", features = ["arch-cortex-ar", "executor-thread"]},
|
||||
{target = "armv7r-none-eabihf", features = ["arch-cortex-ar", "executor-thread"]},
|
||||
{target = "riscv32imac-unknown-none-elf", features = ["arch-riscv32"]},
|
||||
{target = "riscv32imac-unknown-none-elf", features = ["arch-riscv32", "executor-thread"]},
|
||||
# Nightly builds
|
||||
{group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly"]},
|
||||
{group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "log"]},
|
||||
{group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "defmt"]},
|
||||
{group = "nightly", target = "thumbv6m-none-eabi", features = ["nightly", "defmt"]},
|
||||
{group = "nightly", target = "thumbv6m-none-eabi", features = ["nightly", "defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"]},
|
||||
{group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "arch-cortex-m"]},
|
||||
{group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "arch-cortex-m", "executor-thread"]},
|
||||
{group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "arch-cortex-m", "executor-interrupt"]},
|
||||
{group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt"]},
|
||||
{group = "nightly", target = "riscv32imac-unknown-none-elf", features = ["nightly", "arch-riscv32"]},
|
||||
{group = "nightly", target = "riscv32imac-unknown-none-elf", features = ["nightly", "arch-riscv32", "executor-thread"]},
|
||||
{group = "nightly", target = "armv7a-none-eabi", features = ["nightly", "arch-cortex-ar", "executor-thread"]},
|
||||
{group = "nightly", target = "avr-none", features = ["nightly", "arch-avr", "avr-device/atmega328p"], build-std = ["core", "alloc"], env = { RUSTFLAGS = "-Ctarget-cpu=atmega328p" }},
|
||||
# Xtensa builds
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = []},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["log"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = ["defmt"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "arch-spin", "executor-thread"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = ["defmt", "arch-spin", "executor-thread"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s3-none-elf", features = ["defmt", "arch-spin", "executor-thread"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["arch-spin"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["arch-spin", "rtos-trace"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["arch-spin", "executor-thread"]},
|
||||
]
|
||||
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/"
|
||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/"
|
||||
features = ["defmt"]
|
||||
features = ["defmt", "scheduler-deadline", "scheduler-priority"]
|
||||
flavors = [
|
||||
{ name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] },
|
||||
{ name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] },
|
||||
@ -46,7 +77,7 @@ flavors = [
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "thumbv7em-none-eabi"
|
||||
targets = ["thumbv7em-none-eabi"]
|
||||
features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"]
|
||||
features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt", "scheduler-deadline", "scheduler-priority", "embassy-time-driver"]
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "1.0.1", optional = true }
|
||||
@ -76,6 +107,11 @@ js-sys = { version = "0.3", optional = true }
|
||||
# arch-avr dependencies
|
||||
avr-device = { version = "0.7.0", optional = true }
|
||||
|
||||
|
||||
[dependencies.cordyceps]
|
||||
version = "0.3.4"
|
||||
features = ["no-cache-pad"]
|
||||
|
||||
[dev-dependencies]
|
||||
critical-section = { version = "1.1", features = ["std"] }
|
||||
trybuild = "1.0"
|
||||
@ -123,5 +159,16 @@ executor-interrupt = []
|
||||
## Enable tracing hooks
|
||||
trace = ["_any_trace"]
|
||||
## Enable support for rtos-trace framework
|
||||
rtos-trace = ["_any_trace", "metadata-name", "dep:rtos-trace", "dep:embassy-time-driver"]
|
||||
rtos-trace = ["_any_trace", "metadata-name", "dep:rtos-trace", "embassy-time-driver"]
|
||||
_any_trace = []
|
||||
|
||||
## Enable "Earliest Deadline First" Scheduler, using soft-realtime "deadlines" to prioritize
|
||||
## tasks based on the remaining time before their deadline. Adds some overhead.
|
||||
scheduler-deadline = []
|
||||
|
||||
## Enable "Highest Priority First" Scheduler. Adds some overhead.
|
||||
scheduler-priority = []
|
||||
|
||||
## Enable the embassy_time_driver dependency.
|
||||
## This can unlock extra APIs, for example for the `sheduler-deadline`
|
||||
embassy-time-driver = ["dep:embassy-time-driver"]
|
||||
|
@ -1,17 +1,25 @@
|
||||
#[cfg(feature = "metadata-name")]
|
||||
use core::cell::Cell;
|
||||
use core::future::{poll_fn, Future};
|
||||
#[cfg(feature = "scheduler-priority")]
|
||||
use core::sync::atomic::{AtomicU8, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
#[cfg(feature = "metadata-name")]
|
||||
use critical_section::Mutex;
|
||||
|
||||
use crate::raw;
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
use crate::raw::Deadline;
|
||||
|
||||
/// Metadata associated with a task.
|
||||
pub struct Metadata {
|
||||
#[cfg(feature = "metadata-name")]
|
||||
name: Mutex<Cell<Option<&'static str>>>,
|
||||
#[cfg(feature = "scheduler-priority")]
|
||||
priority: AtomicU8,
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
deadline: raw::Deadline,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
@ -19,12 +27,26 @@ impl Metadata {
|
||||
Self {
|
||||
#[cfg(feature = "metadata-name")]
|
||||
name: Mutex::new(Cell::new(None)),
|
||||
#[cfg(feature = "scheduler-priority")]
|
||||
priority: AtomicU8::new(0),
|
||||
// NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This
|
||||
// will be lazily initalized in `initialize_impl`
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
deadline: raw::Deadline::new_unset(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reset(&self) {
|
||||
#[cfg(feature = "metadata-name")]
|
||||
critical_section::with(|cs| self.name.borrow(cs).set(None));
|
||||
|
||||
#[cfg(feature = "scheduler-priority")]
|
||||
self.set_priority(0);
|
||||
|
||||
// By default, deadlines are set to the maximum value, so that any task WITH
|
||||
// a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
self.unset_deadline();
|
||||
}
|
||||
|
||||
/// Get the metadata for the current task.
|
||||
@ -52,4 +74,75 @@ impl Metadata {
|
||||
pub fn set_name(&self, name: &'static str) {
|
||||
critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
|
||||
}
|
||||
|
||||
/// Get this task's priority.
|
||||
#[cfg(feature = "scheduler-priority")]
|
||||
pub fn priority(&self) -> u8 {
|
||||
self.priority.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Set this task's priority.
|
||||
#[cfg(feature = "scheduler-priority")]
|
||||
pub fn set_priority(&self, priority: u8) {
|
||||
self.priority.store(priority, Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Get this task's deadline.
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
pub fn deadline(&self) -> u64 {
|
||||
self.deadline.instant_ticks()
|
||||
}
|
||||
|
||||
/// Set this task's deadline.
|
||||
///
|
||||
/// This method does NOT check whether the deadline has already passed.
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
pub fn set_deadline(&self, instant_ticks: u64) {
|
||||
self.deadline.set(instant_ticks);
|
||||
}
|
||||
|
||||
/// Remove this task's deadline.
|
||||
/// This brings it back to the defaul where it's not scheduled ahead of other tasks.
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
pub fn unset_deadline(&self) {
|
||||
self.deadline.set(Deadline::UNSET_TICKS);
|
||||
}
|
||||
|
||||
/// Set this task's deadline `duration_ticks` in the future from when
|
||||
/// this future is polled. This deadline is saturated to the max tick value.
|
||||
///
|
||||
/// Analogous to `Timer::after`.
|
||||
#[cfg(all(feature = "scheduler-deadline", feature = "embassy-time-driver"))]
|
||||
pub fn set_deadline_after(&self, duration_ticks: u64) {
|
||||
let now = embassy_time_driver::now();
|
||||
|
||||
// Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
|
||||
// it for now, we can probably make this wrapping_add for performance
|
||||
// reasons later.
|
||||
let deadline = now.saturating_add(duration_ticks);
|
||||
|
||||
self.set_deadline(deadline);
|
||||
}
|
||||
|
||||
/// Set the this task's deadline `increment_ticks` from the previous deadline.
|
||||
///
|
||||
/// This deadline is saturated to the max tick value.
|
||||
///
|
||||
/// Note that by default (unless otherwise set), tasks start life with the deadline
|
||||
/// not set, which means this method will have no effect.
|
||||
///
|
||||
/// Analogous to one increment of `Ticker::every().next()`.
|
||||
///
|
||||
/// Returns the deadline that was set.
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
pub fn increment_deadline(&self, duration_ticks: u64) {
|
||||
let last = self.deadline();
|
||||
|
||||
// Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
|
||||
// it for now, we can probably make this wrapping_add for performance
|
||||
// reasons later.
|
||||
let deadline = last.saturating_add(duration_ticks);
|
||||
|
||||
self.set_deadline(deadline);
|
||||
}
|
||||
}
|
||||
|
44
embassy-executor/src/raw/deadline.rs
Normal file
44
embassy-executor/src/raw/deadline.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
/// A type for interacting with the deadline of the current task
|
||||
///
|
||||
/// Requires the `scheduler-deadline` feature.
|
||||
///
|
||||
/// Note: Interacting with the deadline should be done locally in a task.
|
||||
/// In theory you could try to set or read the deadline from another task,
|
||||
/// but that will result in weird (though not unsound) behavior.
|
||||
pub(crate) struct Deadline {
|
||||
instant_ticks_hi: AtomicU32,
|
||||
instant_ticks_lo: AtomicU32,
|
||||
}
|
||||
|
||||
impl Deadline {
|
||||
pub(crate) const fn new(instant_ticks: u64) -> Self {
|
||||
Self {
|
||||
instant_ticks_hi: AtomicU32::new((instant_ticks >> 32) as u32),
|
||||
instant_ticks_lo: AtomicU32::new(instant_ticks as u32),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn new_unset() -> Self {
|
||||
Self::new(Self::UNSET_TICKS)
|
||||
}
|
||||
|
||||
pub(crate) fn set(&self, instant_ticks: u64) {
|
||||
self.instant_ticks_hi
|
||||
.store((instant_ticks >> 32) as u32, Ordering::Relaxed);
|
||||
self.instant_ticks_lo.store(instant_ticks as u32, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Deadline value in ticks, same time base and ticks as `embassy-time`
|
||||
pub(crate) fn instant_ticks(&self) -> u64 {
|
||||
let hi = self.instant_ticks_hi.load(Ordering::Relaxed) as u64;
|
||||
let lo = self.instant_ticks_lo.load(Ordering::Relaxed) as u64;
|
||||
|
||||
(hi << 32) | lo
|
||||
}
|
||||
|
||||
/// Sentinel value representing an "unset" deadline, which has lower priority
|
||||
/// than any other set deadline value
|
||||
pub(crate) const UNSET_TICKS: u64 = u64::MAX;
|
||||
}
|
@ -7,8 +7,6 @@
|
||||
//! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe
|
||||
//! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_executor_macros::task) macro, which are fully safe.
|
||||
|
||||
#[cfg_attr(target_has_atomic = "ptr", path = "run_queue_atomics.rs")]
|
||||
#[cfg_attr(not(target_has_atomic = "ptr"), path = "run_queue_critical_section.rs")]
|
||||
mod run_queue;
|
||||
|
||||
#[cfg_attr(all(cortex_m, target_has_atomic = "32"), path = "state_atomics_arm.rs")]
|
||||
@ -28,6 +26,9 @@ pub(crate) mod util;
|
||||
#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")]
|
||||
mod waker;
|
||||
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
mod deadline;
|
||||
|
||||
use core::future::Future;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
@ -38,6 +39,8 @@ use core::sync::atomic::AtomicPtr;
|
||||
use core::sync::atomic::Ordering;
|
||||
use core::task::{Context, Poll, Waker};
|
||||
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
pub(crate) use deadline::Deadline;
|
||||
use embassy_executor_timer_queue::TimerQueueItem;
|
||||
#[cfg(feature = "arch-avr")]
|
||||
use portable_atomic::AtomicPtr;
|
||||
@ -96,6 +99,7 @@ extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static
|
||||
pub(crate) struct TaskHeader {
|
||||
pub(crate) state: State,
|
||||
pub(crate) run_queue_item: RunQueueItem,
|
||||
|
||||
pub(crate) executor: AtomicPtr<SyncExecutor>,
|
||||
poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
|
||||
|
||||
|
213
embassy-executor/src/raw/run_queue.rs
Normal file
213
embassy-executor/src/raw/run_queue.rs
Normal file
@ -0,0 +1,213 @@
|
||||
use core::ptr::{addr_of_mut, NonNull};
|
||||
|
||||
use cordyceps::sorted_list::Links;
|
||||
use cordyceps::Linked;
|
||||
#[cfg(any(feature = "scheduler-priority", feature = "scheduler-deadline"))]
|
||||
use cordyceps::SortedList;
|
||||
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
type TransferStack<T> = cordyceps::TransferStack<T>;
|
||||
|
||||
#[cfg(not(target_has_atomic = "ptr"))]
|
||||
type TransferStack<T> = MutexTransferStack<T>;
|
||||
|
||||
use super::{TaskHeader, TaskRef};
|
||||
|
||||
/// Use `cordyceps::sorted_list::Links` as the singly linked list
|
||||
/// for RunQueueItems.
|
||||
pub(crate) type RunQueueItem = Links<TaskHeader>;
|
||||
|
||||
/// Implements the `Linked` trait, allowing for singly linked list usage
|
||||
/// of any of cordyceps' `TransferStack` (used for the atomic runqueue),
|
||||
/// `SortedList` (used with the DRS scheduler), or `Stack`, which is
|
||||
/// popped atomically from the `TransferStack`.
|
||||
unsafe impl Linked<Links<TaskHeader>> for TaskHeader {
|
||||
type Handle = TaskRef;
|
||||
|
||||
// Convert a TaskRef into a TaskHeader ptr
|
||||
fn into_ptr(r: TaskRef) -> NonNull<TaskHeader> {
|
||||
r.ptr
|
||||
}
|
||||
|
||||
// Convert a TaskHeader into a TaskRef
|
||||
unsafe fn from_ptr(ptr: NonNull<TaskHeader>) -> TaskRef {
|
||||
TaskRef { ptr }
|
||||
}
|
||||
|
||||
// Given a pointer to a TaskHeader, obtain a pointer to the Links structure,
|
||||
// which can be used to traverse to other TaskHeader nodes in the linked list
|
||||
unsafe fn links(ptr: NonNull<TaskHeader>) -> NonNull<Links<TaskHeader>> {
|
||||
let ptr: *mut TaskHeader = ptr.as_ptr();
|
||||
NonNull::new_unchecked(addr_of_mut!((*ptr).run_queue_item))
|
||||
}
|
||||
}
|
||||
|
||||
/// Atomic task queue using a very, very simple lock-free linked-list queue:
|
||||
///
|
||||
/// To enqueue a task, task.next is set to the old head, and head is atomically set to task.
|
||||
///
|
||||
/// Dequeuing is done in batches: the queue is emptied by atomically replacing head with
|
||||
/// null. Then the batch is iterated following the next pointers until null is reached.
|
||||
///
|
||||
/// Note that batches will be iterated in the reverse order as they were enqueued. This is OK
|
||||
/// for our purposes: it can't create fairness problems since the next batch won't run until the
|
||||
/// current batch is completely processed, so even if a task enqueues itself instantly (for example
|
||||
/// by waking its own waker) can't prevent other tasks from running.
|
||||
pub(crate) struct RunQueue {
|
||||
stack: TransferStack<TaskHeader>,
|
||||
}
|
||||
|
||||
impl RunQueue {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
stack: TransferStack::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enqueues an item. Returns true if the queue was empty.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `item` must NOT be already enqueued in any queue.
|
||||
#[inline(always)]
|
||||
pub(crate) unsafe fn enqueue(&self, task: TaskRef, _tok: super::state::Token) -> bool {
|
||||
self.stack.push_was_empty(
|
||||
task,
|
||||
#[cfg(not(target_has_atomic = "ptr"))]
|
||||
_tok,
|
||||
)
|
||||
}
|
||||
|
||||
/// # Standard atomic runqueue
|
||||
///
|
||||
/// Empty the queue, then call `on_task` for each task that was in the queue.
|
||||
/// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue
|
||||
/// and will be processed by the *next* call to `dequeue_all`, *not* the current one.
|
||||
#[cfg(not(any(feature = "scheduler-priority", feature = "scheduler-deadline")))]
|
||||
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
||||
let taken = self.stack.take_all();
|
||||
for taskref in taken {
|
||||
run_dequeue(&taskref);
|
||||
on_task(taskref);
|
||||
}
|
||||
}
|
||||
|
||||
/// # Earliest Deadline First Scheduler
|
||||
///
|
||||
/// This algorithm will loop until all enqueued tasks are processed.
|
||||
///
|
||||
/// Before polling a task, all currently enqueued tasks will be popped from the
|
||||
/// runqueue, and will be added to the working `sorted` list, a linked-list that
|
||||
/// sorts tasks by their deadline, with nearest deadline items in the front, and
|
||||
/// furthest deadline items in the back.
|
||||
///
|
||||
/// After popping and sorting all pending tasks, the SOONEST task will be popped
|
||||
/// from the front of the queue, and polled by calling `on_task` on it.
|
||||
///
|
||||
/// This process will repeat until the local `sorted` queue AND the global
|
||||
/// runqueue are both empty, at which point this function will return.
|
||||
#[cfg(any(feature = "scheduler-priority", feature = "scheduler-deadline"))]
|
||||
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
||||
let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| {
|
||||
// compare by priority first
|
||||
#[cfg(feature = "scheduler-priority")]
|
||||
{
|
||||
let lp = lhs.metadata.priority();
|
||||
let rp = rhs.metadata.priority();
|
||||
if lp != rp {
|
||||
return lp.cmp(&rp).reverse();
|
||||
}
|
||||
}
|
||||
// compare deadlines in case of tie.
|
||||
#[cfg(feature = "scheduler-deadline")]
|
||||
{
|
||||
let ld = lhs.metadata.deadline();
|
||||
let rd = rhs.metadata.deadline();
|
||||
if ld != rd {
|
||||
return ld.cmp(&rd);
|
||||
}
|
||||
}
|
||||
core::cmp::Ordering::Equal
|
||||
});
|
||||
|
||||
loop {
|
||||
// For each loop, grab any newly pended items
|
||||
let taken = self.stack.take_all();
|
||||
|
||||
// Sort these into the list - this is potentially expensive! We do an
|
||||
// insertion sort of new items, which iterates the linked list.
|
||||
//
|
||||
// Something on the order of `O(n * m)`, where `n` is the number
|
||||
// of new tasks, and `m` is the number of already pending tasks.
|
||||
sorted.extend(taken);
|
||||
|
||||
// Pop the task with the SOONEST deadline. If there are no tasks
|
||||
// pending, then we are done.
|
||||
let Some(taskref) = sorted.pop_front() else {
|
||||
return;
|
||||
};
|
||||
|
||||
// We got one task, mark it as dequeued, and process the task.
|
||||
run_dequeue(&taskref);
|
||||
on_task(taskref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// atomic state does not require a cs...
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
#[inline(always)]
|
||||
fn run_dequeue(taskref: &TaskRef) {
|
||||
taskref.header().state.run_dequeue();
|
||||
}
|
||||
|
||||
/// ...while non-atomic state does
|
||||
#[cfg(not(target_has_atomic = "ptr"))]
|
||||
#[inline(always)]
|
||||
fn run_dequeue(taskref: &TaskRef) {
|
||||
critical_section::with(|cs| {
|
||||
taskref.header().state.run_dequeue(cs);
|
||||
})
|
||||
}
|
||||
|
||||
/// A wrapper type that acts like TransferStack by wrapping a normal Stack in a CS mutex
|
||||
#[cfg(not(target_has_atomic = "ptr"))]
|
||||
struct MutexTransferStack<T: Linked<cordyceps::stack::Links<T>>> {
|
||||
inner: critical_section::Mutex<core::cell::UnsafeCell<cordyceps::Stack<T>>>,
|
||||
}
|
||||
|
||||
#[cfg(not(target_has_atomic = "ptr"))]
|
||||
impl<T: Linked<cordyceps::stack::Links<T>>> MutexTransferStack<T> {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
inner: critical_section::Mutex::new(core::cell::UnsafeCell::new(cordyceps::Stack::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Push an item to the transfer stack, returning whether the stack was previously empty
|
||||
fn push_was_empty(&self, item: T::Handle, token: super::state::Token) -> bool {
|
||||
// SAFETY: The critical-section mutex guarantees that there is no *concurrent* access
|
||||
// for the lifetime of the token, but does NOT protect against re-entrant access.
|
||||
// However, we never *return* the reference, nor do we recurse (or call another method
|
||||
// like `take_all`) that could ever allow for re-entrant aliasing. Therefore, the
|
||||
// presence of the critical section is sufficient to guarantee exclusive access to
|
||||
// the `inner` field for the purposes of this function.
|
||||
let inner = unsafe { &mut *self.inner.borrow(token).get() };
|
||||
let is_empty = inner.is_empty();
|
||||
inner.push(item);
|
||||
is_empty
|
||||
}
|
||||
|
||||
fn take_all(&self) -> cordyceps::Stack<T> {
|
||||
critical_section::with(|cs| {
|
||||
// SAFETY: The critical-section mutex guarantees that there is no *concurrent* access
|
||||
// for the lifetime of the token, but does NOT protect against re-entrant access.
|
||||
// However, we never *return* the reference, nor do we recurse (or call another method
|
||||
// like `push_was_empty`) that could ever allow for re-entrant aliasing. Therefore, the
|
||||
// presence of the critical section is sufficient to guarantee exclusive access to
|
||||
// the `inner` field for the purposes of this function.
|
||||
let inner = unsafe { &mut *self.inner.borrow(cs).get() };
|
||||
inner.take_all()
|
||||
})
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
use core::ptr;
|
||||
use core::ptr::NonNull;
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
|
||||
use super::{TaskHeader, TaskRef};
|
||||
use crate::raw::util::SyncUnsafeCell;
|
||||
|
||||
pub(crate) struct RunQueueItem {
|
||||
next: SyncUnsafeCell<Option<TaskRef>>,
|
||||
}
|
||||
|
||||
impl RunQueueItem {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
next: SyncUnsafeCell::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Atomic task queue using a very, very simple lock-free linked-list queue:
|
||||
///
|
||||
/// To enqueue a task, task.next is set to the old head, and head is atomically set to task.
|
||||
///
|
||||
/// Dequeuing is done in batches: the queue is emptied by atomically replacing head with
|
||||
/// null. Then the batch is iterated following the next pointers until null is reached.
|
||||
///
|
||||
/// Note that batches will be iterated in the reverse order as they were enqueued. This is OK
|
||||
/// for our purposes: it can't create fairness problems since the next batch won't run until the
|
||||
/// current batch is completely processed, so even if a task enqueues itself instantly (for example
|
||||
/// by waking its own waker) can't prevent other tasks from running.
|
||||
pub(crate) struct RunQueue {
|
||||
head: AtomicPtr<TaskHeader>,
|
||||
}
|
||||
|
||||
impl RunQueue {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
head: AtomicPtr::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enqueues an item. Returns true if the queue was empty.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `item` must NOT be already enqueued in any queue.
|
||||
#[inline(always)]
|
||||
pub(crate) unsafe fn enqueue(&self, task: TaskRef, _: super::state::Token) -> bool {
|
||||
let mut was_empty = false;
|
||||
|
||||
self.head
|
||||
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
|
||||
was_empty = prev.is_null();
|
||||
unsafe {
|
||||
// safety: the pointer is either null or valid
|
||||
let prev = NonNull::new(prev).map(|ptr| TaskRef::from_ptr(ptr.as_ptr()));
|
||||
// safety: there are no concurrent accesses to `next`
|
||||
task.header().run_queue_item.next.set(prev);
|
||||
}
|
||||
Some(task.as_ptr() as *mut _)
|
||||
})
|
||||
.ok();
|
||||
|
||||
was_empty
|
||||
}
|
||||
|
||||
/// Empty the queue, then call `on_task` for each task that was in the queue.
|
||||
/// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue
|
||||
/// and will be processed by the *next* call to `dequeue_all`, *not* the current one.
|
||||
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
||||
// Atomically empty the queue.
|
||||
let ptr = self.head.swap(ptr::null_mut(), Ordering::AcqRel);
|
||||
|
||||
// safety: the pointer is either null or valid
|
||||
let mut next = unsafe { NonNull::new(ptr).map(|ptr| TaskRef::from_ptr(ptr.as_ptr())) };
|
||||
|
||||
// Iterate the linked list of tasks that were previously in the queue.
|
||||
while let Some(task) = next {
|
||||
// If the task re-enqueues itself, the `next` pointer will get overwritten.
|
||||
// Therefore, first read the next pointer, and only then process the task.
|
||||
// safety: there are no concurrent accesses to `next`
|
||||
next = unsafe { task.header().run_queue_item.next.get() };
|
||||
|
||||
task.header().state.run_dequeue();
|
||||
on_task(task);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
use core::cell::Cell;
|
||||
|
||||
use critical_section::{CriticalSection, Mutex};
|
||||
|
||||
use super::TaskRef;
|
||||
|
||||
pub(crate) struct RunQueueItem {
|
||||
next: Mutex<Cell<Option<TaskRef>>>,
|
||||
}
|
||||
|
||||
impl RunQueueItem {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
next: Mutex::new(Cell::new(None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Atomic task queue using a very, very simple lock-free linked-list queue:
|
||||
///
|
||||
/// To enqueue a task, task.next is set to the old head, and head is atomically set to task.
|
||||
///
|
||||
/// Dequeuing is done in batches: the queue is emptied by atomically replacing head with
|
||||
/// null. Then the batch is iterated following the next pointers until null is reached.
|
||||
///
|
||||
/// Note that batches will be iterated in the reverse order as they were enqueued. This is OK
|
||||
/// for our purposes: it can't create fairness problems since the next batch won't run until the
|
||||
/// current batch is completely processed, so even if a task enqueues itself instantly (for example
|
||||
/// by waking its own waker) can't prevent other tasks from running.
|
||||
pub(crate) struct RunQueue {
|
||||
head: Mutex<Cell<Option<TaskRef>>>,
|
||||
}
|
||||
|
||||
impl RunQueue {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
head: Mutex::new(Cell::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enqueues an item. Returns true if the queue was empty.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `item` must NOT be already enqueued in any queue.
|
||||
#[inline(always)]
|
||||
pub(crate) unsafe fn enqueue(&self, task: TaskRef, cs: CriticalSection<'_>) -> bool {
|
||||
let prev = self.head.borrow(cs).replace(Some(task));
|
||||
task.header().run_queue_item.next.borrow(cs).set(prev);
|
||||
|
||||
prev.is_none()
|
||||
}
|
||||
|
||||
/// Empty the queue, then call `on_task` for each task that was in the queue.
|
||||
/// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue
|
||||
/// and will be processed by the *next* call to `dequeue_all`, *not* the current one.
|
||||
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
||||
// Atomically empty the queue.
|
||||
let mut next = critical_section::with(|cs| self.head.borrow(cs).take());
|
||||
|
||||
// Iterate the linked list of tasks that were previously in the queue.
|
||||
while let Some(task) = next {
|
||||
// If the task re-enqueues itself, the `next` pointer will get overwritten.
|
||||
// Therefore, first read the next pointer, and only then process the task.
|
||||
|
||||
critical_section::with(|cs| {
|
||||
next = task.header().run_queue_item.next.borrow(cs).get();
|
||||
task.header().state.run_dequeue(cs);
|
||||
});
|
||||
|
||||
on_task(task);
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
<!-- next-header -->
|
||||
## Unreleased - ReleaseDate
|
||||
|
||||
- Added experimental W6100 driver with disabled MAC filter (does not currently work with it enabled)
|
||||
- Introduced `SOCKET_INTR_CLR` register which is needed on W6100 and later models (on W5100/W5500 this is shared with `SOCKET_INTR` and the address is the same)
|
||||
|
||||
## 0.2.1 - 2025-08-26
|
||||
|
||||
## 0.1.1 - 2025-08-14
|
||||
|
@ -4,6 +4,8 @@ pub use w5500::W5500;
|
||||
mod w5100s;
|
||||
use embedded_hal_async::spi::SpiDevice;
|
||||
pub use w5100s::W5100S;
|
||||
mod w6100;
|
||||
pub use w6100::W6100;
|
||||
|
||||
pub(crate) trait SealedChip {
|
||||
type Address;
|
||||
@ -28,7 +30,9 @@ pub(crate) trait SealedChip {
|
||||
const SOCKET_RECVD_SIZE: Self::Address;
|
||||
const SOCKET_RX_DATA_READ_PTR: Self::Address;
|
||||
const SOCKET_INTR_MASK: Self::Address;
|
||||
#[allow(dead_code)]
|
||||
const SOCKET_INTR: Self::Address;
|
||||
const SOCKET_INTR_CLR: Self::Address;
|
||||
|
||||
const SOCKET_MODE_VALUE: u8;
|
||||
|
||||
|
@ -29,6 +29,7 @@ impl super::SealedChip for W5100S {
|
||||
const SOCKET_RX_DATA_READ_PTR: Self::Address = SOCKET_BASE + 0x28;
|
||||
const SOCKET_INTR_MASK: Self::Address = SOCKET_BASE + 0x2C;
|
||||
const SOCKET_INTR: Self::Address = SOCKET_BASE + 0x02;
|
||||
const SOCKET_INTR_CLR: Self::Address = SOCKET_BASE + 0x02;
|
||||
|
||||
const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 6);
|
||||
|
||||
|
@ -33,6 +33,7 @@ impl super::SealedChip for W5500 {
|
||||
const SOCKET_RX_DATA_READ_PTR: Self::Address = (RegisterBlock::Socket0, 0x28);
|
||||
const SOCKET_INTR_MASK: Self::Address = (RegisterBlock::Socket0, 0x2C);
|
||||
const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x02);
|
||||
const SOCKET_INTR_CLR: Self::Address = (RegisterBlock::Socket0, 0x02);
|
||||
|
||||
const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 7);
|
||||
|
||||
|
83
embassy-net-wiznet/src/chip/w6100.rs
Normal file
83
embassy-net-wiznet/src/chip/w6100.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use embedded_hal_async::spi::{Operation, SpiDevice};
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum RegisterBlock {
|
||||
Common = 0x00,
|
||||
Socket0 = 0x01,
|
||||
TxBuf = 0x02,
|
||||
RxBuf = 0x03,
|
||||
}
|
||||
|
||||
/// Wiznet W6100 chip.
|
||||
pub enum W6100 {}
|
||||
|
||||
impl super::Chip for W6100 {}
|
||||
impl super::SealedChip for W6100 {
|
||||
type Address = (RegisterBlock, u16);
|
||||
|
||||
const CHIP_VERSION: u8 = 0x46;
|
||||
|
||||
const COMMON_MODE: Self::Address = (RegisterBlock::Common, 0x2004);
|
||||
const COMMON_MAC: Self::Address = (RegisterBlock::Common, 0x4120);
|
||||
// SIMR (SOCKET Interrupt Mask Register)
|
||||
const COMMON_SOCKET_INTR: Self::Address = (RegisterBlock::Common, 0x2114);
|
||||
const COMMON_PHY_CFG: Self::Address = (RegisterBlock::Common, 0x3000);
|
||||
const COMMON_VERSION: Self::Address = (RegisterBlock::Common, 0x0002);
|
||||
|
||||
const SOCKET_MODE: Self::Address = (RegisterBlock::Socket0, 0x0000);
|
||||
const SOCKET_COMMAND: Self::Address = (RegisterBlock::Socket0, 0x0010);
|
||||
const SOCKET_RXBUF_SIZE: Self::Address = (RegisterBlock::Socket0, 0x0220);
|
||||
const SOCKET_TXBUF_SIZE: Self::Address = (RegisterBlock::Socket0, 0x0200);
|
||||
const SOCKET_TX_FREE_SIZE: Self::Address = (RegisterBlock::Socket0, 0x0204);
|
||||
const SOCKET_TX_DATA_WRITE_PTR: Self::Address = (RegisterBlock::Socket0, 0x020C);
|
||||
const SOCKET_RECVD_SIZE: Self::Address = (RegisterBlock::Socket0, 0x0224);
|
||||
const SOCKET_RX_DATA_READ_PTR: Self::Address = (RegisterBlock::Socket0, 0x0228);
|
||||
// Sn_IMR (SOCKET n Interrupt Mask Register)
|
||||
const SOCKET_INTR_MASK: Self::Address = (RegisterBlock::Socket0, 0x0024);
|
||||
// Sn_IR (SOCKET n Interrupt Register)
|
||||
const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x0020);
|
||||
// Sn_IRCLR (Sn_IR Clear Register)
|
||||
const SOCKET_INTR_CLR: Self::Address = (RegisterBlock::Socket0, 0x0028);
|
||||
|
||||
// MACRAW mode. See Page 57 of https://docs.wiznet.io/img/products/w6100/w6100_ds_v105e.pdf
|
||||
// Note: Bit 7 is MAC filter. On the W5500 this is normally turned ON however the W6100 will not successfully retrieve an IP address with this enabled. Disabling for now and will have live with the extra noise.
|
||||
const SOCKET_MODE_VALUE: u8 = 0b0000_0111;
|
||||
|
||||
const BUF_SIZE: u16 = 0x1000;
|
||||
const AUTO_WRAP: bool = true;
|
||||
|
||||
fn rx_addr(addr: u16) -> Self::Address {
|
||||
(RegisterBlock::RxBuf, addr)
|
||||
}
|
||||
|
||||
fn tx_addr(addr: u16) -> Self::Address {
|
||||
(RegisterBlock::TxBuf, addr)
|
||||
}
|
||||
|
||||
async fn bus_read<SPI: SpiDevice>(
|
||||
spi: &mut SPI,
|
||||
address: Self::Address,
|
||||
data: &mut [u8],
|
||||
) -> Result<(), SPI::Error> {
|
||||
let address_phase = address.1.to_be_bytes();
|
||||
let control_phase = [(address.0 as u8) << 3];
|
||||
let operations = &mut [
|
||||
Operation::Write(&address_phase),
|
||||
Operation::Write(&control_phase),
|
||||
Operation::TransferInPlace(data),
|
||||
];
|
||||
spi.transaction(operations).await
|
||||
}
|
||||
|
||||
async fn bus_write<SPI: SpiDevice>(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error> {
|
||||
let address_phase = address.1.to_be_bytes();
|
||||
let control_phase = [(address.0 as u8) << 3 | 0b0000_0100];
|
||||
let data_phase = data;
|
||||
let operations = &mut [
|
||||
Operation::Write(&address_phase[..]),
|
||||
Operation::Write(&control_phase),
|
||||
Operation::Write(&data_phase),
|
||||
];
|
||||
spi.transaction(operations).await
|
||||
}
|
||||
}
|
@ -125,7 +125,7 @@ impl<C: Chip, SPI: SpiDevice> WiznetDevice<C, SPI> {
|
||||
|
||||
async fn reset_interrupt(&mut self, code: Interrupt) -> Result<(), SPI::Error> {
|
||||
let data = [code as u8];
|
||||
self.bus_write(C::SOCKET_INTR, &data).await
|
||||
self.bus_write(C::SOCKET_INTR_CLR, &data).await
|
||||
}
|
||||
|
||||
async fn get_tx_write_ptr(&mut self) -> Result<u16, SPI::Error> {
|
||||
|
@ -26,6 +26,19 @@ build = [
|
||||
{target = "thumbv7em-none-eabi", features = ["defmt", "dns", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp", "udp"]},
|
||||
{target = "thumbv7em-none-eabi", features = ["defmt", "dns", "medium-ethernet", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp", "udp"]},
|
||||
{target = "thumbv7em-none-eabi", features = ["defmt", "dns", "medium-ethernet", "medium-ieee802154", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp", "udp"]},
|
||||
# Xtensa builds
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "medium-ethernet", "packet-trace"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "multicast", "medium-ethernet"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "medium-ethernet"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "medium-ethernet", "dhcpv4-hostname"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv6", "medium-ethernet"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv6", "medium-ieee802154"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv6", "medium-ethernet", "medium-ieee802154"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv6", "medium-ethernet"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "proto-ipv6", "medium-ethernet"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "proto-ipv6", "medium-ip"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "proto-ipv6", "medium-ip", "medium-ethernet"]},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "proto-ipv6", "medium-ip", "medium-ethernet", "medium-ieee802154"]},
|
||||
]
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
|
@ -25,6 +25,7 @@ unimplemented features of the network protocols.
|
||||
- [`embassy-stm32`](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32) for the builtin Ethernet MAC in all STM32 chips (STM32F1, STM32F2, STM32F4, STM32F7, STM32H7, STM32H5).
|
||||
- [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips (W5100S, W5500)
|
||||
- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU.
|
||||
- [`embassy-nrf`](https://github.com/embassy-rs/embassy/tree/main/embassy-nrf) for IEEE 802.15.4 support on nrf chips.
|
||||
|
||||
## Examples
|
||||
|
||||
|
@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## Unreleased - ReleaseDate
|
||||
|
||||
- changed: nrf54l: Disable glitch detection and enable DC/DC in init.
|
||||
- changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4
|
||||
|
||||
## 0.7.0 - 2025-08-26
|
||||
|
||||
|
@ -79,6 +79,9 @@ gpiote = []
|
||||
## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz
|
||||
time-driver-rtc1 = ["_time-driver"]
|
||||
|
||||
## Enable embassy-net 802.15.4 driver
|
||||
net-driver = ["_net-driver"]
|
||||
|
||||
## Allow using the NFC pins as regular GPIO pins (P0_09/P0_10 on nRF52, P0_02/P0_03 on nRF53)
|
||||
nfc-pins-as-gpio = []
|
||||
|
||||
@ -154,6 +157,8 @@ _nrf91 = []
|
||||
|
||||
_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"]
|
||||
|
||||
_net-driver = ["dep:embassy-net-driver-channel","dep:embassy-futures"]
|
||||
|
||||
# trustzone state.
|
||||
_s = []
|
||||
_ns = []
|
||||
@ -177,6 +182,8 @@ embassy-sync = { version = "0.7.2", path = "../embassy-sync" }
|
||||
embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
|
||||
embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal", default-features = false }
|
||||
embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" }
|
||||
embassy-net-driver-channel = { version = "0.3.2", path = "../embassy-net-driver-channel", optional = true}
|
||||
embassy-futures = { version = "0.1.2", path = "../embassy-futures", optional = true}
|
||||
|
||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
|
||||
|
@ -28,6 +28,10 @@ allows running Rust code without a SPM or TF-M binary, saving flash space and si
|
||||
|
||||
If the `time-driver-rtc1` feature is enabled, the HAL uses the RTC peripheral as a global time driver for [embassy-time](https://crates.io/crates/embassy-time), with a tick rate of 32768 Hz.
|
||||
|
||||
## Embassy-net-driver
|
||||
|
||||
If the board supports IEEE 802.15.4 (see `src/radio/mod.rs`) the corresponding [embassy-net-driver](https://crates.io/crates/embassy-net-driver) implementation can be enabled with the feature `net-driver`.
|
||||
|
||||
## Embedded-hal
|
||||
|
||||
The `embassy-nrf` HAL implements the traits from [embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and [embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as [embedded-io](https://crates.io/crates/embedded-io) and [embedded-io-async](https://crates.io/crates/embedded-io-async).
|
||||
|
96
embassy-nrf/src/embassy_net_802154_driver.rs
Normal file
96
embassy-nrf/src/embassy_net_802154_driver.rs
Normal file
@ -0,0 +1,96 @@
|
||||
//! embassy-net IEEE 802.15.4 driver
|
||||
|
||||
use embassy_futures::select::{select3, Either3};
|
||||
use embassy_net_driver_channel::driver::LinkState;
|
||||
use embassy_net_driver_channel::{self as ch};
|
||||
use embassy_time::{Duration, Ticker};
|
||||
|
||||
use crate::radio::ieee802154::{Packet, Radio};
|
||||
use crate::radio::InterruptHandler;
|
||||
use crate::{self as nrf, interrupt};
|
||||
|
||||
/// MTU for the nrf radio.
|
||||
pub const MTU: usize = Packet::CAPACITY as usize;
|
||||
|
||||
/// embassy-net device for the driver.
|
||||
pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>;
|
||||
|
||||
/// Internal state for the embassy-net driver.
|
||||
pub struct State<const N_RX: usize, const N_TX: usize> {
|
||||
ch_state: ch::State<MTU, N_RX, N_TX>,
|
||||
}
|
||||
|
||||
impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> {
|
||||
/// Create a new `State`.
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
ch_state: ch::State::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Background runner for the driver.
|
||||
///
|
||||
/// You must call `.run()` in a background task for the driver to operate.
|
||||
pub struct Runner<'d, T: nrf::radio::Instance> {
|
||||
radio: nrf::radio::ieee802154::Radio<'d, T>,
|
||||
ch: ch::Runner<'d, MTU>,
|
||||
}
|
||||
|
||||
impl<'d, T: nrf::radio::Instance> Runner<'d, T> {
|
||||
/// Drives the radio. Needs to run to use the driver.
|
||||
pub async fn run(mut self) -> ! {
|
||||
let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
|
||||
let mut tick = Ticker::every(Duration::from_millis(500));
|
||||
let mut packet = Packet::new();
|
||||
state_chan.set_link_state(LinkState::Up);
|
||||
loop {
|
||||
match select3(
|
||||
async {
|
||||
let rx_buf = rx_chan.rx_buf().await;
|
||||
self.radio.receive(&mut packet).await.ok().map(|_| rx_buf)
|
||||
},
|
||||
tx_chan.tx_buf(),
|
||||
tick.next(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Either3::First(Some(rx_buf)) => {
|
||||
let len = rx_buf.len().min(packet.len() as usize);
|
||||
(&mut rx_buf[..len]).copy_from_slice(&*packet);
|
||||
rx_chan.rx_done(len);
|
||||
}
|
||||
Either3::Second(tx_buf) => {
|
||||
let len = tx_buf.len().min(Packet::CAPACITY as usize);
|
||||
packet.copy_from_slice(&tx_buf[..len]);
|
||||
self.radio.try_send(&mut packet).await.ok().unwrap();
|
||||
tx_chan.tx_done();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure to use `HfclkSource::ExternalXtal` as the `hfclk_source`
|
||||
/// to use the radio (nrf52840 product spec v1.11 5.4.1)
|
||||
/// ```
|
||||
/// # use embassy_nrf::config::*;
|
||||
/// let mut config = Config::default();
|
||||
/// config.hfclk_source = HfclkSource::ExternalXtal;
|
||||
/// ```
|
||||
pub async fn new<'a, const N_RX: usize, const N_TX: usize, T: nrf::radio::Instance, Irq>(
|
||||
mac_addr: [u8; 8],
|
||||
radio: nrf::Peri<'a, T>,
|
||||
irq: Irq,
|
||||
state: &'a mut State<N_RX, N_TX>,
|
||||
) -> Result<(Device<'a>, Runner<'a, T>), ()>
|
||||
where
|
||||
Irq: interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
|
||||
{
|
||||
let radio = Radio::new(radio, irq);
|
||||
|
||||
let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ieee802154(mac_addr));
|
||||
|
||||
Ok((device, Runner { ch: runner, radio }))
|
||||
}
|
@ -137,6 +137,17 @@ pub mod qspi;
|
||||
#[cfg(not(feature = "_nrf54l"))] // TODO
|
||||
#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))]
|
||||
pub mod radio;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "nrf52811",
|
||||
feature = "nrf52820",
|
||||
feature = "nrf52833",
|
||||
feature = "nrf52840",
|
||||
feature = "_nrf5340-net"
|
||||
))]
|
||||
#[cfg(feature = "_net-driver")]
|
||||
pub mod embassy_net_802154_driver;
|
||||
|
||||
#[cfg(not(feature = "_nrf54l"))] // TODO
|
||||
#[cfg(feature = "_nrf5340")]
|
||||
pub mod reset;
|
||||
|
@ -7,5 +7,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
<!-- next-header -->
|
||||
## Unreleased - ReleaseDate
|
||||
|
||||
- Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac`
|
||||
- First release with changelog.
|
||||
|
@ -7,7 +7,7 @@ publish = false
|
||||
|
||||
[package.metadata.embassy]
|
||||
build = [
|
||||
{target = "thumbv8m.main-none-eabihf", features = ["defmt", "lpc55"]},
|
||||
{target = "thumbv8m.main-none-eabihf", features = ["defmt", "lpc55-core0"]},
|
||||
{target = "thumbv7em-none-eabihf", features = ["defmt", "mimxrt1011", "rt", "time-driver-pit"]},
|
||||
{target = "thumbv7em-none-eabihf", features = ["defmt", "mimxrt1062", "rt", "time-driver-pit"]},
|
||||
]
|
||||
@ -18,7 +18,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nxp/s
|
||||
features = ["defmt", "unstable-pac" ] # TODO: Add time-driver-any, as both lpc55 and mimxrt1xxx use different drivers.
|
||||
|
||||
flavors = [
|
||||
{ regex_feature = "lpc55", target = "thumbv8m.main-none-eabihf" },
|
||||
{ regex_feature = "lpc55-core0", target = "thumbv8m.main-none-eabihf" },
|
||||
{ regex_feature = "mimxrt.*", target = "thumbv7em-none-eabihf" },
|
||||
]
|
||||
|
||||
@ -36,21 +36,20 @@ embassy-time-queue-utils = { version = "0.3.0", path = "../embassy-time-queue-ut
|
||||
embedded-io = "0.6.1"
|
||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||
## Chip dependencies
|
||||
lpc55-pac = { version = "0.5.0", optional = true }
|
||||
nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e" }
|
||||
nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538"}
|
||||
|
||||
imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] }
|
||||
|
||||
[build-dependencies]
|
||||
cfg_aliases = "0.2.1"
|
||||
nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e", features = ["metadata"], optional = true }
|
||||
nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538", features = ["metadata"], optional = true }
|
||||
proc-macro2 = "1.0.95"
|
||||
quote = "1.0.15"
|
||||
|
||||
[features]
|
||||
default = ["rt"]
|
||||
# Enable PACs as optional dependencies, since some chip families will use different pac crates (temporarily).
|
||||
rt = ["lpc55-pac?/rt", "nxp-pac?/rt"]
|
||||
rt = ["nxp-pac?/rt"]
|
||||
|
||||
## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
|
||||
defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"]
|
||||
@ -79,6 +78,6 @@ _rt1xxx = []
|
||||
_time_driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"]
|
||||
|
||||
#! ### Chip selection features
|
||||
lpc55 = ["dep:lpc55-pac"]
|
||||
lpc55-core0 = ["nxp-pac/lpc55s69_cm33_core0"]
|
||||
mimxrt1011 = ["nxp-pac/mimxrt1011", "_rt1xxx", "dep:imxrt-rt"]
|
||||
mimxrt1062 = ["nxp-pac/mimxrt1062", "_rt1xxx", "dep:imxrt-rt"]
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub use lpc55_pac as pac;
|
||||
pub use nxp_pac as pac;
|
||||
|
||||
embassy_hal_internal::peripherals! {
|
||||
// External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! General purpose input/output (GPIO) driver.
|
||||
#![macro_use]
|
||||
|
||||
#[cfg_attr(feature = "lpc55", path = "./gpio/lpc55.rs")]
|
||||
#[cfg_attr(feature = "lpc55-core0", path = "./gpio/lpc55.rs")]
|
||||
#[cfg_attr(rt1xxx, path = "./gpio/rt1xxx.rs")]
|
||||
mod inner;
|
||||
pub use inner::*;
|
||||
|
@ -1,12 +1,17 @@
|
||||
use embassy_hal_internal::{impl_peripheral, PeripheralType};
|
||||
|
||||
use crate::pac::iocon::vals::{PioDigimode, PioMode};
|
||||
use crate::pac::{GPIO, IOCON, SYSCON};
|
||||
use crate::{peripherals, Peri};
|
||||
|
||||
pub(crate) fn init() {
|
||||
// Enable clocks for GPIO, PINT, and IOCON
|
||||
syscon_reg()
|
||||
.ahbclkctrl0
|
||||
.modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable());
|
||||
SYSCON.ahbclkctrl0().modify(|w| {
|
||||
w.set_gpio0(true);
|
||||
w.set_gpio1(true);
|
||||
w.set_mux(true);
|
||||
w.set_iocon(true);
|
||||
});
|
||||
info!("GPIO initialized");
|
||||
}
|
||||
|
||||
@ -59,21 +64,24 @@ impl<'d> Output<'d> {
|
||||
}
|
||||
|
||||
pub fn set_high(&mut self) {
|
||||
gpio_reg().set[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) })
|
||||
GPIO.set(self.pin.pin_bank() as usize)
|
||||
.write(|w| w.set_setp(self.pin.bit()));
|
||||
}
|
||||
|
||||
pub fn set_low(&mut self) {
|
||||
gpio_reg().clr[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) })
|
||||
GPIO.clr(self.pin.pin_bank() as usize)
|
||||
.write(|w| w.set_clrp(self.pin.bit()));
|
||||
}
|
||||
|
||||
pub fn toggle(&mut self) {
|
||||
gpio_reg().not[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) })
|
||||
GPIO.not(self.pin.pin_bank() as usize)
|
||||
.write(|w| w.set_notp(self.pin.bit()));
|
||||
}
|
||||
|
||||
/// Get the current output level of the pin. Note that the value returned by this function is
|
||||
/// the voltage level reported by the pin, not the value set by the output driver.
|
||||
pub fn level(&self) -> Level {
|
||||
let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits();
|
||||
let bits = GPIO.pin(self.pin.pin_bank() as usize).read().port();
|
||||
if bits & self.pin.bit() != 0 {
|
||||
Level::High
|
||||
} else {
|
||||
@ -101,18 +109,18 @@ impl<'d> Input<'d> {
|
||||
|
||||
/// Set the pull configuration for the pin. To disable the pull, use [Pull::None].
|
||||
pub fn set_pull(&mut self, pull: Pull) {
|
||||
match_iocon!(register, iocon_reg(), self.pin.pin_bank(), self.pin.pin_number(), {
|
||||
register.modify(|_, w| match pull {
|
||||
Pull::None => w.mode().inactive(),
|
||||
Pull::Up => w.mode().pull_up(),
|
||||
Pull::Down => w.mode().pull_down(),
|
||||
match_iocon!(register, self.pin.pin_bank(), self.pin.pin_number(), {
|
||||
register.modify(|w| match pull {
|
||||
Pull::None => w.set_mode(PioMode::INACTIVE),
|
||||
Pull::Up => w.set_mode(PioMode::PULL_UP),
|
||||
Pull::Down => w.set_mode(PioMode::PULL_DOWN),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Get the current input level of the pin.
|
||||
pub fn read(&self) -> Level {
|
||||
let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits();
|
||||
let bits = GPIO.pin(self.pin.pin_bank() as usize).read().port();
|
||||
if bits & self.pin.bit() != 0 {
|
||||
Level::High
|
||||
} else {
|
||||
@ -188,8 +196,8 @@ impl<'d> Flex<'d> {
|
||||
/// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default
|
||||
/// setting for pins is (usually) non-digital.
|
||||
fn set_as_digital(&mut self) {
|
||||
match_iocon!(register, iocon_reg(), self.pin_bank(), self.pin_number(), {
|
||||
register.modify(|_, w| w.digimode().digital());
|
||||
match_iocon!(register, self.pin_bank(), self.pin_number(), {
|
||||
register.modify(|w| w.set_digimode(PioDigimode::DIGITAL));
|
||||
});
|
||||
}
|
||||
|
||||
@ -197,12 +205,14 @@ impl<'d> Flex<'d> {
|
||||
/// function handles itself.
|
||||
pub fn set_as_output(&mut self) {
|
||||
self.set_as_digital();
|
||||
gpio_reg().dirset[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirsetp().bits(self.bit()) })
|
||||
GPIO.dirset(self.pin.pin_bank() as usize)
|
||||
.write(|w| w.set_dirsetp(self.bit()))
|
||||
}
|
||||
|
||||
pub fn set_as_input(&mut self) {
|
||||
self.set_as_digital();
|
||||
gpio_reg().dirclr[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirclrp().bits(self.bit()) })
|
||||
GPIO.dirclr(self.pin.pin_bank() as usize)
|
||||
.write(|w| w.set_dirclrp(self.bit()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,52 +272,6 @@ impl SealedPin for AnyPin {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the GPIO register block. This is used to configure all GPIO pins.
|
||||
///
|
||||
/// # Safety
|
||||
/// Due to the type system of peripherals, access to the settings of a single pin is possible only
|
||||
/// by a single thread at a time. Read/Write operations on a single registers are NOT atomic. You
|
||||
/// must ensure that the GPIO registers are not accessed concurrently by multiple threads.
|
||||
pub(crate) fn gpio_reg() -> &'static lpc55_pac::gpio::RegisterBlock {
|
||||
unsafe { &*lpc55_pac::GPIO::ptr() }
|
||||
}
|
||||
|
||||
/// Get the IOCON register block.
|
||||
///
|
||||
/// # Safety
|
||||
/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
|
||||
/// registers are not accessed concurrently by multiple threads.
|
||||
pub(crate) fn iocon_reg() -> &'static lpc55_pac::iocon::RegisterBlock {
|
||||
unsafe { &*lpc55_pac::IOCON::ptr() }
|
||||
}
|
||||
|
||||
/// Get the INPUTMUX register block.
|
||||
///
|
||||
/// # Safety
|
||||
/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
|
||||
/// registers are not accessed concurrently by multiple threads.
|
||||
pub(crate) fn inputmux_reg() -> &'static lpc55_pac::inputmux::RegisterBlock {
|
||||
unsafe { &*lpc55_pac::INPUTMUX::ptr() }
|
||||
}
|
||||
|
||||
/// Get the SYSCON register block.
|
||||
///
|
||||
/// # Safety
|
||||
/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
|
||||
/// registers are not accessed concurrently by multiple threads.
|
||||
pub(crate) fn syscon_reg() -> &'static lpc55_pac::syscon::RegisterBlock {
|
||||
unsafe { &*lpc55_pac::SYSCON::ptr() }
|
||||
}
|
||||
|
||||
/// Get the PINT register block.
|
||||
///
|
||||
/// # Safety
|
||||
/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
|
||||
/// registers are not accessed concurrently by multiple threads.
|
||||
pub(crate) fn pint_reg() -> &'static lpc55_pac::pint::RegisterBlock {
|
||||
unsafe { &*lpc55_pac::PINT::ptr() }
|
||||
}
|
||||
|
||||
/// Match the pin bank and number of a pin to the corresponding IOCON register.
|
||||
///
|
||||
/// # Example
|
||||
@ -316,270 +280,26 @@ pub(crate) fn pint_reg() -> &'static lpc55_pac::pint::RegisterBlock {
|
||||
/// use embassy_nxp::pac_utils::{iocon_reg, match_iocon};
|
||||
///
|
||||
/// // Make pin PIO1_6 digital and set it to pull-down mode.
|
||||
/// match_iocon!(register, iocon_reg(), Bank::Bank1, 6, {
|
||||
/// register.modify(|_, w| w.mode().pull_down().digimode().digital());
|
||||
/// match_iocon!(register, Bank::Bank1, 6, {
|
||||
/// register.modify(|w|{
|
||||
/// w.set_mode(PioMode::PULL_DOWN);
|
||||
/// w.set_digimode(PioDigimode::DIGITAL);
|
||||
///
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
macro_rules! match_iocon {
|
||||
($register:ident, $iocon_register:expr, $pin_bank:expr, $pin_number:expr, $action:expr) => {
|
||||
match ($pin_bank, $pin_number) {
|
||||
(Bank::Bank0, 0) => {
|
||||
let $register = &($iocon_register).pio0_0;
|
||||
($register:ident, $pin_bank:expr, $pin_number:expr, $action:expr) => {
|
||||
match $pin_bank {
|
||||
Bank::Bank0 => {
|
||||
let $register = IOCON.pio0($pin_number as usize);
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 1) => {
|
||||
let $register = &($iocon_register).pio0_1;
|
||||
|
||||
Bank::Bank1 => {
|
||||
let $register = IOCON.pio1($pin_number as usize);
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 2) => {
|
||||
let $register = &($iocon_register).pio0_2;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 3) => {
|
||||
let $register = &($iocon_register).pio0_3;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 4) => {
|
||||
let $register = &($iocon_register).pio0_4;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 5) => {
|
||||
let $register = &($iocon_register).pio0_5;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 6) => {
|
||||
let $register = &($iocon_register).pio0_6;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 7) => {
|
||||
let $register = &($iocon_register).pio0_7;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 8) => {
|
||||
let $register = &($iocon_register).pio0_8;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 9) => {
|
||||
let $register = &($iocon_register).pio0_9;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 10) => {
|
||||
let $register = &($iocon_register).pio0_10;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 11) => {
|
||||
let $register = &($iocon_register).pio0_11;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 12) => {
|
||||
let $register = &($iocon_register).pio0_12;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 13) => {
|
||||
let $register = &($iocon_register).pio0_13;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 14) => {
|
||||
let $register = &($iocon_register).pio0_14;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 15) => {
|
||||
let $register = &($iocon_register).pio0_15;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 16) => {
|
||||
let $register = &($iocon_register).pio0_16;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 17) => {
|
||||
let $register = &($iocon_register).pio0_17;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 18) => {
|
||||
let $register = &($iocon_register).pio0_18;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 19) => {
|
||||
let $register = &($iocon_register).pio0_19;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 20) => {
|
||||
let $register = &($iocon_register).pio0_20;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 21) => {
|
||||
let $register = &($iocon_register).pio0_21;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 22) => {
|
||||
let $register = &($iocon_register).pio0_22;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 23) => {
|
||||
let $register = &($iocon_register).pio0_23;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 24) => {
|
||||
let $register = &($iocon_register).pio0_24;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 25) => {
|
||||
let $register = &($iocon_register).pio0_25;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 26) => {
|
||||
let $register = &($iocon_register).pio0_26;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 27) => {
|
||||
let $register = &($iocon_register).pio0_27;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 28) => {
|
||||
let $register = &($iocon_register).pio0_28;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 29) => {
|
||||
let $register = &($iocon_register).pio0_29;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 30) => {
|
||||
let $register = &($iocon_register).pio0_30;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank0, 31) => {
|
||||
let $register = &($iocon_register).pio0_31;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 0) => {
|
||||
let $register = &($iocon_register).pio1_0;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 1) => {
|
||||
let $register = &($iocon_register).pio1_1;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 2) => {
|
||||
let $register = &($iocon_register).pio1_2;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 3) => {
|
||||
let $register = &($iocon_register).pio1_3;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 4) => {
|
||||
let $register = &($iocon_register).pio1_4;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 5) => {
|
||||
let $register = &($iocon_register).pio1_5;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 6) => {
|
||||
let $register = &($iocon_register).pio1_6;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 7) => {
|
||||
let $register = &($iocon_register).pio1_7;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 8) => {
|
||||
let $register = &($iocon_register).pio1_8;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 9) => {
|
||||
let $register = &($iocon_register).pio1_9;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 10) => {
|
||||
let $register = &($iocon_register).pio1_10;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 11) => {
|
||||
let $register = &($iocon_register).pio1_11;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 12) => {
|
||||
let $register = &($iocon_register).pio1_12;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 13) => {
|
||||
let $register = &($iocon_register).pio1_13;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 14) => {
|
||||
let $register = &($iocon_register).pio1_14;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 15) => {
|
||||
let $register = &($iocon_register).pio1_15;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 16) => {
|
||||
let $register = &($iocon_register).pio1_16;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 17) => {
|
||||
let $register = &($iocon_register).pio1_17;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 18) => {
|
||||
let $register = &($iocon_register).pio1_18;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 19) => {
|
||||
let $register = &($iocon_register).pio1_19;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 20) => {
|
||||
let $register = &($iocon_register).pio1_20;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 21) => {
|
||||
let $register = &($iocon_register).pio1_21;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 22) => {
|
||||
let $register = &($iocon_register).pio1_22;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 23) => {
|
||||
let $register = &($iocon_register).pio1_23;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 24) => {
|
||||
let $register = &($iocon_register).pio1_24;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 25) => {
|
||||
let $register = &($iocon_register).pio1_25;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 26) => {
|
||||
let $register = &($iocon_register).pio1_26;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 27) => {
|
||||
let $register = &($iocon_register).pio1_27;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 28) => {
|
||||
let $register = &($iocon_register).pio1_28;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 29) => {
|
||||
let $register = &($iocon_register).pio1_29;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 30) => {
|
||||
let $register = &($iocon_register).pio1_30;
|
||||
$action;
|
||||
}
|
||||
(Bank::Bank1, 31) => {
|
||||
let $register = &($iocon_register).pio1_31;
|
||||
$action;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -4,9 +4,9 @@
|
||||
pub(crate) mod fmt;
|
||||
|
||||
pub mod gpio;
|
||||
#[cfg(feature = "lpc55")]
|
||||
#[cfg(feature = "lpc55-core0")]
|
||||
pub mod pint;
|
||||
#[cfg(feature = "lpc55")]
|
||||
#[cfg(feature = "lpc55-core0")]
|
||||
pub mod usart;
|
||||
|
||||
#[cfg(feature = "_time_driver")]
|
||||
@ -15,7 +15,7 @@ pub mod usart;
|
||||
mod time_driver;
|
||||
|
||||
// This mod MUST go last, so that it sees all the `impl_foo!` macros
|
||||
#[cfg_attr(feature = "lpc55", path = "chips/lpc55.rs")]
|
||||
#[cfg_attr(feature = "lpc55-core0", path = "chips/lpc55.rs")]
|
||||
#[cfg_attr(feature = "mimxrt1011", path = "chips/mimxrt1011.rs")]
|
||||
#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")]
|
||||
mod chip;
|
||||
@ -83,10 +83,10 @@ pub fn init(_config: config::Config) -> Peripherals {
|
||||
pac::CCM.ccgr6().modify(|v| v.set_cg0(1));
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "lpc55", rt1xxx))]
|
||||
#[cfg(any(feature = "lpc55-core0", rt1xxx))]
|
||||
gpio::init();
|
||||
|
||||
#[cfg(feature = "lpc55")]
|
||||
#[cfg(feature = "lpc55-core0")]
|
||||
pint::init();
|
||||
|
||||
#[cfg(feature = "_time_driver")]
|
||||
|
@ -5,10 +5,11 @@ use core::pin::Pin as FuturePin;
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use critical_section::Mutex;
|
||||
use embassy_hal_internal::interrupt::InterruptExt;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::gpio::{self, inputmux_reg, pint_reg, syscon_reg, AnyPin, Level, SealedPin};
|
||||
use crate::pac::interrupt;
|
||||
use crate::gpio::{self, AnyPin, Level, SealedPin};
|
||||
use crate::pac::{interrupt, INPUTMUX, PINT, SYSCON};
|
||||
use crate::Peri;
|
||||
|
||||
struct PinInterrupt {
|
||||
@ -88,18 +89,18 @@ enum InterruptOn {
|
||||
}
|
||||
|
||||
pub(crate) fn init() {
|
||||
syscon_reg().ahbclkctrl0.modify(|_, w| w.pint().enable());
|
||||
SYSCON.ahbclkctrl0().modify(|w| w.set_pint(true));
|
||||
|
||||
// Enable interrupts
|
||||
unsafe {
|
||||
crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT0);
|
||||
crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT1);
|
||||
crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT2);
|
||||
crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT3);
|
||||
crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT4);
|
||||
crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT5);
|
||||
crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT6);
|
||||
crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT7);
|
||||
interrupt::PIN_INT0.enable();
|
||||
interrupt::PIN_INT1.enable();
|
||||
interrupt::PIN_INT2.enable();
|
||||
interrupt::PIN_INT3.enable();
|
||||
interrupt::PIN_INT4.enable();
|
||||
interrupt::PIN_INT5.enable();
|
||||
interrupt::PIN_INT6.enable();
|
||||
interrupt::PIN_INT7.enable();
|
||||
};
|
||||
|
||||
info!("Pin interrupts initialized");
|
||||
@ -119,24 +120,19 @@ impl<'d> InputFuture<'d> {
|
||||
let interrupt_number = next_available_interrupt()?;
|
||||
|
||||
// Clear interrupt, just in case
|
||||
pint_reg()
|
||||
.rise
|
||||
.write(|w| unsafe { w.rdet().bits(1 << interrupt_number) });
|
||||
pint_reg()
|
||||
.fall
|
||||
.write(|w| unsafe { w.fdet().bits(1 << interrupt_number) });
|
||||
PINT.rise().write(|w| w.set_rdet(1 << interrupt_number));
|
||||
PINT.fall().write(|w| w.set_fdet(1 << interrupt_number));
|
||||
|
||||
// Enable input multiplexing on pin interrupt register 0 for pin (32*bank + pin_number)
|
||||
inputmux_reg().pintsel[interrupt_number]
|
||||
.write(|w| unsafe { w.intpin().bits(32 * pin.pin_bank() as u8 + pin.pin_number()) });
|
||||
INPUTMUX
|
||||
.pintsel(interrupt_number as usize)
|
||||
.write(|w| w.set_intpin(32 * pin.pin_bank() as u8 + pin.pin_number()));
|
||||
|
||||
match interrupt_on {
|
||||
InterruptOn::Level(level) => {
|
||||
// Set pin interrupt register to edge sensitive or level sensitive
|
||||
// 0 = edge sensitive, 1 = level sensitive
|
||||
pint_reg()
|
||||
.isel
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << interrupt_number)) });
|
||||
PINT.isel().modify(|w| w.set_pmode(w.pmode() | (1 << interrupt_number)));
|
||||
|
||||
// Enable level interrupt.
|
||||
//
|
||||
@ -144,63 +140,44 @@ impl<'d> InputFuture<'d> {
|
||||
// is activated.
|
||||
|
||||
// 0 = no-op, 1 = enable
|
||||
pint_reg()
|
||||
.sienr
|
||||
.write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
|
||||
PINT.sienr().write(|w| w.set_setenrl(1 << interrupt_number));
|
||||
|
||||
// Set active level
|
||||
match level {
|
||||
Level::Low => {
|
||||
// 0 = no-op, 1 = select LOW
|
||||
pint_reg()
|
||||
.cienf
|
||||
.write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
|
||||
PINT.cienf().write(|w| w.set_cenaf(1 << interrupt_number));
|
||||
}
|
||||
Level::High => {
|
||||
// 0 = no-op, 1 = select HIGH
|
||||
pint_reg()
|
||||
.sienf
|
||||
.write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
|
||||
PINT.sienf().write(|w| w.set_setenaf(1 << interrupt_number));
|
||||
}
|
||||
}
|
||||
}
|
||||
InterruptOn::Edge(edge) => {
|
||||
// Set pin interrupt register to edge sensitive or level sensitive
|
||||
// 0 = edge sensitive, 1 = level sensitive
|
||||
pint_reg()
|
||||
.isel
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << interrupt_number)) });
|
||||
PINT.isel()
|
||||
.modify(|w| w.set_pmode(w.pmode() & !(1 << interrupt_number)));
|
||||
|
||||
// Enable rising/falling edge detection
|
||||
match edge {
|
||||
Edge::Rising => {
|
||||
// 0 = no-op, 1 = enable rising edge
|
||||
pint_reg()
|
||||
.sienr
|
||||
.write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
|
||||
PINT.sienr().write(|w| w.set_setenrl(1 << interrupt_number));
|
||||
// 0 = no-op, 1 = disable falling edge
|
||||
pint_reg()
|
||||
.cienf
|
||||
.write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
|
||||
PINT.cienf().write(|w| w.set_cenaf(1 << interrupt_number));
|
||||
}
|
||||
Edge::Falling => {
|
||||
// 0 = no-op, 1 = enable falling edge
|
||||
pint_reg()
|
||||
.sienf
|
||||
.write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
|
||||
PINT.sienf().write(|w| w.set_setenaf(1 << interrupt_number));
|
||||
// 0 = no-op, 1 = disable rising edge
|
||||
pint_reg()
|
||||
.cienr
|
||||
.write(|w| unsafe { w.cenrl().bits(1 << interrupt_number) });
|
||||
PINT.cienr().write(|w| w.set_cenrl(1 << interrupt_number));
|
||||
}
|
||||
Edge::Both => {
|
||||
// 0 = no-op, 1 = enable
|
||||
pint_reg()
|
||||
.sienr
|
||||
.write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
|
||||
pint_reg()
|
||||
.sienf
|
||||
.write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
|
||||
PINT.sienr().write(|w| w.set_setenrl(1 << interrupt_number));
|
||||
PINT.sienf().write(|w| w.set_setenaf(1 << interrupt_number));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -239,12 +216,8 @@ impl<'d> Drop for InputFuture<'d> {
|
||||
|
||||
// Disable pin interrupt
|
||||
// 0 = no-op, 1 = disable
|
||||
pint_reg()
|
||||
.cienr
|
||||
.write(|w| unsafe { w.cenrl().bits(1 << interrupt_number) });
|
||||
pint_reg()
|
||||
.cienf
|
||||
.write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
|
||||
PINT.cienr().write(|w| w.set_cenrl(1 << interrupt_number));
|
||||
PINT.cienf().write(|w| w.set_cenaf(1 << interrupt_number));
|
||||
|
||||
critical_section::with(|cs| {
|
||||
let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
|
||||
@ -277,12 +250,8 @@ impl<'d> Future for InputFuture<'d> {
|
||||
}
|
||||
|
||||
fn handle_interrupt(interrupt_number: usize) {
|
||||
pint_reg()
|
||||
.rise
|
||||
.write(|w| unsafe { w.rdet().bits(1 << interrupt_number) });
|
||||
pint_reg()
|
||||
.fall
|
||||
.write(|w| unsafe { w.fdet().bits(1 << interrupt_number) });
|
||||
PINT.rise().write(|w| w.set_rdet(1 << interrupt_number));
|
||||
PINT.fall().write(|w| w.set_fdet(1 << interrupt_number));
|
||||
|
||||
critical_section::with(|cs| {
|
||||
let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
|
||||
|
@ -6,7 +6,9 @@ use embassy_hal_internal::interrupt::{InterruptExt, Priority};
|
||||
use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
|
||||
use embassy_time_driver::{time_driver_impl, Driver};
|
||||
use embassy_time_queue_utils::Queue;
|
||||
use lpc55_pac::{interrupt, PMC, RTC, SYSCON};
|
||||
|
||||
use crate::pac::{interrupt, pmc, rtc, PMC, RTC, SYSCON};
|
||||
|
||||
struct AlarmState {
|
||||
timestamp: Cell<u64>,
|
||||
}
|
||||
@ -32,33 +34,32 @@ time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
|
||||
});
|
||||
impl RtcDriver {
|
||||
fn init(&'static self) {
|
||||
let syscon = unsafe { &*SYSCON::ptr() };
|
||||
let pmc = unsafe { &*PMC::ptr() };
|
||||
let rtc = unsafe { &*RTC::ptr() };
|
||||
let syscon = SYSCON;
|
||||
let pmc = PMC;
|
||||
let rtc = RTC;
|
||||
|
||||
syscon.ahbclkctrl0.modify(|_, w| w.rtc().enable());
|
||||
syscon.ahbclkctrl0().modify(|w| w.set_rtc(true));
|
||||
|
||||
// By default the RTC enters software reset. If for some reason it is
|
||||
// not in reset, we enter and them promptly leave.q
|
||||
rtc.ctrl.modify(|_, w| w.swreset().set_bit());
|
||||
rtc.ctrl.modify(|_, w| w.swreset().clear_bit());
|
||||
rtc.ctrl().modify(|w| w.set_swreset(true));
|
||||
rtc.ctrl().modify(|w| w.set_swreset(false));
|
||||
|
||||
// Select clock source - either XTAL or FRO
|
||||
// pmc.rtcosc32k.write(|w| w.sel().xtal32k());
|
||||
pmc.rtcosc32k.write(|w| w.sel().fro32k());
|
||||
// pmc.rtcosc32k().write(|w| w.set_sel(pmc::vals::Sel::XTAL32K));
|
||||
pmc.rtcosc32k().write(|w| w.set_sel(pmc::vals::Sel::FRO32K));
|
||||
|
||||
// Start the RTC peripheral
|
||||
rtc.ctrl.modify(|_, w| w.rtc_osc_pd().power_up());
|
||||
|
||||
// rtc.ctrl.modify(|_, w| w.rtc_en().clear_bit()); // EXTRA
|
||||
rtc.ctrl().modify(|w| w.set_rtc_osc_pd(rtc::vals::RtcOscPd::POWER_UP));
|
||||
|
||||
//reset/clear(?) counter
|
||||
rtc.count.reset();
|
||||
rtc.count().modify(|w| w.set_val(0));
|
||||
//en rtc main counter
|
||||
rtc.ctrl.modify(|_, w| w.rtc_en().set_bit());
|
||||
rtc.ctrl.modify(|_, w| w.rtc1khz_en().set_bit());
|
||||
rtc.ctrl().modify(|w| w.set_rtc_en(true));
|
||||
rtc.ctrl().modify(|w| w.set_rtc1khz_en(true));
|
||||
// subsec counter enable
|
||||
rtc.ctrl.modify(|_, w| w.rtc_subsec_ena().set_bit());
|
||||
rtc.ctrl()
|
||||
.modify(|w| w.set_rtc_subsec_ena(rtc::vals::RtcSubsecEna::POWER_UP));
|
||||
|
||||
// enable irq
|
||||
unsafe {
|
||||
@ -68,7 +69,7 @@ impl RtcDriver {
|
||||
}
|
||||
|
||||
fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
|
||||
let rtc = unsafe { &*RTC::ptr() };
|
||||
let rtc = RTC;
|
||||
let alarm = &self.alarms.borrow(cs);
|
||||
alarm.timestamp.set(timestamp);
|
||||
let now = self.now();
|
||||
@ -83,33 +84,38 @@ impl RtcDriver {
|
||||
let sec = (diff / 32768) as u32;
|
||||
let subsec = (diff % 32768) as u32;
|
||||
|
||||
let current_sec = rtc.count.read().val().bits();
|
||||
let current_sec = rtc.count().read().val();
|
||||
let target_sec = current_sec.wrapping_add(sec as u32);
|
||||
|
||||
rtc.match_.write(|w| unsafe { w.matval().bits(target_sec) });
|
||||
rtc.wake.write(|w| unsafe {
|
||||
rtc.match_().write(|w| w.set_matval(target_sec));
|
||||
rtc.wake().write(|w| {
|
||||
let ms = (subsec * 1000) / 32768;
|
||||
w.val().bits(ms as u16)
|
||||
w.set_val(ms as u16)
|
||||
});
|
||||
|
||||
if subsec > 0 {
|
||||
let ms = (subsec * 1000) / 32768;
|
||||
rtc.wake.write(|w| unsafe { w.val().bits(ms as u16) });
|
||||
rtc.wake().write(|w| w.set_val(ms as u16));
|
||||
}
|
||||
rtc.ctrl.modify(|_, w| w.alarm1hz().clear_bit().wake1khz().clear_bit());
|
||||
|
||||
rtc.ctrl().modify(|w| {
|
||||
w.set_alarm1hz(false);
|
||||
w.set_wake1khz(rtc::vals::Wake1khz::RUN)
|
||||
});
|
||||
true
|
||||
}
|
||||
|
||||
fn on_interrupt(&self) {
|
||||
critical_section::with(|cs| {
|
||||
let rtc = unsafe { &*RTC::ptr() };
|
||||
let flags = rtc.ctrl.read();
|
||||
if flags.alarm1hz().bit_is_clear() {
|
||||
rtc.ctrl.modify(|_, w| w.alarm1hz().set_bit());
|
||||
let rtc = RTC;
|
||||
let flags = rtc.ctrl().read();
|
||||
if flags.alarm1hz() == false {
|
||||
rtc.ctrl().modify(|w| w.set_alarm1hz(true));
|
||||
self.trigger_alarm(cs);
|
||||
}
|
||||
|
||||
if flags.wake1khz().bit_is_clear() {
|
||||
rtc.ctrl.modify(|_, w| w.wake1khz().set_bit());
|
||||
if flags.wake1khz() == rtc::vals::Wake1khz::RUN {
|
||||
rtc.ctrl().modify(|w| w.set_wake1khz(rtc::vals::Wake1khz::TIMEOUT));
|
||||
self.trigger_alarm(cs);
|
||||
}
|
||||
});
|
||||
@ -135,13 +141,13 @@ impl RtcDriver {
|
||||
|
||||
impl Driver for RtcDriver {
|
||||
fn now(&self) -> u64 {
|
||||
let rtc = unsafe { &*RTC::ptr() };
|
||||
let rtc = RTC;
|
||||
|
||||
loop {
|
||||
let sec1 = rtc.count.read().val().bits() as u64;
|
||||
let sub1 = rtc.subsec.read().subsec().bits() as u64;
|
||||
let sec2 = rtc.count.read().val().bits() as u64;
|
||||
let sub2 = rtc.subsec.read().subsec().bits() as u64;
|
||||
let sec1 = rtc.count().read().val() as u64;
|
||||
let sub1 = rtc.subsec().read().subsec() as u64;
|
||||
let sec2 = rtc.count().read().val() as u64;
|
||||
let sub2 = rtc.subsec().read().subsec() as u64;
|
||||
|
||||
if sec1 == sec2 && sub1 == sub2 {
|
||||
return sec1 * 32768 + sub1;
|
||||
@ -162,7 +168,7 @@ impl Driver for RtcDriver {
|
||||
})
|
||||
}
|
||||
}
|
||||
#[cortex_m_rt::interrupt]
|
||||
#[interrupt]
|
||||
fn RTC() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
//! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver.
|
||||
#![macro_use]
|
||||
|
||||
#[cfg_attr(feature = "lpc55", path = "./usart/lpc55.rs")]
|
||||
#[cfg_attr(feature = "lpc55-core0", path = "./usart/lpc55.rs")]
|
||||
mod inner;
|
||||
pub use inner::*;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Add PIO SPI
|
||||
- Add PIO I2S input
|
||||
- Add PIO onewire parasite power strong pullup
|
||||
|
||||
## 0.8.0 - 2025-08-26
|
||||
|
||||
|
@ -52,7 +52,8 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> {
|
||||
|
||||
; The low pulse was already done, we only need to delay and poll the bit in case we are reading
|
||||
write_1:
|
||||
nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin
|
||||
jmp y--, continue_1 side 0 [( 6 / CLK) - 1] ; Delay before sampling input. Always decrement y
|
||||
continue_1:
|
||||
in pins, 1 side 0 [(48 / CLK) - 1] ; This writes the state of the pin into the ISR
|
||||
; Fallthrough
|
||||
|
||||
@ -61,9 +62,24 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> {
|
||||
.wrap_target
|
||||
out x, 1 side 0 [(12 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR
|
||||
jmp x--, write_1 side 1 [( 6 / CLK) - 1] ; Do the always low part of a bit, jump to write_1 if we want to write a 1 bit
|
||||
in null, 1 side 1 [(54 / CLK) - 1] ; Do the remainder of the low part of a 0 bit
|
||||
; This writes 0 into the ISR so that the shift count stays in sync
|
||||
jmp y--, continue_0 side 1 [(48 / CLK) - 1] ; Do the remainder of the low part of a 0 bit
|
||||
jmp pullup side 1 [( 6 / CLK) - 1] ; Remain low while jumping
|
||||
continue_0:
|
||||
in null, 1 side 1 [( 6 / CLK) - 1] ; This writes 0 into the ISR so that the shift count stays in sync
|
||||
.wrap
|
||||
|
||||
; Assume that strong pullup commands always have MSB (the last bit) = 0,
|
||||
; since the rising edge can be used to start the operation.
|
||||
; That's the case for DS18B20 (44h and 48h).
|
||||
pullup:
|
||||
set pins, 1 side 1[( 6 / CLK) - 1] ; Drive pin high output immediately.
|
||||
; Strong pullup must be within 10us of rise.
|
||||
in null, 1 side 1[( 6 / CLK) - 1] ; Keep ISR in sync. Must occur after the y--.
|
||||
out null, 8 side 1[( 6 / CLK) - 1] ; Wait for write_bytes_pullup() delay to complete.
|
||||
; The delay is hundreds of ms, so done externally.
|
||||
set pins, 0 side 0[( 6 / CLK) - 1] ; Back to open drain, pin low when driven
|
||||
in null, 8 side 1[( 6 / CLK) - 1] ; Inform write_bytes_pullup() it's ready
|
||||
jmp next_bit side 0[( 6 / CLK) - 1] ; Continue
|
||||
"#
|
||||
);
|
||||
|
||||
@ -98,6 +114,7 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
|
||||
let mut cfg = Config::default();
|
||||
cfg.use_program(&program.prg, &[&pin]);
|
||||
cfg.set_in_pins(&[&pin]);
|
||||
cfg.set_set_pins(&[&pin]);
|
||||
|
||||
let shift_cfg = ShiftConfig {
|
||||
auto_fill: true,
|
||||
@ -146,6 +163,7 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
|
||||
|
||||
/// Write bytes to the onewire bus
|
||||
pub async fn write_bytes(&mut self, data: &[u8]) {
|
||||
unsafe { self.sm.set_y(u32::MAX as u32) };
|
||||
let (rx, tx) = self.sm.rx_tx();
|
||||
for b in data {
|
||||
tx.wait_push(*b as u32).await;
|
||||
@ -155,8 +173,29 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Write bytes to the onewire bus, then apply a strong pullup
|
||||
pub async fn write_bytes_pullup(&mut self, data: &[u8], pullup_time: embassy_time::Duration) {
|
||||
unsafe { self.sm.set_y(data.len() as u32 * 8 - 1) };
|
||||
let (rx, tx) = self.sm.rx_tx();
|
||||
for b in data {
|
||||
tx.wait_push(*b as u32).await;
|
||||
|
||||
// Empty the buffer that is being filled with every write
|
||||
let _ = rx.wait_pull().await;
|
||||
}
|
||||
|
||||
// Perform the delay, usually hundreds of ms.
|
||||
embassy_time::Timer::after(pullup_time).await;
|
||||
|
||||
// Signal that delay has completed
|
||||
tx.wait_push(0 as u32).await;
|
||||
// Wait until it's back at 0 low, open drain
|
||||
let _ = rx.wait_pull().await;
|
||||
}
|
||||
|
||||
/// Read bytes from the onewire bus
|
||||
pub async fn read_bytes(&mut self, data: &mut [u8]) {
|
||||
unsafe { self.sm.set_y(u32::MAX as u32) };
|
||||
let (rx, tx) = self.sm.rx_tx();
|
||||
for b in data {
|
||||
// Write all 1's so that we can read what the device responds
|
||||
|
@ -16,6 +16,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- fix: STM32: Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope ([#4577](https://github.com/embassy-rs/embassy/pull/4577))
|
||||
- feat: Added support for more OctoSPI configurations (e.g. APS6408 RAM) ([#4581](https://github.com/embassy-rs/embassy/pull/4581))
|
||||
- feat: More ADC enums for g0 PAC, API change for over sampling, allow separate sample times
|
||||
- fix: stm32/usart: fix bug with blocking flush in buffered uart ([#4648](https://github.com/embassy-rs/embassy/pull/4648))
|
||||
- fix: stm32/(ospi/hspi/xspi): Fix the alternate bytes register config sticking around for subsequent writes
|
||||
- feat: Configurable gpio speed for QSPI
|
||||
- feat: derive Clone, Copy and defmt::Format for all *SPI-related configs
|
||||
- fix: handle address and data-length errors in OSPI
|
||||
- feat: Allow OSPI DMA writes larger than 64kB using chunking
|
||||
|
||||
## 0.4.0 - 2025-08-26
|
||||
|
||||
|
@ -83,7 +83,8 @@ pub enum DacChannel {
|
||||
}
|
||||
|
||||
/// Number of samples used for averaging.
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Averaging {
|
||||
Disabled,
|
||||
Samples2,
|
||||
|
@ -138,7 +138,8 @@ impl<'a> defmt::Format for Prescaler {
|
||||
/// Number of samples used for averaging.
|
||||
/// TODO: Implement hardware averaging setting.
|
||||
#[allow(unused)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Averaging {
|
||||
Disabled,
|
||||
Samples2,
|
||||
|
@ -107,6 +107,8 @@ cfg_if! {
|
||||
}
|
||||
|
||||
/// Number of samples used for averaging.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Averaging {
|
||||
Disabled,
|
||||
Samples2,
|
||||
|
@ -142,7 +142,8 @@ impl Prescaler {
|
||||
}
|
||||
|
||||
/// Number of samples used for averaging.
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Averaging {
|
||||
Disabled,
|
||||
Samples2,
|
||||
|
@ -86,6 +86,8 @@ impl Default for Config {
|
||||
}
|
||||
|
||||
/// HSPI transfer configuration.
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct TransferConfig {
|
||||
/// Instruction width (IMODE)
|
||||
pub iwidth: HspiWidth,
|
||||
@ -116,7 +118,7 @@ pub struct TransferConfig {
|
||||
|
||||
/// Data width (DMODE)
|
||||
pub dwidth: HspiWidth,
|
||||
/// Data buffer
|
||||
/// Data Double Transfer rate enable
|
||||
pub ddtr: bool,
|
||||
|
||||
/// Number of dummy cycles (DCYC)
|
||||
@ -395,11 +397,6 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
|
||||
// Configure alternate bytes
|
||||
if let Some(ab) = command.alternate_bytes {
|
||||
T::REGS.abr().write(|v| v.set_alternate(ab));
|
||||
T::REGS.ccr().modify(|w| {
|
||||
w.set_abmode(command.abwidth.into());
|
||||
w.set_abdtr(command.abdtr);
|
||||
w.set_absize(command.absize.into());
|
||||
})
|
||||
}
|
||||
|
||||
// Configure dummy cycles
|
||||
@ -411,14 +408,14 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
|
||||
if let Some(data_length) = data_len {
|
||||
T::REGS.dlr().write(|v| {
|
||||
v.set_dl((data_length - 1) as u32);
|
||||
})
|
||||
});
|
||||
} else {
|
||||
T::REGS.dlr().write(|v| {
|
||||
v.set_dl((0) as u32);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// Configure instruction/address/data modes
|
||||
// Configure instruction/address/alternate bytes/data modes
|
||||
T::REGS.ccr().modify(|w| {
|
||||
w.set_imode(command.iwidth.into());
|
||||
w.set_idtr(command.idtr);
|
||||
@ -428,6 +425,10 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
|
||||
w.set_addtr(command.addtr);
|
||||
w.set_adsize(command.adsize.into());
|
||||
|
||||
w.set_abmode(command.abwidth.into());
|
||||
w.set_abdtr(command.abdtr);
|
||||
w.set_absize(command.absize.into());
|
||||
|
||||
w.set_dmode(command.dwidth.into());
|
||||
w.set_ddtr(command.ddtr);
|
||||
});
|
||||
|
@ -23,6 +23,7 @@ impl Into<u8> for OspiMode {
|
||||
/// Ospi lane width
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum OspiWidth {
|
||||
/// None
|
||||
NONE,
|
||||
@ -71,6 +72,7 @@ impl Into<bool> for FlashSelection {
|
||||
#[allow(dead_code)]
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum WrapSize {
|
||||
None,
|
||||
_16Bytes,
|
||||
@ -95,6 +97,7 @@ impl Into<u8> for WrapSize {
|
||||
#[allow(missing_docs)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum MemoryType {
|
||||
Micron,
|
||||
Macronix,
|
||||
@ -120,6 +123,7 @@ impl Into<u8> for MemoryType {
|
||||
/// Ospi memory size.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum MemorySize {
|
||||
_1KiB,
|
||||
_2KiB,
|
||||
@ -180,6 +184,7 @@ impl Into<u8> for MemorySize {
|
||||
|
||||
/// Ospi Address size
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum AddressSize {
|
||||
/// 8-bit address
|
||||
_8Bit,
|
||||
@ -205,6 +210,7 @@ impl Into<u8> for AddressSize {
|
||||
/// Time the Chip Select line stays high.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ChipSelectHighTime {
|
||||
_1Cycle,
|
||||
_2Cycle,
|
||||
@ -234,6 +240,7 @@ impl Into<u8> for ChipSelectHighTime {
|
||||
/// FIFO threshold.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum FIFOThresholdLevel {
|
||||
_1Bytes,
|
||||
_2Bytes,
|
||||
@ -311,6 +318,7 @@ impl Into<u8> for FIFOThresholdLevel {
|
||||
/// Dummy cycle count
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum DummyCycles {
|
||||
_0,
|
||||
_1,
|
||||
|
@ -23,6 +23,7 @@ use crate::{peripherals, Peri};
|
||||
|
||||
/// OPSI driver config.
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct Config {
|
||||
/// Fifo threshold used by the peripheral to generate the interrupt indicating data
|
||||
/// or space is available in the FIFO
|
||||
@ -30,7 +31,9 @@ pub struct Config {
|
||||
/// Indicates the type of external device connected
|
||||
pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface
|
||||
/// Defines the size of the external device connected to the OSPI corresponding
|
||||
/// to the number of address bits required to access the device
|
||||
/// to the number of address bits required to access the device.
|
||||
/// When using indirect mode, [`TransferConfig::address`] + the length of the data being read
|
||||
/// or written must fit within the configured `device_size`, otherwise an error is returned.
|
||||
pub device_size: MemorySize,
|
||||
/// Sets the minimum number of clock cycles that the chip select signal must be held high
|
||||
/// between commands
|
||||
@ -83,6 +86,8 @@ impl Default for Config {
|
||||
}
|
||||
|
||||
/// OSPI transfer configuration.
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct TransferConfig {
|
||||
/// Instruction width (IMODE)
|
||||
pub iwidth: OspiWidth,
|
||||
@ -92,10 +97,11 @@ pub struct TransferConfig {
|
||||
pub isize: AddressSize,
|
||||
/// Instruction Double Transfer rate enable
|
||||
pub idtr: bool,
|
||||
|
||||
/// Address width (ADMODE)
|
||||
pub adwidth: OspiWidth,
|
||||
/// Device memory address
|
||||
/// Device memory address.
|
||||
/// In indirect mode, this value + the length of the data being read or written must be within
|
||||
/// configured [`Config::device_size`], otherwise the transfer returns an error.
|
||||
pub address: Option<u32>,
|
||||
/// Number of Address Bytes
|
||||
pub adsize: AddressSize,
|
||||
@ -113,7 +119,7 @@ pub struct TransferConfig {
|
||||
|
||||
/// Data width (DMODE)
|
||||
pub dwidth: OspiWidth,
|
||||
/// Data buffer
|
||||
/// Data Double Transfer rate enable
|
||||
pub ddtr: bool,
|
||||
|
||||
/// Number of dummy cycles (DCYC)
|
||||
@ -451,11 +457,6 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
|
||||
// Configure alternate bytes
|
||||
if let Some(ab) = command.alternate_bytes {
|
||||
T::REGS.abr().write(|v| v.set_alternate(ab));
|
||||
T::REGS.ccr().modify(|w| {
|
||||
w.set_abmode(PhaseMode::from_bits(command.abwidth.into()));
|
||||
w.set_abdtr(command.abdtr);
|
||||
w.set_absize(SizeInBits::from_bits(command.absize.into()));
|
||||
})
|
||||
}
|
||||
|
||||
// Configure dummy cycles
|
||||
@ -467,14 +468,14 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
|
||||
if let Some(data_length) = data_len {
|
||||
T::REGS.dlr().write(|v| {
|
||||
v.set_dl((data_length - 1) as u32);
|
||||
})
|
||||
});
|
||||
} else {
|
||||
T::REGS.dlr().write(|v| {
|
||||
v.set_dl((0) as u32);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// Configure instruction/address/data/communication modes
|
||||
// Configure instruction/address/alternate bytes/data/communication modes
|
||||
T::REGS.ccr().modify(|w| {
|
||||
w.set_imode(PhaseMode::from_bits(command.iwidth.into()));
|
||||
w.set_idtr(command.idtr);
|
||||
@ -484,6 +485,10 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
|
||||
w.set_addtr(command.addtr);
|
||||
w.set_adsize(SizeInBits::from_bits(command.adsize.into()));
|
||||
|
||||
w.set_abmode(PhaseMode::from_bits(command.abwidth.into()));
|
||||
w.set_abdtr(command.abdtr);
|
||||
w.set_absize(SizeInBits::from_bits(command.absize.into()));
|
||||
|
||||
w.set_dmode(PhaseMode::from_bits(command.dwidth.into()));
|
||||
w.set_ddtr(command.ddtr);
|
||||
|
||||
@ -491,7 +496,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
|
||||
w.set_sioo(command.sioo);
|
||||
});
|
||||
|
||||
// Set informationrequired to initiate transaction
|
||||
// Set information required to initiate transaction
|
||||
if let Some(instruction) = command.instruction {
|
||||
if let Some(address) = command.address {
|
||||
T::REGS.ir().write(|v| {
|
||||
@ -526,6 +531,18 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
|
||||
}
|
||||
}
|
||||
|
||||
// The following errors set the TEF flag in OCTOSPI_SR register:
|
||||
// - in indirect or automatic status-polling mode, when a wrong address has been programmed
|
||||
// in OCTOSPI_AR (according to the device size defined by DEVSIZE[4:0])
|
||||
// - in indirect mode, if the address plus the data length exceed the device size: TEF is
|
||||
// set as soon as the access is triggered.
|
||||
if T::REGS.sr().read().tef() {
|
||||
// Clear the TEF register to make it ready for the next transfer.
|
||||
T::REGS.fcr().write(|w| w.set_ctef(true));
|
||||
|
||||
return Err(OspiError::InvalidCommand);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1181,16 +1198,19 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
|
||||
.cr()
|
||||
.modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
|
||||
|
||||
let transfer = unsafe {
|
||||
self.dma
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
|
||||
};
|
||||
// TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
|
||||
for chunk in buf.chunks(0xFFFF) {
|
||||
let transfer = unsafe {
|
||||
self.dma
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
|
||||
};
|
||||
|
||||
T::REGS.cr().modify(|w| w.set_dmaen(true));
|
||||
T::REGS.cr().modify(|w| w.set_dmaen(true));
|
||||
|
||||
transfer.blocking_wait();
|
||||
transfer.blocking_wait();
|
||||
}
|
||||
|
||||
finish_dma(T::REGS);
|
||||
|
||||
@ -1251,16 +1271,19 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
|
||||
.cr()
|
||||
.modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
|
||||
|
||||
let transfer = unsafe {
|
||||
self.dma
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
|
||||
};
|
||||
// TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
|
||||
for chunk in buf.chunks(0xFFFF) {
|
||||
let transfer = unsafe {
|
||||
self.dma
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
|
||||
};
|
||||
|
||||
T::REGS.cr().modify(|w| w.set_dmaen(true));
|
||||
T::REGS.cr().modify(|w| w.set_dmaen(true));
|
||||
|
||||
transfer.await;
|
||||
transfer.await;
|
||||
}
|
||||
|
||||
finish_dma(T::REGS);
|
||||
|
||||
|
@ -23,6 +23,7 @@ impl From<QspiMode> for u8 {
|
||||
/// QSPI lane width
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum QspiWidth {
|
||||
/// None
|
||||
NONE,
|
||||
@ -67,6 +68,7 @@ impl From<FlashSelection> for bool {
|
||||
/// QSPI memory size.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum MemorySize {
|
||||
_1KiB,
|
||||
_2KiB,
|
||||
@ -127,6 +129,7 @@ impl From<MemorySize> for u8 {
|
||||
|
||||
/// QSPI Address size
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum AddressSize {
|
||||
/// 8-bit address
|
||||
_8Bit,
|
||||
@ -152,6 +155,7 @@ impl From<AddressSize> for u8 {
|
||||
/// Time the Chip Select line stays high.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ChipSelectHighTime {
|
||||
_1Cycle,
|
||||
_2Cycle,
|
||||
@ -181,6 +185,7 @@ impl From<ChipSelectHighTime> for u8 {
|
||||
/// FIFO threshold.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum FIFOThresholdLevel {
|
||||
_1Bytes,
|
||||
_2Bytes,
|
||||
@ -258,6 +263,7 @@ impl From<FIFOThresholdLevel> for u8 {
|
||||
/// Dummy cycle count
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum DummyCycles {
|
||||
_0,
|
||||
_1,
|
||||
@ -334,6 +340,7 @@ impl From<DummyCycles> for u8 {
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum SampleShifting {
|
||||
None,
|
||||
HalfCycle,
|
||||
|
@ -18,6 +18,7 @@ use crate::{peripherals, Peri};
|
||||
|
||||
/// QSPI transfer configuration.
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct TransferConfig {
|
||||
/// Instruction width (IMODE)
|
||||
pub iwidth: QspiWidth,
|
||||
@ -48,6 +49,8 @@ impl Default for TransferConfig {
|
||||
|
||||
/// QSPI driver configuration.
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[non_exhaustive]
|
||||
pub struct Config {
|
||||
/// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
|
||||
/// If you need other value the whose predefined use `Other` variant.
|
||||
@ -62,6 +65,8 @@ pub struct Config {
|
||||
pub cs_high_time: ChipSelectHighTime,
|
||||
/// Shift sampling point of input data (none, or half-cycle)
|
||||
pub sample_shifting: SampleShifting,
|
||||
/// GPIO Speed
|
||||
pub gpio_speed: Speed,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@ -73,6 +78,7 @@ impl Default for Config {
|
||||
fifo_threshold: FIFOThresholdLevel::_17Bytes,
|
||||
cs_high_time: ChipSelectHighTime::_5Cycle,
|
||||
sample_shifting: SampleShifting::None,
|
||||
gpio_speed: Speed::VeryHigh,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -286,14 +292,14 @@ impl<'d, T: Instance> Qspi<'d, T, Blocking> {
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(
|
||||
nss,
|
||||
AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
|
||||
AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
|
||||
),
|
||||
None,
|
||||
config,
|
||||
@ -314,14 +320,14 @@ impl<'d, T: Instance> Qspi<'d, T, Blocking> {
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(
|
||||
nss,
|
||||
AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
|
||||
AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
|
||||
),
|
||||
None,
|
||||
config,
|
||||
@ -345,14 +351,14 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(
|
||||
nss,
|
||||
AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
|
||||
AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
|
||||
),
|
||||
new_dma!(dma),
|
||||
config,
|
||||
@ -374,14 +380,14 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
|
||||
new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
|
||||
new_pin!(
|
||||
nss,
|
||||
AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
|
||||
AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
|
||||
),
|
||||
new_dma!(dma),
|
||||
config,
|
||||
|
@ -692,6 +692,8 @@ impl<'d> BufferedUartTx<'d> {
|
||||
fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> {
|
||||
loop {
|
||||
let state = self.state;
|
||||
state.tx_done.store(false, Ordering::Release);
|
||||
|
||||
let empty = state.tx_buf.is_empty();
|
||||
|
||||
let mut tx_writer = unsafe { state.tx_buf.writer() };
|
||||
@ -713,7 +715,7 @@ impl<'d> BufferedUartTx<'d> {
|
||||
fn blocking_flush(&self) -> Result<(), Error> {
|
||||
loop {
|
||||
let state = self.state;
|
||||
if state.tx_buf.is_empty() {
|
||||
if state.tx_done.load(Ordering::Acquire) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ impl Into<u8> for XspiMode {
|
||||
|
||||
/// Xspi lane width
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum XspiWidth {
|
||||
/// None
|
||||
NONE,
|
||||
@ -50,6 +51,7 @@ impl Into<u8> for XspiWidth {
|
||||
/// Wrap Size
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum WrapSize {
|
||||
None,
|
||||
_16Bytes,
|
||||
@ -73,6 +75,7 @@ impl Into<u8> for WrapSize {
|
||||
/// Memory Type
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum MemoryType {
|
||||
Micron,
|
||||
Macronix,
|
||||
@ -98,6 +101,7 @@ impl Into<u8> for MemoryType {
|
||||
/// Xspi memory size.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum MemorySize {
|
||||
_1KiB,
|
||||
_2KiB,
|
||||
@ -158,6 +162,7 @@ impl Into<u8> for MemorySize {
|
||||
|
||||
/// Xspi Address size
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum AddressSize {
|
||||
/// 8-bit address
|
||||
_8bit,
|
||||
@ -183,6 +188,7 @@ impl Into<u8> for AddressSize {
|
||||
/// Time the Chip Select line stays high.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ChipSelectHighTime {
|
||||
_1Cycle,
|
||||
_2Cycle,
|
||||
@ -212,6 +218,7 @@ impl Into<u8> for ChipSelectHighTime {
|
||||
/// FIFO threshold.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum FIFOThresholdLevel {
|
||||
_1Bytes,
|
||||
_2Bytes,
|
||||
@ -289,6 +296,7 @@ impl Into<u8> for FIFOThresholdLevel {
|
||||
/// Dummy cycle count
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum DummyCycles {
|
||||
_0,
|
||||
_1,
|
||||
|
@ -23,6 +23,7 @@ use crate::{peripherals, Peri};
|
||||
|
||||
/// XPSI driver config.
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct Config {
|
||||
/// Fifo threshold used by the peripheral to generate the interrupt indicating data
|
||||
/// or space is available in the FIFO
|
||||
@ -80,6 +81,8 @@ impl Default for Config {
|
||||
}
|
||||
|
||||
/// XSPI transfer configuration.
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct TransferConfig {
|
||||
/// Instruction width (IMODE)
|
||||
pub iwidth: XspiWidth,
|
||||
@ -110,7 +113,7 @@ pub struct TransferConfig {
|
||||
|
||||
/// Data width (DMODE)
|
||||
pub dwidth: XspiWidth,
|
||||
/// Data buffer
|
||||
/// Data Double Transfer rate enable
|
||||
pub ddtr: bool,
|
||||
|
||||
/// Number of dummy cycles (DCYC)
|
||||
@ -424,11 +427,6 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
|
||||
// Configure alternate bytes
|
||||
if let Some(ab) = command.alternate_bytes {
|
||||
T::REGS.abr().write(|v| v.set_alternate(ab));
|
||||
T::REGS.ccr().modify(|w| {
|
||||
w.set_abmode(CcrAbmode::from_bits(command.abwidth.into()));
|
||||
w.set_abdtr(command.abdtr);
|
||||
w.set_absize(CcrAbsize::from_bits(command.absize.into()));
|
||||
})
|
||||
} else {
|
||||
T::REGS.ccr().modify(|w| {
|
||||
// disable alternate bytes
|
||||
@ -445,14 +443,14 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
|
||||
if let Some(data_length) = data_len {
|
||||
T::REGS.dlr().write(|v| {
|
||||
v.set_dl((data_length - 1) as u32);
|
||||
})
|
||||
});
|
||||
} else {
|
||||
T::REGS.dlr().write(|v| {
|
||||
v.set_dl((0) as u32);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// Configure instruction/address/data modes
|
||||
// Configure instruction/address/alternate bytes/data modes
|
||||
T::REGS.ccr().modify(|w| {
|
||||
w.set_imode(CcrImode::from_bits(command.iwidth.into()));
|
||||
w.set_idtr(command.idtr);
|
||||
@ -462,6 +460,10 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
|
||||
w.set_addtr(command.addtr);
|
||||
w.set_adsize(CcrAdsize::from_bits(command.adsize.into()));
|
||||
|
||||
w.set_abmode(CcrAbmode::from_bits(command.abwidth.into()));
|
||||
w.set_abdtr(command.abdtr);
|
||||
w.set_absize(CcrAbsize::from_bits(command.absize.into()));
|
||||
|
||||
w.set_dmode(CcrDmode::from_bits(command.dwidth.into()));
|
||||
w.set_ddtr(command.ddtr);
|
||||
});
|
||||
|
@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
<!-- next-header -->
|
||||
## Unreleased - ReleaseDate
|
||||
- Fix wakers getting dropped by `Signal::reset`
|
||||
- Remove `Sized` trait bound from `MutexGuard::map`
|
||||
|
||||
## 0.7.2 - 2025-08-26
|
||||
|
||||
|
@ -17,6 +17,8 @@ categories = [
|
||||
[package.metadata.embassy]
|
||||
build = [
|
||||
{target = "thumbv6m-none-eabi", features = ["defmt"]},
|
||||
# Xtensa builds
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = ["defmt"]},
|
||||
]
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
|
@ -187,7 +187,7 @@ where
|
||||
T: ?Sized,
|
||||
{
|
||||
/// Returns a locked view over a portion of the locked data.
|
||||
pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
|
||||
pub fn map<U: ?Sized>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
|
||||
let mutex = this.mutex;
|
||||
let value = fun(unsafe { &mut *this.mutex.inner.get() });
|
||||
// Don't run the `drop` method for MutexGuard. The ownership of the underlying
|
||||
@ -279,7 +279,7 @@ where
|
||||
T: ?Sized,
|
||||
{
|
||||
/// Returns a locked view over a portion of the locked data.
|
||||
pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
|
||||
pub fn map<U: ?Sized>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
|
||||
let state = this.state;
|
||||
let value = fun(unsafe { &mut *this.value });
|
||||
// Don't run the `drop` method for MutexGuard. The ownership of the underlying
|
||||
|
@ -56,6 +56,9 @@ _generic-queue = []
|
||||
build = [
|
||||
{target = "thumbv6m-none-eabi", features = []},
|
||||
{target = "thumbv6m-none-eabi", features = ["generic-queue-8"]},
|
||||
# Xtensa builds
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = []},
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = ["generic-queue-8"]},
|
||||
]
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
|
@ -17,6 +17,8 @@ categories = [
|
||||
[package.metadata.embassy]
|
||||
build = [
|
||||
{target = "thumbv6m-none-eabi", features = ["defmt", "defmt-timestamp-uptime", "mock-driver"]},
|
||||
# Xtensa builds
|
||||
{group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = ["defmt", "defmt-timestamp-uptime", "mock-driver"]},
|
||||
]
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
|
@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
<!-- next-header -->
|
||||
## Unreleased - ReleaseDate
|
||||
|
||||
- Allow enabling the `application` and `dfu` feature at the same time
|
||||
|
||||
## 0.2.0 - 2025-08-27
|
||||
|
||||
- First release with changelog.
|
||||
|
@ -1,3 +1,4 @@
|
||||
//! Application part of DFU logic
|
||||
use embassy_boot::BlockingFirmwareState;
|
||||
use embassy_time::{Duration, Instant};
|
||||
use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
|
||||
|
@ -1,3 +1,4 @@
|
||||
//! DFU bootloader part of DFU logic
|
||||
use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError};
|
||||
use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
|
||||
use embassy_usb::driver::Driver;
|
||||
|
@ -6,21 +6,15 @@ mod fmt;
|
||||
pub mod consts;
|
||||
|
||||
#[cfg(feature = "dfu")]
|
||||
mod dfu;
|
||||
#[cfg(feature = "dfu")]
|
||||
pub mod dfu;
|
||||
#[cfg(all(feature = "dfu", not(feature = "application")))]
|
||||
pub use self::dfu::*;
|
||||
|
||||
#[cfg(feature = "application")]
|
||||
mod application;
|
||||
#[cfg(feature = "application")]
|
||||
pub mod application;
|
||||
#[cfg(all(feature = "application", not(feature = "dfu")))]
|
||||
pub use self::application::*;
|
||||
|
||||
#[cfg(any(
|
||||
all(feature = "dfu", feature = "application"),
|
||||
not(any(feature = "dfu", feature = "application"))
|
||||
))]
|
||||
compile_error!("usb-dfu must be compiled with exactly one of `dfu`, or `application` features");
|
||||
|
||||
/// Provides a platform-agnostic interface for initiating a system reset.
|
||||
///
|
||||
/// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a
|
||||
|
@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55", "rt", "defmt", "time-driver-rtc"] }
|
||||
embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55-core0", "rt", "defmt", "time-driver-rtc"] }
|
||||
embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
|
||||
embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
|
||||
embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768"] }
|
||||
|
@ -33,7 +33,6 @@ lto = true
|
||||
codegen-units = 1
|
||||
|
||||
[package.metadata.embassy]
|
||||
skip = true # TODO: remove when we find a way to decrease the defmt buffer size in ci.
|
||||
build = [
|
||||
{ target = "thumbv6m-none-eabi", artifact-dir = "out/examples/mspm0c1104" }
|
||||
{ target = "thumbv6m-none-eabi", artifact-dir = "out/examples/mspm0c1104", env = { DEFMT_RTT_BUFFER_SIZE = "72" }}
|
||||
]
|
||||
|
9
examples/nrf52840-edf/.cargo/config.toml
Normal file
9
examples/nrf52840-edf/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --chip nRF52840_xxAA"
|
||||
|
||||
[build]
|
||||
target = "thumbv7em-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "debug"
|
27
examples/nrf52840-edf/Cargo.toml
Normal file
27
examples/nrf52840-edf/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-nrf52840-edf-examples"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
# NOTE: "scheduler-deadline" and "embassy-time-driver" features are enabled
|
||||
embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "scheduler-deadline", "embassy-time-driver"] }
|
||||
embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||
embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
|
||||
|
||||
defmt = "1.0.1"
|
||||
defmt-rtt = "1.0.0"
|
||||
|
||||
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7.0"
|
||||
panic-probe = { version = "1.0.0", features = ["print-defmt"] }
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
||||
|
||||
[package.metadata.embassy]
|
||||
build = [
|
||||
{ target = "thumbv7em-none-eabi", artifact-dir = "out/examples/nrf52840-edf" }
|
||||
]
|
35
examples/nrf52840-edf/build.rs
Normal file
35
examples/nrf52840-edf/build.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! This build script copies the `memory.x` file from the crate root into
|
||||
//! a directory where the linker can always find it at build time.
|
||||
//! For many projects this is optional, as the linker always searches the
|
||||
//! project root directory -- wherever `Cargo.toml` is. However, if you
|
||||
//! are using a workspace or have a more complicated build setup, this
|
||||
//! build script becomes required. Additionally, by requesting that
|
||||
//! Cargo re-run the build script whenever `memory.x` is changed,
|
||||
//! updating `memory.x` ensures a rebuild of the application with the
|
||||
//! new memory settings.
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
// Put `memory.x` in our output directory and ensure it's
|
||||
// on the linker search path.
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
File::create(out.join("memory.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("memory.x"))
|
||||
.unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// By default, Cargo will re-run a build script whenever
|
||||
// any file in the project changes. By specifying `memory.x`
|
||||
// here, we ensure the build script is only re-run when
|
||||
// `memory.x` is changed.
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
12
examples/nrf52840-edf/memory.x
Normal file
12
examples/nrf52840-edf/memory.x
Normal file
@ -0,0 +1,12 @@
|
||||
MEMORY
|
||||
{
|
||||
/* NOTE 1 K = 1 KiBi = 1024 bytes */
|
||||
FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 256K
|
||||
|
||||
/* These values correspond to the NRF52840 with Softdevices S140 7.3.0 */
|
||||
/*
|
||||
FLASH : ORIGIN = 0x00027000, LENGTH = 868K
|
||||
RAM : ORIGIN = 0x20020000, LENGTH = 128K
|
||||
*/
|
||||
}
|
194
examples/nrf52840-edf/src/bin/basic.rs
Normal file
194
examples/nrf52840-edf/src/bin/basic.rs
Normal file
@ -0,0 +1,194 @@
|
||||
//! Basic side-by-side example of the Earliest Deadline First scheduler
|
||||
//!
|
||||
//! This test spawns a number of background "ambient system load" workers
|
||||
//! that are constantly working, and runs two sets of trials.
|
||||
//!
|
||||
//! The first trial runs with no deadline set, so our trial task is at the
|
||||
//! same prioritization level as the background worker tasks.
|
||||
//!
|
||||
//! The second trial sets a deadline, meaning that it will be given higher
|
||||
//! scheduling priority than background tasks, that have no deadline set
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
use defmt::unwrap;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
embassy_nrf::init(Default::default());
|
||||
|
||||
// Enable flash cache to remove some flash latency jitter
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
embassy_nrf::pac::NVMC.icachecnf().write(|w| {
|
||||
w.set_cacheen(true);
|
||||
});
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
//
|
||||
// Baseline system load tunables
|
||||
//
|
||||
|
||||
// how many load tasks? More load tasks means more tasks contending
|
||||
// for the runqueue
|
||||
let tasks = 32;
|
||||
// how long should each task work for? The longer the working time,
|
||||
// the longer the max jitter possible, even when a task is prioritized,
|
||||
// as EDF is still cooperative and not pre-emptive
|
||||
//
|
||||
// 33 ticks ~= 1ms
|
||||
let work_time_ticks = 33;
|
||||
// what fraction, 1/denominator, should the system be busy?
|
||||
// bigger number means **less** busy
|
||||
//
|
||||
// 2 => 50%
|
||||
// 4 => 25%
|
||||
// 10 => 10%
|
||||
let denominator = 2;
|
||||
|
||||
// Total time window, so each worker is working 1/denominator
|
||||
// amount of the total time
|
||||
let time_window = work_time_ticks * u64::from(tasks) * denominator;
|
||||
|
||||
// Spawn all of our load workers!
|
||||
for i in 0..tasks {
|
||||
spawner.spawn(unwrap!(load_task(i, work_time_ticks, time_window)));
|
||||
}
|
||||
|
||||
// Let all the tasks spin up
|
||||
defmt::println!("Spinning up load tasks...");
|
||||
Timer::after_secs(1).await;
|
||||
|
||||
//
|
||||
// Trial task worker tunables
|
||||
//
|
||||
|
||||
// How many steps should the workers under test run?
|
||||
// More steps means more chances to have to wait for other tasks
|
||||
// in line ahead of us.
|
||||
let num_steps = 100;
|
||||
|
||||
// How many ticks should the worker take working on each step?
|
||||
//
|
||||
// 33 ticks ~= 1ms
|
||||
let work_ticks = 33;
|
||||
// How many ticks should the worker wait on each step?
|
||||
//
|
||||
// 66 ticks ~= 2ms
|
||||
let idle_ticks = 66;
|
||||
|
||||
// How many times to repeat each trial?
|
||||
let trials = 3;
|
||||
|
||||
// The total time a trial would take, in a perfect unloaded system
|
||||
let theoretical = (num_steps * work_ticks) + (num_steps * idle_ticks);
|
||||
|
||||
defmt::println!("");
|
||||
defmt::println!("Starting UNPRIORITIZED worker trials");
|
||||
for _ in 0..trials {
|
||||
//
|
||||
// UNPRIORITIZED worker
|
||||
//
|
||||
defmt::println!("");
|
||||
defmt::println!("Starting unprioritized worker");
|
||||
let start = Instant::now();
|
||||
for _ in 0..num_steps {
|
||||
let now = Instant::now();
|
||||
while now.elapsed().as_ticks() < work_ticks {}
|
||||
Timer::after_ticks(idle_ticks).await;
|
||||
}
|
||||
let elapsed = start.elapsed().as_ticks();
|
||||
defmt::println!(
|
||||
"Trial complete, theoretical ticks: {=u64}, actual ticks: {=u64}",
|
||||
theoretical,
|
||||
elapsed
|
||||
);
|
||||
let ratio = ((elapsed as f32) / (theoretical as f32)) * 100.0;
|
||||
defmt::println!("Took {=f32}% of ideal time", ratio);
|
||||
Timer::after_millis(500).await;
|
||||
}
|
||||
|
||||
Timer::after_secs(1).await;
|
||||
|
||||
defmt::println!("");
|
||||
defmt::println!("Starting PRIORITIZED worker trials");
|
||||
for _ in 0..trials {
|
||||
//
|
||||
// PRIORITIZED worker
|
||||
//
|
||||
defmt::println!("");
|
||||
defmt::println!("Starting prioritized worker");
|
||||
let start = Instant::now();
|
||||
// Set the deadline to ~2x the theoretical time. In practice, setting any deadline
|
||||
// here elevates the current task above all other worker tasks.
|
||||
let meta = embassy_executor::Metadata::for_current_task().await;
|
||||
meta.set_deadline_after(theoretical * 2);
|
||||
|
||||
// Perform the trial
|
||||
for _ in 0..num_steps {
|
||||
let now = Instant::now();
|
||||
while now.elapsed().as_ticks() < work_ticks {}
|
||||
Timer::after_ticks(idle_ticks).await;
|
||||
}
|
||||
|
||||
let elapsed = start.elapsed().as_ticks();
|
||||
defmt::println!(
|
||||
"Trial complete, theoretical ticks: {=u64}, actual ticks: {=u64}",
|
||||
theoretical,
|
||||
elapsed
|
||||
);
|
||||
let ratio = ((elapsed as f32) / (theoretical as f32)) * 100.0;
|
||||
defmt::println!("Took {=f32}% of ideal time", ratio);
|
||||
|
||||
// Unset the deadline, deadlines are not automatically cleared, and if our
|
||||
// deadline is in the past, then we get very high priority!
|
||||
meta.unset_deadline();
|
||||
|
||||
Timer::after_millis(500).await;
|
||||
}
|
||||
|
||||
defmt::println!("");
|
||||
defmt::println!("Trials Complete.");
|
||||
}
|
||||
|
||||
#[embassy_executor::task(pool_size = 32)]
|
||||
async fn load_task(id: u32, ticks_on: u64, ttl_ticks: u64) {
|
||||
let mut last_print = Instant::now();
|
||||
let mut last_tick = last_print;
|
||||
let mut variance = 0;
|
||||
let mut max_variance = 0;
|
||||
loop {
|
||||
let tgt = last_tick + Duration::from_ticks(ttl_ticks);
|
||||
assert!(tgt > Instant::now(), "fell too behind!");
|
||||
|
||||
Timer::at(tgt).await;
|
||||
let now = Instant::now();
|
||||
// How late are we from the target?
|
||||
let var = now.duration_since(tgt).as_ticks();
|
||||
max_variance = max_variance.max(var);
|
||||
variance += var;
|
||||
|
||||
// blocking work
|
||||
while now.elapsed().as_ticks() < ticks_on {}
|
||||
|
||||
if last_print.elapsed() >= Duration::from_secs(1) {
|
||||
defmt::trace!(
|
||||
"Task {=u32} variance ticks (1s): {=u64}, max: {=u64}, act: {=u64}",
|
||||
id,
|
||||
variance,
|
||||
max_variance,
|
||||
ticks_on,
|
||||
);
|
||||
max_variance = 0;
|
||||
variance = 0;
|
||||
last_print = Instant::now();
|
||||
}
|
||||
|
||||
last_tick = tgt;
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
|
@ -10,8 +10,8 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
|
||||
embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
|
||||
embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
|
||||
embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||
embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
|
||||
embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
|
||||
embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "net-driver"] }
|
||||
embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet","udp", "medium-ieee802154", "proto-ipv6"] }
|
||||
embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] }
|
||||
embedded-io = { version = "0.6.0", features = ["defmt-03"] }
|
||||
embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
|
||||
|
120
examples/nrf52840/src/bin/sixlowpan.rs
Normal file
120
examples/nrf52840/src/bin/sixlowpan.rs
Normal file
@ -0,0 +1,120 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::net::Ipv6Addr;
|
||||
|
||||
use defmt::{info, unwrap, warn};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_net::udp::{PacketMetadata, UdpMetadata, UdpSocket};
|
||||
use embassy_net::{IpAddress, IpEndpoint, IpListenEndpoint, Ipv6Cidr, StackResources, StaticConfigV6};
|
||||
use embassy_nrf::config::{Config, HfclkSource};
|
||||
use embassy_nrf::rng::Rng;
|
||||
use embassy_nrf::{bind_interrupts, embassy_net_802154_driver as net, peripherals, radio};
|
||||
use embassy_time::Delay;
|
||||
use embedded_hal_async::delay::DelayNs;
|
||||
use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
RADIO => radio::InterruptHandler<peripherals::RADIO>;
|
||||
RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
|
||||
});
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn ieee802154_task(runner: net::Runner<'static, peripherals::RADIO>) -> ! {
|
||||
runner.run().await
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn net_task(mut runner: embassy_net::Runner<'static, net::Device<'static>>) -> ! {
|
||||
runner.run().await
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let mut config = Config::default();
|
||||
// Necessary to run the radio nrf52840 v1.11 5.4.1
|
||||
config.hfclk_source = HfclkSource::ExternalXtal;
|
||||
let p = embassy_nrf::init(config);
|
||||
|
||||
let mac_addr: [u8; 8] = [2, 3, 4, 5, 6, 7, 8, 9];
|
||||
static NRF802154_STATE: StaticCell<net::State<20, 20>> = StaticCell::new();
|
||||
let (device, runner) = net::new(mac_addr, p.RADIO, Irqs, NRF802154_STATE.init(net::State::new()))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
spawner.spawn(unwrap!(ieee802154_task(runner)));
|
||||
|
||||
// Swap these when flashing a second board
|
||||
let peer = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xd701, 0xda3f, 0x3955, 0x82a4);
|
||||
let local = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xd701, 0xda3f, 0x3955, 0x82a5);
|
||||
|
||||
let config = embassy_net::Config::ipv6_static(StaticConfigV6 {
|
||||
address: Ipv6Cidr::new(local, 64),
|
||||
gateway: None,
|
||||
dns_servers: Default::default(),
|
||||
});
|
||||
|
||||
// Generate random seed
|
||||
let mut rng = Rng::new(p.RNG, Irqs);
|
||||
let mut seed = [0; 8];
|
||||
rng.blocking_fill_bytes(&mut seed);
|
||||
let seed = u64::from_le_bytes(seed);
|
||||
|
||||
// Init network stack
|
||||
static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
|
||||
let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
|
||||
|
||||
spawner.spawn(unwrap!(net_task(runner)));
|
||||
|
||||
let mut rx_buffer = [0; 2096];
|
||||
let mut tx_buffer = [0; 2096];
|
||||
let mut tx_m_buffer = [PacketMetadata::EMPTY; 5];
|
||||
let mut rx_m_buffer = [PacketMetadata::EMPTY; 5];
|
||||
|
||||
let mut delay = Delay;
|
||||
loop {
|
||||
let mut socket = UdpSocket::new(
|
||||
stack,
|
||||
&mut tx_m_buffer,
|
||||
&mut rx_buffer,
|
||||
&mut rx_m_buffer,
|
||||
&mut tx_buffer,
|
||||
);
|
||||
socket
|
||||
.bind(IpListenEndpoint {
|
||||
addr: Some(IpAddress::Ipv6(local)),
|
||||
port: 1234,
|
||||
})
|
||||
.unwrap();
|
||||
let rep = UdpMetadata {
|
||||
endpoint: IpEndpoint {
|
||||
addr: IpAddress::Ipv6(peer),
|
||||
port: 1234,
|
||||
},
|
||||
local_address: Some(IpAddress::Ipv6(local)),
|
||||
meta: Default::default(),
|
||||
};
|
||||
|
||||
info!("Listening on {:?} UDP:1234...", local);
|
||||
|
||||
let mut recv_buf = [0; 12];
|
||||
loop {
|
||||
delay.delay_ms(2000).await;
|
||||
if socket.may_recv() {
|
||||
let n = match socket.recv_from(&mut recv_buf).await {
|
||||
Ok((0, _)) => panic!(),
|
||||
Ok((n, _)) => n,
|
||||
Err(e) => {
|
||||
warn!("read error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
info!("Received {:02x}", &recv_buf[..n]);
|
||||
}
|
||||
|
||||
info!("Sending");
|
||||
socket.send_to(b"Hello World", rep).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
155
examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs
Normal file
155
examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs
Normal file
@ -0,0 +1,155 @@
|
||||
//! This example implements a TCP echo server on port 1234 and using DHCP.
|
||||
//! Send it some data, you should see it echoed back and printed in the console.
|
||||
//!
|
||||
//! Example written for the [`WIZnet W55RP20-EVB-Pico`](https://docs.wiznet.io/Product/ioNIC/W55RP20/w55rp20-evb-pico) board.
|
||||
//! Note: the W55RP20 is a single package that contains both a RP2040 and the Wiznet W5500 ethernet
|
||||
//! controller
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::yield_now;
|
||||
use embassy_net::{Stack, StackResources};
|
||||
use embassy_net_wiznet::chip::W5500;
|
||||
use embassy_net_wiznet::*;
|
||||
use embassy_rp::clocks::RoscRng;
|
||||
use embassy_rp::gpio::{Input, Level, Output, Pull};
|
||||
use embassy_rp::peripherals::PIO0;
|
||||
use embassy_rp::pio_programs::spi::Spi;
|
||||
use embassy_rp::spi::{Async, Config as SpiConfig};
|
||||
use embassy_rp::{bind_interrupts, pio};
|
||||
use embassy_time::{Delay, Duration};
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use embedded_io_async::Write;
|
||||
use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
PIO0_IRQ_0 => pio::InterruptHandler<PIO0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn ethernet_task(
|
||||
runner: Runner<
|
||||
'static,
|
||||
W5500,
|
||||
ExclusiveDevice<Spi<'static, PIO0, 0, Async>, Output<'static>, Delay>,
|
||||
Input<'static>,
|
||||
Output<'static>,
|
||||
>,
|
||||
) -> ! {
|
||||
runner.run().await
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
|
||||
runner.run().await
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
let mut rng = RoscRng;
|
||||
let mut led = Output::new(p.PIN_19, Level::Low);
|
||||
|
||||
// The W55RP20 uses a PIO unit for SPI communication, once the SPI bus has been formed using a
|
||||
// PIO statemachine everything else is generally unchanged from the other examples that use the W5500
|
||||
let mosi = p.PIN_23;
|
||||
let miso = p.PIN_22;
|
||||
let clk = p.PIN_21;
|
||||
|
||||
let pio::Pio { mut common, sm0, .. } = pio::Pio::new(p.PIO0, Irqs);
|
||||
|
||||
// Construct an SPI driver backed by a PIO state machine
|
||||
let mut spi_cfg = SpiConfig::default();
|
||||
spi_cfg.frequency = 12_500_000; // The PIO SPI program is much less stable than the actual SPI
|
||||
// peripheral, use higher speeds at your peril
|
||||
let spi = Spi::new(&mut common, sm0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
|
||||
|
||||
// Further control pins
|
||||
let cs = Output::new(p.PIN_20, Level::High);
|
||||
let w5500_int = Input::new(p.PIN_24, Pull::Up);
|
||||
let w5500_reset = Output::new(p.PIN_25, Level::High);
|
||||
|
||||
let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
|
||||
static STATE: StaticCell<State<8, 8>> = StaticCell::new();
|
||||
let state = STATE.init(State::<8, 8>::new());
|
||||
let (device, runner) = embassy_net_wiznet::new(
|
||||
mac_addr,
|
||||
state,
|
||||
ExclusiveDevice::new(spi, cs, Delay),
|
||||
w5500_int,
|
||||
w5500_reset,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
spawner.spawn(unwrap!(ethernet_task(runner)));
|
||||
|
||||
// Generate random seed
|
||||
let seed = rng.next_u64();
|
||||
|
||||
// Init network stack
|
||||
static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
|
||||
let (stack, runner) = embassy_net::new(
|
||||
device,
|
||||
embassy_net::Config::dhcpv4(Default::default()),
|
||||
RESOURCES.init(StackResources::new()),
|
||||
seed,
|
||||
);
|
||||
|
||||
// Launch network task
|
||||
spawner.spawn(unwrap!(net_task(runner)));
|
||||
|
||||
info!("Waiting for DHCP...");
|
||||
let cfg = wait_for_config(stack).await;
|
||||
let local_addr = cfg.address.address();
|
||||
info!("IP address: {:?}", local_addr);
|
||||
|
||||
let mut rx_buffer = [0; 4096];
|
||||
let mut tx_buffer = [0; 4096];
|
||||
let mut buf = [0; 4096];
|
||||
loop {
|
||||
let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
||||
socket.set_timeout(Some(Duration::from_secs(10)));
|
||||
|
||||
led.set_low();
|
||||
info!("Listening on TCP:1234...");
|
||||
if let Err(e) = socket.accept(1234).await {
|
||||
warn!("accept error: {:?}", e);
|
||||
continue;
|
||||
}
|
||||
info!("Received connection from {:?}", socket.remote_endpoint());
|
||||
led.set_high();
|
||||
|
||||
loop {
|
||||
let n = match socket.read(&mut buf).await {
|
||||
Ok(0) => {
|
||||
warn!("read EOF");
|
||||
break;
|
||||
}
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
warn!("{:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
info!("rxd {}", core::str::from_utf8(&buf[..n]).unwrap());
|
||||
|
||||
if let Err(e) = socket.write_all(&buf[..n]).await {
|
||||
warn!("write error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
|
||||
loop {
|
||||
if let Some(config) = stack.config_v4() {
|
||||
return config.clone();
|
||||
}
|
||||
yield_now().await;
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors.
|
||||
//! This uses externally powered sensors. For parasite power, see the pio_onewire_parasite.rs example.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
89
examples/rp/src/bin/pio_onewire_parasite.rs
Normal file
89
examples/rp/src/bin/pio_onewire_parasite.rs
Normal file
@ -0,0 +1,89 @@
|
||||
//! This example shows how you can use PIO to read one or more `DS18B20`
|
||||
//! one-wire temperature sensors using parasite power.
|
||||
//! It applies a strong pullup during conversion, see "Powering the DS18B20" in the datasheet.
|
||||
//! For externally powered sensors, use the pio_onewire.rs example.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::bind_interrupts;
|
||||
use embassy_rp::peripherals::PIO0;
|
||||
use embassy_rp::pio::{InterruptHandler, Pio};
|
||||
use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
|
||||
use embassy_time::Duration;
|
||||
use heapless::Vec;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
PIO0_IRQ_0 => InterruptHandler<PIO0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
let mut pio = Pio::new(p.PIO0, Irqs);
|
||||
|
||||
let prg = PioOneWireProgram::new(&mut pio.common);
|
||||
let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
|
||||
|
||||
info!("Starting onewire search");
|
||||
|
||||
let mut devices = Vec::<u64, 10>::new();
|
||||
let mut search = PioOneWireSearch::new();
|
||||
for _ in 0..10 {
|
||||
if !search.is_finished() {
|
||||
if let Some(address) = search.next(&mut onewire).await {
|
||||
if crc8(&address.to_le_bytes()) == 0 {
|
||||
info!("Found address: {:x}", address);
|
||||
let _ = devices.push(address);
|
||||
} else {
|
||||
warn!("Found invalid address: {:x}", address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("Search done, found {} devices", devices.len());
|
||||
|
||||
loop {
|
||||
// Read all devices one by one
|
||||
for device in &devices {
|
||||
onewire.reset().await;
|
||||
onewire.write_bytes(&[0x55]).await; // Match rom
|
||||
onewire.write_bytes(&device.to_le_bytes()).await;
|
||||
// 750 ms delay required for default 12-bit resolution.
|
||||
onewire.write_bytes_pullup(&[0x44], Duration::from_millis(750)).await;
|
||||
|
||||
onewire.reset().await;
|
||||
onewire.write_bytes(&[0x55]).await; // Match rom
|
||||
onewire.write_bytes(&device.to_le_bytes()).await;
|
||||
onewire.write_bytes(&[0xBE]).await; // Read scratchpad
|
||||
|
||||
let mut data = [0; 9];
|
||||
onewire.read_bytes(&mut data).await;
|
||||
if crc8(&data) == 0 {
|
||||
let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.;
|
||||
info!("Read device {:x}: {} deg C", device, temp);
|
||||
} else {
|
||||
warn!("Reading device {:x} failed. {:02x}", device, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn crc8(data: &[u8]) -> u8 {
|
||||
let mut crc = 0;
|
||||
for b in data {
|
||||
let mut data_byte = *b;
|
||||
for _ in 0..8 {
|
||||
let temp = (crc ^ data_byte) & 0x01;
|
||||
crc >>= 1;
|
||||
if temp != 0 {
|
||||
crc ^= 0x8C;
|
||||
}
|
||||
data_byte >>= 1;
|
||||
}
|
||||
}
|
||||
crc
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor.
|
||||
//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors.
|
||||
//! This uses externally powered sensors. For parasite power, see the pio_onewire_parasite.rs example.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
@ -6,9 +7,10 @@ use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::bind_interrupts;
|
||||
use embassy_rp::peripherals::PIO0;
|
||||
use embassy_rp::pio::{self, InterruptHandler, Pio};
|
||||
use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram};
|
||||
use embassy_rp::pio::{InterruptHandler, Pio};
|
||||
use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
|
||||
use embassy_time::Timer;
|
||||
use heapless::Vec;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
@ -21,63 +23,66 @@ async fn main(_spawner: Spawner) {
|
||||
let mut pio = Pio::new(p.PIO0, Irqs);
|
||||
|
||||
let prg = PioOneWireProgram::new(&mut pio.common);
|
||||
let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
|
||||
let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
|
||||
|
||||
let mut sensor = Ds18b20::new(onewire);
|
||||
info!("Starting onewire search");
|
||||
|
||||
let mut devices = Vec::<u64, 10>::new();
|
||||
let mut search = PioOneWireSearch::new();
|
||||
for _ in 0..10 {
|
||||
if !search.is_finished() {
|
||||
if let Some(address) = search.next(&mut onewire).await {
|
||||
if crc8(&address.to_le_bytes()) == 0 {
|
||||
info!("Found addres: {:x}", address);
|
||||
let _ = devices.push(address);
|
||||
} else {
|
||||
warn!("Found invalid address: {:x}", address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("Search done, found {} devices", devices.len());
|
||||
|
||||
loop {
|
||||
sensor.start().await; // Start a new measurement
|
||||
onewire.reset().await;
|
||||
// Skip rom and trigger conversion, we can trigger all devices on the bus immediately
|
||||
onewire.write_bytes(&[0xCC, 0x44]).await;
|
||||
|
||||
Timer::after_secs(1).await; // Allow 1s for the measurement to finish
|
||||
match sensor.temperature().await {
|
||||
Ok(temp) => info!("temp = {:?} deg C", temp),
|
||||
_ => error!("sensor error"),
|
||||
|
||||
// Read all devices one by one
|
||||
for device in &devices {
|
||||
onewire.reset().await;
|
||||
onewire.write_bytes(&[0x55]).await; // Match rom
|
||||
onewire.write_bytes(&device.to_le_bytes()).await;
|
||||
onewire.write_bytes(&[0xBE]).await; // Read scratchpad
|
||||
|
||||
let mut data = [0; 9];
|
||||
onewire.read_bytes(&mut data).await;
|
||||
if crc8(&data) == 0 {
|
||||
let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.;
|
||||
info!("Read device {:x}: {} deg C", device, temp);
|
||||
} else {
|
||||
warn!("Reading device {:x} failed", device);
|
||||
}
|
||||
}
|
||||
Timer::after_secs(1).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// DS18B20 temperature sensor driver
|
||||
pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> {
|
||||
wire: PioOneWire<'d, PIO, SM>,
|
||||
}
|
||||
|
||||
impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> {
|
||||
pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self {
|
||||
Self { wire }
|
||||
}
|
||||
|
||||
/// Calculate CRC8 of the data
|
||||
fn crc8(data: &[u8]) -> u8 {
|
||||
let mut temp;
|
||||
let mut data_byte;
|
||||
let mut crc = 0;
|
||||
for b in data {
|
||||
data_byte = *b;
|
||||
for _ in 0..8 {
|
||||
temp = (crc ^ data_byte) & 0x01;
|
||||
crc >>= 1;
|
||||
if temp != 0 {
|
||||
crc ^= 0x8C;
|
||||
}
|
||||
data_byte >>= 1;
|
||||
fn crc8(data: &[u8]) -> u8 {
|
||||
let mut crc = 0;
|
||||
for b in data {
|
||||
let mut data_byte = *b;
|
||||
for _ in 0..8 {
|
||||
let temp = (crc ^ data_byte) & 0x01;
|
||||
crc >>= 1;
|
||||
if temp != 0 {
|
||||
crc ^= 0x8C;
|
||||
}
|
||||
}
|
||||
crc
|
||||
}
|
||||
|
||||
/// Start a new measurement. Allow at least 1000ms before getting `temperature`.
|
||||
pub async fn start(&mut self) {
|
||||
self.wire.write_bytes(&[0xCC, 0x44]).await;
|
||||
}
|
||||
|
||||
/// Read the temperature. Ensure >1000ms has passed since `start` before calling this.
|
||||
pub async fn temperature(&mut self) -> Result<f32, ()> {
|
||||
self.wire.write_bytes(&[0xCC, 0xBE]).await;
|
||||
let mut data = [0; 9];
|
||||
self.wire.read_bytes(&mut data).await;
|
||||
match Self::crc8(&data) == 0 {
|
||||
true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.),
|
||||
false => Err(()),
|
||||
data_byte >>= 1;
|
||||
}
|
||||
}
|
||||
crc
|
||||
}
|
||||
|
89
examples/rp235x/src/bin/pio_onewire_parasite.rs
Normal file
89
examples/rp235x/src/bin/pio_onewire_parasite.rs
Normal file
@ -0,0 +1,89 @@
|
||||
//! This example shows how you can use PIO to read one or more `DS18B20`
|
||||
//! one-wire temperature sensors using parasite power.
|
||||
//! It applies a strong pullup during conversion, see "Powering the DS18B20" in the datasheet.
|
||||
//! For externally powered sensors, use the pio_onewire.rs example.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::bind_interrupts;
|
||||
use embassy_rp::peripherals::PIO0;
|
||||
use embassy_rp::pio::{InterruptHandler, Pio};
|
||||
use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
|
||||
use embassy_time::Duration;
|
||||
use heapless::Vec;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
PIO0_IRQ_0 => InterruptHandler<PIO0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
let mut pio = Pio::new(p.PIO0, Irqs);
|
||||
|
||||
let prg = PioOneWireProgram::new(&mut pio.common);
|
||||
let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
|
||||
|
||||
info!("Starting onewire search");
|
||||
|
||||
let mut devices = Vec::<u64, 10>::new();
|
||||
let mut search = PioOneWireSearch::new();
|
||||
for _ in 0..10 {
|
||||
if !search.is_finished() {
|
||||
if let Some(address) = search.next(&mut onewire).await {
|
||||
if crc8(&address.to_le_bytes()) == 0 {
|
||||
info!("Found address: {:x}", address);
|
||||
let _ = devices.push(address);
|
||||
} else {
|
||||
warn!("Found invalid address: {:x}", address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("Search done, found {} devices", devices.len());
|
||||
|
||||
loop {
|
||||
// Read all devices one by one
|
||||
for device in &devices {
|
||||
onewire.reset().await;
|
||||
onewire.write_bytes(&[0x55]).await; // Match rom
|
||||
onewire.write_bytes(&device.to_le_bytes()).await;
|
||||
// 750 ms delay required for default 12-bit resolution.
|
||||
onewire.write_bytes_pullup(&[0x44], Duration::from_millis(750)).await;
|
||||
|
||||
onewire.reset().await;
|
||||
onewire.write_bytes(&[0x55]).await; // Match rom
|
||||
onewire.write_bytes(&device.to_le_bytes()).await;
|
||||
onewire.write_bytes(&[0xBE]).await; // Read scratchpad
|
||||
|
||||
let mut data = [0; 9];
|
||||
onewire.read_bytes(&mut data).await;
|
||||
if crc8(&data) == 0 {
|
||||
let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.;
|
||||
info!("Read device {:x}: {} deg C", device, temp);
|
||||
} else {
|
||||
warn!("Reading device {:x} failed. {:02x}", device, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn crc8(data: &[u8]) -> u8 {
|
||||
let mut crc = 0;
|
||||
for b in data {
|
||||
let mut data_byte = *b;
|
||||
for _ in 0..8 {
|
||||
let temp = (crc ^ data_byte) & 0x01;
|
||||
crc >>= 1;
|
||||
if temp != 0 {
|
||||
crc ^= 0x8C;
|
||||
}
|
||||
data_byte >>= 1;
|
||||
}
|
||||
}
|
||||
crc
|
||||
}
|
@ -273,14 +273,14 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
let p = embassy_stm32::init(config);
|
||||
info!("Embassy initialized");
|
||||
|
||||
let config = QspiCfg {
|
||||
memory_size: MemorySize::_8MiB,
|
||||
address_size: AddressSize::_24bit,
|
||||
prescaler: 16,
|
||||
cs_high_time: ChipSelectHighTime::_1Cycle,
|
||||
fifo_threshold: FIFOThresholdLevel::_16Bytes,
|
||||
sample_shifting: SampleShifting::None,
|
||||
};
|
||||
let mut config = QspiCfg::default();
|
||||
config.memory_size = MemorySize::_8MiB;
|
||||
config.address_size = AddressSize::_24bit;
|
||||
config.prescaler = 16;
|
||||
config.cs_high_time = ChipSelectHighTime::_1Cycle;
|
||||
config.fifo_threshold = FIFOThresholdLevel::_16Bytes;
|
||||
config.sample_shifting = SampleShifting::None;
|
||||
|
||||
let driver = Qspi::new_bank1(
|
||||
p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config,
|
||||
);
|
||||
|
@ -266,14 +266,14 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
let p = embassy_stm32::init(config);
|
||||
info!("Embassy initialized");
|
||||
|
||||
let config = QspiCfg {
|
||||
memory_size: MemorySize::_8MiB,
|
||||
address_size: AddressSize::_24bit,
|
||||
prescaler: 16,
|
||||
cs_high_time: ChipSelectHighTime::_1Cycle,
|
||||
fifo_threshold: FIFOThresholdLevel::_16Bytes,
|
||||
sample_shifting: SampleShifting::None,
|
||||
};
|
||||
let mut config = QspiCfg::default();
|
||||
config.memory_size = MemorySize::_8MiB;
|
||||
config.address_size = AddressSize::_24bit;
|
||||
config.prescaler = 16;
|
||||
config.cs_high_time = ChipSelectHighTime::_1Cycle;
|
||||
config.fifo_threshold = FIFOThresholdLevel::_16Bytes;
|
||||
config.sample_shifting = SampleShifting::None;
|
||||
|
||||
let driver = Qspi::new_blocking_bank1(p.QUADSPI, p.PD11, p.PD12, p.PE2, p.PD13, p.PB2, p.PB10, config);
|
||||
let mut flash = FlashMemory::new(driver);
|
||||
let flash_id = flash.read_id();
|
||||
|
@ -246,14 +246,14 @@ const MEMORY_ADDR: u32 = 0x00000000 as u32;
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
let config = qspi::Config {
|
||||
memory_size: MemorySize::_16MiB,
|
||||
address_size: AddressSize::_24bit,
|
||||
prescaler: 200,
|
||||
cs_high_time: ChipSelectHighTime::_1Cycle,
|
||||
fifo_threshold: FIFOThresholdLevel::_16Bytes,
|
||||
sample_shifting: SampleShifting::None,
|
||||
};
|
||||
let mut config = qspi::Config::default();
|
||||
config.memory_size = MemorySize::_16MiB;
|
||||
config.address_size = AddressSize::_24bit;
|
||||
config.prescaler = 200;
|
||||
config.cs_high_time = ChipSelectHighTime::_1Cycle;
|
||||
config.fifo_threshold = FIFOThresholdLevel::_16Bytes;
|
||||
config.sample_shifting = SampleShifting::None;
|
||||
|
||||
let driver = qspi::Qspi::new_bank1(p.QUADSPI, p.PB1, p.PB0, p.PA7, p.PA6, p.PA3, p.PA2, p.DMA2_CH7, config);
|
||||
let mut flash = FlashMemory::new(driver);
|
||||
let mut wr_buf = [0u8; 256];
|
||||
|
Loading…
x
Reference in New Issue
Block a user