aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnmanuel Parache <[email protected]>2024-11-06 17:02:39 -0400
committerDario Nieuwenhuis <[email protected]>2024-12-03 00:34:23 +0100
commit6494429a20f6d32e9afdd82417392bcfafc73687 (patch)
tree8efcaabf3eb86d10f0699424001255172dd486f6
parent4b901f9a5b6706841c01dfea149504bc8abf33eb (diff)
stm32/usart: Changing baud rate
-rw-r--r--embassy-stm32/src/usart/mod.rs149
-rw-r--r--examples/stm32l1/src/bin/usart.rs37
2 files changed, 171 insertions, 15 deletions
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index d2fb85ee3..b5db672f2 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -539,6 +539,12 @@ impl<'d, M: Mode> UartTx<'d, M> {
539 pub fn send_break(&self) { 539 pub fn send_break(&self) {
540 send_break(&self.info.regs); 540 send_break(&self.info.regs);
541 } 541 }
542
543 /// Set baudrate
544 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError>
545 {
546 set_baudrate(self.info, self.kernel_clock, baudrate)
547 }
542} 548}
543 549
544/// Wait until transmission complete 550/// Wait until transmission complete
@@ -1014,6 +1020,12 @@ impl<'d, M: Mode> UartRx<'d, M> {
1014 } 1020 }
1015 Ok(()) 1021 Ok(())
1016 } 1022 }
1023
1024 /// Set baudrate
1025 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError>
1026 {
1027 set_baudrate(self.info, self.kernel_clock, baudrate)
1028 }
1017} 1029}
1018 1030
1019impl<'d, M: Mode> Drop for UartTx<'d, M> { 1031impl<'d, M: Mode> Drop for UartTx<'d, M> {
@@ -1455,6 +1467,14 @@ impl<'d, M: Mode> Uart<'d, M> {
1455 pub fn send_break(&self) { 1467 pub fn send_break(&self) {
1456 self.tx.send_break(); 1468 self.tx.send_break();
1457 } 1469 }
1470
1471 /// Set baudrate
1472 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError>
1473 {
1474 self.tx.set_baudrate(baudrate)?;
1475 self.rx.set_baudrate(baudrate)?;
1476 Ok(())
1477 }
1458} 1478}
1459 1479
1460fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> { 1480fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> {
@@ -1470,6 +1490,120 @@ fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(),
1470 Ok(()) 1490 Ok(())
1471} 1491}
1472 1492
1493fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 {
1494 // The calculation to be done to get the BRR is `mul * pclk / presc / baud`
1495 // To do this in 32-bit only we can't multiply `mul` and `pclk`
1496 let clock = pclk / presc;
1497
1498 // The mul is applied as the last operation to prevent overflow
1499 let brr = clock / baud * mul;
1500
1501 // The BRR calculation will be a bit off because of integer rounding.
1502 // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul.
1503 let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
1504
1505 brr + rounding
1506}
1507
1508fn set_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> {
1509 info.interrupt.disable();
1510
1511 set_usart_baudrate(info, kernel_clock, baudrate)?;
1512
1513 info.interrupt.unpend();
1514 unsafe { info.interrupt.enable() };
1515
1516 Ok(())
1517}
1518
1519fn set_usart_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> {
1520 let r = info.regs;
1521 let kind = info.kind;
1522
1523 #[cfg(not(usart_v4))]
1524 static DIVS: [(u16, ()); 1] = [(1, ())];
1525
1526 #[cfg(usart_v4)]
1527 static DIVS: [(u16, vals::Presc); 12] = [
1528 (1, vals::Presc::DIV1),
1529 (2, vals::Presc::DIV2),
1530 (4, vals::Presc::DIV4),
1531 (6, vals::Presc::DIV6),
1532 (8, vals::Presc::DIV8),
1533 (10, vals::Presc::DIV10),
1534 (12, vals::Presc::DIV12),
1535 (16, vals::Presc::DIV16),
1536 (32, vals::Presc::DIV32),
1537 (64, vals::Presc::DIV64),
1538 (128, vals::Presc::DIV128),
1539 (256, vals::Presc::DIV256),
1540 ];
1541
1542 let (mul, brr_min, brr_max) = match kind {
1543 #[cfg(any(usart_v3, usart_v4))]
1544 Kind::Lpuart => {
1545 trace!("USART: Kind::Lpuart");
1546 (256, 0x300, 0x10_0000)
1547 }
1548 Kind::Uart => {
1549 trace!("USART: Kind::Uart");
1550 (1, 0x10, 0x1_0000)
1551 }
1552 };
1553
1554 r.cr1().modify(|w| {
1555 // disable uart
1556 w.set_ue(false);
1557 });
1558
1559 let mut found_brr = None;
1560 for &(presc, _presc_val) in &DIVS {
1561 let brr = calculate_brr(baudrate, kernel_clock.0, presc as u32, mul);
1562 trace!(
1563 "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
1564 presc,
1565 brr,
1566 brr >> 4,
1567 brr & 0x0F
1568 );
1569
1570 if brr < brr_min {
1571 #[cfg(not(usart_v1))]
1572 if brr * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
1573 r.brr().write_value(regs::Brr(((brr << 1) & !0xF) | (brr & 0x07)));
1574 #[cfg(usart_v4)]
1575 r.presc().write(|w| w.set_prescaler(_presc_val));
1576 found_brr = Some(brr);
1577 break;
1578 }
1579 return Err(ConfigError::BaudrateTooHigh);
1580 }
1581
1582 if brr < brr_max {
1583 r.brr().write_value(regs::Brr(brr));
1584 #[cfg(usart_v4)]
1585 r.presc().write(|w| w.set_prescaler(_presc_val));
1586 found_brr = Some(brr);
1587 break;
1588 }
1589 }
1590
1591 let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?;
1592
1593 trace!(
1594 "Desired baudrate: {}, actual baudrate: {}",
1595 baudrate,
1596 kernel_clock.0 / brr * mul
1597 );
1598
1599 r.cr1().modify(|w| {
1600 // enable uart
1601 w.set_ue(true);
1602 });
1603
1604 Ok(())
1605}
1606
1473fn configure( 1607fn configure(
1474 info: &Info, 1608 info: &Info,
1475 kernel_clock: Hertz, 1609 kernel_clock: Hertz,
@@ -1515,21 +1649,6 @@ fn configure(
1515 } 1649 }
1516 }; 1650 };
1517 1651
1518 fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 {
1519 // The calculation to be done to get the BRR is `mul * pclk / presc / baud`
1520 // To do this in 32-bit only we can't multiply `mul` and `pclk`
1521 let clock = pclk / presc;
1522
1523 // The mul is applied as the last operation to prevent overflow
1524 let brr = clock / baud * mul;
1525
1526 // The BRR calculation will be a bit off because of integer rounding.
1527 // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul.
1528 let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
1529
1530 brr + rounding
1531 }
1532
1533 // UART must be disabled during configuration. 1652 // UART must be disabled during configuration.
1534 r.cr1().modify(|w| { 1653 r.cr1().modify(|w| {
1535 w.set_ue(false); 1654 w.set_ue(false);
diff --git a/examples/stm32l1/src/bin/usart.rs b/examples/stm32l1/src/bin/usart.rs
new file mode 100644
index 000000000..dba79b8b4
--- /dev/null
+++ b/examples/stm32l1/src/bin/usart.rs
@@ -0,0 +1,37 @@
1#![no_std]
2#![no_main]
3
4use cortex_m_rt::entry;
5use defmt::*;
6use embassy_stm32::usart::{Config, Uart};
7use embassy_stm32::{bind_interrupts, peripherals, usart};
8use {defmt_rtt as _, panic_probe as _};
9
10bind_interrupts!(struct Irqs {
11 USART2 => usart::InterruptHandler<peripherals::USART2>;
12});
13
14#[entry]
15fn main() -> ! {
16 info!("Hello World!");
17
18 let p = embassy_stm32::init(Default::default());
19
20 let config = Config::default();
21 let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap();
22 let desired_baudrate = 9600; // Default is 115200 and 9600 is used as example
23
24 match usart.set_baudrate(desired_baudrate) {
25 Ok(_) => info!("Baud rate set to {}", desired_baudrate),
26 Err(err) => error!("Error setting baudrate to {}: {}", desired_baudrate, err),
27 }
28
29 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
30 info!("wrote Hello, starting echo");
31
32 let mut buf = [0u8; 1];
33 loop {
34 unwrap!(usart.blocking_read(&mut buf));
35 unwrap!(usart.blocking_write(&buf));
36 }
37}