mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 08:12:30 +00:00
Merge branch 'embassy-rs:main' into main
This commit is contained in:
commit
aeb4daa22f
1
.github/ci/test-nightly.sh
vendored
1
.github/ci/test-nightly.sh
vendored
@ -11,3 +11,4 @@ mv rust-toolchain-nightly.toml rust-toolchain.toml
|
||||
|
||||
MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml
|
||||
MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly
|
||||
MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-sync/Cargo.toml
|
||||
|
1
.github/ci/test.sh
vendored
1
.github/ci/test.sh
vendored
@ -8,6 +8,7 @@ export RUSTUP_HOME=/ci/cache/rustup
|
||||
export CARGO_HOME=/ci/cache/cargo
|
||||
export CARGO_TARGET_DIR=/ci/cache/target
|
||||
|
||||
cargo test --manifest-path ./embassy-futures/Cargo.toml
|
||||
cargo test --manifest-path ./embassy-sync/Cargo.toml
|
||||
cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml
|
||||
cargo test --manifest-path ./embassy-hal-internal/Cargo.toml
|
||||
|
@ -7,7 +7,7 @@ Embassy is the next-generation framework for embedded applications. Write safe,
|
||||
|
||||
The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system.
|
||||
|
||||
Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows for unprecedently easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation, and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is <a href="https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown">faster and smaller than one!</a>
|
||||
Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows for unprecedentedly easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation, and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is <a href="https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown">faster and smaller than one!</a>
|
||||
|
||||
## Batteries included
|
||||
|
||||
@ -89,7 +89,7 @@ async fn main(spawner: Spawner) {
|
||||
|
||||
## Examples
|
||||
|
||||
Examples are found in the `examples/` folder seperated by the chip manufacturer they are designed to run on. For example:
|
||||
Examples are found in the `examples/` folder separated by the chip manufacturer they are designed to run on. For example:
|
||||
|
||||
* `examples/nrf52840` run on the `nrf52840-dk` board (PCA10056) but should be easily adaptable to other nRF52 chips and boards.
|
||||
* `examples/nrf5340` run on the `nrf5340-dk` board (PCA10095).
|
||||
|
3
ci.sh
3
ci.sh
@ -149,6 +149,9 @@ cargo batch \
|
||||
--- 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 stm32h562ag,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 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 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' \
|
||||
|
@ -9,10 +9,16 @@ use core::task::{Context, Poll};
|
||||
/// hold, while still allowing other tasks to run concurrently (not monopolizing
|
||||
/// the executor thread).
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// ```rust
|
||||
/// # use embassy_futures::{block_on, yield_now};
|
||||
/// # async fn test_fn() {
|
||||
/// # let mut iter_count: u32 = 0;
|
||||
/// # let mut some_condition = || { iter_count += 1; iter_count > 10 };
|
||||
/// while !some_condition() {
|
||||
/// yield_now().await;
|
||||
/// }
|
||||
/// # }
|
||||
/// # block_on(test_fn());
|
||||
/// ```
|
||||
///
|
||||
/// The downside is this will spin in a busy loop, using 100% of the CPU, while
|
||||
|
@ -16,11 +16,11 @@ categories = [
|
||||
[package.metadata.embassy_docs]
|
||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/"
|
||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/"
|
||||
features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"]
|
||||
features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"]
|
||||
target = "thumbv7em-none-eabi"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"]
|
||||
features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
@ -38,6 +38,8 @@ packet-trace = []
|
||||
|
||||
## Enable UDP support
|
||||
udp = ["smoltcp/socket-udp"]
|
||||
## Enable Raw support
|
||||
raw = ["smoltcp/socket-raw"]
|
||||
## Enable TCP support
|
||||
tcp = ["smoltcp/socket-tcp"]
|
||||
## Enable DNS support
|
||||
|
@ -15,6 +15,8 @@ pub(crate) mod fmt;
|
||||
mod device;
|
||||
#[cfg(feature = "dns")]
|
||||
pub mod dns;
|
||||
#[cfg(feature = "raw")]
|
||||
pub mod raw;
|
||||
#[cfg(feature = "tcp")]
|
||||
pub mod tcp;
|
||||
mod time;
|
||||
|
120
embassy-net/src/raw.rs
Normal file
120
embassy-net/src/raw.rs
Normal file
@ -0,0 +1,120 @@
|
||||
//! Raw sockets.
|
||||
|
||||
use core::cell::RefCell;
|
||||
use core::future::poll_fn;
|
||||
use core::mem;
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use embassy_net_driver::Driver;
|
||||
use smoltcp::iface::{Interface, SocketHandle};
|
||||
use smoltcp::socket::raw;
|
||||
pub use smoltcp::socket::raw::PacketMetadata;
|
||||
use smoltcp::wire::{IpProtocol, IpVersion};
|
||||
|
||||
use crate::{SocketStack, Stack};
|
||||
|
||||
/// Error returned by [`RawSocket::recv`] and [`RawSocket::send`].
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum RecvError {
|
||||
/// Provided buffer was smaller than the received packet.
|
||||
Truncated,
|
||||
}
|
||||
|
||||
/// An Raw socket.
|
||||
pub struct RawSocket<'a> {
|
||||
stack: &'a RefCell<SocketStack>,
|
||||
handle: SocketHandle,
|
||||
}
|
||||
|
||||
impl<'a> RawSocket<'a> {
|
||||
/// Create a new Raw socket using the provided stack and buffers.
|
||||
pub fn new<D: Driver>(
|
||||
stack: &'a Stack<D>,
|
||||
ip_version: IpVersion,
|
||||
ip_protocol: IpProtocol,
|
||||
rx_meta: &'a mut [PacketMetadata],
|
||||
rx_buffer: &'a mut [u8],
|
||||
tx_meta: &'a mut [PacketMetadata],
|
||||
tx_buffer: &'a mut [u8],
|
||||
) -> Self {
|
||||
let s = &mut *stack.socket.borrow_mut();
|
||||
|
||||
let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) };
|
||||
let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
|
||||
let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) };
|
||||
let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
|
||||
let handle = s.sockets.add(raw::Socket::new(
|
||||
ip_version,
|
||||
ip_protocol,
|
||||
raw::PacketBuffer::new(rx_meta, rx_buffer),
|
||||
raw::PacketBuffer::new(tx_meta, tx_buffer),
|
||||
));
|
||||
|
||||
Self {
|
||||
stack: &stack.socket,
|
||||
handle,
|
||||
}
|
||||
}
|
||||
|
||||
fn with_mut<R>(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R {
|
||||
let s = &mut *self.stack.borrow_mut();
|
||||
let socket = s.sockets.get_mut::<raw::Socket>(self.handle);
|
||||
let res = f(socket, &mut s.iface);
|
||||
s.waker.wake();
|
||||
res
|
||||
}
|
||||
|
||||
/// Receive a datagram.
|
||||
///
|
||||
/// This method will wait until a datagram is received.
|
||||
pub async fn recv(&self, buf: &mut [u8]) -> Result<usize, RecvError> {
|
||||
poll_fn(move |cx| self.poll_recv(buf, cx)).await
|
||||
}
|
||||
|
||||
/// Receive a datagram.
|
||||
///
|
||||
/// When no datagram is available, this method will return `Poll::Pending` and
|
||||
/// register the current task to be notified when a datagram is received.
|
||||
pub fn poll_recv(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll<Result<usize, RecvError>> {
|
||||
self.with_mut(|s, _| match s.recv_slice(buf) {
|
||||
Ok(n) => Poll::Ready(Ok(n)),
|
||||
// No data ready
|
||||
Err(raw::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)),
|
||||
Err(raw::RecvError::Exhausted) => {
|
||||
s.register_recv_waker(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Send a datagram.
|
||||
///
|
||||
/// This method will wait until the datagram has been sent.`
|
||||
pub async fn send(&self, buf: &[u8]) {
|
||||
poll_fn(move |cx| self.poll_send(buf, cx)).await
|
||||
}
|
||||
|
||||
/// Send a datagram.
|
||||
///
|
||||
/// When the datagram has been sent, this method will return `Poll::Ready(Ok())`.
|
||||
///
|
||||
/// When the socket's send buffer is full, this method will return `Poll::Pending`
|
||||
/// and register the current task to be notified when the buffer has space available.
|
||||
pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll<()> {
|
||||
self.with_mut(|s, _| match s.send_slice(buf) {
|
||||
// Entire datagram has been sent
|
||||
Ok(()) => Poll::Ready(()),
|
||||
Err(raw::SendError::BufferFull) => {
|
||||
s.register_send_waker(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RawSocket<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.stack.borrow_mut().sockets.remove(self.handle);
|
||||
}
|
||||
}
|
40
embassy-nrf/CHANGELOG.md
Normal file
40
embassy-nrf/CHANGELOG.md
Normal file
@ -0,0 +1,40 @@
|
||||
# Changelog for embassy-nrf
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Drop `sealed` mod
|
||||
- nrf52840: Add dcdc voltage parameter to configure REG0 regulator
|
||||
- radio: Add support for IEEE 802.15.4 and BLE via radio peripheral
|
||||
- spim: Reduce trace-level messages ("Copying SPIM tx buffer..")
|
||||
- uart: Add support for rx- or tx-only BufferedUart
|
||||
- uart: Implement splitting Rx/Tx
|
||||
- spi: Allow specifying OutputDrive for SPI spins
|
||||
- pdm: Fix gain register value derivation
|
||||
- spim: Implement chunked DMA transfers
|
||||
- spi: Add bounds checks for EasyDMA buffer size
|
||||
- uarte: Add support for handling RX errors
|
||||
- nrf51: Implement support for nrf51 chip
|
||||
- pwm: Expose `duty` method
|
||||
- pwm: Fix infinite loop
|
||||
- spi: Add support for configuring bit order for bus
|
||||
- pwm: Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method
|
||||
- gpio: Drop GPIO Pin generics (API break)
|
||||
|
||||
## 0.1.0 - 2024-01-12
|
||||
|
||||
- First release with support for following NRF chips:
|
||||
- nrf52805
|
||||
- nrf52810
|
||||
- nrf52811
|
||||
- nrf52820
|
||||
- nrf52832
|
||||
- nrf52833
|
||||
- nrf52840
|
||||
- nrf5340
|
||||
- nrf9160
|
||||
|
@ -30,6 +30,7 @@ flavors = [
|
||||
{ regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" },
|
||||
{ regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" },
|
||||
{ regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] },
|
||||
{ regex_feature = "stm32u0.*", target = "thumbv6m-none-eabi" },
|
||||
{ regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" },
|
||||
{ regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" },
|
||||
{ regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" },
|
||||
@ -70,7 +71,7 @@ rand_core = "0.6.3"
|
||||
sdio-host = "0.5.0"
|
||||
critical-section = "1.1"
|
||||
#stm32-metapac = { version = "15" }
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b7ec569a5510c324693f0515ac8ea20b12917a9" }
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d674277b78ca7400ecfeeb1b5af4e460a65c1a61" }
|
||||
|
||||
vcell = "0.1.3"
|
||||
nb = "1.0.0"
|
||||
@ -96,7 +97,7 @@ proc-macro2 = "1.0.36"
|
||||
quote = "1.0.15"
|
||||
|
||||
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b7ec569a5510c324693f0515ac8ea20b12917a9", default-features = false, features = ["metadata"]}
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d674277b78ca7400ecfeeb1b5af4e460a65c1a61", default-features = false, features = ["metadata"]}
|
||||
|
||||
[features]
|
||||
default = ["rt"]
|
||||
@ -1419,6 +1420,38 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ]
|
||||
stm32l562re = [ "stm32-metapac/stm32l562re" ]
|
||||
stm32l562ve = [ "stm32-metapac/stm32l562ve" ]
|
||||
stm32l562ze = [ "stm32-metapac/stm32l562ze" ]
|
||||
stm32u031c6 = [ "stm32-metapac/stm32u031c6" ]
|
||||
stm32u031c8 = [ "stm32-metapac/stm32u031c8" ]
|
||||
stm32u031f4 = [ "stm32-metapac/stm32u031f4" ]
|
||||
stm32u031f6 = [ "stm32-metapac/stm32u031f6" ]
|
||||
stm32u031f8 = [ "stm32-metapac/stm32u031f8" ]
|
||||
stm32u031g6 = [ "stm32-metapac/stm32u031g6" ]
|
||||
stm32u031g8 = [ "stm32-metapac/stm32u031g8" ]
|
||||
stm32u031k4 = [ "stm32-metapac/stm32u031k4" ]
|
||||
stm32u031k6 = [ "stm32-metapac/stm32u031k6" ]
|
||||
stm32u031k8 = [ "stm32-metapac/stm32u031k8" ]
|
||||
stm32u031r6 = [ "stm32-metapac/stm32u031r6" ]
|
||||
stm32u031r8 = [ "stm32-metapac/stm32u031r8" ]
|
||||
stm32u073c8 = [ "stm32-metapac/stm32u073c8" ]
|
||||
stm32u073cb = [ "stm32-metapac/stm32u073cb" ]
|
||||
stm32u073cc = [ "stm32-metapac/stm32u073cc" ]
|
||||
stm32u073h8 = [ "stm32-metapac/stm32u073h8" ]
|
||||
stm32u073hb = [ "stm32-metapac/stm32u073hb" ]
|
||||
stm32u073hc = [ "stm32-metapac/stm32u073hc" ]
|
||||
stm32u073k8 = [ "stm32-metapac/stm32u073k8" ]
|
||||
stm32u073kb = [ "stm32-metapac/stm32u073kb" ]
|
||||
stm32u073kc = [ "stm32-metapac/stm32u073kc" ]
|
||||
stm32u073m8 = [ "stm32-metapac/stm32u073m8" ]
|
||||
stm32u073mb = [ "stm32-metapac/stm32u073mb" ]
|
||||
stm32u073mc = [ "stm32-metapac/stm32u073mc" ]
|
||||
stm32u073r8 = [ "stm32-metapac/stm32u073r8" ]
|
||||
stm32u073rb = [ "stm32-metapac/stm32u073rb" ]
|
||||
stm32u073rc = [ "stm32-metapac/stm32u073rc" ]
|
||||
stm32u083cc = [ "stm32-metapac/stm32u083cc" ]
|
||||
stm32u083hc = [ "stm32-metapac/stm32u083hc" ]
|
||||
stm32u083kc = [ "stm32-metapac/stm32u083kc" ]
|
||||
stm32u083mc = [ "stm32-metapac/stm32u083mc" ]
|
||||
stm32u083rc = [ "stm32-metapac/stm32u083rc" ]
|
||||
stm32u535cb = [ "stm32-metapac/stm32u535cb" ]
|
||||
stm32u535cc = [ "stm32-metapac/stm32u535cc" ]
|
||||
stm32u535ce = [ "stm32-metapac/stm32u535ce" ]
|
||||
@ -1474,6 +1507,7 @@ stm32u599vj = [ "stm32-metapac/stm32u599vj" ]
|
||||
stm32u599zi = [ "stm32-metapac/stm32u599zi" ]
|
||||
stm32u599zj = [ "stm32-metapac/stm32u599zj" ]
|
||||
stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ]
|
||||
stm32u5a5qi = [ "stm32-metapac/stm32u5a5qi" ]
|
||||
stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ]
|
||||
stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ]
|
||||
stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ]
|
||||
|
@ -272,8 +272,6 @@ fn main() {
|
||||
"Bank1"
|
||||
} else if region.name.starts_with("BANK_2") {
|
||||
"Bank2"
|
||||
} else if region.name == "OTP" {
|
||||
"Otp"
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@ -664,6 +662,7 @@ fn main() {
|
||||
#(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[non_exhaustive]
|
||||
pub struct ClockMux {
|
||||
#( #struct_fields, )*
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use super::blocking_delay_us;
|
||||
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||
use crate::time::Hertz;
|
||||
use crate::{interrupt, Peripheral};
|
||||
@ -48,14 +48,14 @@ impl<T: Instance> super::SealedAdcPin<T> for Temperature {
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
T::regs().cr2().modify(|reg| reg.set_adon(true));
|
||||
|
||||
// 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
|
||||
// for at least two ADC clock cycles
|
||||
delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1);
|
||||
// for at least two ADC clock cycles.
|
||||
blocking_delay_us((1_000_000 * 2) / Self::freq().0 + 1);
|
||||
|
||||
// Reset calibration
|
||||
T::regs().cr2().modify(|reg| reg.set_rstcal(true));
|
||||
@ -70,7 +70,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
|
||||
// One cycle after calibration
|
||||
delay.delay_us((1_000_000) / Self::freq().0 + 1);
|
||||
blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1);
|
||||
|
||||
Self {
|
||||
adc,
|
||||
@ -95,7 +95,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
|
||||
pub fn enable_vref(&self) -> Vref {
|
||||
T::regs().cr2().modify(|reg| {
|
||||
reg.set_tsvrefe(true);
|
||||
});
|
||||
|
@ -3,8 +3,8 @@ use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use super::blocking_delay_us;
|
||||
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::time::Hertz;
|
||||
@ -58,7 +58,6 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(
|
||||
adc: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
delay: &mut impl DelayUs<u32>,
|
||||
) -> Self {
|
||||
use crate::pac::adc::vals;
|
||||
|
||||
@ -71,7 +70,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED));
|
||||
|
||||
// Wait for the regulator to stabilize
|
||||
delay.delay_us(10);
|
||||
blocking_delay_us(10);
|
||||
|
||||
assert!(!T::regs().cr().read().aden());
|
||||
|
||||
@ -81,8 +80,8 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
|
||||
while T::regs().cr().read().adcal() {}
|
||||
|
||||
// Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223)
|
||||
delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0));
|
||||
// Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223).
|
||||
blocking_delay_us((1_000_000 * 4) / Self::freq().0 + 1);
|
||||
|
||||
// Enable the adc
|
||||
T::regs().cr().modify(|w| w.set_aden(true));
|
||||
@ -117,7 +116,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
|
||||
pub fn enable_vref(&self) -> Vref {
|
||||
T::common_regs().ccr().modify(|w| w.set_vrefen(true));
|
||||
|
||||
Vref {}
|
||||
|
304
embassy-stm32/src/adc/g4.rs
Normal file
304
embassy-stm32/src/adc/g4.rs
Normal file
@ -0,0 +1,304 @@
|
||||
#[allow(unused)]
|
||||
use pac::adc::vals::{Adcaldif, Difsel, Exten};
|
||||
use pac::adccommon::vals::Presc;
|
||||
|
||||
use super::{blocking_delay_us, Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
|
||||
use crate::time::Hertz;
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
/// Default VREF voltage used for sample conversion to millivolts.
|
||||
pub const VREF_DEFAULT_MV: u32 = 3300;
|
||||
/// VREF voltage used for factory calibration of VREFINTCAL register.
|
||||
pub const VREF_CALIB_MV: u32 = 3300;
|
||||
|
||||
/// Max single ADC operation clock frequency
|
||||
#[cfg(stm32g4)]
|
||||
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
|
||||
#[cfg(stm32h7)]
|
||||
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
|
||||
|
||||
#[cfg(stm32g4)]
|
||||
const VREF_CHANNEL: u8 = 18;
|
||||
#[cfg(stm32g4)]
|
||||
const TEMP_CHANNEL: u8 = 16;
|
||||
|
||||
#[cfg(stm32h7)]
|
||||
const VREF_CHANNEL: u8 = 19;
|
||||
#[cfg(stm32h7)]
|
||||
const TEMP_CHANNEL: u8 = 18;
|
||||
|
||||
// TODO this should be 14 for H7a/b/35
|
||||
const VBAT_CHANNEL: u8 = 17;
|
||||
|
||||
// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
|
||||
/// Internal voltage reference channel.
|
||||
pub struct VrefInt;
|
||||
impl<T: Instance> InternalChannel<T> for VrefInt {}
|
||||
impl<T: Instance> super::SealedInternalChannel<T> for VrefInt {
|
||||
fn channel(&self) -> u8 {
|
||||
VREF_CHANNEL
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal temperature channel.
|
||||
pub struct Temperature;
|
||||
impl<T: Instance> InternalChannel<T> for Temperature {}
|
||||
impl<T: Instance> super::SealedInternalChannel<T> for Temperature {
|
||||
fn channel(&self) -> u8 {
|
||||
TEMP_CHANNEL
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal battery voltage channel.
|
||||
pub struct Vbat;
|
||||
impl<T: Instance> InternalChannel<T> for Vbat {}
|
||||
impl<T: Instance> super::SealedInternalChannel<T> for Vbat {
|
||||
fn channel(&self) -> u8 {
|
||||
VBAT_CHANNEL
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
|
||||
// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
|
||||
#[allow(unused)]
|
||||
enum Prescaler {
|
||||
NotDivided,
|
||||
DividedBy2,
|
||||
DividedBy4,
|
||||
DividedBy6,
|
||||
DividedBy8,
|
||||
DividedBy10,
|
||||
DividedBy12,
|
||||
DividedBy16,
|
||||
DividedBy32,
|
||||
DividedBy64,
|
||||
DividedBy128,
|
||||
DividedBy256,
|
||||
}
|
||||
|
||||
impl Prescaler {
|
||||
fn from_ker_ck(frequency: Hertz) -> Self {
|
||||
let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
|
||||
match raw_prescaler {
|
||||
0 => Self::NotDivided,
|
||||
1 => Self::DividedBy2,
|
||||
2..=3 => Self::DividedBy4,
|
||||
4..=5 => Self::DividedBy6,
|
||||
6..=7 => Self::DividedBy8,
|
||||
8..=9 => Self::DividedBy10,
|
||||
10..=11 => Self::DividedBy12,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn divisor(&self) -> u32 {
|
||||
match self {
|
||||
Prescaler::NotDivided => 1,
|
||||
Prescaler::DividedBy2 => 2,
|
||||
Prescaler::DividedBy4 => 4,
|
||||
Prescaler::DividedBy6 => 6,
|
||||
Prescaler::DividedBy8 => 8,
|
||||
Prescaler::DividedBy10 => 10,
|
||||
Prescaler::DividedBy12 => 12,
|
||||
Prescaler::DividedBy16 => 16,
|
||||
Prescaler::DividedBy32 => 32,
|
||||
Prescaler::DividedBy64 => 64,
|
||||
Prescaler::DividedBy128 => 128,
|
||||
Prescaler::DividedBy256 => 256,
|
||||
}
|
||||
}
|
||||
|
||||
fn presc(&self) -> Presc {
|
||||
match self {
|
||||
Prescaler::NotDivided => Presc::DIV1,
|
||||
Prescaler::DividedBy2 => Presc::DIV2,
|
||||
Prescaler::DividedBy4 => Presc::DIV4,
|
||||
Prescaler::DividedBy6 => Presc::DIV6,
|
||||
Prescaler::DividedBy8 => Presc::DIV8,
|
||||
Prescaler::DividedBy10 => Presc::DIV10,
|
||||
Prescaler::DividedBy12 => Presc::DIV12,
|
||||
Prescaler::DividedBy16 => Presc::DIV16,
|
||||
Prescaler::DividedBy32 => Presc::DIV32,
|
||||
Prescaler::DividedBy64 => Presc::DIV64,
|
||||
Prescaler::DividedBy128 => Presc::DIV128,
|
||||
Prescaler::DividedBy256 => Presc::DIV256,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
/// Create a new ADC driver.
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
|
||||
embassy_hal_internal::into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
|
||||
let prescaler = Prescaler::from_ker_ck(T::frequency());
|
||||
|
||||
T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
|
||||
|
||||
let frequency = Hertz(T::frequency().0 / prescaler.divisor());
|
||||
info!("ADC frequency set to {} Hz", frequency.0);
|
||||
|
||||
if frequency > MAX_ADC_CLK_FREQ {
|
||||
panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
|
||||
}
|
||||
|
||||
let mut s = Self {
|
||||
adc,
|
||||
sample_time: SampleTime::from_bits(0),
|
||||
};
|
||||
s.power_up();
|
||||
s.configure_differential_inputs();
|
||||
|
||||
s.calibrate();
|
||||
blocking_delay_us(1);
|
||||
|
||||
s.enable();
|
||||
s.configure();
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
fn power_up(&mut self) {
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_deeppwd(false);
|
||||
reg.set_advregen(true);
|
||||
});
|
||||
|
||||
blocking_delay_us(10);
|
||||
}
|
||||
|
||||
fn configure_differential_inputs(&mut self) {
|
||||
T::regs().difsel().modify(|w| {
|
||||
for n in 0..20 {
|
||||
w.set_difsel(n, Difsel::SINGLEENDED);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn calibrate(&mut self) {
|
||||
T::regs().cr().modify(|w| {
|
||||
w.set_adcaldif(Adcaldif::SINGLEENDED);
|
||||
});
|
||||
|
||||
T::regs().cr().modify(|w| w.set_adcal(true));
|
||||
|
||||
while T::regs().cr().read().adcal() {}
|
||||
}
|
||||
|
||||
fn enable(&mut self) {
|
||||
T::regs().isr().write(|w| w.set_adrdy(true));
|
||||
T::regs().cr().modify(|w| w.set_aden(true));
|
||||
while !T::regs().isr().read().adrdy() {}
|
||||
T::regs().isr().write(|w| w.set_adrdy(true));
|
||||
}
|
||||
|
||||
fn configure(&mut self) {
|
||||
// single conversion mode, software trigger
|
||||
T::regs().cfgr().modify(|w| {
|
||||
w.set_cont(false);
|
||||
w.set_exten(Exten::DISABLED);
|
||||
});
|
||||
}
|
||||
|
||||
/// Enable reading the voltage reference internal channel.
|
||||
pub fn enable_vrefint(&self) -> VrefInt {
|
||||
T::common_regs().ccr().modify(|reg| {
|
||||
reg.set_vrefen(true);
|
||||
});
|
||||
|
||||
VrefInt {}
|
||||
}
|
||||
|
||||
/// Enable reading the temperature internal channel.
|
||||
pub fn enable_temperature(&self) -> Temperature {
|
||||
T::common_regs().ccr().modify(|reg| {
|
||||
reg.set_vsenseen(true);
|
||||
});
|
||||
|
||||
Temperature {}
|
||||
}
|
||||
|
||||
/// Enable reading the vbat internal channel.
|
||||
pub fn enable_vbat(&self) -> Vbat {
|
||||
T::common_regs().ccr().modify(|reg| {
|
||||
reg.set_vbaten(true);
|
||||
});
|
||||
|
||||
Vbat {}
|
||||
}
|
||||
|
||||
/// Set the ADC sample time.
|
||||
pub fn set_sample_time(&mut self, sample_time: SampleTime) {
|
||||
self.sample_time = sample_time;
|
||||
}
|
||||
|
||||
/// Set the ADC resolution.
|
||||
pub fn set_resolution(&mut self, resolution: Resolution) {
|
||||
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
|
||||
}
|
||||
|
||||
/// Perform a single conversion.
|
||||
fn convert(&mut self) -> u16 {
|
||||
T::regs().isr().modify(|reg| {
|
||||
reg.set_eos(true);
|
||||
reg.set_eoc(true);
|
||||
});
|
||||
|
||||
// Start conversion
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_adstart(true);
|
||||
});
|
||||
|
||||
while !T::regs().isr().read().eos() {
|
||||
// spin
|
||||
}
|
||||
|
||||
T::regs().dr().read().0 as u16
|
||||
}
|
||||
|
||||
/// Read an ADC pin.
|
||||
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
||||
where
|
||||
P: AdcPin<T>,
|
||||
P: crate::gpio::Pin,
|
||||
{
|
||||
pin.set_as_analog();
|
||||
|
||||
self.read_channel(pin.channel())
|
||||
}
|
||||
|
||||
/// Read an ADC internal channel.
|
||||
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
|
||||
self.read_channel(channel.channel())
|
||||
}
|
||||
|
||||
fn read_channel(&mut self, channel: u8) -> u16 {
|
||||
// Configure channel
|
||||
Self::set_channel_sample_time(channel, self.sample_time);
|
||||
|
||||
#[cfg(stm32h7)]
|
||||
{
|
||||
T::regs().cfgr2().modify(|w| w.set_lshift(0));
|
||||
T::regs()
|
||||
.pcsel()
|
||||
.write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
|
||||
}
|
||||
|
||||
T::regs().sqr1().write(|reg| {
|
||||
reg.set_sq(0, channel);
|
||||
reg.set_l(0);
|
||||
});
|
||||
|
||||
self.convert()
|
||||
}
|
||||
|
||||
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||
let sample_time = sample_time.into();
|
||||
if ch <= 9 {
|
||||
T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||
} else {
|
||||
T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
#[cfg_attr(adc_v2, path = "v2.rs")]
|
||||
#[cfg_attr(any(adc_v3, adc_g0, adc_h5), path = "v3.rs")]
|
||||
#[cfg_attr(adc_v4, path = "v4.rs")]
|
||||
#[cfg_attr(adc_g4, path = "g4.rs")]
|
||||
mod _version;
|
||||
|
||||
#[allow(unused)]
|
||||
@ -69,14 +70,47 @@ trait SealedInternalChannel<T> {
|
||||
fn channel(&self) -> u8;
|
||||
}
|
||||
|
||||
/// Performs a busy-wait delay for a specified number of microseconds.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn blocking_delay_us(us: u32) {
|
||||
#[cfg(time)]
|
||||
embassy_time::block_for(embassy_time::Duration::from_micros(us));
|
||||
#[cfg(not(time))]
|
||||
cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 * us / 1_000_000);
|
||||
}
|
||||
|
||||
/// ADC instance.
|
||||
#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5)))]
|
||||
#[cfg(not(any(
|
||||
adc_f1,
|
||||
adc_v1,
|
||||
adc_l0,
|
||||
adc_v2,
|
||||
adc_v3,
|
||||
adc_v4,
|
||||
adc_g4,
|
||||
adc_f3,
|
||||
adc_f3_v1_1,
|
||||
adc_g0,
|
||||
adc_h5
|
||||
)))]
|
||||
#[allow(private_bounds)]
|
||||
pub trait Instance: SealedInstance + crate::Peripheral<P = Self> {
|
||||
type Interrupt: crate::interrupt::typelevel::Interrupt;
|
||||
}
|
||||
/// ADC instance.
|
||||
#[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5))]
|
||||
#[cfg(any(
|
||||
adc_f1,
|
||||
adc_v1,
|
||||
adc_l0,
|
||||
adc_v2,
|
||||
adc_v3,
|
||||
adc_v4,
|
||||
adc_g4,
|
||||
adc_f3,
|
||||
adc_f3_v1_1,
|
||||
adc_g0,
|
||||
adc_h5
|
||||
))]
|
||||
#[allow(private_bounds)]
|
||||
pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {
|
||||
type Interrupt: crate::interrupt::typelevel::Interrupt;
|
||||
|
@ -3,10 +3,10 @@ use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
#[cfg(adc_l0)]
|
||||
use stm32_metapac::adc::vals::Ckmode;
|
||||
|
||||
use super::blocking_delay_us;
|
||||
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::peripherals::ADC;
|
||||
@ -65,7 +65,6 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(
|
||||
adc: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
delay: &mut impl DelayUs<u32>,
|
||||
) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
@ -74,7 +73,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
//
|
||||
// Table 57. ADC characteristics
|
||||
// tstab = 14 * 1/fadc
|
||||
delay.delay_us(1);
|
||||
blocking_delay_us(1);
|
||||
|
||||
// set default PCKL/2 on L0s because HSI is disabled in the default clock config
|
||||
#[cfg(adc_l0)]
|
||||
@ -114,7 +113,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
|
||||
#[cfg(not(adc_l0))]
|
||||
pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
|
||||
pub fn enable_vbat(&self) -> Vbat {
|
||||
// SMP must be ≥ 56 ADC clock cycles when using HSI14.
|
||||
//
|
||||
// 6.3.20 Vbat monitoring characteristics
|
||||
@ -123,22 +122,22 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
Vbat
|
||||
}
|
||||
|
||||
pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref {
|
||||
pub fn enable_vref(&self) -> Vref {
|
||||
// Table 28. Embedded internal reference voltage
|
||||
// tstart = 10μs
|
||||
T::regs().ccr().modify(|reg| reg.set_vrefen(true));
|
||||
delay.delay_us(10);
|
||||
blocking_delay_us(10);
|
||||
Vref
|
||||
}
|
||||
|
||||
pub fn enable_temperature(&self, delay: &mut impl DelayUs<u32>) -> Temperature {
|
||||
pub fn enable_temperature(&self) -> Temperature {
|
||||
// SMP must be ≥ 56 ADC clock cycles when using HSI14.
|
||||
//
|
||||
// 6.3.19 Temperature sensor characteristics
|
||||
// tstart ≤ 10μs
|
||||
// ts_temp ≥ 4μs
|
||||
T::regs().ccr().modify(|reg| reg.set_tsen(true));
|
||||
delay.delay_us(10);
|
||||
blocking_delay_us(10);
|
||||
Temperature
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use super::blocking_delay_us;
|
||||
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
|
||||
use crate::peripherals::ADC1;
|
||||
use crate::time::Hertz;
|
||||
@ -11,9 +11,6 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
|
||||
/// VREF voltage used for factory calibration of VREFINTCAL register.
|
||||
pub const VREF_CALIB_MV: u32 = 3300;
|
||||
|
||||
/// ADC turn-on time
|
||||
pub const ADC_POWERUP_TIME_US: u32 = 3;
|
||||
|
||||
pub struct VrefInt;
|
||||
impl AdcPin<ADC1> for VrefInt {}
|
||||
impl super::SealedAdcPin<ADC1> for VrefInt {
|
||||
@ -97,7 +94,7 @@ impl<'d, T> Adc<'d, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
|
||||
@ -107,7 +104,7 @@ where
|
||||
reg.set_adon(true);
|
||||
});
|
||||
|
||||
delay.delay_us(ADC_POWERUP_TIME_US);
|
||||
blocking_delay_us(3);
|
||||
|
||||
Self {
|
||||
adc,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use cfg_if::cfg_if;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use super::blocking_delay_us;
|
||||
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
|
||||
use crate::Peripheral;
|
||||
|
||||
@ -74,7 +74,7 @@ cfg_if! {
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
T::regs().cr().modify(|reg| {
|
||||
@ -88,7 +88,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
reg.set_chselrmod(false);
|
||||
});
|
||||
|
||||
delay.delay_us(20);
|
||||
blocking_delay_us(20);
|
||||
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_adcal(true);
|
||||
@ -98,7 +98,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
// spin
|
||||
}
|
||||
|
||||
delay.delay_us(1);
|
||||
blocking_delay_us(1);
|
||||
|
||||
Self {
|
||||
adc,
|
||||
@ -106,7 +106,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt {
|
||||
pub fn enable_vrefint(&self) -> VrefInt {
|
||||
#[cfg(not(adc_g0))]
|
||||
T::common_regs().ccr().modify(|reg| {
|
||||
reg.set_vrefen(true);
|
||||
@ -117,10 +117,8 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
});
|
||||
|
||||
// "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
|
||||
// to stabilize the internal voltage reference, we wait a little more.
|
||||
// TODO: delay 15us
|
||||
//cortex_m::asm::delay(20_000_000);
|
||||
delay.delay_us(15);
|
||||
// to stabilize the internal voltage reference.
|
||||
blocking_delay_us(15);
|
||||
|
||||
VrefInt {}
|
||||
}
|
||||
@ -222,6 +220,13 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
// spin
|
||||
}
|
||||
|
||||
// RM0492, RM0481, etc.
|
||||
// "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
|
||||
#[cfg(adc_h5)]
|
||||
if pin.channel() == 0 {
|
||||
T::regs().or().modify(|reg| reg.set_op0(true));
|
||||
}
|
||||
|
||||
// Configure channel
|
||||
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
||||
|
||||
@ -244,6 +249,13 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
|
||||
T::regs().cr().modify(|reg| reg.set_addis(true));
|
||||
|
||||
// RM0492, RM0481, etc.
|
||||
// "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
|
||||
#[cfg(adc_h5)]
|
||||
if pin.channel() == 0 {
|
||||
T::regs().or().modify(|reg| reg.set_op0(false));
|
||||
}
|
||||
|
||||
val
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
#[allow(unused)]
|
||||
use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
|
||||
use pac::adccommon::vals::Presc;
|
||||
|
||||
use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
|
||||
use super::{blocking_delay_us, Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
|
||||
use crate::time::Hertz;
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -129,7 +128,7 @@ impl Prescaler {
|
||||
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
/// Create a new ADC driver.
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
|
||||
embassy_hal_internal::into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
|
||||
@ -161,11 +160,11 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
adc,
|
||||
sample_time: SampleTime::from_bits(0),
|
||||
};
|
||||
s.power_up(delay);
|
||||
s.power_up();
|
||||
s.configure_differential_inputs();
|
||||
|
||||
s.calibrate();
|
||||
delay.delay_us(1);
|
||||
blocking_delay_us(1);
|
||||
|
||||
s.enable();
|
||||
s.configure();
|
||||
@ -173,13 +172,13 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
s
|
||||
}
|
||||
|
||||
fn power_up(&mut self, delay: &mut impl DelayUs<u16>) {
|
||||
fn power_up(&mut self) {
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_deeppwd(false);
|
||||
reg.set_advregen(true);
|
||||
});
|
||||
|
||||
delay.delay_us(10);
|
||||
blocking_delay_us(10);
|
||||
}
|
||||
|
||||
fn configure_differential_inputs(&mut self) {
|
||||
|
@ -32,6 +32,9 @@ impl<'d> Crc<'d> {
|
||||
/// Feeds a word to the peripheral and returns the current CRC value
|
||||
pub fn feed_word(&mut self, word: u32) -> u32 {
|
||||
// write a single byte to the device, and return the result
|
||||
#[cfg(not(crc_v1))]
|
||||
PAC_CRC.dr32().write_value(word);
|
||||
#[cfg(crc_v1)]
|
||||
PAC_CRC.dr().write_value(word);
|
||||
self.read()
|
||||
}
|
||||
@ -39,6 +42,9 @@ impl<'d> Crc<'d> {
|
||||
/// Feed a slice of words to the peripheral and return the result.
|
||||
pub fn feed_words(&mut self, words: &[u32]) -> u32 {
|
||||
for word in words {
|
||||
#[cfg(not(crc_v1))]
|
||||
PAC_CRC.dr32().write_value(*word);
|
||||
#[cfg(crc_v1)]
|
||||
PAC_CRC.dr().write_value(*word);
|
||||
}
|
||||
|
||||
@ -46,6 +52,12 @@ impl<'d> Crc<'d> {
|
||||
}
|
||||
|
||||
/// Read the CRC result value.
|
||||
#[cfg(not(crc_v1))]
|
||||
pub fn read(&self) -> u32 {
|
||||
PAC_CRC.dr32().read()
|
||||
}
|
||||
/// Read the CRC result value.
|
||||
#[cfg(crc_v1)]
|
||||
pub fn read(&self) -> u32 {
|
||||
PAC_CRC.dr().read()
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ impl<'d> Crc<'d> {
|
||||
/// Feeds a byte into the CRC peripheral. Returns the computed checksum.
|
||||
pub fn feed_byte(&mut self, byte: u8) -> u32 {
|
||||
PAC_CRC.dr8().write_value(byte);
|
||||
PAC_CRC.dr().read()
|
||||
PAC_CRC.dr32().read()
|
||||
}
|
||||
|
||||
/// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
|
||||
@ -144,30 +144,30 @@ impl<'d> Crc<'d> {
|
||||
for byte in bytes {
|
||||
PAC_CRC.dr8().write_value(*byte);
|
||||
}
|
||||
PAC_CRC.dr().read()
|
||||
PAC_CRC.dr32().read()
|
||||
}
|
||||
/// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
|
||||
pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
|
||||
PAC_CRC.dr16().write_value(halfword);
|
||||
PAC_CRC.dr().read()
|
||||
PAC_CRC.dr32().read()
|
||||
}
|
||||
/// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
|
||||
pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
|
||||
for halfword in halfwords {
|
||||
PAC_CRC.dr16().write_value(*halfword);
|
||||
}
|
||||
PAC_CRC.dr().read()
|
||||
PAC_CRC.dr32().read()
|
||||
}
|
||||
/// Feeds a words into the CRC peripheral. Returns the computed checksum.
|
||||
pub fn feed_word(&mut self, word: u32) -> u32 {
|
||||
PAC_CRC.dr().write_value(word as u32);
|
||||
PAC_CRC.dr().read()
|
||||
PAC_CRC.dr32().write_value(word as u32);
|
||||
PAC_CRC.dr32().read()
|
||||
}
|
||||
/// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
|
||||
pub fn feed_words(&mut self, words: &[u32]) -> u32 {
|
||||
for word in words {
|
||||
PAC_CRC.dr().write_value(*word as u32);
|
||||
PAC_CRC.dr32().write_value(*word as u32);
|
||||
}
|
||||
PAC_CRC.dr().read()
|
||||
PAC_CRC.dr32().read()
|
||||
}
|
||||
}
|
||||
|
@ -27,11 +27,11 @@ fn cpu_regs() -> pac::exti::Exti {
|
||||
EXTI
|
||||
}
|
||||
|
||||
#[cfg(not(any(exti_c0, exti_g0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))]
|
||||
#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))]
|
||||
fn exticr_regs() -> pac::syscfg::Syscfg {
|
||||
pac::SYSCFG
|
||||
}
|
||||
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
|
||||
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
|
||||
fn exticr_regs() -> pac::exti::Exti {
|
||||
EXTI
|
||||
}
|
||||
@ -44,9 +44,9 @@ unsafe fn on_irq() {
|
||||
#[cfg(feature = "low-power")]
|
||||
crate::low_power::on_wakeup_irq();
|
||||
|
||||
#[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
|
||||
#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
|
||||
let bits = EXTI.pr(0).read().0;
|
||||
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
|
||||
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
|
||||
let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0;
|
||||
|
||||
// We don't handle or change any EXTI lines above 16.
|
||||
@ -61,9 +61,9 @@ unsafe fn on_irq() {
|
||||
}
|
||||
|
||||
// Clear pending
|
||||
#[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
|
||||
#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
|
||||
EXTI.pr(0).write_value(Lines(bits));
|
||||
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
|
||||
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
|
||||
{
|
||||
EXTI.rpr(0).write_value(Lines(bits));
|
||||
EXTI.fpr(0).write_value(Lines(bits));
|
||||
@ -241,9 +241,9 @@ impl<'a> ExtiInputFuture<'a> {
|
||||
EXTI.ftsr(0).modify(|w| w.set_line(pin, falling));
|
||||
|
||||
// clear pending bit
|
||||
#[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
|
||||
#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
|
||||
EXTI.pr(0).write(|w| w.set_line(pin, true));
|
||||
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
|
||||
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
|
||||
{
|
||||
EXTI.rpr(0).write(|w| w.set_line(pin, true));
|
||||
EXTI.fpr(0).write(|w| w.set_line(pin, true));
|
||||
|
@ -16,7 +16,7 @@ mod alt_regions {
|
||||
use embassy_hal_internal::PeripheralRef;
|
||||
use stm32_metapac::FLASH_SIZE;
|
||||
|
||||
use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION};
|
||||
use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3};
|
||||
use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion};
|
||||
use crate::peripherals::FLASH;
|
||||
|
||||
@ -62,7 +62,6 @@ mod alt_regions {
|
||||
pub bank2_region1: AltBank2Region1<'d, MODE>,
|
||||
pub bank2_region2: AltBank2Region2<'d, MODE>,
|
||||
pub bank2_region3: AltBank2Region3<'d, MODE>,
|
||||
pub otp_region: OTPRegion<'d, MODE>,
|
||||
}
|
||||
|
||||
impl<'d> Flash<'d> {
|
||||
@ -79,7 +78,6 @@ mod alt_regions {
|
||||
bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
|
||||
bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
|
||||
bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
|
||||
otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,7 +94,6 @@ mod alt_regions {
|
||||
bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
|
||||
bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
|
||||
bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
|
||||
otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
|
||||
assert!(sector.bank != FlashBank::Otp);
|
||||
assert!(sector.index_in_bank < 8);
|
||||
|
||||
while busy() {}
|
||||
@ -63,9 +62,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
|
||||
interrupt::free(|_| {
|
||||
pac::FLASH.nscr().modify(|w| {
|
||||
w.set_bksel(match sector.bank {
|
||||
FlashBank::Bank1 => Bksel::B_0X0,
|
||||
FlashBank::Bank2 => Bksel::B_0X1,
|
||||
_ => unreachable!(),
|
||||
FlashBank::Bank1 => Bksel::BANK1,
|
||||
FlashBank::Bank2 => Bksel::BANK2,
|
||||
});
|
||||
w.set_snb(sector.index_in_bank);
|
||||
w.set_ser(true);
|
||||
|
@ -89,8 +89,6 @@ pub enum FlashBank {
|
||||
Bank1 = 0,
|
||||
/// Bank 2
|
||||
Bank2 = 1,
|
||||
/// OTP region
|
||||
Otp,
|
||||
}
|
||||
|
||||
#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")]
|
||||
|
@ -49,6 +49,7 @@ pub struct Config {
|
||||
pub sys: Sysclk,
|
||||
pub ahb_pre: AHBPrescaler,
|
||||
pub apb1_pre: APBPrescaler,
|
||||
#[cfg(not(stm32u0))]
|
||||
pub apb2_pre: APBPrescaler,
|
||||
#[cfg(any(stm32wl5x, stm32wb))]
|
||||
pub core2_ahb_pre: AHBPrescaler,
|
||||
@ -75,6 +76,7 @@ impl Default for Config {
|
||||
sys: Sysclk::MSI,
|
||||
ahb_pre: AHBPrescaler::DIV1,
|
||||
apb1_pre: APBPrescaler::DIV1,
|
||||
#[cfg(not(stm32u0))]
|
||||
apb2_pre: APBPrescaler::DIV1,
|
||||
#[cfg(any(stm32wl5x, stm32wb))]
|
||||
core2_ahb_pre: AHBPrescaler::DIV1,
|
||||
@ -130,7 +132,7 @@ pub const WPAN_DEFAULT: Config = Config {
|
||||
};
|
||||
|
||||
fn msi_enable(range: MSIRange) {
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
|
||||
RCC.cr().modify(|w| {
|
||||
#[cfg(not(stm32wb))]
|
||||
w.set_msirgsel(crate::pac::rcc::vals::Msirgsel::CR);
|
||||
@ -240,7 +242,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
let pll_input = PllInput {
|
||||
hse,
|
||||
hsi,
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
|
||||
msi,
|
||||
};
|
||||
let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
|
||||
@ -254,6 +256,10 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
Sysclk::HSI => hsi.unwrap(),
|
||||
Sysclk::MSI => msi.unwrap(),
|
||||
Sysclk::PLL1_R => pll.r.unwrap(),
|
||||
#[cfg(stm32u0)]
|
||||
Sysclk::LSI | Sysclk::LSE => todo!(),
|
||||
#[cfg(stm32u0)]
|
||||
Sysclk::_RESERVED_6 | Sysclk::_RESERVED_7 => unreachable!(),
|
||||
};
|
||||
|
||||
#[cfg(rcc_l4plus)]
|
||||
@ -263,6 +269,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
let hclk1 = sys_clk / config.ahb_pre;
|
||||
let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
|
||||
#[cfg(not(stm32u0))]
|
||||
let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wlex))]
|
||||
let hclk2 = hclk1;
|
||||
@ -315,6 +322,13 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
..=64_000_000 => 3,
|
||||
_ => 4,
|
||||
};
|
||||
#[cfg(stm32u0)]
|
||||
let latency = match hclk1.0 {
|
||||
// VOS RANGE1, others TODO.
|
||||
..=24_000_000 => 0,
|
||||
..=48_000_000 => 1,
|
||||
_ => 2,
|
||||
};
|
||||
|
||||
#[cfg(stm32l1)]
|
||||
FLASH.acr().write(|w| w.set_acc64(true));
|
||||
@ -326,7 +340,11 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
RCC.cfgr().modify(|w| {
|
||||
w.set_sw(config.sys);
|
||||
w.set_hpre(config.ahb_pre);
|
||||
#[cfg(stm32u0)]
|
||||
w.set_ppre(config.apb1_pre);
|
||||
#[cfg(not(stm32u0))]
|
||||
w.set_ppre1(config.apb1_pre);
|
||||
#[cfg(not(stm32u0))]
|
||||
w.set_ppre2(config.apb2_pre);
|
||||
});
|
||||
while RCC.cfgr().read().sws() != config.sys {}
|
||||
@ -353,8 +371,10 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
|
||||
hclk3: Some(hclk3),
|
||||
pclk1: Some(pclk1),
|
||||
#[cfg(not(stm32u0))]
|
||||
pclk2: Some(pclk2),
|
||||
pclk1_tim: Some(pclk1_tim),
|
||||
#[cfg(not(stm32u0))]
|
||||
pclk2_tim: Some(pclk2_tim),
|
||||
#[cfg(stm32wl)]
|
||||
pclk3: Some(hclk3),
|
||||
@ -408,7 +428,7 @@ fn msirange_to_hertz(range: MSIRange) -> Hertz {
|
||||
Hertz(32_768 * (1 << (range as u8 + 1)))
|
||||
}
|
||||
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
|
||||
fn msirange_to_hertz(range: MSIRange) -> Hertz {
|
||||
match range {
|
||||
MSIRange::RANGE100K => Hertz(100_000),
|
||||
@ -521,7 +541,7 @@ mod pll {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
|
||||
mod pll {
|
||||
use super::{pll_enable, PllInstance};
|
||||
pub use crate::pac::rcc::vals::{
|
||||
|
@ -52,7 +52,7 @@ macro_rules! impl_peri {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(any(rcc_c0, rcc_g0))]
|
||||
#[cfg(any(rcc_c0, rcc_g0, rcc_u0))]
|
||||
#[allow(unused_imports)]
|
||||
use self::{McoSource as Mco1Source, McoSource as Mco2Source};
|
||||
|
||||
|
@ -25,7 +25,7 @@ pub use hsi48::*;
|
||||
#[cfg_attr(stm32g0, path = "g0.rs")]
|
||||
#[cfg_attr(stm32g4, path = "g4.rs")]
|
||||
#[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")]
|
||||
#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl), path = "l.rs")]
|
||||
#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")]
|
||||
#[cfg_attr(stm32u5, path = "u5.rs")]
|
||||
#[cfg_attr(stm32wba, path = "wba.rs")]
|
||||
mod _version;
|
||||
@ -111,7 +111,7 @@ mod util {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the kernel clocok frequency of the peripheral `T`.
|
||||
/// Get the kernel clock frequency of the peripheral `T`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@ -119,3 +119,21 @@ mod util {
|
||||
pub fn frequency<T: RccPeripheral>() -> Hertz {
|
||||
T::frequency()
|
||||
}
|
||||
|
||||
/// Enables and resets peripheral `T`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Peripheral must not be in use.
|
||||
pub unsafe fn enable_and_reset<T: RccPeripheral>() {
|
||||
T::enable_and_reset();
|
||||
}
|
||||
|
||||
/// Disables peripheral `T`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Peripheral must not be in use.
|
||||
pub unsafe fn disable<T: RccPeripheral>() {
|
||||
T::disable();
|
||||
}
|
||||
|
@ -735,18 +735,22 @@ trait RegsExt {
|
||||
|
||||
impl RegsExt for Regs {
|
||||
fn tx_ptr<W>(&self) -> *mut W {
|
||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
let dr = self.dr();
|
||||
#[cfg(spi_v2)]
|
||||
let dr = self.dr16();
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
let dr = self.txdr();
|
||||
let dr = self.txdr32();
|
||||
dr.as_ptr() as *mut W
|
||||
}
|
||||
|
||||
fn rx_ptr<W>(&self) -> *mut W {
|
||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
let dr = self.dr();
|
||||
#[cfg(spi_v2)]
|
||||
let dr = self.dr16();
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
let dr = self.rxdr();
|
||||
let dr = self.rxdr32();
|
||||
dr.as_ptr() as *mut W
|
||||
}
|
||||
}
|
||||
@ -815,11 +819,14 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
|
||||
fn flush_rx_fifo(regs: Regs) {
|
||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||
while regs.sr().read().rxne() {
|
||||
#[cfg(not(spi_v2))]
|
||||
let _ = regs.dr().read();
|
||||
#[cfg(spi_v2)]
|
||||
let _ = regs.dr16().read();
|
||||
}
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
while regs.sr().read().rxp() {
|
||||
let _ = regs.rxdr().read();
|
||||
let _ = regs.rxdr32().read();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,7 +317,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets.
|
||||
/// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
|
||||
/// Must be large enough to fit all OUT endpoint max packet sizes.
|
||||
/// Endpoint allocation will fail if it is too small.
|
||||
pub fn new_fs(
|
||||
@ -348,7 +348,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets.
|
||||
/// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
|
||||
/// Must be large enough to fit all OUT endpoint max packet sizes.
|
||||
/// Endpoint allocation will fail if it is too small.
|
||||
pub fn new_hs_ulpi(
|
||||
@ -562,51 +562,29 @@ impl<'d, T: Instance> Bus<'d, T> {
|
||||
fn init(&mut self) {
|
||||
super::common_init::<T>();
|
||||
|
||||
#[cfg(stm32f7)]
|
||||
{
|
||||
// Enable ULPI clock if external PHY is used
|
||||
let ulpien = !self.phy_type.internal();
|
||||
critical_section::with(|_| {
|
||||
crate::pac::RCC.ahb1enr().modify(|w| {
|
||||
if T::HIGH_SPEED {
|
||||
w.set_usb_otg_hsulpien(ulpien);
|
||||
} else {
|
||||
w.set_usb_otg_hsen(ulpien);
|
||||
}
|
||||
});
|
||||
// Enable ULPI clock if external PHY is used
|
||||
let _ulpien = !self.phy_type.internal();
|
||||
|
||||
// Low power mode
|
||||
crate::pac::RCC.ahb1lpenr().modify(|w| {
|
||||
if T::HIGH_SPEED {
|
||||
w.set_usb_otg_hsulpilpen(ulpien);
|
||||
} else {
|
||||
w.set_usb_otg_hslpen(ulpien);
|
||||
}
|
||||
});
|
||||
#[cfg(any(stm32f2, stm32f4, stm32f7))]
|
||||
if T::HIGH_SPEED {
|
||||
critical_section::with(|_| {
|
||||
let rcc = crate::pac::RCC;
|
||||
rcc.ahb1enr().modify(|w| w.set_usb_otg_hsulpien(_ulpien));
|
||||
rcc.ahb1lpenr().modify(|w| w.set_usb_otg_hsulpilpen(_ulpien));
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(stm32h7)]
|
||||
{
|
||||
// Enable ULPI clock if external PHY is used
|
||||
let ulpien = !self.phy_type.internal();
|
||||
critical_section::with(|_| {
|
||||
crate::pac::RCC.ahb1enr().modify(|w| {
|
||||
if T::HIGH_SPEED {
|
||||
w.set_usb_otg_hs_ulpien(ulpien);
|
||||
} else {
|
||||
w.set_usb_otg_fs_ulpien(ulpien);
|
||||
}
|
||||
});
|
||||
crate::pac::RCC.ahb1lpenr().modify(|w| {
|
||||
if T::HIGH_SPEED {
|
||||
w.set_usb_otg_hs_ulpilpen(ulpien);
|
||||
} else {
|
||||
w.set_usb_otg_fs_ulpilpen(ulpien);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
critical_section::with(|_| {
|
||||
let rcc = crate::pac::RCC;
|
||||
if T::HIGH_SPEED {
|
||||
rcc.ahb1enr().modify(|w| w.set_usb_otg_hs_ulpien(_ulpien));
|
||||
rcc.ahb1lpenr().modify(|w| w.set_usb_otg_hs_ulpilpen(_ulpien));
|
||||
} else {
|
||||
rcc.ahb1enr().modify(|w| w.set_usb_otg_fs_ulpien(_ulpien));
|
||||
rcc.ahb1lpenr().modify(|w| w.set_usb_otg_fs_ulpilpen(_ulpien));
|
||||
}
|
||||
});
|
||||
|
||||
let r = T::regs();
|
||||
let core_id = r.cid().read().0;
|
||||
|
@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Add `len`, `is_empty` and `is_full` functions to `Channel`.
|
||||
|
||||
## 0.5.0 - 2023-12-04
|
||||
|
||||
- Add a PriorityChannel.
|
||||
@ -35,7 +39,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Remove unnecessary uses of `atomic-polyfill`
|
||||
- Add `#[must_use]` to all futures.
|
||||
|
||||
|
||||
## 0.1.0 - 2022-08-26
|
||||
|
||||
- First release
|
||||
|
@ -449,6 +449,18 @@ impl<T, const N: usize> ChannelState<T, N> {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.queue.len()
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.queue.is_empty()
|
||||
}
|
||||
|
||||
fn is_full(&self) -> bool {
|
||||
self.queue.is_full()
|
||||
}
|
||||
}
|
||||
|
||||
/// A bounded channel for communicating between asynchronous tasks
|
||||
@ -572,6 +584,21 @@ where
|
||||
pub fn try_receive(&self) -> Result<T, TryReceiveError> {
|
||||
self.lock(|c| c.try_receive())
|
||||
}
|
||||
|
||||
/// Returns the number of elements currently in the channel.
|
||||
pub fn len(&self) -> usize {
|
||||
self.lock(|c| c.len())
|
||||
}
|
||||
|
||||
/// Returns whether the channel is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.lock(|c| c.is_empty())
|
||||
}
|
||||
|
||||
/// Returns whether the channel is full.
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.lock(|c| c.is_full())
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements the DynamicChannel to allow creating types that are unaware of the queue size with the
|
||||
|
@ -3,6 +3,7 @@
|
||||
//! This module provides a mutex that can be used to synchronize data between asynchronous tasks.
|
||||
use core::cell::{RefCell, UnsafeCell};
|
||||
use core::future::poll_fn;
|
||||
use core::mem;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::task::Poll;
|
||||
|
||||
@ -134,6 +135,7 @@ where
|
||||
/// successfully locked the mutex, and grants access to the contents.
|
||||
///
|
||||
/// Dropping it unlocks the mutex.
|
||||
#[clippy::has_significant_drop]
|
||||
pub struct MutexGuard<'a, M, T>
|
||||
where
|
||||
M: RawMutex,
|
||||
@ -142,6 +144,25 @@ where
|
||||
mutex: &'a Mutex<M, T>,
|
||||
}
|
||||
|
||||
impl<'a, M, T> MutexGuard<'a, M, T>
|
||||
where
|
||||
M: RawMutex,
|
||||
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> {
|
||||
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
|
||||
// locked state is being moved to the returned MappedMutexGuard.
|
||||
mem::forget(this);
|
||||
MappedMutexGuard {
|
||||
state: &mutex.state,
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, M, T> Drop for MutexGuard<'a, M, T>
|
||||
where
|
||||
M: RawMutex,
|
||||
@ -180,3 +201,115 @@ where
|
||||
unsafe { &mut *(self.mutex.inner.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or
|
||||
/// [`MappedMutexGuard::map`].
|
||||
///
|
||||
/// This can be used to hold a subfield of the protected data.
|
||||
#[clippy::has_significant_drop]
|
||||
pub struct MappedMutexGuard<'a, M, T>
|
||||
where
|
||||
M: RawMutex,
|
||||
T: ?Sized,
|
||||
{
|
||||
state: &'a BlockingMutex<M, RefCell<State>>,
|
||||
value: *mut T,
|
||||
}
|
||||
|
||||
impl<'a, M, T> MappedMutexGuard<'a, M, T>
|
||||
where
|
||||
M: RawMutex,
|
||||
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> {
|
||||
let state = this.state;
|
||||
let value = fun(unsafe { &mut *this.value });
|
||||
// Don't run the `drop` method for MutexGuard. The ownership of the underlying
|
||||
// locked state is being moved to the returned MappedMutexGuard.
|
||||
mem::forget(this);
|
||||
MappedMutexGuard { state, value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, M, T> Deref for MappedMutexGuard<'a, M, T>
|
||||
where
|
||||
M: RawMutex,
|
||||
T: ?Sized,
|
||||
{
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
// Safety: the MutexGuard represents exclusive access to the contents
|
||||
// of the mutex, so it's OK to get it.
|
||||
unsafe { &*self.value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, M, T> DerefMut for MappedMutexGuard<'a, M, T>
|
||||
where
|
||||
M: RawMutex,
|
||||
T: ?Sized,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
// Safety: the MutexGuard represents exclusive access to the contents
|
||||
// of the mutex, so it's OK to get it.
|
||||
unsafe { &mut *self.value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, M, T> Drop for MappedMutexGuard<'a, M, T>
|
||||
where
|
||||
M: RawMutex,
|
||||
T: ?Sized,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.state.lock(|s| {
|
||||
let mut s = unwrap!(s.try_borrow_mut());
|
||||
s.locked = false;
|
||||
s.waker.wake();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<M, T> Send for MappedMutexGuard<'_, M, T>
|
||||
where
|
||||
M: RawMutex + Sync,
|
||||
T: Send + ?Sized,
|
||||
{
|
||||
}
|
||||
|
||||
unsafe impl<M, T> Sync for MappedMutexGuard<'_, M, T>
|
||||
where
|
||||
M: RawMutex + Sync,
|
||||
T: Sync + ?Sized,
|
||||
{
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::blocking_mutex::raw::NoopRawMutex;
|
||||
use crate::mutex::{Mutex, MutexGuard};
|
||||
|
||||
#[futures_test::test]
|
||||
async fn mapped_guard_releases_lock_when_dropped() {
|
||||
let mutex: Mutex<NoopRawMutex, [i32; 2]> = Mutex::new([0, 1]);
|
||||
|
||||
{
|
||||
let guard = mutex.lock().await;
|
||||
assert_eq!(*guard, [0, 1]);
|
||||
let mut mapped = MutexGuard::map(guard, |this| &mut this[1]);
|
||||
assert_eq!(*mapped, 1);
|
||||
*mapped = 2;
|
||||
}
|
||||
|
||||
{
|
||||
let guard = mutex.lock().await;
|
||||
assert_eq!(*guard, [0, 2]);
|
||||
let mut mapped = MutexGuard::map(guard, |this| &mut this[1]);
|
||||
assert_eq!(*mapped, 2);
|
||||
*mapped = 3;
|
||||
}
|
||||
|
||||
assert_eq!(*mutex.lock().await, [0, 3]);
|
||||
}
|
||||
}
|
||||
|
@ -38,11 +38,12 @@ pub struct Config<'a> {
|
||||
|
||||
/// Maximum packet size in bytes for the control endpoint 0.
|
||||
///
|
||||
/// Valid values are 8, 16, 32 and 64. There's generally no need to change this from the default
|
||||
/// value of 8 bytes unless a class uses control transfers for sending large amounts of data, in
|
||||
/// which case using a larger packet size may be more efficient.
|
||||
/// Valid values depend on the speed at which the bus is enumerated.
|
||||
/// - low speed: 8
|
||||
/// - full speed: 8, 16, 32, or 64
|
||||
/// - high speed: 64
|
||||
///
|
||||
/// Default: 8 bytes
|
||||
/// Default: 64 bytes
|
||||
pub max_packet_size_0: u8,
|
||||
|
||||
/// Manufacturer name string descriptor.
|
||||
|
@ -12,7 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature
|
||||
embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] }
|
||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||
embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
|
||||
embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet"] }
|
||||
embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
|
||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||
embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" }
|
||||
|
@ -6,7 +6,7 @@ use embassy_executor::Spawner;
|
||||
use embassy_stm32::adc::{Adc, SampleTime};
|
||||
use embassy_stm32::peripherals::ADC;
|
||||
use embassy_stm32::{adc, bind_interrupts};
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
info!("Hello World!");
|
||||
|
||||
let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);
|
||||
let mut adc = Adc::new(p.ADC, Irqs);
|
||||
adc.set_sample_time(SampleTime::CYCLES71_5);
|
||||
let mut pin = p.PA1;
|
||||
|
||||
let mut vrefint = adc.enable_vref(&mut Delay);
|
||||
let mut vrefint = adc.enable_vref();
|
||||
let vrefint_sample = adc.read(&mut vrefint).await;
|
||||
let convert_to_millivolts = |sample| {
|
||||
// From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf
|
||||
|
@ -126,6 +126,11 @@ fn main() -> ! {
|
||||
// Initialize and create handle for devicer peripherals
|
||||
let _p = embassy_stm32::init(Default::default());
|
||||
|
||||
// STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
|
||||
// by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
|
||||
// In this case we’re using UART1 and UART2, but there’s nothing special about them. Any otherwise unused interrupt
|
||||
// vector would work exactly the same.
|
||||
|
||||
// High-priority executor: USART1, priority level 6
|
||||
interrupt::USART1.set_priority(Priority::P6);
|
||||
let spawner = EXECUTOR_HIGH.start(interrupt::USART1);
|
||||
|
@ -6,7 +6,7 @@ use embassy_executor::Spawner;
|
||||
use embassy_stm32::adc::Adc;
|
||||
use embassy_stm32::peripherals::ADC1;
|
||||
use embassy_stm32::{adc, bind_interrupts};
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
@ -18,10 +18,10 @@ async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
info!("Hello World!");
|
||||
|
||||
let mut adc = Adc::new(p.ADC1, &mut Delay);
|
||||
let mut adc = Adc::new(p.ADC1);
|
||||
let mut pin = p.PB1;
|
||||
|
||||
let mut vrefint = adc.enable_vref(&mut Delay);
|
||||
let mut vrefint = adc.enable_vref();
|
||||
let vrefint_sample = adc.read(&mut vrefint).await;
|
||||
let convert_to_millivolts = |sample| {
|
||||
// From http://www.st.com/resource/en/datasheet/CD00161566.pdf
|
||||
|
@ -127,6 +127,11 @@ fn main() -> ! {
|
||||
|
||||
let _p = embassy_stm32::init(Default::default());
|
||||
|
||||
// STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
|
||||
// by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
|
||||
// In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
|
||||
// vector would work exactly the same.
|
||||
|
||||
// High-priority executor: UART4, priority level 6
|
||||
interrupt::UART4.set_priority(Priority::P6);
|
||||
let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
|
||||
|
@ -7,7 +7,7 @@ use embassy_stm32::adc::{Adc, SampleTime};
|
||||
use embassy_stm32::peripherals::ADC1;
|
||||
use embassy_stm32::time::mhz;
|
||||
use embassy_stm32::{adc, bind_interrupts, Config};
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
|
||||
info!("create adc...");
|
||||
|
||||
let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay);
|
||||
let mut adc = Adc::new(p.ADC1, Irqs);
|
||||
|
||||
adc.set_sample_time(SampleTime::CYCLES601_5);
|
||||
|
||||
info!("enable vrefint...");
|
||||
|
||||
let mut vrefint = adc.enable_vref(&mut Delay);
|
||||
let mut vrefint = adc.enable_vref();
|
||||
let mut temperature = adc.enable_temperature();
|
||||
|
||||
loop {
|
||||
|
@ -8,7 +8,7 @@ use embassy_stm32::opamp::{OpAmp, OpAmpGain};
|
||||
use embassy_stm32::peripherals::ADC2;
|
||||
use embassy_stm32::time::mhz;
|
||||
use embassy_stm32::{adc, bind_interrupts, Config};
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
@ -39,14 +39,14 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
|
||||
info!("create adc...");
|
||||
|
||||
let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay);
|
||||
let mut adc = Adc::new(p.ADC2, Irqs);
|
||||
let mut opamp = OpAmp::new(p.OPAMP2);
|
||||
|
||||
adc.set_sample_time(SampleTime::CYCLES601_5);
|
||||
|
||||
info!("enable vrefint...");
|
||||
|
||||
let mut vrefint = adc.enable_vref(&mut Delay);
|
||||
let mut vrefint = adc.enable_vref();
|
||||
let mut temperature = adc.enable_temperature();
|
||||
let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1);
|
||||
|
||||
|
@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
|
||||
info!("Hello World!");
|
||||
|
||||
let mut delay = Delay;
|
||||
let mut adc = Adc::new(p.ADC1, &mut delay);
|
||||
let mut adc = Adc::new(p.ADC1);
|
||||
let mut pin = p.PC1;
|
||||
|
||||
let mut vrefint = adc.enable_vrefint();
|
||||
|
@ -127,6 +127,11 @@ fn main() -> ! {
|
||||
|
||||
let _p = embassy_stm32::init(Default::default());
|
||||
|
||||
// STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
|
||||
// by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
|
||||
// In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
|
||||
// vector would work exactly the same.
|
||||
|
||||
// High-priority executor: UART4, priority level 6
|
||||
interrupt::UART4.set_priority(Priority::P6);
|
||||
let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
|
||||
|
@ -49,6 +49,7 @@ async fn main(_spawner: Spawner) {
|
||||
// Create the driver, from the HAL.
|
||||
let mut ep_out_buffer = [0u8; 256];
|
||||
let mut config = embassy_stm32::usb::Config::default();
|
||||
// If the board you’re using doesn’t have the VBUS pin wired up correctly for detecting the USB bus voltage (e.g. on the f4 blackpill board), set this to false
|
||||
config.vbus_detection = true;
|
||||
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
// If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA.
|
||||
//
|
||||
// Warning:
|
||||
// DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn.
|
||||
// DO NOT stare at ws2812 directly (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
@ -4,7 +4,7 @@
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::adc::Adc;
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -12,7 +12,7 @@ async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
info!("Hello World!");
|
||||
|
||||
let mut adc = Adc::new(p.ADC1, &mut Delay);
|
||||
let mut adc = Adc::new(p.ADC1);
|
||||
let mut pin = p.PA3;
|
||||
|
||||
let mut vrefint = adc.enable_vrefint();
|
||||
|
@ -5,7 +5,7 @@ use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::adc::{Adc, SampleTime};
|
||||
use embassy_stm32::Config;
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -28,8 +28,8 @@ async fn main(_spawner: Spawner) {
|
||||
let mut p = embassy_stm32::init(config);
|
||||
info!("Hello World!");
|
||||
|
||||
let mut adc = Adc::new(p.ADC2, &mut Delay);
|
||||
adc.set_sample_time(SampleTime::CYCLES32_5);
|
||||
let mut adc = Adc::new(p.ADC2);
|
||||
adc.set_sample_time(SampleTime::CYCLES24_5);
|
||||
|
||||
loop {
|
||||
let measured = adc.read(&mut p.PA7);
|
||||
|
@ -5,7 +5,7 @@ use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::adc::{Adc, SampleTime};
|
||||
use embassy_stm32::Config;
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
info!("Hello World!");
|
||||
|
||||
let mut adc = Adc::new(p.ADC3, &mut Delay);
|
||||
let mut adc = Adc::new(p.ADC3);
|
||||
|
||||
adc.set_sample_time(SampleTime::CYCLES32_5);
|
||||
|
||||
|
@ -127,6 +127,11 @@ fn main() -> ! {
|
||||
|
||||
let _p = embassy_stm32::init(Default::default());
|
||||
|
||||
// STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
|
||||
// by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
|
||||
// In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
|
||||
// vector would work exactly the same.
|
||||
|
||||
// High-priority executor: UART4, priority level 6
|
||||
interrupt::UART4.set_priority(Priority::P6);
|
||||
let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
|
||||
|
@ -6,7 +6,7 @@ use embassy_executor::Spawner;
|
||||
use embassy_stm32::adc::{Adc, SampleTime};
|
||||
use embassy_stm32::peripherals::ADC;
|
||||
use embassy_stm32::{adc, bind_interrupts};
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
info!("Hello World!");
|
||||
|
||||
let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);
|
||||
let mut adc = Adc::new(p.ADC, Irqs);
|
||||
adc.set_sample_time(SampleTime::CYCLES79_5);
|
||||
let mut pin = p.PA1;
|
||||
|
||||
let mut vrefint = adc.enable_vref(&mut Delay);
|
||||
let mut vrefint = adc.enable_vref();
|
||||
let vrefint_sample = adc.read(&mut vrefint).await;
|
||||
let convert_to_millivolts = |sample| {
|
||||
// From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf
|
||||
|
@ -4,7 +4,6 @@
|
||||
use defmt::*;
|
||||
use embassy_stm32::adc::{Adc, Resolution};
|
||||
use embassy_stm32::Config;
|
||||
use embassy_time::Delay;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[cortex_m_rt::entry]
|
||||
@ -18,7 +17,7 @@ fn main() -> ! {
|
||||
}
|
||||
let p = embassy_stm32::init(config);
|
||||
|
||||
let mut adc = Adc::new(p.ADC1, &mut Delay);
|
||||
let mut adc = Adc::new(p.ADC1);
|
||||
//adc.enable_vref();
|
||||
adc.set_resolution(Resolution::BITS8);
|
||||
let mut channel = p.PC0;
|
||||
|
9
examples/stm32u0/.cargo/config.toml
Normal file
9
examples/stm32u0/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace stm32u083rctx with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --chip stm32u083rctx"
|
||||
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "trace"
|
25
examples/stm32u0/Cargo.toml
Normal file
25
examples/stm32u0/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-stm32u0-examples"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
# Change stm32u083rc to your chip name, if necessary.
|
||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] }
|
||||
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||
embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||
embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
|
||||
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7.0"
|
||||
embedded-hal = "0.2.6"
|
||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
||||
heapless = { version = "0.8", default-features = false }
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
5
examples/stm32u0/build.rs
Normal file
5
examples/stm32u0/build.rs
Normal file
@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
26
examples/stm32u0/src/bin/blinky.rs
Normal file
26
examples/stm32u0/src/bin/blinky.rs
Normal file
@ -0,0 +1,26 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
info!("Hello World!");
|
||||
|
||||
let mut led = Output::new(p.PA5, Level::High, Speed::Low);
|
||||
|
||||
loop {
|
||||
info!("high");
|
||||
led.set_high();
|
||||
Timer::after_millis(300).await;
|
||||
|
||||
info!("low");
|
||||
led.set_low();
|
||||
Timer::after_millis(300).await;
|
||||
}
|
||||
}
|
24
examples/stm32u0/src/bin/button.rs
Normal file
24
examples/stm32u0/src/bin/button.rs
Normal file
@ -0,0 +1,24 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::*;
|
||||
use embassy_stm32::gpio::{Input, Pull};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
info!("Hello World!");
|
||||
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
let button = Input::new(p.PC13, Pull::Up);
|
||||
|
||||
loop {
|
||||
if button.is_high() {
|
||||
info!("high");
|
||||
} else {
|
||||
info!("low");
|
||||
}
|
||||
}
|
||||
}
|
25
examples/stm32u0/src/bin/button_exti.rs
Normal file
25
examples/stm32u0/src/bin/button_exti.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::exti::ExtiInput;
|
||||
use embassy_stm32::gpio::Pull;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
info!("Hello World!");
|
||||
|
||||
let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
|
||||
|
||||
info!("Press the USER button...");
|
||||
|
||||
loop {
|
||||
button.wait_for_falling_edge().await;
|
||||
info!("Pressed!");
|
||||
button.wait_for_rising_edge().await;
|
||||
info!("Released!");
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2024-03-20"
|
||||
channel = "nightly-2024-04-14"
|
||||
components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
|
||||
targets = [
|
||||
"thumbv7em-none-eabi",
|
||||
|
@ -13,7 +13,7 @@ use embassy_executor::Spawner;
|
||||
use embassy_stm32::adc::Adc;
|
||||
use embassy_stm32::dac::{DacCh1, Value};
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_time::{Delay, Timer};
|
||||
use embassy_time::Timer;
|
||||
use micromath::F32Ext;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
|
||||
|
||||
let mut dac = DacCh1::new(dac, NoDma, dac_pin);
|
||||
let mut adc = Adc::new(adc, &mut Delay);
|
||||
let mut adc = Adc::new(adc);
|
||||
|
||||
#[cfg(feature = "stm32h755zi")]
|
||||
let normalization_factor = 256;
|
||||
|
Loading…
Reference in New Issue
Block a user