Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stm32 spi rxonly slave #1250

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 80 additions & 20 deletions embassy-stm32/src/spi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Some(miso.map_into()),
txdma,
rxdma,
freq,
Some(freq),
config,
)
}
Expand Down Expand Up @@ -144,7 +144,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Some(miso.map_into()),
txdma,
rxdma,
freq,
Some(freq),
config,
)
}
Expand Down Expand Up @@ -173,7 +173,33 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
None,
txdma,
rxdma,
freq,
Some(freq),
config,
)
}

pub fn new_rxonly_slave(
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, // TODO remove
rxdma: impl Peripheral<P = Rx> + 'd,
config: Config,
) -> Self {
into_ref!(sck, mosi);
unsafe {
sck.set_as_af(sck.af_num(), AFType::Input);
mosi.set_as_af(mosi.af_num(), AFType::Input);
}

Self::new_inner(
peri,
Some(sck.map_into()),
None,
Some(mosi.map_into()), /* miso/mosi reversed in slave mode */
txdma,
rxdma,
None,
config,
)
}
Expand All @@ -188,7 +214,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
freq: Hertz,
config: Config,
) -> Self {
Self::new_inner(peri, None, None, None, txdma, rxdma, freq, config)
Self::new_inner(peri, None, None, None, txdma, rxdma, Some(freq), config)
}

fn new_inner(
Expand All @@ -198,13 +224,13 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
miso: Option<PeripheralRef<'d, AnyPin>>,
txdma: impl Peripheral<P = Tx> + 'd,
rxdma: impl Peripheral<P = Rx> + 'd,
freq: Hertz,
freq: Option<Hertz>, /* None in slave mode */
config: Config,
) -> Self {
into_ref!(peri, txdma, rxdma);

let pclk = T::frequency();
let br = compute_baud_rate(pclk, freq.into());
let br = freq.map(|f| compute_baud_rate(pclk, f.into()));

let cpha = config.raw_phase();
let cpol = config.raw_polarity();
Expand All @@ -223,12 +249,17 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
w.set_cpha(cpha);
w.set_cpol(cpol);

w.set_mstr(vals::Mstr::MASTER);
w.set_br(br);
if let Some(br) = br {
w.set_mstr(vals::Mstr::MASTER);
w.set_br(br);
w.set_ssm(true);
} else {
w.set_mstr(vals::Mstr::SLAVE);
w.set_ssm(false);
}
w.set_spe(true);
w.set_lsbfirst(lsbfirst);
w.set_ssi(true);
w.set_ssm(true);
w.set_crcen(false);
w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
if mosi.is_none() {
Expand All @@ -248,11 +279,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
w.set_cpha(cpha);
w.set_cpol(cpol);

w.set_mstr(vals::Mstr::MASTER);
w.set_br(br);
if let Some(br) = br {
w.set_mstr(vals::Mstr::MASTER);
w.set_br(br);
w.set_ssm(true);
} else {
w.set_mstr(vals::Mstr::SLAVE);
w.set_ssm(false);
}
w.set_lsbfirst(lsbfirst);
w.set_ssi(true);
w.set_ssm(true);
w.set_crcen(false);
w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
w.set_spe(true);
Expand All @@ -267,8 +303,13 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
w.set_cpha(cpha);
w.set_cpol(cpol);
w.set_lsbfirst(lsbfirst);
w.set_ssm(true);
w.set_master(vals::Master::MASTER);
if let Some(_) = br {
w.set_mstr(vals::Mstr::MASTER);
w.set_ssm(true);
} else {
w.set_mstr(vals::Mstr::SLAVE);
w.set_ssm(false);
}
w.set_comm(vals::Comm::FULLDUPLEX);
w.set_ssom(vals::Ssom::ASSERTED);
w.set_midi(0);
Expand All @@ -278,7 +319,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
});
T::REGS.cfg1().modify(|w| {
w.set_crcen(false);
w.set_mbr(br);
if let Some(br) = br {
w.set_br(br);
}
w.set_dsize(WordSize::EightBit.dsize());
});
T::REGS.cr2().modify(|w| {
Expand Down Expand Up @@ -456,7 +499,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
set_rxdmaen(T::REGS, true);
}

// SPIv3 clears rxfifo on SPE=0
Expand All @@ -470,12 +512,24 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
unsafe { self.rxdma.start_read(rx_request, rx_src, data, Default::default()) };
let rx_f = Transfer::new(&mut self.rxdma);

let master = unsafe { T::REGS.cr1().read().mstr() == vals::Mstr::MASTER };
let tx_request = self.txdma.request();
let tx_dst = T::REGS.tx_ptr();
let clock_byte = 0x00u8;
let tx_f = crate::dma::write_repeated(&mut self.txdma, tx_request, &clock_byte, clock_byte_count, tx_dst);
let tx_f = if master {
Some(crate::dma::write_repeated(
&mut self.txdma,
tx_request,
&clock_byte,
clock_byte_count,
tx_dst,
))
} else {
None
};

unsafe {
set_rxdmaen(T::REGS, true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's some versions where the RM explicitly says you must set RXDMAEN=true, start DMAs, set TXDMAEN=true in that exact order. It was F4 iirc. And indeed if you don't do that it doesn't work.

set_txdmaen(T::REGS, true);
T::REGS.cr1().modify(|w| {
w.set_spe(true);
Expand All @@ -486,7 +540,11 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
});
}

join(tx_f, rx_f).await;
if let Some(tx_f) = tx_f {
join(tx_f, rx_f).await;
} else {
rx_f.await;
}

finish_dma(T::REGS);

Expand All @@ -510,7 +568,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
set_rxdmaen(T::REGS, true);
}

// SPIv3 clears rxfifo on SPE=0
Expand All @@ -528,6 +585,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
let tx_f = Transfer::new(&mut self.txdma);

unsafe {
set_rxdmaen(T::REGS, true);
set_txdmaen(T::REGS, true);
T::REGS.cr1().modify(|w| {
w.set_spe(true);
Expand Down Expand Up @@ -769,7 +827,9 @@ fn finish_dma(regs: Regs) {
#[cfg(any(spi_v3, spi_v4))]
while !regs.sr().read().txc() {}
#[cfg(not(any(spi_v3, spi_v4)))]
while regs.sr().read().bsy() {}
if regs.cr1().read().mstr() == vals::Mstr::MASTER {
while regs.sr().read().bsy() {}
}

// Disable the spi peripheral
regs.cr1().modify(|w| {
Expand Down