mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 00:02:28 +00:00
stm32/spi: remove DMA generic params.
This commit is contained in:
parent
40e7ea47ba
commit
be087e5d43
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": "thumbv7em-none-eabi",
|
||||||
//"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
|
//"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
|
||||||
"rust-analyzer.cargo.features": [
|
"rust-analyzer.cargo.features": [
|
||||||
"stm32f103c8",
|
"stm32f446re",
|
||||||
"time-driver-any",
|
"time-driver-any",
|
||||||
"unstable-pac",
|
"unstable-pac",
|
||||||
"exti",
|
"exti",
|
||||||
|
"rt",
|
||||||
],
|
],
|
||||||
"rust-analyzer.linkedProjects": [
|
"rust-analyzer.linkedProjects": [
|
||||||
// Uncomment ONE line for the chip you want to work on.
|
// Uncomment ONE line for the chip you want to work on.
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
use embassy_hal_internal::into_ref;
|
use embassy_hal_internal::into_ref;
|
||||||
|
|
||||||
use crate::gpio::{AFType, AnyPin, SealedPin};
|
use crate::gpio::{AFType, AnyPin, SealedPin};
|
||||||
|
use crate::mode::Async;
|
||||||
use crate::pac::spi::vals;
|
use crate::pac::spi::vals;
|
||||||
use crate::spi::{Config as SpiConfig, *};
|
use crate::spi::{Config as SpiConfig, *};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
@ -152,15 +153,15 @@ impl Default for Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// I2S driver.
|
/// I2S driver.
|
||||||
pub struct I2S<'d, T: Instance, Tx, Rx> {
|
pub struct I2S<'d, T: Instance> {
|
||||||
_peri: Spi<'d, T, Tx, Rx>,
|
_peri: Spi<'d, T, Async>,
|
||||||
sd: Option<PeripheralRef<'d, AnyPin>>,
|
sd: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
ws: Option<PeripheralRef<'d, AnyPin>>,
|
ws: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
ck: Option<PeripheralRef<'d, AnyPin>>,
|
ck: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
mck: 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
|
/// Note: Full-Duplex modes are not supported at this time
|
||||||
pub fn new(
|
pub fn new(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
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,
|
ws: impl Peripheral<P = impl WsPin<T>> + 'd,
|
||||||
ck: impl Peripheral<P = impl CkPin<T>> + 'd,
|
ck: impl Peripheral<P = impl CkPin<T>> + 'd,
|
||||||
mck: impl Peripheral<P = impl MckPin<T>> + 'd,
|
mck: impl Peripheral<P = impl MckPin<T>> + 'd,
|
||||||
txdma: impl Peripheral<P = Tx> + 'd,
|
txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||||
freq: Hertz,
|
freq: Hertz,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -265,24 +266,17 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write audio data.
|
/// Write audio data.
|
||||||
pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
|
pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
|
||||||
where
|
|
||||||
Tx: TxDma<T>,
|
|
||||||
{
|
|
||||||
self._peri.write(data).await
|
self._peri.write(data).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read audio data.
|
/// Read audio data.
|
||||||
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
|
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||||
where
|
|
||||||
Tx: TxDma<T>,
|
|
||||||
Rx: RxDma<T>,
|
|
||||||
{
|
|
||||||
self._peri.read(data).await
|
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) {
|
fn drop(&mut self) {
|
||||||
self.sd.as_ref().map(|x| x.set_as_disconnected());
|
self.sd.as_ref().map(|x| x.set_as_disconnected());
|
||||||
self.ws.as_ref().map(|x| x.set_as_disconnected());
|
self.ws.as_ref().map(|x| x.set_as_disconnected());
|
||||||
|
@ -17,6 +17,29 @@ include!(concat!(env!("OUT_DIR"), "/_macros.rs"));
|
|||||||
// Utilities
|
// Utilities
|
||||||
pub mod time;
|
pub mod time;
|
||||||
mod traits;
|
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
|
// Always-present hardware
|
||||||
pub mod dma;
|
pub mod dma;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Serial Peripheral Interface (SPI)
|
//! Serial Peripheral Interface (SPI)
|
||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
use embassy_embedded_hal::SetConfig;
|
use embassy_embedded_hal::SetConfig;
|
||||||
@ -8,8 +9,9 @@ use embassy_futures::join::join;
|
|||||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||||
pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
|
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::dma::{slice_ptr_parts, word, AnyChannel, Request, Transfer};
|
||||||
use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _};
|
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::pac::spi::{regs, vals, Spi as Regs};
|
||||||
use crate::rcc::RccPeripheral;
|
use crate::rcc::RccPeripheral;
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
@ -81,163 +83,37 @@ impl Config {
|
|||||||
BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST,
|
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.
|
/// SPI driver.
|
||||||
pub struct Spi<'d, T: Instance, Tx, Rx> {
|
pub struct Spi<'d, T: Instance, M: PeriMode> {
|
||||||
_peri: PeripheralRef<'d, T>,
|
_peri: PeripheralRef<'d, T>,
|
||||||
sck: Option<PeripheralRef<'d, AnyPin>>,
|
sck: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
mosi: Option<PeripheralRef<'d, AnyPin>>,
|
mosi: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
txdma: PeripheralRef<'d, Tx>,
|
txdma: Option<(PeripheralRef<'d, AnyChannel>, Request)>,
|
||||||
rxdma: PeripheralRef<'d, Rx>,
|
rxdma: Option<(PeripheralRef<'d, AnyChannel>, Request)>,
|
||||||
|
_phantom: PhantomData<M>,
|
||||||
current_word_size: word_impl::Config,
|
current_word_size: word_impl::Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
|
||||||
/// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_inner(
|
fn new_inner(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
sck: Option<PeripheralRef<'d, AnyPin>>,
|
sck: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
mosi: Option<PeripheralRef<'d, AnyPin>>,
|
mosi: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
txdma: impl Peripheral<P = Tx> + 'd,
|
txdma: Option<(PeripheralRef<'d, AnyChannel>, Request)>,
|
||||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
rxdma: Option<(PeripheralRef<'d, AnyChannel>, Request)>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, txdma, rxdma);
|
into_ref!(peri);
|
||||||
|
|
||||||
let pclk = T::frequency();
|
let pclk = T::frequency();
|
||||||
let freq = config.frequency;
|
let freq = config.frequency;
|
||||||
@ -336,6 +212,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
|||||||
txdma,
|
txdma,
|
||||||
rxdma,
|
rxdma,
|
||||||
current_word_size: <u8 as SealedWord>::CONFIG,
|
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;
|
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.
|
/// Blocking write.
|
||||||
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
|
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
|
||||||
T::REGS.cr1().modify(|w| w.set_spe(true));
|
T::REGS.cr1().modify(|w| w.set_spe(true));
|
||||||
@ -682,7 +396,338 @@ 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,
|
||||||
|
txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||||
|
rxdma: 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!(txdma),
|
||||||
|
new_dma!(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,
|
||||||
|
rxdma: 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!(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 = 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!(txdma),
|
||||||
|
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,
|
||||||
|
txdma: 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!(txdma),
|
||||||
|
None,
|
||||||
|
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 = impl TxDma<T>> + 'd,
|
||||||
|
rxdma: 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!(txdma), new_dma!(rxdma), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn new_internal(
|
||||||
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
|
txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||||
|
rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||||
|
config: Config,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_inner(peri, None, None, None, new_dma!(txdma), new_dma!(rxdma), 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 (txdma, tx_request) = self.txdma.as_mut().unwrap();
|
||||||
|
let tx_dst = T::REGS.tx_ptr();
|
||||||
|
let tx_f = unsafe { Transfer::new_write(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> {
|
||||||
|
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 (rxdma, rx_request) = self.rxdma.as_mut().unwrap();
|
||||||
|
let rx_src = T::REGS.rx_ptr();
|
||||||
|
let rx_f = unsafe { Transfer::new_read(rxdma, *rx_request, rx_src, data, Default::default()) };
|
||||||
|
|
||||||
|
let (txdma, tx_request) = self.txdma.as_mut().unwrap();
|
||||||
|
let tx_dst = T::REGS.tx_ptr();
|
||||||
|
let clock_byte = 0x00u8;
|
||||||
|
let tx_f = unsafe {
|
||||||
|
Transfer::new_write_repeated(
|
||||||
|
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> {
|
||||||
|
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 (rxdma, rx_request) = self.rxdma.as_mut().unwrap();
|
||||||
|
let rx_src = T::REGS.rx_ptr();
|
||||||
|
let rx_f = unsafe { Transfer::new_read_raw(rxdma, *rx_request, rx_src, read, Default::default()) };
|
||||||
|
|
||||||
|
let (txdma, tx_request) = self.txdma.as_mut().unwrap();
|
||||||
|
let tx_dst = T::REGS.tx_ptr();
|
||||||
|
let tx_f = unsafe { Transfer::new_write_raw(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> {
|
||||||
|
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) {
|
fn drop(&mut self) {
|
||||||
self.sck.as_ref().map(|x| x.set_as_disconnected());
|
self.sck.as_ref().map(|x| x.set_as_disconnected());
|
||||||
self.mosi.as_ref().map(|x| x.set_as_disconnected());
|
self.mosi.as_ref().map(|x| x.set_as_disconnected());
|
||||||
@ -900,7 +945,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
|
// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
|
||||||
macro_rules! impl_blocking {
|
macro_rules! impl_blocking {
|
||||||
($w:ident) => {
|
($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;
|
type Error = Error;
|
||||||
|
|
||||||
fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
|
fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
|
||||||
@ -908,7 +953,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;
|
type Error = Error;
|
||||||
|
|
||||||
fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
|
fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
|
||||||
@ -922,11 +967,11 @@ macro_rules! impl_blocking {
|
|||||||
impl_blocking!(u8);
|
impl_blocking!(u8);
|
||||||
impl_blocking!(u16);
|
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;
|
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> {
|
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -959,7 +1004,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> {
|
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1094,7 +1139,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 Config = Config;
|
||||||
type ConfigError = ();
|
type ConfigError = ();
|
||||||
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
|
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
|
||||||
|
@ -69,3 +69,26 @@ macro_rules! dma_trait_impl {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! new_dma {
|
||||||
|
($name:ident) => {{
|
||||||
|
let dma = $name.into_ref();
|
||||||
|
let req = dma.request();
|
||||||
|
Some((dma.map_into(), req))
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! new_pin {
|
||||||
|
($name:ident, $aftype:expr, $speed:expr) => {{
|
||||||
|
let pin = $name.into_ref();
|
||||||
|
pin.set_as_af(pin.af_num(), $aftype);
|
||||||
|
pin.set_speed($speed);
|
||||||
|
Some(pin.map_into())
|
||||||
|
}};
|
||||||
|
($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())
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||||
use embassy_stm32::spi::{Config, Spi};
|
use embassy_stm32::spi::{Config, Spi};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
@ -18,7 +17,7 @@ fn main() -> ! {
|
|||||||
let mut spi_config = Config::default();
|
let mut spi_config = Config::default();
|
||||||
spi_config.frequency = Hertz(1_000_000);
|
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);
|
let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
use embassy_stm32::spi;
|
||||||
use embassy_stm32::time::khz;
|
use embassy_stm32::time::khz;
|
||||||
use embassy_stm32::{dma, spi};
|
|
||||||
use embassy_time::{Duration, Ticker, Timer};
|
use embassy_time::{Duration, Ticker, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
|
|||||||
spi_config.frequency = khz(12_800);
|
spi_config.frequency = khz(12_800);
|
||||||
|
|
||||||
// Since we only output waveform, then the Rx and Sck and RxDma it is not considered
|
// 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
|
// flip color at 2 Hz
|
||||||
let mut ticker = Ticker::every(Duration::from_millis(500));
|
let mut ticker = Ticker::every(Duration::from_millis(500));
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::dma::word::U5;
|
use embassy_stm32::dma::word::U5;
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use embassy_stm32::spi::{Config, Spi};
|
use embassy_stm32::spi::{Config, Spi};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
@ -77,7 +76,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.frequency = Hertz(4_000_000);
|
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();
|
let mut neopixels = Ws2812::new();
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use core::str::from_utf8;
|
|||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Executor;
|
use embassy_executor::Executor;
|
||||||
use embassy_stm32::dma::NoDma;
|
use embassy_stm32::mode::Blocking;
|
||||||
use embassy_stm32::peripherals::SPI3;
|
use embassy_stm32::peripherals::SPI3;
|
||||||
use embassy_stm32::time::mhz;
|
use embassy_stm32::time::mhz;
|
||||||
use embassy_stm32::{spi, Config};
|
use embassy_stm32::{spi, Config};
|
||||||
@ -16,7 +16,7 @@ use static_cell::StaticCell;
|
|||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[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.. {
|
for n in 0u32.. {
|
||||||
let mut write: String<128> = String::new();
|
let mut write: String<128> = String::new();
|
||||||
core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
|
core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
|
||||||
@ -62,7 +62,7 @@ fn main() -> ! {
|
|||||||
let mut spi_config = spi::Config::default();
|
let mut spi_config = spi::Config::default();
|
||||||
spi_config.frequency = mhz(1);
|
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());
|
let executor = EXECUTOR.init(Executor::new());
|
||||||
|
|
||||||
|
@ -7,15 +7,15 @@ use core::str::from_utf8;
|
|||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Executor;
|
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::time::mhz;
|
||||||
use embassy_stm32::{spi, Config};
|
use embassy_stm32::{peripherals, spi, Config};
|
||||||
use heapless::String;
|
use heapless::String;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[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.. {
|
for n in 0u32.. {
|
||||||
let mut write: String<128> = String::new();
|
let mut write: String<128> = String::new();
|
||||||
let mut read = [0; 128];
|
let mut read = [0; 128];
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||||
use embassy_stm32::spi::{Config, Spi};
|
use embassy_stm32::spi::{Config, Spi};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut spi_config = Config::default();
|
let mut spi_config = Config::default();
|
||||||
spi_config.frequency = Hertz(1_000_000);
|
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);
|
let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh);
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||||
use embassy_stm32::spi::{Config, Spi};
|
use embassy_stm32::spi::{Config, Spi};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut spi_config = Config::default();
|
let mut spi_config = Config::default();
|
||||||
spi_config.frequency = Hertz(1_000_000);
|
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);
|
let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh);
|
||||||
|
|
||||||
|
@ -23,18 +23,23 @@ use embassy_futures::select::{select, Either};
|
|||||||
use embassy_futures::yield_now;
|
use embassy_futures::yield_now;
|
||||||
use embassy_net::tcp::TcpSocket;
|
use embassy_net::tcp::TcpSocket;
|
||||||
use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4};
|
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 embassy_time::{Delay, Duration, Ticker, Timer};
|
||||||
use embedded_hal_async::i2c::I2c as I2cBus;
|
use embedded_hal_async::i2c::I2c as I2cBus;
|
||||||
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||||
use embedded_io::Write as bWrite;
|
use embedded_io::Write as bWrite;
|
||||||
use embedded_io_async::Write;
|
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 heapless::Vec;
|
||||||
|
use panic_probe as _;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {embassy_stm32 as hal, panic_probe as _};
|
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
|
I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
|
||||||
@ -42,13 +47,6 @@ bind_interrupts!(struct Irqs {
|
|||||||
RNG => rng::InterruptHandler<peripherals::RNG>;
|
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
|
// Basic settings
|
||||||
// MAC-address used by the adin1110
|
// MAC-address used by the adin1110
|
||||||
const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
|
const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
|
||||||
@ -57,7 +55,7 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24);
|
|||||||
// Listen port for the webserver
|
// Listen port for the webserver
|
||||||
const HTTP_LISTEN_PORT: u16 = 80;
|
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 SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>;
|
||||||
pub type SpeInt = exti::ExtiInput<'static>;
|
pub type SpeInt = exti::ExtiInput<'static>;
|
||||||
pub type SpeRst = Output<'static>;
|
pub type SpeRst = Output<'static>;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||||
use embassy_stm32::spi::{Config, Spi};
|
use embassy_stm32::spi::{Config, Spi};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
@ -17,7 +16,7 @@ fn main() -> ! {
|
|||||||
let mut spi_config = Config::default();
|
let mut spi_config = Config::default();
|
||||||
spi_config.frequency = Hertz(1_000_000);
|
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);
|
let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_embedded_hal::adapter::BlockingAsync;
|
use embassy_embedded_hal::adapter::BlockingAsync;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
|
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
|
||||||
use embassy_stm32::spi::{Config, Spi};
|
use embassy_stm32::spi::{Config, Spi};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut spi_config = Config::default();
|
let mut spi_config = Config::default();
|
||||||
spi_config.frequency = Hertz(1_000_000);
|
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);
|
let mut spi = BlockingAsync::new(spi);
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ mod common;
|
|||||||
use common::*;
|
use common::*;
|
||||||
use defmt::assert_eq;
|
use defmt::assert_eq;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::dma::NoDma;
|
|
||||||
use embassy_stm32::spi::{self, Spi};
|
use embassy_stm32::spi::{self, Spi};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
|
|
||||||
@ -23,11 +22,11 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut spi_config = spi::Config::default();
|
let mut spi_config = spi::Config::default();
|
||||||
spi_config.frequency = Hertz(1_000_000);
|
spi_config.frequency = Hertz(1_000_000);
|
||||||
|
|
||||||
let mut spi = Spi::new(
|
let mut spi = Spi::new_blocking(
|
||||||
spi, sck, // Arduino D13
|
spi, sck, // Arduino D13
|
||||||
mosi, // Arduino D11
|
mosi, // Arduino D11
|
||||||
miso, // Arduino D12
|
miso, // Arduino D12
|
||||||
NoDma, NoDma, spi_config,
|
spi_config,
|
||||||
);
|
);
|
||||||
|
|
||||||
let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];
|
let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];
|
||||||
|
Loading…
Reference in New Issue
Block a user