libs/kaptan-stm32f7: add USART1 transmit driver
This commit is contained in:
1 parent
d7028a9bc1
commit
182c86a766
1 file changed
+84
@@ -0,0 +1,84 @@
|
||||
//! 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<Self, BaudRateError> {
|
||||
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<u16, BaudRateError> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user