//! USART1 transmit configuration for STM32F722. use stm32f7::stm32f722; /// UART baud-rate configuration error. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum BaudRateError { /// Zero is not a valid baud rate. Zero, /// The requested divisor cannot fit USART BRR. OutOfRange, } /// Owns configured transmit-only USART1 hardware. /// /// Pin alternate-function setup remains board-owned because it depends on the /// schematic. Configure pins before constructing this type. pub struct Usart1Tx { peripheral: stm32f722::USART1, } impl Usart1Tx { /// Enables USART1 and configures 8N1 transmit-only operation. pub fn new( rcc: &stm32f722::RCC, peripheral: stm32f722::USART1, peripheral_clock_hz: u32, baud: u32, ) -> Result { let brr = calculate_brr(peripheral_clock_hz, baud)?; rcc.apb2rstr() .modify(|_, write| write.usart1rst().set_bit()); rcc.apb2rstr() .modify(|_, write| write.usart1rst().clear_bit()); rcc.apb2enr().modify(|_, write| write.usart1en().set_bit()); peripheral.brr().write(|write| { // SAFETY: `brr` is validated to fit the complete BRR register. unsafe { write.bits(u32::from(brr)) } }); peripheral .cr1() .write(|write| write.te().set_bit().ue().set_bit()); peripheral.cr2().write(|write| write.stop().stop1()); Ok(Self { peripheral }) } pub(crate) fn enable_dma_transmit(&self) { self.peripheral.cr3().write(|write| write.dmat().set_bit()); } pub(crate) fn transmit_data_register_address(&self) -> u32 { self.peripheral.tdr().as_ptr() as u32 } } const fn calculate_brr(peripheral_clock_hz: u32, baud: u32) -> Result { if baud == 0 { return Err(BaudRateError::Zero); } let divisor = (peripheral_clock_hz + (baud / 2)) / baud; if divisor == 0 || divisor > u16::MAX as u32 { Err(BaudRateError::OutOfRange) } else { Ok(divisor as u16) } } #[cfg(test)] mod tests { use super::{BaudRateError, calculate_brr}; #[test] fn calculates_reset_clock_brr() { assert_eq!(calculate_brr(16_000_000, 115_200), Ok(139)); } #[test] fn rejects_zero_baud() { assert_eq!(calculate_brr(16_000_000, 0), Err(BaudRateError::Zero)); } }