Clear Receiver enable flag before write in Half-Duplex mode

This commit is contained in:
Роман Кривенков 2024-04-30 15:42:11 +04:00
parent 56a7b10064
commit d5f0bceb7c

View File

@ -359,16 +359,32 @@ impl<'d, T: BasicInstance> UartTx<'d, T, Async> {
/// Initiate an asynchronous UART write /// Initiate an asynchronous UART write
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs();
// Disable Receiver for Half-Duplex mode
if r.cr3().read().hdsel() {
r.cr1().modify(|reg| reg.set_re(false));
}
let ch = self.tx_dma.as_mut().unwrap(); let ch = self.tx_dma.as_mut().unwrap();
T::regs().cr3().modify(|reg| { r.cr3().modify(|reg| {
reg.set_dmat(true); reg.set_dmat(true);
}); });
// If we don't assign future to a variable, the data register pointer // If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send. // is held across an await and makes the future non-Send.
let transfer = unsafe { ch.write(buffer, tdr(T::regs()), Default::default()) }; let transfer = unsafe { ch.write(buffer, tdr(r), Default::default()) };
transfer.await; transfer.await;
Ok(()) Ok(())
} }
async fn flush_inner() -> Result<(), Error> {
Self::blocking_flush_inner()
}
/// Wait until transmission complete
pub async fn flush(&mut self) -> Result<(), Error> {
Self::flush_inner().await
}
} }
impl<'d, T: BasicInstance> UartTx<'d, T, Blocking> { impl<'d, T: BasicInstance> UartTx<'d, T, Blocking> {
@ -436,6 +452,12 @@ impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
/// Perform a blocking UART write /// Perform a blocking UART write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
// Disable Receiver for Half-Duplex mode
if r.cr3().read().hdsel() {
r.cr1().modify(|reg| reg.set_re(false));
}
for &b in buffer { for &b in buffer {
while !sr(r).read().txe() {} while !sr(r).read().txe() {}
unsafe { tdr(r).write_volatile(b) }; unsafe { tdr(r).write_volatile(b) };
@ -443,12 +465,21 @@ impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
Ok(()) Ok(())
} }
/// Block until transmission complete fn blocking_flush_inner() -> Result<(), Error> {
pub fn blocking_flush(&mut self) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
while !sr(r).read().tc() {} while !sr(r).read().tc() {}
// Enable Receiver after transmission complete for Half-Duplex mode
if r.cr3().read().hdsel() {
r.cr1().modify(|reg| reg.set_re(true));
}
Ok(()) Ok(())
} }
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> {
Self::blocking_flush_inner()
}
} }
impl<'d, T: BasicInstance> UartRx<'d, T, Async> { impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
@ -502,6 +533,11 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
) -> Result<ReadCompletionEvent, Error> { ) -> Result<ReadCompletionEvent, Error> {
let r = T::regs(); let r = T::regs();
// Call flush for Half-Duplex mode. It prevents reading of bytes which have just been written.
if r.cr3().read().hdsel() {
UartTx::<'d, T, Async>::flush_inner().await?;
}
// make sure USART state is restored to neutral state when this future is dropped // make sure USART state is restored to neutral state when this future is dropped
let on_drop = OnDrop::new(move || { let on_drop = OnDrop::new(move || {
// defmt::trace!("Clear all USART interrupts and DMA Read Request"); // defmt::trace!("Clear all USART interrupts and DMA Read Request");
@ -825,6 +861,12 @@ impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
/// Perform a blocking read into `buffer` /// Perform a blocking read into `buffer`
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
// Call flush for Half-Duplex mode. It prevents reading of bytes which have just been written.
if r.cr3().read().hdsel() {
UartTx::<'d, T, M>::blocking_flush_inner()?;
}
for b in buffer { for b in buffer {
while !self.check_rx_flags()? {} while !self.check_rx_flags()? {}
unsafe { *b = rdr(r).read_volatile() } unsafe { *b = rdr(r).read_volatile() }