Merge pull request #3512 from EnmanuelParache/stm32_usart_set_baudrate
stm32/usart: Changing baud rate
This commit is contained in:
		
						commit
						86b53a2ce3
					
				@ -12,8 +12,8 @@ use embassy_sync::waitqueue::AtomicWaker;
 | 
				
			|||||||
#[cfg(not(any(usart_v1, usart_v2)))]
 | 
					#[cfg(not(any(usart_v1, usart_v2)))]
 | 
				
			||||||
use super::DePin;
 | 
					use super::DePin;
 | 
				
			||||||
use super::{
 | 
					use super::{
 | 
				
			||||||
    clear_interrupt_flags, configure, rdr, reconfigure, send_break, sr, tdr, Config, ConfigError, CtsPin, Error, Info,
 | 
					    clear_interrupt_flags, configure, rdr, reconfigure, send_break, set_baudrate, sr, tdr, Config, ConfigError, CtsPin,
 | 
				
			||||||
    Instance, Regs, RtsPin, RxPin, TxPin,
 | 
					    Error, Info, Instance, Regs, RtsPin, RxPin, TxPin,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
 | 
					use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
 | 
				
			||||||
use crate::interrupt::{self, InterruptExt};
 | 
					use crate::interrupt::{self, InterruptExt};
 | 
				
			||||||
@ -441,6 +441,13 @@ impl<'d> BufferedUart<'d> {
 | 
				
			|||||||
    pub fn send_break(&self) {
 | 
					    pub fn send_break(&self) {
 | 
				
			||||||
        self.tx.send_break()
 | 
					        self.tx.send_break()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Set baudrate
 | 
				
			||||||
 | 
					    pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
 | 
				
			||||||
 | 
					        self.tx.set_baudrate(baudrate)?;
 | 
				
			||||||
 | 
					        self.rx.set_baudrate(baudrate)?;
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'d> BufferedUartRx<'d> {
 | 
					impl<'d> BufferedUartRx<'d> {
 | 
				
			||||||
@ -535,6 +542,11 @@ impl<'d> BufferedUartRx<'d> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Set baudrate
 | 
				
			||||||
 | 
					    pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
 | 
				
			||||||
 | 
					        set_baudrate(self.info, self.kernel_clock, baudrate)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'d> BufferedUartTx<'d> {
 | 
					impl<'d> BufferedUartTx<'d> {
 | 
				
			||||||
@ -625,6 +637,11 @@ impl<'d> BufferedUartTx<'d> {
 | 
				
			|||||||
    pub fn send_break(&self) {
 | 
					    pub fn send_break(&self) {
 | 
				
			||||||
        send_break(&self.info.regs);
 | 
					        send_break(&self.info.regs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Set baudrate
 | 
				
			||||||
 | 
					    pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
 | 
				
			||||||
 | 
					        set_baudrate(self.info, self.kernel_clock, baudrate)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'d> Drop for BufferedUartRx<'d> {
 | 
					impl<'d> Drop for BufferedUartRx<'d> {
 | 
				
			||||||
 | 
				
			|||||||
@ -539,6 +539,11 @@ impl<'d, M: Mode> UartTx<'d, M> {
 | 
				
			|||||||
    pub fn send_break(&self) {
 | 
					    pub fn send_break(&self) {
 | 
				
			||||||
        send_break(&self.info.regs);
 | 
					        send_break(&self.info.regs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Set baudrate
 | 
				
			||||||
 | 
					    pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
 | 
				
			||||||
 | 
					        set_baudrate(self.info, self.kernel_clock, baudrate)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Wait until transmission complete
 | 
					/// Wait until transmission complete
 | 
				
			||||||
@ -1014,6 +1019,11 @@ impl<'d, M: Mode> UartRx<'d, M> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Set baudrate
 | 
				
			||||||
 | 
					    pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
 | 
				
			||||||
 | 
					        set_baudrate(self.info, self.kernel_clock, baudrate)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'d, M: Mode> Drop for UartTx<'d, M> {
 | 
					impl<'d, M: Mode> Drop for UartTx<'d, M> {
 | 
				
			||||||
@ -1455,6 +1465,13 @@ impl<'d, M: Mode> Uart<'d, M> {
 | 
				
			|||||||
    pub fn send_break(&self) {
 | 
					    pub fn send_break(&self) {
 | 
				
			||||||
        self.tx.send_break();
 | 
					        self.tx.send_break();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Set baudrate
 | 
				
			||||||
 | 
					    pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
 | 
				
			||||||
 | 
					        self.tx.set_baudrate(baudrate)?;
 | 
				
			||||||
 | 
					        self.rx.set_baudrate(baudrate)?;
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> {
 | 
					fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> {
 | 
				
			||||||
@ -1470,20 +1487,33 @@ fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(),
 | 
				
			|||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn configure(
 | 
					fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 {
 | 
				
			||||||
    info: &Info,
 | 
					    // The calculation to be done to get the BRR is `mul * pclk / presc / baud`
 | 
				
			||||||
    kernel_clock: Hertz,
 | 
					    // To do this in 32-bit only we can't multiply `mul` and `pclk`
 | 
				
			||||||
    config: &Config,
 | 
					    let clock = pclk / presc;
 | 
				
			||||||
    enable_rx: bool,
 | 
					 | 
				
			||||||
    enable_tx: bool,
 | 
					 | 
				
			||||||
) -> Result<(), ConfigError> {
 | 
					 | 
				
			||||||
    let r = info.regs;
 | 
					 | 
				
			||||||
    let kind = info.kind;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if !enable_rx && !enable_tx {
 | 
					    // The mul is applied as the last operation to prevent overflow
 | 
				
			||||||
        return Err(ConfigError::RxOrTxNotEnabled);
 | 
					    let brr = clock / baud * mul;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The BRR calculation will be a bit off because of integer rounding.
 | 
				
			||||||
 | 
					    // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul.
 | 
				
			||||||
 | 
					    let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    brr + rounding
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn set_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> {
 | 
				
			||||||
 | 
					    info.interrupt.disable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set_usart_baudrate(info, kernel_clock, baudrate)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    info.interrupt.unpend();
 | 
				
			||||||
 | 
					    unsafe { info.interrupt.enable() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn find_and_set_brr(r: Regs, kind: Kind, kernel_clock: Hertz, baudrate: u32) -> Result<bool, ConfigError> {
 | 
				
			||||||
    #[cfg(not(usart_v4))]
 | 
					    #[cfg(not(usart_v4))]
 | 
				
			||||||
    static DIVS: [(u16, ()); 1] = [(1, ())];
 | 
					    static DIVS: [(u16, ()); 1] = [(1, ())];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1515,31 +1545,14 @@ fn configure(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 {
 | 
					    let mut found_brr = None;
 | 
				
			||||||
        // The calculation to be done to get the BRR is `mul * pclk / presc / baud`
 | 
					 | 
				
			||||||
        // To do this in 32-bit only we can't multiply `mul` and `pclk`
 | 
					 | 
				
			||||||
        let clock = pclk / presc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // The mul is applied as the last operation to prevent overflow
 | 
					 | 
				
			||||||
        let brr = clock / baud * mul;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // The BRR calculation will be a bit off because of integer rounding.
 | 
					 | 
				
			||||||
        // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul.
 | 
					 | 
				
			||||||
        let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        brr + rounding
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // UART must be disabled during configuration.
 | 
					 | 
				
			||||||
    r.cr1().modify(|w| {
 | 
					 | 
				
			||||||
        w.set_ue(false);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[cfg(not(usart_v1))]
 | 
					    #[cfg(not(usart_v1))]
 | 
				
			||||||
    let mut over8 = false;
 | 
					    let mut over8 = false;
 | 
				
			||||||
    let mut found_brr = None;
 | 
					    #[cfg(usart_v1)]
 | 
				
			||||||
 | 
					    let over8 = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for &(presc, _presc_val) in &DIVS {
 | 
					    for &(presc, _presc_val) in &DIVS {
 | 
				
			||||||
        let brr = calculate_brr(config.baudrate, kernel_clock.0, presc as u32, mul);
 | 
					        let brr = calculate_brr(baudrate, kernel_clock.0, presc as u32, mul);
 | 
				
			||||||
        trace!(
 | 
					        trace!(
 | 
				
			||||||
            "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
 | 
					            "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
 | 
				
			||||||
            presc,
 | 
					            presc,
 | 
				
			||||||
@ -1570,18 +1583,70 @@ fn configure(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?;
 | 
					    match found_brr {
 | 
				
			||||||
 | 
					        Some(brr) => {
 | 
				
			||||||
 | 
					            #[cfg(not(usart_v1))]
 | 
				
			||||||
 | 
					            let oversampling = if over8 { "8 bit" } else { "16 bit" };
 | 
				
			||||||
 | 
					            #[cfg(usart_v1)]
 | 
				
			||||||
 | 
					            let oversampling = "default";
 | 
				
			||||||
 | 
					            trace!(
 | 
				
			||||||
 | 
					                "Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
 | 
				
			||||||
 | 
					                oversampling,
 | 
				
			||||||
 | 
					                baudrate,
 | 
				
			||||||
 | 
					                kernel_clock.0 / brr * mul
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            Ok(over8)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        None => Err(ConfigError::BaudrateTooLow),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn set_usart_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> {
 | 
				
			||||||
 | 
					    let r = info.regs;
 | 
				
			||||||
 | 
					    r.cr1().modify(|w| {
 | 
				
			||||||
 | 
					        // disable uart
 | 
				
			||||||
 | 
					        w.set_ue(false);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[cfg(not(usart_v1))]
 | 
					    #[cfg(not(usart_v1))]
 | 
				
			||||||
    let oversampling = if over8 { "8 bit" } else { "16 bit" };
 | 
					    let over8 = find_and_set_brr(r, info.kind, kernel_clock, baudrate)?;
 | 
				
			||||||
    #[cfg(usart_v1)]
 | 
					    #[cfg(usart_v1)]
 | 
				
			||||||
    let oversampling = "default";
 | 
					    let _over8 = find_and_set_brr(r, info.kind, kernel_clock, baudrate)?;
 | 
				
			||||||
    trace!(
 | 
					
 | 
				
			||||||
        "Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
 | 
					    r.cr1().modify(|w| {
 | 
				
			||||||
        oversampling,
 | 
					        // enable uart
 | 
				
			||||||
        config.baudrate,
 | 
					        w.set_ue(true);
 | 
				
			||||||
        kernel_clock.0 / brr * mul
 | 
					
 | 
				
			||||||
    );
 | 
					        #[cfg(not(usart_v1))]
 | 
				
			||||||
 | 
					        w.set_over8(vals::Over8::from_bits(over8 as _));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn configure(
 | 
				
			||||||
 | 
					    info: &Info,
 | 
				
			||||||
 | 
					    kernel_clock: Hertz,
 | 
				
			||||||
 | 
					    config: &Config,
 | 
				
			||||||
 | 
					    enable_rx: bool,
 | 
				
			||||||
 | 
					    enable_tx: bool,
 | 
				
			||||||
 | 
					) -> Result<(), ConfigError> {
 | 
				
			||||||
 | 
					    let r = info.regs;
 | 
				
			||||||
 | 
					    let kind = info.kind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if !enable_rx && !enable_tx {
 | 
				
			||||||
 | 
					        return Err(ConfigError::RxOrTxNotEnabled);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // UART must be disabled during configuration.
 | 
				
			||||||
 | 
					    r.cr1().modify(|w| {
 | 
				
			||||||
 | 
					        w.set_ue(false);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[cfg(not(usart_v1))]
 | 
				
			||||||
 | 
					    let over8 = find_and_set_brr(r, kind, kernel_clock, config.baudrate)?;
 | 
				
			||||||
 | 
					    #[cfg(usart_v1)]
 | 
				
			||||||
 | 
					    let _over8 = find_and_set_brr(r, kind, kernel_clock, config.baudrate)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    r.cr2().write(|w| {
 | 
					    r.cr2().write(|w| {
 | 
				
			||||||
        w.set_stop(match config.stop_bits {
 | 
					        w.set_stop(match config.stop_bits {
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,9 @@ use embassy_hal_internal::PeripheralRef;
 | 
				
			|||||||
use embedded_io_async::ReadReady;
 | 
					use embedded_io_async::ReadReady;
 | 
				
			||||||
use futures_util::future::{select, Either};
 | 
					use futures_util::future::{select, Either};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx};
 | 
					use super::{
 | 
				
			||||||
 | 
					    clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
use crate::dma::ReadableRingBuffer;
 | 
					use crate::dma::ReadableRingBuffer;
 | 
				
			||||||
use crate::gpio::{AnyPin, SealedPin as _};
 | 
					use crate::gpio::{AnyPin, SealedPin as _};
 | 
				
			||||||
use crate::mode::Async;
 | 
					use crate::mode::Async;
 | 
				
			||||||
@ -213,6 +215,11 @@ impl<'d> RingBufferedUartRx<'d> {
 | 
				
			|||||||
            Either::Right(((), _)) => Ok(()),
 | 
					            Either::Right(((), _)) => Ok(()),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Set baudrate
 | 
				
			||||||
 | 
					    pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
 | 
				
			||||||
 | 
					        set_baudrate(self.info, self.kernel_clock, baudrate)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Drop for RingBufferedUartRx<'_> {
 | 
					impl Drop for RingBufferedUartRx<'_> {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										37
									
								
								examples/stm32l1/src/bin/usart.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								examples/stm32l1/src/bin/usart.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![no_main]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use cortex_m_rt::entry;
 | 
				
			||||||
 | 
					use defmt::*;
 | 
				
			||||||
 | 
					use embassy_stm32::usart::{Config, Uart};
 | 
				
			||||||
 | 
					use embassy_stm32::{bind_interrupts, peripherals, usart};
 | 
				
			||||||
 | 
					use {defmt_rtt as _, panic_probe as _};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bind_interrupts!(struct Irqs {
 | 
				
			||||||
 | 
					    USART2 => usart::InterruptHandler<peripherals::USART2>;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[entry]
 | 
				
			||||||
 | 
					fn main() -> ! {
 | 
				
			||||||
 | 
					    info!("Hello World!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let p = embassy_stm32::init(Default::default());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let config = Config::default();
 | 
				
			||||||
 | 
					    let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap();
 | 
				
			||||||
 | 
					    let desired_baudrate = 9600; // Default is 115200 and 9600 is used as example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    match usart.set_baudrate(desired_baudrate) {
 | 
				
			||||||
 | 
					        Ok(_) => info!("Baud rate set to {}", desired_baudrate),
 | 
				
			||||||
 | 
					        Err(err) => error!("Error setting baudrate to {}: {}", desired_baudrate, err),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user