Unify blocking trait impls

This commit is contained in:
Grant Miller 2021-12-06 22:45:40 -06:00
parent 3a17e3a2a5
commit bf1f80afa1
4 changed files with 125 additions and 382 deletions

View file

@ -1,6 +1,7 @@
#![macro_use]
use crate::dma;
use crate::dma::NoDma;
use crate::gpio::sealed::{AFType, Pin};
use crate::gpio::{AnyPin, NoPin, OptionalPin};
use crate::pac::spi::{regs, vals};
@ -9,6 +10,7 @@ use crate::rcc::RccPeripheral;
use crate::time::Hertz;
use core::future::Future;
use core::marker::PhantomData;
use core::ptr;
use embassy::util::Unborrow;
use embassy_hal_common::unborrow;
use embassy_traits::spi as traits;
@ -403,11 +405,121 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> {
Ok(())
}
fn spin_until_tx_ready(regs: &'static crate::pac::spi::Spi) -> Result<(), Error> {
loop {
let sr = unsafe { regs.sr().read() };
check_error_flags(sr)?;
#[cfg(not(spi_v3))]
if sr.txe() {
return Ok(());
}
#[cfg(spi_v3)]
if sr.txp() {
return Ok(());
}
}
}
fn spin_until_rx_ready(regs: &'static crate::pac::spi::Spi) -> Result<(), Error> {
loop {
let sr = unsafe { regs.sr().read() };
check_error_flags(sr)?;
#[cfg(not(spi_v3))]
if sr.rxne() {
return Ok(());
}
#[cfg(spi_v3)]
if sr.rxp() {
return Ok(());
}
}
}
trait Word {}
impl Word for u8 {}
impl Word for u16 {}
fn transfer_word<W: Word>(regs: &'static crate::pac::spi::Spi, tx_word: W) -> Result<W, Error> {
spin_until_tx_ready(regs)?;
unsafe {
ptr::write_volatile(regs.tx_ptr(), tx_word);
#[cfg(spi_v3)]
regs.cr1().modify(|reg| reg.set_cstart(true));
}
spin_until_rx_ready(regs)?;
let rx_word = unsafe { ptr::read_volatile(regs.rx_ptr()) };
return Ok(rx_word);
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.set_word_size(WordSize::EightBit);
let regs = T::regs();
for word in words.iter() {
let _ = transfer_word(regs, *word)?;
}
Ok(())
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
self.set_word_size(WordSize::EightBit);
let regs = T::regs();
for word in words.iter_mut() {
*word = transfer_word(regs, *word)?;
}
Ok(words)
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
self.set_word_size(WordSize::SixteenBit);
let regs = T::regs();
for word in words.iter() {
let _ = transfer_word(regs, *word)?;
}
Ok(())
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> {
self.set_word_size(WordSize::SixteenBit);
let regs = T::regs();
for word in words.iter_mut() {
*word = transfer_word(regs, *word)?;
}
Ok(words)
}
}
impl<'d, T: Instance, Tx, Rx> traits::Spi<u8> for Spi<'d, T, Tx, Rx> {
type Error = Error;
}

View file

@ -1,15 +1,10 @@
#![macro_use]
use crate::dma::NoDma;
use crate::spi::{
check_error_flags, Error, Instance, RegsExt, RxDmaChannel, TxDmaChannel, WordSize,
};
use core::ptr;
pub use embedded_hal::blocking;
pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
use futures::future::join3;
use super::Spi;
use super::*;
impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
pub(super) async fn write_dma_u8(&mut self, write: &[u8]) -> Result<(), Error>
@ -155,99 +150,3 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.set_word_size(WordSize::EightBit);
let regs = T::regs();
for word in words.iter() {
write_word(regs, *word)?;
let _: u8 = read_word(regs)?;
}
Ok(())
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
self.set_word_size(WordSize::EightBit);
let regs = T::regs();
for word in words.iter_mut() {
write_word(regs, *word)?;
*word = read_word(regs)?;
}
Ok(words)
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
self.set_word_size(WordSize::SixteenBit);
let regs = T::regs();
for word in words.iter() {
write_word(regs, *word)?;
let _: u8 = read_word(regs)?;
}
Ok(())
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> {
self.set_word_size(WordSize::SixteenBit);
let regs = T::regs();
for word in words.iter_mut() {
write_word(regs, *word)?;
*word = read_word(regs)?;
}
Ok(words)
}
}
use super::Word;
fn write_word<W: Word>(regs: &'static crate::pac::spi::Spi, word: W) -> Result<(), Error> {
loop {
let sr = unsafe { regs.sr().read() };
check_error_flags(sr)?;
if sr.txe() {
unsafe {
ptr::write_volatile(regs.tx_ptr(), word);
}
return Ok(());
}
}
}
/// Read a single word blocking. Assumes word size have already been set.
fn read_word<W: Word>(regs: &'static crate::pac::spi::Spi) -> Result<W, Error> {
loop {
let sr = unsafe { regs.sr().read() };
check_error_flags(sr)?;
if sr.rxne() {
unsafe {
return Ok(ptr::read_volatile(regs.rx_ptr()));
}
}
}
}

View file

@ -1,14 +1,9 @@
#![macro_use]
use crate::dma::NoDma;
use crate::spi::{
check_error_flags, Error, Instance, RegsExt, RxDmaChannel, TxDmaChannel, WordSize,
};
use core::ptr;
pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
use futures::future::{join, join3};
use super::Spi;
use super::*;
impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
pub(super) async fn write_dma_u8(&mut self, write: &[u8]) -> Result<(), Error>
@ -100,7 +95,11 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Ok(())
}
pub(super) async fn read_write_dma_u8(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error>
pub(super) async fn read_write_dma_u8(
&mut self,
read: &mut [u8],
write: &[u8],
) -> Result<(), Error>
where
Tx: TxDmaChannel<T>,
Rx: RxDmaChannel<T>,
@ -170,100 +169,3 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
}
}
use super::Word;
/// Write a single word blocking. Assumes word size have already been set.
fn write_word<W: Word>(regs: &'static crate::pac::spi::Spi, word: W) -> Result<(), Error> {
loop {
let sr = unsafe { regs.sr().read() };
check_error_flags(sr)?;
if sr.txe() {
unsafe {
ptr::write_volatile(regs.tx_ptr(), word);
}
return Ok(());
}
}
}
/// Read a single word blocking. Assumes word size have already been set.
fn read_word<W: Word>(regs: &'static crate::pac::spi::Spi) -> Result<W, Error> {
loop {
let sr = unsafe { regs.sr().read() };
check_error_flags(sr)?;
if sr.rxne() {
unsafe {
return Ok(ptr::read_volatile(regs.rx_ptr()));
}
}
}
}
impl<'d, T: Instance, Rx> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T, NoDma, Rx> {
type Error = Error;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.set_word_size(WordSize::EightBit);
let regs = T::regs();
for word in words.iter() {
write_word(regs, *word)?;
let _: u8 = read_word(regs)?;
}
Ok(())
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
self.set_word_size(WordSize::EightBit);
let regs = T::regs();
for word in words.iter_mut() {
write_word(regs, *word)?;
*word = read_word(regs)?;
}
Ok(words)
}
}
impl<'d, T: Instance, Rx> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T, NoDma, Rx> {
type Error = Error;
fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
self.set_word_size(WordSize::SixteenBit);
let regs = T::regs();
for word in words.iter() {
write_word(regs, *word)?;
let _: u16 = read_word(regs)?;
}
Ok(())
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> {
self.set_word_size(WordSize::SixteenBit);
let regs = T::regs();
for word in words.iter_mut() {
write_word(regs, *word)?;
*word = read_word(regs)?;
}
Ok(words)
}
}

View file

@ -1,15 +1,9 @@
#![macro_use]
use crate::dma::NoDma;
use crate::spi::{
check_error_flags, Error, Instance, RegsExt, RxDmaChannel, TxDmaChannel, WordSize,
};
use core::ptr;
pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
use futures::future::join3;
use super::Spi;
use super::*;
impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
pub(super) async fn write_dma_u8(&mut self, write: &[u8]) -> Result<(), Error>
@ -105,7 +99,11 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Ok(())
}
pub(super) async fn read_write_dma_u8(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error>
pub(super) async fn read_write_dma_u8(
&mut self,
read: &mut [u8],
write: &[u8],
) -> Result<(), Error>
where
Tx: TxDmaChannel<T>,
Rx: RxDmaChannel<T>,
@ -173,171 +171,3 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.set_word_size(WordSize::EightBit);
let regs = T::regs();
for word in words.iter() {
while unsafe { !regs.sr().read().txp() } {
// spin
}
unsafe {
ptr::write_volatile(regs.tx_ptr(), *word);
regs.cr1().modify(|reg| reg.set_cstart(true));
}
loop {
let sr = unsafe { regs.sr().read() };
if sr.tifre() {
return Err(Error::Framing);
}
if sr.ovr() {
return Err(Error::Overrun);
}
if sr.crce() {
return Err(Error::Crc);
}
if !sr.txp() {
// loop waiting for TXE
continue;
}
break;
}
unsafe {
// discard read to prevent pverrun.
let _: u8 = ptr::read_volatile(T::regs().rx_ptr());
}
}
while unsafe { !regs.sr().read().txc() } {
// spin
}
Ok(())
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
self.set_word_size(WordSize::EightBit);
let regs = T::regs();
for word in words.iter_mut() {
unsafe {
regs.cr1().modify(|reg| {
reg.set_ssi(false);
});
}
while unsafe { !regs.sr().read().txp() } {
// spin
}
unsafe {
ptr::write_volatile(T::regs().tx_ptr(), *word);
regs.cr1().modify(|reg| reg.set_cstart(true));
}
loop {
let sr = unsafe { regs.sr().read() };
if sr.rxp() {
break;
}
check_error_flags(sr)?;
}
unsafe {
*word = ptr::read_volatile(T::regs().rx_ptr());
}
let sr = unsafe { regs.sr().read() };
check_error_flags(sr)?;
}
Ok(words)
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
self.set_word_size(WordSize::SixteenBit);
let regs = T::regs();
for word in words.iter() {
while unsafe { !regs.sr().read().txp() } {
// spin
}
unsafe {
let txdr = regs.txdr().ptr() as *mut u16;
ptr::write_volatile(txdr, *word);
regs.cr1().modify(|reg| reg.set_cstart(true));
}
loop {
let sr = unsafe { regs.sr().read() };
check_error_flags(sr)?;
if !sr.txp() {
// loop waiting for TXE
continue;
}
break;
}
unsafe {
let rxdr = regs.rxdr().ptr() as *const u8;
// discard read to prevent pverrun.
let _ = ptr::read_volatile(rxdr);
}
}
while unsafe { !regs.sr().read().txc() } {
// spin
}
Ok(())
}
}
impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T, NoDma, NoDma> {
type Error = Error;
fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> {
self.set_word_size(WordSize::SixteenBit);
let regs = T::regs();
for word in words.iter_mut() {
while unsafe { !regs.sr().read().txp() } {
// spin
}
unsafe {
let txdr = regs.txdr().ptr() as *mut u16;
ptr::write_volatile(txdr, *word);
regs.cr1().modify(|reg| reg.set_cstart(true));
}
loop {
let sr = unsafe { regs.sr().read() };
if sr.rxp() {
break;
}
check_error_flags(sr)?;
}
unsafe {
let rxdr = regs.rxdr().ptr() as *const u16;
*word = ptr::read_volatile(rxdr);
}
let sr = unsafe { regs.sr().read() };
check_error_flags(sr)?;
}
Ok(words)
}
}