mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 22:32:29 +00:00
Merge branch 'master' into u0-dion
This commit is contained in:
commit
c8c7c718f3
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
|
||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -15,10 +15,11 @@
|
||||
"rust-analyzer.cargo.target": "thumbv7em-none-eabi",
|
||||
//"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
|
||||
"rust-analyzer.cargo.features": [
|
||||
"stm32f103c8",
|
||||
"stm32f446re",
|
||||
"time-driver-any",
|
||||
"unstable-pac",
|
||||
"exti",
|
||||
"rt",
|
||||
],
|
||||
"rust-analyzer.linkedProjects": [
|
||||
// Uncomment ONE line for the chip you want to work on.
|
||||
|
3
ci.sh
3
ci.sh
@ -253,6 +253,9 @@ rm out/tests/stm32f207zg/eth
|
||||
# doesn't work, gives "noise error", no idea why. usart_dma does pass.
|
||||
rm out/tests/stm32u5a5zj/usart
|
||||
|
||||
# flaky, perhaps bad wire
|
||||
rm out/tests/stm32l152re/usart_rx_ringbuffered
|
||||
|
||||
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
|
||||
echo No teleprobe token found, skipping running HIL tests
|
||||
exit
|
||||
|
@ -124,8 +124,7 @@ impl<'a> Control<'a> {
|
||||
self.set_iovar_u32("apsta", 1).await;
|
||||
|
||||
// read MAC addr.
|
||||
let mut mac_addr = [0; 6];
|
||||
assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
|
||||
let mac_addr = self.address().await;
|
||||
debug!("mac addr: {:02x}", Bytes(&mac_addr));
|
||||
|
||||
let country = countries::WORLD_WIDE_XX;
|
||||
@ -574,6 +573,13 @@ impl<'a> Control<'a> {
|
||||
self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await;
|
||||
info!("Disassociated")
|
||||
}
|
||||
|
||||
/// Gets the MAC address of the device
|
||||
pub async fn address(&mut self) -> [u8; 6] {
|
||||
let mut mac_addr = [0; 6];
|
||||
assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6);
|
||||
mac_addr
|
||||
}
|
||||
}
|
||||
|
||||
/// WiFi network scanner.
|
||||
|
@ -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
|
||||
|
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
|
||||
|
@ -115,6 +115,9 @@ low-power-debug-with-sleep = []
|
||||
## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/)
|
||||
memory-x = ["stm32-metapac/memory-x"]
|
||||
|
||||
## Use secure registers when TrustZone is enabled
|
||||
trustzone-secure = []
|
||||
|
||||
## Re-export stm32-metapac at `embassy_stm32::pac`.
|
||||
## This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
|
||||
## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
|
||||
|
@ -662,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, )*
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ mod dmamux;
|
||||
#[cfg(dmamux)]
|
||||
pub use dmamux::*;
|
||||
|
||||
mod util;
|
||||
pub(crate) use util::*;
|
||||
|
||||
pub(crate) mod ringbuffer;
|
||||
pub mod word;
|
||||
|
||||
|
60
embassy-stm32/src/dma/util.rs
Normal file
60
embassy-stm32/src/dma/util.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use embassy_hal_internal::PeripheralRef;
|
||||
|
||||
use super::word::Word;
|
||||
use super::{AnyChannel, Request, Transfer, TransferOptions};
|
||||
|
||||
/// Convenience wrapper, contains a channel and a request number.
|
||||
///
|
||||
/// Commonly used in peripheral drivers that own DMA channels.
|
||||
pub(crate) struct ChannelAndRequest<'d> {
|
||||
pub channel: PeripheralRef<'d, AnyChannel>,
|
||||
pub request: Request,
|
||||
}
|
||||
|
||||
impl<'d> ChannelAndRequest<'d> {
|
||||
pub unsafe fn read<'a, W: Word>(
|
||||
&'a mut self,
|
||||
peri_addr: *mut W,
|
||||
buf: &'a mut [W],
|
||||
options: TransferOptions,
|
||||
) -> Transfer<'a> {
|
||||
Transfer::new_read(&mut self.channel, self.request, peri_addr, buf, options)
|
||||
}
|
||||
|
||||
pub unsafe fn read_raw<'a, W: Word>(
|
||||
&'a mut self,
|
||||
peri_addr: *mut W,
|
||||
buf: *mut [W],
|
||||
options: TransferOptions,
|
||||
) -> Transfer<'a> {
|
||||
Transfer::new_read_raw(&mut self.channel, self.request, peri_addr, buf, options)
|
||||
}
|
||||
|
||||
pub unsafe fn write<'a, W: Word>(
|
||||
&'a mut self,
|
||||
buf: &'a [W],
|
||||
peri_addr: *mut W,
|
||||
options: TransferOptions,
|
||||
) -> Transfer<'a> {
|
||||
Transfer::new_write(&mut self.channel, self.request, buf, peri_addr, options)
|
||||
}
|
||||
|
||||
pub unsafe fn write_raw<'a, W: Word>(
|
||||
&'a mut self,
|
||||
buf: *const [W],
|
||||
peri_addr: *mut W,
|
||||
options: TransferOptions,
|
||||
) -> Transfer<'a> {
|
||||
Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options)
|
||||
}
|
||||
|
||||
pub unsafe fn write_repeated<'a, W: Word>(
|
||||
&'a mut self,
|
||||
repeated: &'a W,
|
||||
count: usize,
|
||||
peri_addr: *mut W,
|
||||
options: TransferOptions,
|
||||
) -> Transfer<'a> {
|
||||
Transfer::new_write_repeated(&mut self.channel, self.request, repeated, count, peri_addr, options)
|
||||
}
|
||||
}
|
@ -61,9 +61,12 @@ 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::BANK1,
|
||||
FlashBank::Bank2 => Bksel::BANK2,
|
||||
// BKSEL ignores SWAP_BANK, so we must take it into account here
|
||||
w.set_bksel(match (sector.bank, banks_swapped()) {
|
||||
(FlashBank::Bank1, false) => Bksel::BANK1,
|
||||
(FlashBank::Bank2, true) => Bksel::BANK1,
|
||||
(FlashBank::Bank2, false) => Bksel::BANK2,
|
||||
(FlashBank::Bank1, true) => Bksel::BANK2,
|
||||
});
|
||||
w.set_snb(sector.index_in_bank);
|
||||
w.set_ser(true);
|
||||
@ -111,6 +114,47 @@ pub(crate) unsafe fn clear_all_err() {
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the current SWAP_BANK option.
|
||||
///
|
||||
/// This value is only loaded on system or power-on reset. `perform_bank_swap()`
|
||||
/// will not reflect here.
|
||||
pub fn banks_swapped() -> bool {
|
||||
pac::FLASH.optcr().read().swap_bank()
|
||||
}
|
||||
|
||||
/// Logical, persistent swap of flash banks 1 and 2.
|
||||
///
|
||||
/// This allows the application to write a new firmware blob into bank 2, then
|
||||
/// swap the banks and perform a reset, loading the new firmware.
|
||||
///
|
||||
/// Swap does not take effect until system or power-on reset.
|
||||
///
|
||||
/// PLEASE READ THE REFERENCE MANUAL - there are nuances to this feature. For
|
||||
/// instance, erase commands and interrupt enables which take a flash bank as a
|
||||
/// parameter ignore the swap!
|
||||
pub fn perform_bank_swap() {
|
||||
while busy() {}
|
||||
|
||||
unsafe {
|
||||
clear_all_err();
|
||||
}
|
||||
|
||||
// unlock OPTLOCK
|
||||
pac::FLASH.optkeyr().write(|w| *w = 0x0819_2A3B);
|
||||
pac::FLASH.optkeyr().write(|w| *w = 0x4C5D_6E7F);
|
||||
while pac::FLASH.optcr().read().optlock() {}
|
||||
|
||||
// toggle SWAP_BANK option
|
||||
pac::FLASH.optsr_prg().modify(|w| w.set_swap_bank(!banks_swapped()));
|
||||
|
||||
// load option bytes
|
||||
pac::FLASH.optcr().modify(|w| w.set_optstrt(true));
|
||||
while pac::FLASH.optcr().read().optstrt() {}
|
||||
|
||||
// re-lock OPTLOCK
|
||||
pac::FLASH.optcr().modify(|w| w.set_optlock(true));
|
||||
}
|
||||
|
||||
fn sr_busy(sr: Nssr) -> bool {
|
||||
// Note: RM0492 sometimes incorrectly refers to WBNE as NSWBNE
|
||||
sr.bsy() || sr.dbne() || sr.wbne()
|
||||
|
@ -14,26 +14,43 @@ pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn lock() {
|
||||
#[cfg(feature = "trustzone-secure")]
|
||||
pac::FLASH.seccr().modify(|w| w.set_lock(true));
|
||||
#[cfg(not(feature = "trustzone-secure"))]
|
||||
pac::FLASH.nscr().modify(|w| w.set_lock(true));
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn unlock() {
|
||||
#[cfg(feature = "trustzone-secure")]
|
||||
if pac::FLASH.seccr().read().lock() {
|
||||
pac::FLASH.seckeyr().write_value(0x4567_0123);
|
||||
pac::FLASH.seckeyr().write_value(0xCDEF_89AB);
|
||||
}
|
||||
#[cfg(not(feature = "trustzone-secure"))]
|
||||
if pac::FLASH.nscr().read().lock() {
|
||||
pac::FLASH.nskeyr().write_value(0x4567_0123);
|
||||
pac::FLASH.nskeyr().write_value(0xCDEF_89AB);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn enable_blocking_write() {
|
||||
assert_eq!(0, WRITE_SIZE % 4);
|
||||
|
||||
#[cfg(feature = "trustzone-secure")]
|
||||
pac::FLASH.seccr().write(|w| {
|
||||
w.set_pg(pac::flash::vals::SeccrPg::B_0X1);
|
||||
});
|
||||
#[cfg(not(feature = "trustzone-secure"))]
|
||||
pac::FLASH.nscr().write(|w| {
|
||||
w.set_pg(pac::flash::vals::NscrPg::B_0X1);
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn disable_blocking_write() {
|
||||
#[cfg(feature = "trustzone-secure")]
|
||||
pac::FLASH.seccr().write(|w| w.set_pg(pac::flash::vals::SeccrPg::B_0X0));
|
||||
#[cfg(not(feature = "trustzone-secure"))]
|
||||
pac::FLASH.nscr().write(|w| w.set_pg(pac::flash::vals::NscrPg::B_0X0));
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
|
||||
@ -50,19 +67,35 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
|
||||
#[cfg(feature = "trustzone-secure")]
|
||||
pac::FLASH.seccr().modify(|w| {
|
||||
w.set_per(pac::flash::vals::SeccrPer::B_0X1);
|
||||
w.set_pnb(sector.index_in_bank)
|
||||
});
|
||||
#[cfg(not(feature = "trustzone-secure"))]
|
||||
pac::FLASH.nscr().modify(|w| {
|
||||
w.set_per(pac::flash::vals::NscrPer::B_0X1);
|
||||
w.set_pnb(sector.index_in_bank)
|
||||
});
|
||||
|
||||
#[cfg(feature = "trustzone-secure")]
|
||||
pac::FLASH.seccr().modify(|w| {
|
||||
w.set_strt(true);
|
||||
});
|
||||
#[cfg(not(feature = "trustzone-secure"))]
|
||||
pac::FLASH.nscr().modify(|w| {
|
||||
w.set_strt(true);
|
||||
});
|
||||
|
||||
let ret: Result<(), Error> = blocking_wait_ready();
|
||||
#[cfg(feature = "trustzone-secure")]
|
||||
pac::FLASH
|
||||
.seccr()
|
||||
.modify(|w| w.set_per(pac::flash::vals::SeccrPer::B_0X0));
|
||||
#[cfg(not(feature = "trustzone-secure"))]
|
||||
pac::FLASH
|
||||
.nscr()
|
||||
.modify(|w| w.set_per(pac::flash::vals::NscrPer::B_0X0));
|
||||
clear_all_err();
|
||||
ret
|
||||
}
|
||||
@ -70,12 +103,18 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
|
||||
pub(crate) unsafe fn clear_all_err() {
|
||||
// read and write back the same value.
|
||||
// This clears all "write 1 to clear" bits.
|
||||
#[cfg(feature = "trustzone-secure")]
|
||||
pac::FLASH.secsr().modify(|_| {});
|
||||
#[cfg(not(feature = "trustzone-secure"))]
|
||||
pac::FLASH.nssr().modify(|_| {});
|
||||
}
|
||||
|
||||
unsafe fn blocking_wait_ready() -> Result<(), Error> {
|
||||
loop {
|
||||
#[cfg(feature = "trustzone-secure")]
|
||||
let sr = pac::FLASH.secsr().read();
|
||||
#[cfg(not(feature = "trustzone-secure"))]
|
||||
let sr = pac::FLASH.nssr().read();
|
||||
|
||||
if !sr.bsy() {
|
||||
if sr.pgserr() {
|
||||
|
@ -14,9 +14,10 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
#[cfg(feature = "time")]
|
||||
use embassy_time::{Duration, Instant};
|
||||
|
||||
use crate::dma::NoDma;
|
||||
use crate::dma::ChannelAndRequest;
|
||||
use crate::gpio::{AFType, Pull};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::mode::{Async, Blocking, Mode};
|
||||
use crate::time::Hertz;
|
||||
use crate::{interrupt, peripherals};
|
||||
|
||||
@ -71,17 +72,16 @@ impl Default for Config {
|
||||
}
|
||||
|
||||
/// I2C driver.
|
||||
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
|
||||
pub struct I2c<'d, T: Instance, M: Mode> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
#[allow(dead_code)]
|
||||
tx_dma: PeripheralRef<'d, TXDMA>,
|
||||
#[allow(dead_code)]
|
||||
rx_dma: PeripheralRef<'d, RXDMA>,
|
||||
tx_dma: Option<ChannelAndRequest<'d>>,
|
||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||
#[cfg(feature = "time")]
|
||||
timeout: Duration,
|
||||
_phantom: PhantomData<M>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'d, T: Instance> I2c<'d, T, Async> {
|
||||
/// Create a new I2C driver.
|
||||
pub fn new(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
@ -90,12 +90,40 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
_irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
|
||||
+ interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
|
||||
+ 'd,
|
||||
tx_dma: impl Peripheral<P = TXDMA> + 'd,
|
||||
rx_dma: impl Peripheral<P = RXDMA> + 'd,
|
||||
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(peri, scl, sda, tx_dma, rx_dma);
|
||||
Self::new_inner(peri, scl, sda, new_dma!(tx_dma), new_dma!(rx_dma), freq, config)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> I2c<'d, T, Blocking> {
|
||||
/// Create a new blocking I2C driver.
|
||||
pub fn new_blocking(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
||||
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(peri, scl, sda, None, None, freq, config)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
|
||||
/// Create a new I2C driver.
|
||||
fn new_inner(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
||||
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
||||
tx_dma: Option<ChannelAndRequest<'d>>,
|
||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(peri, scl, sda);
|
||||
|
||||
T::enable_and_reset();
|
||||
|
||||
@ -125,6 +153,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
rx_dma,
|
||||
#[cfg(feature = "time")]
|
||||
timeout: config.timeout,
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
|
||||
this.init(freq, config);
|
||||
@ -249,7 +278,7 @@ foreach_peripheral!(
|
||||
};
|
||||
);
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||
@ -257,7 +286,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
|
||||
@ -265,7 +294,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
||||
@ -289,11 +318,11 @@ impl embedded_hal_1::i2c::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, T, M> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> {
|
||||
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_read(address, read)
|
||||
}
|
||||
@ -315,7 +344,7 @@ impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'d, T: Instance> embedded_hal_async::i2c::I2c for I2c<'d, T, Async> {
|
||||
async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.read(address, read).await
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use embassy_hal_internal::drop::OnDrop;
|
||||
use embedded_hal_1::i2c::Operation;
|
||||
|
||||
use super::*;
|
||||
use crate::dma::Transfer;
|
||||
use crate::mode::Mode as PeriMode;
|
||||
use crate::pac::i2c;
|
||||
|
||||
// /!\ /!\
|
||||
@ -41,7 +41,7 @@ pub unsafe fn on_interrupt<T: Instance>() {
|
||||
});
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'d, T: Instance, M: PeriMode> I2c<'d, T, M> {
|
||||
pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
|
||||
T::regs().cr1().modify(|reg| {
|
||||
reg.set_pe(false);
|
||||
@ -326,11 +326,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
w.set_itevten(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error>
|
||||
where
|
||||
TXDMA: crate::i2c::TxDma<T>,
|
||||
{
|
||||
impl<'d, T: Instance> I2c<'d, T, Async> {
|
||||
async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> {
|
||||
T::regs().cr2().modify(|w| {
|
||||
// Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
|
||||
// reception.
|
||||
@ -415,9 +414,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
// this address from the memory after each TxE event.
|
||||
let dst = T::regs().dr().as_ptr() as *mut u8;
|
||||
|
||||
let ch = &mut self.tx_dma;
|
||||
let request = ch.request();
|
||||
Transfer::new_write(ch, request, write, dst, Default::default())
|
||||
self.tx_dma.as_mut().unwrap().write(write, dst, Default::default())
|
||||
};
|
||||
|
||||
// Wait for bytes to be sent, or an error to occur.
|
||||
@ -479,10 +476,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
}
|
||||
|
||||
/// Write.
|
||||
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
|
||||
where
|
||||
TXDMA: crate::i2c::TxDma<T>,
|
||||
{
|
||||
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
|
||||
self.write_frame(address, write, FrameOptions::FirstAndLastFrame)
|
||||
.await?;
|
||||
|
||||
@ -490,20 +484,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
}
|
||||
|
||||
/// Read.
|
||||
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
|
||||
where
|
||||
RXDMA: crate::i2c::RxDma<T>,
|
||||
{
|
||||
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error>
|
||||
where
|
||||
RXDMA: crate::i2c::RxDma<T>,
|
||||
{
|
||||
async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> {
|
||||
if buffer.is_empty() {
|
||||
return Err(Error::Overrun);
|
||||
}
|
||||
@ -623,9 +611,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
// from this address from the memory after each RxE event.
|
||||
let src = T::regs().dr().as_ptr() as *mut u8;
|
||||
|
||||
let ch = &mut self.rx_dma;
|
||||
let request = ch.request();
|
||||
Transfer::new_read(ch, request, src, buffer, Default::default())
|
||||
self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
|
||||
};
|
||||
|
||||
// Wait for bytes to be received, or an error to occur.
|
||||
@ -664,11 +650,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
}
|
||||
|
||||
/// Write, restart, read.
|
||||
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
|
||||
where
|
||||
RXDMA: crate::i2c::RxDma<T>,
|
||||
TXDMA: crate::i2c::TxDma<T>,
|
||||
{
|
||||
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
|
||||
// Check empty read buffer before starting transaction. Otherwise, we would not generate the
|
||||
// stop condition below.
|
||||
if read.is_empty() {
|
||||
@ -684,11 +666,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
/// Consecutive operations of same type are merged. See [transaction contract] for details.
|
||||
///
|
||||
/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
|
||||
pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error>
|
||||
where
|
||||
RXDMA: crate::i2c::RxDma<T>,
|
||||
TXDMA: crate::i2c::TxDma<T>,
|
||||
{
|
||||
pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
|
||||
for (op, frame) in operation_frames(operations)? {
|
||||
match op {
|
||||
Operation::Read(read) => self.read_frame(addr, read, frame).await?,
|
||||
@ -700,7 +678,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'d, T: Instance, M: PeriMode> Drop for I2c<'d, T, M> {
|
||||
fn drop(&mut self) {
|
||||
T::disable();
|
||||
}
|
||||
@ -806,7 +784,7 @@ impl Timings {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
||||
impl<'d, T: Instance, M: PeriMode> SetConfig for I2c<'d, T, M> {
|
||||
type Config = Hertz;
|
||||
type ConfigError = ();
|
||||
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
|
||||
|
@ -7,7 +7,6 @@ use embassy_hal_internal::drop::OnDrop;
|
||||
use embedded_hal_1::i2c::Operation;
|
||||
|
||||
use super::*;
|
||||
use crate::dma::Transfer;
|
||||
use crate::pac::i2c;
|
||||
|
||||
pub(crate) unsafe fn on_interrupt<T: Instance>() {
|
||||
@ -24,7 +23,7 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
|
||||
});
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
|
||||
pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
|
||||
T::regs().cr1().modify(|reg| {
|
||||
reg.set_pe(false);
|
||||
@ -302,276 +301,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
result
|
||||
}
|
||||
|
||||
async fn write_dma_internal(
|
||||
&mut self,
|
||||
address: u8,
|
||||
write: &[u8],
|
||||
first_slice: bool,
|
||||
last_slice: bool,
|
||||
timeout: Timeout,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
TXDMA: crate::i2c::TxDma<T>,
|
||||
{
|
||||
let total_len = write.len();
|
||||
|
||||
let dma_transfer = unsafe {
|
||||
let regs = T::regs();
|
||||
regs.cr1().modify(|w| {
|
||||
w.set_txdmaen(true);
|
||||
if first_slice {
|
||||
w.set_tcie(true);
|
||||
}
|
||||
});
|
||||
let dst = regs.txdr().as_ptr() as *mut u8;
|
||||
|
||||
let ch = &mut self.tx_dma;
|
||||
let request = ch.request();
|
||||
Transfer::new_write(ch, request, write, dst, Default::default())
|
||||
};
|
||||
|
||||
let state = T::state();
|
||||
let mut remaining_len = total_len;
|
||||
|
||||
let on_drop = OnDrop::new(|| {
|
||||
let regs = T::regs();
|
||||
regs.cr1().modify(|w| {
|
||||
if last_slice {
|
||||
w.set_txdmaen(false);
|
||||
}
|
||||
w.set_tcie(false);
|
||||
})
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
state.waker.register(cx.waker());
|
||||
|
||||
let isr = T::regs().isr().read();
|
||||
if remaining_len == total_len {
|
||||
if first_slice {
|
||||
Self::master_write(
|
||||
address,
|
||||
total_len.min(255),
|
||||
Stop::Software,
|
||||
(total_len > 255) || !last_slice,
|
||||
timeout,
|
||||
)?;
|
||||
} else {
|
||||
Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, timeout)?;
|
||||
T::regs().cr1().modify(|w| w.set_tcie(true));
|
||||
}
|
||||
} else if !(isr.tcr() || isr.tc()) {
|
||||
// poll_fn was woken without an interrupt present
|
||||
return Poll::Pending;
|
||||
} else if remaining_len == 0 {
|
||||
return Poll::Ready(Ok(()));
|
||||
} else {
|
||||
let last_piece = (remaining_len <= 255) && last_slice;
|
||||
|
||||
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) {
|
||||
return Poll::Ready(Err(e));
|
||||
}
|
||||
T::regs().cr1().modify(|w| w.set_tcie(true));
|
||||
}
|
||||
|
||||
remaining_len = remaining_len.saturating_sub(255);
|
||||
Poll::Pending
|
||||
})
|
||||
.await?;
|
||||
|
||||
dma_transfer.await;
|
||||
|
||||
if last_slice {
|
||||
// This should be done already
|
||||
self.wait_tc(timeout)?;
|
||||
self.master_stop();
|
||||
}
|
||||
|
||||
drop(on_drop);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn read_dma_internal(
|
||||
&mut self,
|
||||
address: u8,
|
||||
buffer: &mut [u8],
|
||||
restart: bool,
|
||||
timeout: Timeout,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
RXDMA: crate::i2c::RxDma<T>,
|
||||
{
|
||||
let total_len = buffer.len();
|
||||
|
||||
let dma_transfer = unsafe {
|
||||
let regs = T::regs();
|
||||
regs.cr1().modify(|w| {
|
||||
w.set_rxdmaen(true);
|
||||
w.set_tcie(true);
|
||||
});
|
||||
let src = regs.rxdr().as_ptr() as *mut u8;
|
||||
|
||||
let ch = &mut self.rx_dma;
|
||||
let request = ch.request();
|
||||
Transfer::new_read(ch, request, src, buffer, Default::default())
|
||||
};
|
||||
|
||||
let state = T::state();
|
||||
let mut remaining_len = total_len;
|
||||
|
||||
let on_drop = OnDrop::new(|| {
|
||||
let regs = T::regs();
|
||||
regs.cr1().modify(|w| {
|
||||
w.set_rxdmaen(false);
|
||||
w.set_tcie(false);
|
||||
})
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
state.waker.register(cx.waker());
|
||||
|
||||
let isr = T::regs().isr().read();
|
||||
if remaining_len == total_len {
|
||||
Self::master_read(
|
||||
address,
|
||||
total_len.min(255),
|
||||
Stop::Software,
|
||||
total_len > 255,
|
||||
restart,
|
||||
timeout,
|
||||
)?;
|
||||
} else if !(isr.tcr() || isr.tc()) {
|
||||
// poll_fn was woken without an interrupt present
|
||||
return Poll::Pending;
|
||||
} else if remaining_len == 0 {
|
||||
return Poll::Ready(Ok(()));
|
||||
} else {
|
||||
let last_piece = remaining_len <= 255;
|
||||
|
||||
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) {
|
||||
return Poll::Ready(Err(e));
|
||||
}
|
||||
T::regs().cr1().modify(|w| w.set_tcie(true));
|
||||
}
|
||||
|
||||
remaining_len = remaining_len.saturating_sub(255);
|
||||
Poll::Pending
|
||||
})
|
||||
.await?;
|
||||
|
||||
dma_transfer.await;
|
||||
|
||||
// This should be done already
|
||||
self.wait_tc(timeout)?;
|
||||
self.master_stop();
|
||||
|
||||
drop(on_drop);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// =========================
|
||||
// Async public API
|
||||
|
||||
/// Write.
|
||||
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
|
||||
where
|
||||
TXDMA: crate::i2c::TxDma<T>,
|
||||
{
|
||||
let timeout = self.timeout();
|
||||
if write.is_empty() {
|
||||
self.write_internal(address, write, true, timeout)
|
||||
} else {
|
||||
timeout
|
||||
.with(self.write_dma_internal(address, write, true, true, timeout))
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
/// Write multiple buffers.
|
||||
///
|
||||
/// The buffers are concatenated in a single write transaction.
|
||||
pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
|
||||
where
|
||||
TXDMA: crate::i2c::TxDma<T>,
|
||||
{
|
||||
let timeout = self.timeout();
|
||||
|
||||
if write.is_empty() {
|
||||
return Err(Error::ZeroLengthTransfer);
|
||||
}
|
||||
let mut iter = write.iter();
|
||||
|
||||
let mut first = true;
|
||||
let mut current = iter.next();
|
||||
while let Some(c) = current {
|
||||
let next = iter.next();
|
||||
let is_last = next.is_none();
|
||||
|
||||
let fut = self.write_dma_internal(address, c, first, is_last, timeout);
|
||||
timeout.with(fut).await?;
|
||||
first = false;
|
||||
current = next;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read.
|
||||
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
|
||||
where
|
||||
RXDMA: crate::i2c::RxDma<T>,
|
||||
{
|
||||
let timeout = self.timeout();
|
||||
|
||||
if buffer.is_empty() {
|
||||
self.read_internal(address, buffer, false, timeout)
|
||||
} else {
|
||||
let fut = self.read_dma_internal(address, buffer, false, timeout);
|
||||
timeout.with(fut).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Write, restart, read.
|
||||
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
|
||||
where
|
||||
TXDMA: super::TxDma<T>,
|
||||
RXDMA: super::RxDma<T>,
|
||||
{
|
||||
let timeout = self.timeout();
|
||||
|
||||
if write.is_empty() {
|
||||
self.write_internal(address, write, false, timeout)?;
|
||||
} else {
|
||||
let fut = self.write_dma_internal(address, write, true, true, timeout);
|
||||
timeout.with(fut).await?;
|
||||
}
|
||||
|
||||
if read.is_empty() {
|
||||
self.read_internal(address, read, true, timeout)?;
|
||||
} else {
|
||||
let fut = self.read_dma_internal(address, read, true, timeout);
|
||||
timeout.with(fut).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Transaction with operations.
|
||||
///
|
||||
/// Consecutive operations of same type are merged. See [transaction contract] for details.
|
||||
///
|
||||
/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
|
||||
pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error>
|
||||
where
|
||||
RXDMA: crate::i2c::RxDma<T>,
|
||||
TXDMA: crate::i2c::TxDma<T>,
|
||||
{
|
||||
let _ = addr;
|
||||
let _ = operations;
|
||||
todo!()
|
||||
}
|
||||
|
||||
// =========================
|
||||
// Blocking public API
|
||||
|
||||
@ -684,7 +413,252 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'d, T: Instance> I2c<'d, T, Async> {
|
||||
async fn write_dma_internal(
|
||||
&mut self,
|
||||
address: u8,
|
||||
write: &[u8],
|
||||
first_slice: bool,
|
||||
last_slice: bool,
|
||||
timeout: Timeout,
|
||||
) -> Result<(), Error> {
|
||||
let total_len = write.len();
|
||||
|
||||
let dma_transfer = unsafe {
|
||||
let regs = T::regs();
|
||||
regs.cr1().modify(|w| {
|
||||
w.set_txdmaen(true);
|
||||
if first_slice {
|
||||
w.set_tcie(true);
|
||||
}
|
||||
});
|
||||
let dst = regs.txdr().as_ptr() as *mut u8;
|
||||
|
||||
self.tx_dma.as_mut().unwrap().write(write, dst, Default::default())
|
||||
};
|
||||
|
||||
let state = T::state();
|
||||
let mut remaining_len = total_len;
|
||||
|
||||
let on_drop = OnDrop::new(|| {
|
||||
let regs = T::regs();
|
||||
regs.cr1().modify(|w| {
|
||||
if last_slice {
|
||||
w.set_txdmaen(false);
|
||||
}
|
||||
w.set_tcie(false);
|
||||
})
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
state.waker.register(cx.waker());
|
||||
|
||||
let isr = T::regs().isr().read();
|
||||
if remaining_len == total_len {
|
||||
if first_slice {
|
||||
Self::master_write(
|
||||
address,
|
||||
total_len.min(255),
|
||||
Stop::Software,
|
||||
(total_len > 255) || !last_slice,
|
||||
timeout,
|
||||
)?;
|
||||
} else {
|
||||
Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, timeout)?;
|
||||
T::regs().cr1().modify(|w| w.set_tcie(true));
|
||||
}
|
||||
} else if !(isr.tcr() || isr.tc()) {
|
||||
// poll_fn was woken without an interrupt present
|
||||
return Poll::Pending;
|
||||
} else if remaining_len == 0 {
|
||||
return Poll::Ready(Ok(()));
|
||||
} else {
|
||||
let last_piece = (remaining_len <= 255) && last_slice;
|
||||
|
||||
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) {
|
||||
return Poll::Ready(Err(e));
|
||||
}
|
||||
T::regs().cr1().modify(|w| w.set_tcie(true));
|
||||
}
|
||||
|
||||
remaining_len = remaining_len.saturating_sub(255);
|
||||
Poll::Pending
|
||||
})
|
||||
.await?;
|
||||
|
||||
dma_transfer.await;
|
||||
|
||||
if last_slice {
|
||||
// This should be done already
|
||||
self.wait_tc(timeout)?;
|
||||
self.master_stop();
|
||||
}
|
||||
|
||||
drop(on_drop);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn read_dma_internal(
|
||||
&mut self,
|
||||
address: u8,
|
||||
buffer: &mut [u8],
|
||||
restart: bool,
|
||||
timeout: Timeout,
|
||||
) -> Result<(), Error> {
|
||||
let total_len = buffer.len();
|
||||
|
||||
let dma_transfer = unsafe {
|
||||
let regs = T::regs();
|
||||
regs.cr1().modify(|w| {
|
||||
w.set_rxdmaen(true);
|
||||
w.set_tcie(true);
|
||||
});
|
||||
let src = regs.rxdr().as_ptr() as *mut u8;
|
||||
|
||||
self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
|
||||
};
|
||||
|
||||
let state = T::state();
|
||||
let mut remaining_len = total_len;
|
||||
|
||||
let on_drop = OnDrop::new(|| {
|
||||
let regs = T::regs();
|
||||
regs.cr1().modify(|w| {
|
||||
w.set_rxdmaen(false);
|
||||
w.set_tcie(false);
|
||||
})
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
state.waker.register(cx.waker());
|
||||
|
||||
let isr = T::regs().isr().read();
|
||||
if remaining_len == total_len {
|
||||
Self::master_read(
|
||||
address,
|
||||
total_len.min(255),
|
||||
Stop::Software,
|
||||
total_len > 255,
|
||||
restart,
|
||||
timeout,
|
||||
)?;
|
||||
} else if !(isr.tcr() || isr.tc()) {
|
||||
// poll_fn was woken without an interrupt present
|
||||
return Poll::Pending;
|
||||
} else if remaining_len == 0 {
|
||||
return Poll::Ready(Ok(()));
|
||||
} else {
|
||||
let last_piece = remaining_len <= 255;
|
||||
|
||||
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) {
|
||||
return Poll::Ready(Err(e));
|
||||
}
|
||||
T::regs().cr1().modify(|w| w.set_tcie(true));
|
||||
}
|
||||
|
||||
remaining_len = remaining_len.saturating_sub(255);
|
||||
Poll::Pending
|
||||
})
|
||||
.await?;
|
||||
|
||||
dma_transfer.await;
|
||||
|
||||
// This should be done already
|
||||
self.wait_tc(timeout)?;
|
||||
self.master_stop();
|
||||
|
||||
drop(on_drop);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// =========================
|
||||
// Async public API
|
||||
|
||||
/// Write.
|
||||
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
|
||||
let timeout = self.timeout();
|
||||
if write.is_empty() {
|
||||
self.write_internal(address, write, true, timeout)
|
||||
} else {
|
||||
timeout
|
||||
.with(self.write_dma_internal(address, write, true, true, timeout))
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
/// Write multiple buffers.
|
||||
///
|
||||
/// The buffers are concatenated in a single write transaction.
|
||||
pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
|
||||
let timeout = self.timeout();
|
||||
|
||||
if write.is_empty() {
|
||||
return Err(Error::ZeroLengthTransfer);
|
||||
}
|
||||
let mut iter = write.iter();
|
||||
|
||||
let mut first = true;
|
||||
let mut current = iter.next();
|
||||
while let Some(c) = current {
|
||||
let next = iter.next();
|
||||
let is_last = next.is_none();
|
||||
|
||||
let fut = self.write_dma_internal(address, c, first, is_last, timeout);
|
||||
timeout.with(fut).await?;
|
||||
first = false;
|
||||
current = next;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read.
|
||||
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
let timeout = self.timeout();
|
||||
|
||||
if buffer.is_empty() {
|
||||
self.read_internal(address, buffer, false, timeout)
|
||||
} else {
|
||||
let fut = self.read_dma_internal(address, buffer, false, timeout);
|
||||
timeout.with(fut).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Write, restart, read.
|
||||
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
|
||||
let timeout = self.timeout();
|
||||
|
||||
if write.is_empty() {
|
||||
self.write_internal(address, write, false, timeout)?;
|
||||
} else {
|
||||
let fut = self.write_dma_internal(address, write, true, true, timeout);
|
||||
timeout.with(fut).await?;
|
||||
}
|
||||
|
||||
if read.is_empty() {
|
||||
self.read_internal(address, read, true, timeout)?;
|
||||
} else {
|
||||
let fut = self.read_dma_internal(address, read, true, timeout);
|
||||
timeout.with(fut).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Transaction with operations.
|
||||
///
|
||||
/// Consecutive operations of same type are merged. See [transaction contract] for details.
|
||||
///
|
||||
/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
|
||||
pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
|
||||
let _ = addr;
|
||||
let _ = operations;
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> Drop for I2c<'d, T, M> {
|
||||
fn drop(&mut self) {
|
||||
T::disable();
|
||||
}
|
||||
@ -814,7 +788,7 @@ impl Timings {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
||||
impl<'d, T: Instance, M: Mode> SetConfig for I2c<'d, T, M> {
|
||||
type Config = Hertz;
|
||||
type ConfigError = ();
|
||||
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
|
||||
|
@ -2,6 +2,7 @@
|
||||
use embassy_hal_internal::into_ref;
|
||||
|
||||
use crate::gpio::{AFType, AnyPin, SealedPin};
|
||||
use crate::mode::Async;
|
||||
use crate::pac::spi::vals;
|
||||
use crate::spi::{Config as SpiConfig, *};
|
||||
use crate::time::Hertz;
|
||||
@ -152,15 +153,15 @@ impl Default for Config {
|
||||
}
|
||||
|
||||
/// I2S driver.
|
||||
pub struct I2S<'d, T: Instance, Tx, Rx> {
|
||||
_peri: Spi<'d, T, Tx, Rx>,
|
||||
pub struct I2S<'d, T: Instance> {
|
||||
_peri: Spi<'d, T, Async>,
|
||||
sd: Option<PeripheralRef<'d, AnyPin>>,
|
||||
ws: Option<PeripheralRef<'d, AnyPin>>,
|
||||
ck: Option<PeripheralRef<'d, AnyPin>>,
|
||||
mck: Option<PeripheralRef<'d, AnyPin>>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
||||
impl<'d, T: Instance> I2S<'d, T> {
|
||||
/// Note: Full-Duplex modes are not supported at this time
|
||||
pub fn new(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
@ -168,8 +169,8 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
||||
ws: impl Peripheral<P = impl WsPin<T>> + 'd,
|
||||
ck: impl Peripheral<P = impl CkPin<T>> + 'd,
|
||||
mck: impl Peripheral<P = impl MckPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
||||
txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
@ -265,24 +266,17 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
||||
}
|
||||
|
||||
/// Write audio data.
|
||||
pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
|
||||
where
|
||||
Tx: TxDma<T>,
|
||||
{
|
||||
pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
|
||||
self._peri.write(data).await
|
||||
}
|
||||
|
||||
/// Read audio data.
|
||||
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
|
||||
where
|
||||
Tx: TxDma<T>,
|
||||
Rx: RxDma<T>,
|
||||
{
|
||||
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||
self._peri.read(data).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> {
|
||||
impl<'d, T: Instance> Drop for I2S<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
self.sd.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.ws.as_ref().map(|x| x.set_as_disconnected());
|
||||
|
@ -15,8 +15,31 @@ mod fmt;
|
||||
include!(concat!(env!("OUT_DIR"), "/_macros.rs"));
|
||||
|
||||
// Utilities
|
||||
mod macros;
|
||||
pub mod time;
|
||||
mod traits;
|
||||
/// Operating modes for peripherals.
|
||||
pub mod mode {
|
||||
trait SealedMode {}
|
||||
|
||||
/// Operating mode for a peripheral.
|
||||
#[allow(private_bounds)]
|
||||
pub trait Mode: SealedMode {}
|
||||
|
||||
macro_rules! impl_mode {
|
||||
($name:ident) => {
|
||||
impl SealedMode for $name {}
|
||||
impl Mode for $name {}
|
||||
};
|
||||
}
|
||||
|
||||
/// Blocking mode.
|
||||
pub struct Blocking;
|
||||
/// Async mode.
|
||||
pub struct Async;
|
||||
|
||||
impl_mode!(Blocking);
|
||||
impl_mode!(Async);
|
||||
}
|
||||
|
||||
// Always-present hardware
|
||||
pub mod dma;
|
||||
|
@ -69,3 +69,29 @@ macro_rules! dma_trait_impl {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! new_dma {
|
||||
($name:ident) => {{
|
||||
let dma = $name.into_ref();
|
||||
let request = dma.request();
|
||||
Some(crate::dma::ChannelAndRequest {
|
||||
channel: dma.map_into(),
|
||||
request,
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! new_pin {
|
||||
($name:ident, $aftype:expr) => {{
|
||||
new_pin!($name, $aftype, crate::gpio::Speed::Medium, crate::gpio::Pull::None)
|
||||
}};
|
||||
($name:ident, $aftype:expr, $speed:expr) => {
|
||||
new_pin!($name, $aftype, $speed, crate::gpio::Pull::None)
|
||||
};
|
||||
($name:ident, $aftype:expr, $speed:expr, $pull:expr) => {{
|
||||
let pin = $name.into_ref();
|
||||
pin.set_as_af_pull(pin.af_num(), $aftype, $pull);
|
||||
pin.set_speed($speed);
|
||||
Some(pin.map_into())
|
||||
}};
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Serial Peripheral Interface (SPI)
|
||||
#![macro_use]
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
@ -8,8 +9,9 @@ use embassy_futures::join::join;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
|
||||
|
||||
use crate::dma::{slice_ptr_parts, word, Transfer};
|
||||
use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _};
|
||||
use crate::dma::{slice_ptr_parts, word, ChannelAndRequest};
|
||||
use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
|
||||
use crate::mode::{Async, Blocking, Mode as PeriMode};
|
||||
use crate::pac::spi::{regs, vals, Spi as Regs};
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::time::Hertz;
|
||||
@ -81,163 +83,37 @@ impl Config {
|
||||
BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sck_pull_mode(&self) -> Pull {
|
||||
match self.mode.polarity {
|
||||
Polarity::IdleLow => Pull::Down,
|
||||
Polarity::IdleHigh => Pull::Up,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// SPI driver.
|
||||
pub struct Spi<'d, T: Instance, Tx, Rx> {
|
||||
pub struct Spi<'d, T: Instance, M: PeriMode> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
sck: Option<PeripheralRef<'d, AnyPin>>,
|
||||
mosi: Option<PeripheralRef<'d, AnyPin>>,
|
||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||
txdma: PeripheralRef<'d, Tx>,
|
||||
rxdma: PeripheralRef<'d, Rx>,
|
||||
tx_dma: Option<ChannelAndRequest<'d>>,
|
||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||
_phantom: PhantomData<M>,
|
||||
current_word_size: word_impl::Config,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
/// Create a new SPI driver.
|
||||
pub fn new(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(peri, sck, mosi, miso);
|
||||
|
||||
let sck_pull_mode = match config.mode.polarity {
|
||||
Polarity::IdleLow => Pull::Down,
|
||||
Polarity::IdleHigh => Pull::Up,
|
||||
};
|
||||
|
||||
sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
|
||||
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
|
||||
mosi.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
miso.set_as_af(miso.af_num(), AFType::Input);
|
||||
miso.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
|
||||
Self::new_inner(
|
||||
peri,
|
||||
Some(sck.map_into()),
|
||||
Some(mosi.map_into()),
|
||||
Some(miso.map_into()),
|
||||
txdma,
|
||||
rxdma,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
|
||||
pub fn new_rxonly(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd, // TODO remove
|
||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sck, miso);
|
||||
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
|
||||
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
miso.set_as_af(miso.af_num(), AFType::Input);
|
||||
miso.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
|
||||
Self::new_inner(
|
||||
peri,
|
||||
Some(sck.map_into()),
|
||||
None,
|
||||
Some(miso.map_into()),
|
||||
txdma,
|
||||
rxdma,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
|
||||
pub fn new_txonly(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd, // TODO remove
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sck, mosi);
|
||||
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
|
||||
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
|
||||
mosi.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
|
||||
Self::new_inner(
|
||||
peri,
|
||||
Some(sck.map_into()),
|
||||
Some(mosi.map_into()),
|
||||
None,
|
||||
txdma,
|
||||
rxdma,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new SPI driver, in TX-only mode, without SCK pin.
|
||||
///
|
||||
/// This can be useful for bit-banging non-SPI protocols.
|
||||
pub fn new_txonly_nosck(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd, // TODO: remove
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(mosi);
|
||||
mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
|
||||
mosi.set_speed(crate::gpio::Speed::Medium);
|
||||
|
||||
Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, config)
|
||||
}
|
||||
|
||||
#[cfg(stm32wl)]
|
||||
/// Useful for on chip peripherals like SUBGHZ which are hardwired.
|
||||
pub fn new_subghz(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
||||
) -> Self {
|
||||
// see RM0453 rev 1 section 7.2.13 page 291
|
||||
// The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
|
||||
// The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
|
||||
let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0;
|
||||
let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
|
||||
let mut config = Config::default();
|
||||
config.mode = MODE_0;
|
||||
config.bit_order = BitOrder::MsbFirst;
|
||||
config.frequency = freq;
|
||||
Self::new_inner(peri, None, None, None, txdma, rxdma, config)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn new_internal(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(peri, None, None, None, txdma, rxdma, config)
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
|
||||
fn new_inner(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: Option<PeripheralRef<'d, AnyPin>>,
|
||||
mosi: Option<PeripheralRef<'d, AnyPin>>,
|
||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
||||
tx_dma: Option<ChannelAndRequest<'d>>,
|
||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(peri, txdma, rxdma);
|
||||
into_ref!(peri);
|
||||
|
||||
let pclk = T::frequency();
|
||||
let freq = config.frequency;
|
||||
@ -333,9 +209,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
sck,
|
||||
mosi,
|
||||
miso,
|
||||
txdma,
|
||||
rxdma,
|
||||
tx_dma,
|
||||
rx_dma,
|
||||
current_word_size: <u8 as SealedWord>::CONFIG,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,169 +339,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
self.current_word_size = word_size;
|
||||
}
|
||||
|
||||
/// SPI write, using DMA.
|
||||
pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
|
||||
where
|
||||
Tx: TxDma<T>,
|
||||
{
|
||||
if data.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.set_word_size(W::CONFIG);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(false);
|
||||
});
|
||||
|
||||
let tx_request = self.txdma.request();
|
||||
let tx_dst = T::REGS.tx_ptr();
|
||||
let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) };
|
||||
|
||||
set_txdmaen(T::REGS, true);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(true);
|
||||
});
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_cstart(true);
|
||||
});
|
||||
|
||||
tx_f.await;
|
||||
|
||||
finish_dma(T::REGS);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// SPI read, using DMA.
|
||||
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
|
||||
where
|
||||
Tx: TxDma<T>,
|
||||
Rx: RxDma<T>,
|
||||
{
|
||||
if data.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.set_word_size(W::CONFIG);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(false);
|
||||
});
|
||||
|
||||
// SPIv3 clears rxfifo on SPE=0
|
||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||
flush_rx_fifo(T::REGS);
|
||||
|
||||
set_rxdmaen(T::REGS, true);
|
||||
|
||||
let clock_byte_count = data.len();
|
||||
|
||||
let rx_request = self.rxdma.request();
|
||||
let rx_src = T::REGS.rx_ptr();
|
||||
let rx_f = unsafe { Transfer::new_read(&mut self.rxdma, rx_request, rx_src, data, Default::default()) };
|
||||
|
||||
let tx_request = self.txdma.request();
|
||||
let tx_dst = T::REGS.tx_ptr();
|
||||
let clock_byte = 0x00u8;
|
||||
let tx_f = unsafe {
|
||||
Transfer::new_write_repeated(
|
||||
&mut self.txdma,
|
||||
tx_request,
|
||||
&clock_byte,
|
||||
clock_byte_count,
|
||||
tx_dst,
|
||||
Default::default(),
|
||||
)
|
||||
};
|
||||
|
||||
set_txdmaen(T::REGS, true);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(true);
|
||||
});
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_cstart(true);
|
||||
});
|
||||
|
||||
join(tx_f, rx_f).await;
|
||||
|
||||
finish_dma(T::REGS);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error>
|
||||
where
|
||||
Tx: TxDma<T>,
|
||||
Rx: RxDma<T>,
|
||||
{
|
||||
let (_, rx_len) = slice_ptr_parts(read);
|
||||
let (_, tx_len) = slice_ptr_parts(write);
|
||||
assert_eq!(rx_len, tx_len);
|
||||
if rx_len == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.set_word_size(W::CONFIG);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(false);
|
||||
});
|
||||
|
||||
// SPIv3 clears rxfifo on SPE=0
|
||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||
flush_rx_fifo(T::REGS);
|
||||
|
||||
set_rxdmaen(T::REGS, true);
|
||||
|
||||
let rx_request = self.rxdma.request();
|
||||
let rx_src = T::REGS.rx_ptr();
|
||||
let rx_f = unsafe { Transfer::new_read_raw(&mut self.rxdma, rx_request, rx_src, read, Default::default()) };
|
||||
|
||||
let tx_request = self.txdma.request();
|
||||
let tx_dst = T::REGS.tx_ptr();
|
||||
let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) };
|
||||
|
||||
set_txdmaen(T::REGS, true);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(true);
|
||||
});
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_cstart(true);
|
||||
});
|
||||
|
||||
join(tx_f, rx_f).await;
|
||||
|
||||
finish_dma(T::REGS);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Bidirectional transfer, using DMA.
|
||||
///
|
||||
/// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
|
||||
///
|
||||
/// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
|
||||
/// If `write` is shorter it is padded with zero bytes.
|
||||
pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error>
|
||||
where
|
||||
Tx: TxDma<T>,
|
||||
Rx: RxDma<T>,
|
||||
{
|
||||
self.transfer_inner(read, write).await
|
||||
}
|
||||
|
||||
/// In-place bidirectional transfer, using DMA.
|
||||
///
|
||||
/// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
|
||||
pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
|
||||
where
|
||||
Tx: TxDma<T>,
|
||||
Rx: RxDma<T>,
|
||||
{
|
||||
self.transfer_inner(data, data).await
|
||||
}
|
||||
|
||||
/// Blocking write.
|
||||
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
|
||||
T::REGS.cr1().modify(|w| w.set_spe(true));
|
||||
@ -682,7 +396,334 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
|
||||
impl<'d, T: Instance> Spi<'d, T, Blocking> {
|
||||
/// Create a new blocking SPI driver.
|
||||
pub fn new_blocking(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
|
||||
new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
|
||||
new_pin!(miso, AFType::Input, Speed::VeryHigh),
|
||||
None,
|
||||
None,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI).
|
||||
pub fn new_blocking_rxonly(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
|
||||
None,
|
||||
new_pin!(miso, AFType::Input, Speed::VeryHigh),
|
||||
None,
|
||||
None,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO).
|
||||
pub fn new_blocking_txonly(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
|
||||
new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new SPI driver, in TX-only mode, without SCK pin.
|
||||
///
|
||||
/// This can be useful for bit-banging non-SPI protocols.
|
||||
pub fn new_blocking_txonly_nosck(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
None,
|
||||
new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
config,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Spi<'d, T, Async> {
|
||||
/// Create a new SPI driver.
|
||||
pub fn new(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
|
||||
new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
|
||||
new_pin!(miso, AFType::Input, Speed::VeryHigh),
|
||||
new_dma!(tx_dma),
|
||||
new_dma!(rx_dma),
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
|
||||
pub fn new_rxonly(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
|
||||
None,
|
||||
new_pin!(miso, AFType::Input, Speed::VeryHigh),
|
||||
None,
|
||||
new_dma!(rx_dma),
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
|
||||
pub fn new_txonly(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
|
||||
new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
|
||||
None,
|
||||
new_dma!(tx_dma),
|
||||
None,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new SPI driver, in TX-only mode, without SCK pin.
|
||||
///
|
||||
/// This can be useful for bit-banging non-SPI protocols.
|
||||
pub fn new_txonly_nosck(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(
|
||||
peri,
|
||||
None,
|
||||
new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
|
||||
None,
|
||||
new_dma!(tx_dma),
|
||||
None,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(stm32wl)]
|
||||
/// Useful for on chip peripherals like SUBGHZ which are hardwired.
|
||||
pub fn new_subghz(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||
) -> Self {
|
||||
// see RM0453 rev 1 section 7.2.13 page 291
|
||||
// The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
|
||||
// The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
|
||||
let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0;
|
||||
let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
|
||||
let mut config = Config::default();
|
||||
config.mode = MODE_0;
|
||||
config.bit_order = BitOrder::MsbFirst;
|
||||
config.frequency = freq;
|
||||
|
||||
Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn new_internal(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
|
||||
}
|
||||
|
||||
/// SPI write, using DMA.
|
||||
pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
|
||||
if data.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.set_word_size(W::CONFIG);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(false);
|
||||
});
|
||||
|
||||
let tx_dst = T::REGS.tx_ptr();
|
||||
let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) };
|
||||
|
||||
set_txdmaen(T::REGS, true);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(true);
|
||||
});
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_cstart(true);
|
||||
});
|
||||
|
||||
tx_f.await;
|
||||
|
||||
finish_dma(T::REGS);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// SPI read, using DMA.
|
||||
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||
if data.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.set_word_size(W::CONFIG);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(false);
|
||||
});
|
||||
|
||||
// SPIv3 clears rxfifo on SPE=0
|
||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||
flush_rx_fifo(T::REGS);
|
||||
|
||||
set_rxdmaen(T::REGS, true);
|
||||
|
||||
let clock_byte_count = data.len();
|
||||
|
||||
let rx_src = T::REGS.rx_ptr();
|
||||
let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) };
|
||||
|
||||
let tx_dst = T::REGS.tx_ptr();
|
||||
let clock_byte = 0x00u8;
|
||||
let tx_f = unsafe {
|
||||
self.tx_dma
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write_repeated(&clock_byte, clock_byte_count, tx_dst, Default::default())
|
||||
};
|
||||
|
||||
set_txdmaen(T::REGS, true);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(true);
|
||||
});
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_cstart(true);
|
||||
});
|
||||
|
||||
join(tx_f, rx_f).await;
|
||||
|
||||
finish_dma(T::REGS);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> {
|
||||
let (_, rx_len) = slice_ptr_parts(read);
|
||||
let (_, tx_len) = slice_ptr_parts(write);
|
||||
assert_eq!(rx_len, tx_len);
|
||||
if rx_len == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.set_word_size(W::CONFIG);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(false);
|
||||
});
|
||||
|
||||
// SPIv3 clears rxfifo on SPE=0
|
||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||
flush_rx_fifo(T::REGS);
|
||||
|
||||
set_rxdmaen(T::REGS, true);
|
||||
|
||||
let rx_src = T::REGS.rx_ptr();
|
||||
let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) };
|
||||
|
||||
let tx_dst = T::REGS.tx_ptr();
|
||||
let tx_f = unsafe {
|
||||
self.tx_dma
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write_raw(write, tx_dst, Default::default())
|
||||
};
|
||||
|
||||
set_txdmaen(T::REGS, true);
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_spe(true);
|
||||
});
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_cstart(true);
|
||||
});
|
||||
|
||||
join(tx_f, rx_f).await;
|
||||
|
||||
finish_dma(T::REGS);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Bidirectional transfer, using DMA.
|
||||
///
|
||||
/// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
|
||||
///
|
||||
/// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
|
||||
/// If `write` is shorter it is padded with zero bytes.
|
||||
pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
|
||||
self.transfer_inner(read, write).await
|
||||
}
|
||||
|
||||
/// In-place bidirectional transfer, using DMA.
|
||||
///
|
||||
/// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
|
||||
pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||
self.transfer_inner(data, data).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: PeriMode> Drop for Spi<'d, T, M> {
|
||||
fn drop(&mut self) {
|
||||
self.sck.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.mosi.as_ref().map(|x| x.set_as_disconnected());
|
||||
@ -819,7 +860,7 @@ 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(spi_v1)]
|
||||
#[cfg(not(spi_v2))]
|
||||
let _ = regs.dr().read();
|
||||
#[cfg(spi_v2)]
|
||||
let _ = regs.dr16().read();
|
||||
@ -900,7 +941,7 @@ fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
|
||||
// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
|
||||
macro_rules! impl_blocking {
|
||||
($w:ident) => {
|
||||
impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, Tx, Rx> {
|
||||
impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
|
||||
@ -908,7 +949,7 @@ macro_rules! impl_blocking {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, Tx, Rx> {
|
||||
impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, M> {
|
||||
type Error = Error;
|
||||
|
||||
fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
|
||||
@ -922,11 +963,11 @@ macro_rules! impl_blocking {
|
||||
impl_blocking!(u8);
|
||||
impl_blocking!(u16);
|
||||
|
||||
impl<'d, T: Instance, Tx, Rx> embedded_hal_1::spi::ErrorType for Spi<'d, T, Tx, Rx> {
|
||||
impl<'d, T: Instance, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, T, M> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
|
||||
impl<'d, T: Instance, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, M> {
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
@ -959,7 +1000,7 @@ impl embedded_hal_1::spi::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
|
||||
impl<'d, T: Instance, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Async> {
|
||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
@ -1094,7 +1135,7 @@ foreach_peripheral!(
|
||||
};
|
||||
);
|
||||
|
||||
impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> {
|
||||
impl<'d, T: Instance, M: PeriMode> SetConfig for Spi<'d, T, M> {
|
||||
type Config = Config;
|
||||
type ConfigError = ();
|
||||
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,22 @@
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
use embassy_hal_internal::PeripheralRef;
|
||||
use futures::future::{select, Either};
|
||||
|
||||
use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx};
|
||||
use crate::dma::ReadableRingBuffer;
|
||||
use crate::mode::Async;
|
||||
use crate::usart::{Regs, Sr};
|
||||
|
||||
/// Rx-only Ring-buffered UART Driver
|
||||
///
|
||||
/// Created with [UartRx::into_ring_buffered]
|
||||
pub struct RingBufferedUartRx<'d, T: BasicInstance> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
_phantom: PhantomData<T>,
|
||||
ring_buf: ReadableRingBuffer<'d, u8>,
|
||||
}
|
||||
|
||||
@ -28,26 +29,29 @@ impl<'d, T: BasicInstance> SetConfig for RingBufferedUartRx<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
|
||||
impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
|
||||
/// Turn the `UartRx` into a buffered uart which can continously receive in the background
|
||||
/// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the
|
||||
/// DMA controller, and must be large enough to prevent overflows.
|
||||
pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T> {
|
||||
pub fn into_ring_buffered(mut self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T> {
|
||||
assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
|
||||
|
||||
let request = self.rx_dma.request();
|
||||
let opts = Default::default();
|
||||
|
||||
// Safety: we forget the struct before this function returns.
|
||||
let rx_dma = unsafe { self.rx_dma.clone_unchecked() };
|
||||
let _peri = unsafe { self._peri.clone_unchecked() };
|
||||
let rx_dma = self.rx_dma.as_mut().unwrap();
|
||||
let request = rx_dma.request;
|
||||
let rx_dma = unsafe { rx_dma.channel.clone_unchecked() };
|
||||
|
||||
let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) };
|
||||
|
||||
// Don't disable the clock
|
||||
mem::forget(self);
|
||||
|
||||
RingBufferedUartRx { _peri, ring_buf }
|
||||
RingBufferedUartRx {
|
||||
_phantom: PhantomData,
|
||||
ring_buf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ use core::fmt::Write;
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use heapless::String;
|
||||
@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
|
||||
info!("Hello World!");
|
||||
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, p.DMA1_CH5, config).unwrap();
|
||||
|
||||
for n in 0u32.. {
|
||||
let mut s: String<128> = String::new();
|
||||
|
@ -3,35 +3,19 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::i2c::{Error, I2c};
|
||||
use embassy_stm32::time::Hertz;
|
||||
use embassy_stm32::{bind_interrupts, i2c, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const ADDRESS: u8 = 0x5F;
|
||||
const WHOAMI: u8 = 0x0F;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
|
||||
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
info!("Hello world!");
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
let mut i2c = I2c::new(
|
||||
p.I2C2,
|
||||
p.PB10,
|
||||
p.PB11,
|
||||
Irqs,
|
||||
NoDma,
|
||||
NoDma,
|
||||
Hertz(100_000),
|
||||
Default::default(),
|
||||
);
|
||||
let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
|
||||
|
||||
let mut data = [0u8; 1];
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::*;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||
use embassy_stm32::spi::{Config, Spi};
|
||||
use embassy_stm32::time::Hertz;
|
||||
@ -18,7 +17,7 @@ fn main() -> ! {
|
||||
let mut spi_config = Config::default();
|
||||
spi_config.frequency = Hertz(1_000_000);
|
||||
|
||||
let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config);
|
||||
let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
|
||||
|
||||
let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::*;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
@ -19,7 +18,7 @@ fn main() -> ! {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new_blocking(p.USART3, p.PD9, p.PD8, config).unwrap();
|
||||
|
||||
unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
|
||||
info!("wrote Hello, starting echo");
|
||||
|
@ -5,7 +5,6 @@ use core::fmt::Write;
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use heapless::String;
|
||||
@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
|
||||
info!("Hello World!");
|
||||
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, p.DMA1_CH1, config).unwrap();
|
||||
|
||||
for n in 0u32.. {
|
||||
let mut s: String<128> = String::new();
|
||||
|
@ -13,8 +13,8 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use embassy_stm32::spi;
|
||||
use embassy_stm32::time::khz;
|
||||
use embassy_stm32::{dma, spi};
|
||||
use embassy_time::{Duration, Ticker, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
@ -78,7 +78,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
|
||||
spi_config.frequency = khz(12_800);
|
||||
|
||||
// Since we only output waveform, then the Rx and Sck and RxDma it is not considered
|
||||
let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, dma::NoDma, spi_config);
|
||||
let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, spi_config);
|
||||
|
||||
// flip color at 2 Hz
|
||||
let mut ticker = Ticker::every(Duration::from_millis(500));
|
||||
|
@ -5,7 +5,6 @@ use core::fmt::Write;
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use heapless::String;
|
||||
@ -19,7 +18,7 @@ bind_interrupts!(struct Irqs {
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, p.DMA1_CH3, config).unwrap();
|
||||
|
||||
for n in 0u32.. {
|
||||
let mut s: String<128> = String::new();
|
||||
|
@ -4,7 +4,6 @@
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::word::U5;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::spi::{Config, Spi};
|
||||
use embassy_stm32::time::Hertz;
|
||||
use embassy_time::Timer;
|
||||
@ -77,7 +76,7 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
let mut config = Config::default();
|
||||
config.frequency = Hertz(4_000_000);
|
||||
let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, NoDma, config);
|
||||
let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, config);
|
||||
|
||||
let mut neopixels = Ws2812::new();
|
||||
|
||||
|
@ -4,22 +4,16 @@
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::*;
|
||||
use embassy_executor::Executor;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UART7 => usart::InterruptHandler<peripherals::UART7>;
|
||||
});
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn main_task() {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap();
|
||||
|
||||
unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
|
||||
info!("wrote Hello, starting echo");
|
||||
|
@ -6,7 +6,6 @@ use core::fmt::Write;
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::*;
|
||||
use embassy_executor::Executor;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use heapless::String;
|
||||
@ -22,7 +21,7 @@ async fn main_task() {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap();
|
||||
|
||||
for n in 0u32.. {
|
||||
let mut s: String<128> = String::new();
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::peripherals::{GPDMA1_CH1, UART7};
|
||||
use embassy_stm32::mode::Async;
|
||||
use embassy_stm32::peripherals::UART7;
|
||||
use embassy_stm32::usart::{Config, Uart, UartRx};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||
@ -15,18 +15,6 @@ bind_interrupts!(struct Irqs {
|
||||
UART7 => usart::InterruptHandler<peripherals::UART7>;
|
||||
});
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
|
||||
unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
|
||||
info!("wrote Hello, starting echo");
|
||||
|
||||
let mut buf = [0u8; 1];
|
||||
loop {
|
||||
unwrap!(usart.blocking_read(&mut buf));
|
||||
unwrap!(usart.blocking_write(&buf));
|
||||
}
|
||||
}
|
||||
|
||||
static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -50,7 +38,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) {
|
||||
async fn reader(mut rx: UartRx<'static, UART7, Async>) {
|
||||
let mut buf = [0; 8];
|
||||
loop {
|
||||
info!("reading...");
|
||||
|
@ -7,7 +7,7 @@ use core::str::from_utf8;
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::*;
|
||||
use embassy_executor::Executor;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::mode::Blocking;
|
||||
use embassy_stm32::peripherals::SPI3;
|
||||
use embassy_stm32::time::mhz;
|
||||
use embassy_stm32::{spi, Config};
|
||||
@ -16,7 +16,7 @@ use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn main_task(mut spi: spi::Spi<'static, SPI3, NoDma, NoDma>) {
|
||||
async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) {
|
||||
for n in 0u32.. {
|
||||
let mut write: String<128> = String::new();
|
||||
core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
|
||||
@ -62,7 +62,7 @@ fn main() -> ! {
|
||||
let mut spi_config = spi::Config::default();
|
||||
spi_config.frequency = mhz(1);
|
||||
|
||||
let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, NoDma, NoDma, spi_config);
|
||||
let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config);
|
||||
|
||||
let executor = EXECUTOR.init(Executor::new());
|
||||
|
||||
|
@ -7,15 +7,15 @@ use core::str::from_utf8;
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::*;
|
||||
use embassy_executor::Executor;
|
||||
use embassy_stm32::peripherals::{DMA1_CH3, DMA1_CH4, SPI3};
|
||||
use embassy_stm32::mode::Async;
|
||||
use embassy_stm32::time::mhz;
|
||||
use embassy_stm32::{spi, Config};
|
||||
use embassy_stm32::{peripherals, spi, Config};
|
||||
use heapless::String;
|
||||
use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn main_task(mut spi: spi::Spi<'static, SPI3, DMA1_CH3, DMA1_CH4>) {
|
||||
async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) {
|
||||
for n in 0u32.. {
|
||||
let mut write: String<128> = String::new();
|
||||
let mut read = [0; 128];
|
||||
|
@ -4,22 +4,16 @@
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::*;
|
||||
use embassy_executor::Executor;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UART7 => usart::InterruptHandler<peripherals::UART7>;
|
||||
});
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn main_task() {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap();
|
||||
|
||||
unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
|
||||
info!("wrote Hello, starting echo");
|
||||
|
@ -6,7 +6,6 @@ use core::fmt::Write;
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::*;
|
||||
use embassy_executor::Executor;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use heapless::String;
|
||||
@ -22,7 +21,7 @@ async fn main_task() {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config).unwrap();
|
||||
|
||||
for n in 0u32.. {
|
||||
let mut s: String<128> = String::new();
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::peripherals::{DMA1_CH1, UART7};
|
||||
use embassy_stm32::mode::Async;
|
||||
use embassy_stm32::peripherals::UART7;
|
||||
use embassy_stm32::usart::{Config, Uart, UartRx};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||
@ -15,18 +15,6 @@ bind_interrupts!(struct Irqs {
|
||||
UART7 => usart::InterruptHandler<peripherals::UART7>;
|
||||
});
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
|
||||
unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
|
||||
info!("wrote Hello, starting echo");
|
||||
|
||||
let mut buf = [0u8; 1];
|
||||
loop {
|
||||
unwrap!(usart.blocking_read(&mut buf));
|
||||
unwrap!(usart.blocking_write(&buf));
|
||||
}
|
||||
}
|
||||
|
||||
static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -50,7 +38,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn reader(mut rx: UartRx<'static, UART7, DMA1_CH1>) {
|
||||
async fn reader(mut rx: UartRx<'static, UART7, Async>) {
|
||||
let mut buf = [0; 8];
|
||||
loop {
|
||||
info!("reading...");
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||
use embassy_stm32::spi::{Config, Spi};
|
||||
use embassy_stm32::time::Hertz;
|
||||
@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut spi_config = Config::default();
|
||||
spi_config.frequency = Hertz(1_000_000);
|
||||
|
||||
let mut spi = Spi::new(p.SPI1, p.PB3, p.PA7, p.PA6, NoDma, NoDma, spi_config);
|
||||
let mut spi = Spi::new_blocking(p.SPI1, p.PB3, p.PA7, p.PA6, spi_config);
|
||||
|
||||
let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh);
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||
use embassy_stm32::spi::{Config, Spi};
|
||||
use embassy_stm32::time::Hertz;
|
||||
@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut spi_config = Config::default();
|
||||
spi_config.frequency = Hertz(1_000_000);
|
||||
|
||||
let mut spi = Spi::new(p.SPI1, p.PA5, p.PA7, p.PA6, NoDma, NoDma, spi_config);
|
||||
let mut spi = Spi::new_blocking(p.SPI1, p.PA5, p.PA7, p.PA6, spi_config);
|
||||
|
||||
let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh);
|
||||
|
||||
|
@ -3,33 +3,17 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::i2c::I2c;
|
||||
use embassy_stm32::time::Hertz;
|
||||
use embassy_stm32::{bind_interrupts, i2c, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const ADDRESS: u8 = 0x5F;
|
||||
const WHOAMI: u8 = 0x0F;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
|
||||
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
let mut i2c = I2c::new(
|
||||
p.I2C2,
|
||||
p.PB10,
|
||||
p.PB11,
|
||||
Irqs,
|
||||
NoDma,
|
||||
NoDma,
|
||||
Hertz(100_000),
|
||||
Default::default(),
|
||||
);
|
||||
let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
|
||||
|
||||
let mut data = [0u8; 1];
|
||||
unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data));
|
||||
|
@ -4,34 +4,18 @@
|
||||
use defmt::*;
|
||||
use embassy_embedded_hal::adapter::BlockingAsync;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::i2c::I2c;
|
||||
use embassy_stm32::time::Hertz;
|
||||
use embassy_stm32::{bind_interrupts, i2c, peripherals};
|
||||
use embedded_hal_async::i2c::I2c as I2cTrait;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const ADDRESS: u8 = 0x5F;
|
||||
const WHOAMI: u8 = 0x0F;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
|
||||
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
let i2c = I2c::new(
|
||||
p.I2C2,
|
||||
p.PB10,
|
||||
p.PB11,
|
||||
Irqs,
|
||||
NoDma,
|
||||
NoDma,
|
||||
Hertz(100_000),
|
||||
Default::default(),
|
||||
);
|
||||
let i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default());
|
||||
let mut i2c = BlockingAsync::new(i2c);
|
||||
|
||||
let mut data = [0u8; 1];
|
||||
|
@ -23,18 +23,23 @@ use embassy_futures::select::{select, Either};
|
||||
use embassy_futures::yield_now;
|
||||
use embassy_net::tcp::TcpSocket;
|
||||
use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4};
|
||||
use embassy_net_adin1110::{Device, Runner, ADIN1110};
|
||||
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
|
||||
use embassy_stm32::i2c::{self, Config as I2C_Config, I2c};
|
||||
use embassy_stm32::mode::Async;
|
||||
use embassy_stm32::rng::{self, Rng};
|
||||
use embassy_stm32::spi::{Config as SPI_Config, Spi};
|
||||
use embassy_stm32::time::Hertz;
|
||||
use embassy_stm32::{bind_interrupts, exti, pac, peripherals};
|
||||
use embassy_time::{Delay, Duration, Ticker, Timer};
|
||||
use embedded_hal_async::i2c::I2c as I2cBus;
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use embedded_io::Write as bWrite;
|
||||
use embedded_io_async::Write;
|
||||
use hal::gpio::{Input, Level, Output, Speed};
|
||||
use hal::i2c::{self, I2c};
|
||||
use hal::rng::{self, Rng};
|
||||
use hal::{bind_interrupts, exti, pac, peripherals};
|
||||
use heapless::Vec;
|
||||
use panic_probe as _;
|
||||
use rand::RngCore;
|
||||
use static_cell::StaticCell;
|
||||
use {embassy_stm32 as hal, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
|
||||
@ -42,13 +47,6 @@ bind_interrupts!(struct Irqs {
|
||||
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||
});
|
||||
|
||||
use embassy_net_adin1110::{Device, Runner, ADIN1110};
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use hal::gpio::Pull;
|
||||
use hal::i2c::Config as I2C_Config;
|
||||
use hal::spi::{Config as SPI_Config, Spi};
|
||||
use hal::time::Hertz;
|
||||
|
||||
// Basic settings
|
||||
// MAC-address used by the adin1110
|
||||
const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
|
||||
@ -57,12 +55,12 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24);
|
||||
// Listen port for the webserver
|
||||
const HTTP_LISTEN_PORT: u16 = 80;
|
||||
|
||||
pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>;
|
||||
pub type SpeSpi = Spi<'static, peripherals::SPI2, Async>;
|
||||
pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>;
|
||||
pub type SpeInt = exti::ExtiInput<'static>;
|
||||
pub type SpeRst = Output<'static>;
|
||||
pub type Adin1110T = ADIN1110<SpeSpiCs>;
|
||||
pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>;
|
||||
pub type TempSensI2c = I2c<'static, peripherals::I2C3, Async>;
|
||||
|
||||
static TEMP: AtomicI32 = AtomicI32::new(0);
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||
use embassy_stm32::spi::{Config, Spi};
|
||||
use embassy_stm32::time::Hertz;
|
||||
@ -17,7 +16,7 @@ fn main() -> ! {
|
||||
let mut spi_config = Config::default();
|
||||
spi_config.frequency = Hertz(1_000_000);
|
||||
|
||||
let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config);
|
||||
let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
|
||||
|
||||
let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
use defmt::*;
|
||||
use embassy_embedded_hal::adapter::BlockingAsync;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
|
||||
use embassy_stm32::spi::{Config, Spi};
|
||||
use embassy_stm32::time::Hertz;
|
||||
@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut spi_config = Config::default();
|
||||
spi_config.frequency = Hertz(1_000_000);
|
||||
|
||||
let spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config);
|
||||
let spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
|
||||
|
||||
let mut spi = BlockingAsync::new(spi);
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
@ -18,7 +17,7 @@ fn main() -> ! {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new_blocking(p.UART4, p.PA1, p.PA0, config).unwrap();
|
||||
|
||||
unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
|
||||
info!("wrote Hello, starting echo");
|
||||
|
@ -5,7 +5,6 @@ use core::fmt::Write;
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, Uart};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||
use heapless::String;
|
||||
@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) {
|
||||
info!("Hello World!");
|
||||
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, p.DMA1_CH4, config).unwrap();
|
||||
|
||||
for n in 0u32.. {
|
||||
let mut s: String<128> = String::new();
|
||||
|
@ -1,6 +1,6 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --chip STM32u083rctx"
|
||||
# replace stm32u083rctx with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --chip stm32u083rctx"
|
||||
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
@ -5,7 +5,7 @@ version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
# Change stm32c031c6 to your chip name, if necessary.
|
||||
# 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"] }
|
||||
|
@ -24,5 +24,9 @@ heapless = { version = "0.8", default-features = false }
|
||||
|
||||
micromath = "2.0.0"
|
||||
|
||||
[features]
|
||||
## Use secure registers when TrustZone is enabled
|
||||
trustzone-secure = ["embassy-stm32/trustzone-secure"]
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
||||
|
@ -3,33 +3,17 @@
|
||||
|
||||
use defmt::{info, unwrap};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::i2c::I2c;
|
||||
use embassy_stm32::time::Hertz;
|
||||
use embassy_stm32::{bind_interrupts, i2c, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const HTS221_ADDRESS: u8 = 0x5F;
|
||||
const WHOAMI: u8 = 0x0F;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
|
||||
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
let mut i2c = I2c::new(
|
||||
p.I2C2,
|
||||
p.PH4,
|
||||
p.PH5,
|
||||
Irqs,
|
||||
NoDma,
|
||||
NoDma,
|
||||
Hertz(100_000),
|
||||
Default::default(),
|
||||
);
|
||||
let mut i2c = I2c::new_blocking(p.I2C2, p.PH4, p.PH5, Hertz(100_000), Default::default());
|
||||
|
||||
let mut data = [0u8; 1];
|
||||
unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data));
|
||||
|
@ -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",
|
||||
|
@ -6,7 +6,6 @@ mod common;
|
||||
use common::*;
|
||||
use defmt::assert_eq;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::spi::{self, Spi};
|
||||
use embassy_stm32::time::Hertz;
|
||||
|
||||
@ -23,11 +22,11 @@ async fn main(_spawner: Spawner) {
|
||||
let mut spi_config = spi::Config::default();
|
||||
spi_config.frequency = Hertz(1_000_000);
|
||||
|
||||
let mut spi = Spi::new(
|
||||
let mut spi = Spi::new_blocking(
|
||||
spi, sck, // Arduino D13
|
||||
mosi, // Arduino D11
|
||||
miso, // Arduino D12
|
||||
NoDma, NoDma, spi_config,
|
||||
spi_config,
|
||||
);
|
||||
|
||||
let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];
|
||||
|
@ -6,7 +6,6 @@ mod common;
|
||||
use common::*;
|
||||
use defmt::{assert, assert_eq, unreachable};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::dma::NoDma;
|
||||
use embassy_stm32::usart::{Config, ConfigError, Error, Uart};
|
||||
use embassy_time::{block_for, Duration, Instant};
|
||||
|
||||
@ -20,11 +19,10 @@ async fn main(_spawner: Spawner) {
|
||||
let mut usart = peri!(p, UART);
|
||||
let mut rx = peri!(p, UART_RX);
|
||||
let mut tx = peri!(p, UART_TX);
|
||||
let irq = irqs!(UART);
|
||||
|
||||
{
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new_blocking(&mut usart, &mut rx, &mut tx, config).unwrap();
|
||||
|
||||
// We can't send too many bytes, they have to fit in the FIFO.
|
||||
// This is because we aren't sending+receiving at the same time.
|
||||
@ -40,7 +38,7 @@ async fn main(_spawner: Spawner) {
|
||||
// Test error handling with with an overflow error
|
||||
{
|
||||
let config = Config::default();
|
||||
let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config).unwrap();
|
||||
let mut usart = Uart::new_blocking(&mut usart, &mut rx, &mut tx, config).unwrap();
|
||||
|
||||
// Send enough bytes to fill the RX FIFOs off all USART versions.
|
||||
let data = [0; 64];
|
||||
@ -70,7 +68,7 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
let mut config = Config::default();
|
||||
config.baudrate = baudrate;
|
||||
let mut usart = match Uart::new(&mut usart, &mut rx, &mut tx, irq, NoDma, NoDma, config) {
|
||||
let mut usart = match Uart::new_blocking(&mut usart, &mut rx, &mut tx, config) {
|
||||
Ok(x) => x,
|
||||
Err(ConfigError::BaudrateTooHigh) => {
|
||||
info!("baudrate too high");
|
||||
|
@ -8,6 +8,7 @@ mod common;
|
||||
use common::*;
|
||||
use defmt::{assert_eq, panic};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::mode::Async;
|
||||
use embassy_stm32::usart::{Config, DataBits, Parity, RingBufferedUartRx, StopBits, Uart, UartTx};
|
||||
use embassy_time::Timer;
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
@ -51,7 +52,7 @@ async fn main(spawner: Spawner) {
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn transmit_task(mut tx: UartTx<'static, peris::UART, peris::UART_TX_DMA>) {
|
||||
async fn transmit_task(mut tx: UartTx<'static, peris::UART, Async>) {
|
||||
// workaround https://github.com/embassy-rs/embassy/issues/1426
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user