aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-12-02 23:52:20 +0000
committerGitHub <[email protected]>2024-12-02 23:52:20 +0000
commit86b53a2ce3d93d07e5c8e4f4122e9588b87aafb7 (patch)
tree679c0c1ddf37c55cede52b50d1adcc845fc22200
parentf7a1f5bf562a5511f6c609bfbd32b03814b8d8f9 (diff)
parent8d2fbf0e143c99c0f10b204e5efbaa81749decbf (diff)
Merge pull request #3512 from EnmanuelParache/stm32_usart_set_baudrate
stm32/usart: Changing baud rate
-rw-r--r--embassy-stm32/src/usart/buffered.rs21
-rw-r--r--embassy-stm32/src/usart/mod.rs151
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs9
-rw-r--r--examples/stm32l1/src/bin/usart.rs37
4 files changed, 172 insertions, 46 deletions
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index f7b2bf4b4..814be2858 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -12,8 +12,8 @@ use embassy_sync::waitqueue::AtomicWaker;
12#[cfg(not(any(usart_v1, usart_v2)))] 12#[cfg(not(any(usart_v1, usart_v2)))]
13use super::DePin; 13use super::DePin;
14use super::{ 14use super::{
15 clear_interrupt_flags, configure, rdr, reconfigure, send_break, sr, tdr, Config, ConfigError, CtsPin, Error, Info, 15 clear_interrupt_flags, configure, rdr, reconfigure, send_break, set_baudrate, sr, tdr, Config, ConfigError, CtsPin,
16 Instance, Regs, RtsPin, RxPin, TxPin, 16 Error, Info, Instance, Regs, RtsPin, RxPin, TxPin,
17}; 17};
18use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 18use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
19use crate::interrupt::{self, InterruptExt}; 19use crate::interrupt::{self, InterruptExt};
@@ -441,6 +441,13 @@ impl<'d> BufferedUart<'d> {
441 pub fn send_break(&self) { 441 pub fn send_break(&self) {
442 self.tx.send_break() 442 self.tx.send_break()
443 } 443 }
444
445 /// Set baudrate
446 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
447 self.tx.set_baudrate(baudrate)?;
448 self.rx.set_baudrate(baudrate)?;
449 Ok(())
450 }
444} 451}
445 452
446impl<'d> BufferedUartRx<'d> { 453impl<'d> BufferedUartRx<'d> {
@@ -535,6 +542,11 @@ impl<'d> BufferedUartRx<'d> {
535 542
536 Ok(()) 543 Ok(())
537 } 544 }
545
546 /// Set baudrate
547 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
548 set_baudrate(self.info, self.kernel_clock, baudrate)
549 }
538} 550}
539 551
540impl<'d> BufferedUartTx<'d> { 552impl<'d> BufferedUartTx<'d> {
@@ -625,6 +637,11 @@ impl<'d> BufferedUartTx<'d> {
625 pub fn send_break(&self) { 637 pub fn send_break(&self) {
626 send_break(&self.info.regs); 638 send_break(&self.info.regs);
627 } 639 }
640
641 /// Set baudrate
642 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
643 set_baudrate(self.info, self.kernel_clock, baudrate)
644 }
628} 645}
629 646
630impl<'d> Drop for BufferedUartRx<'d> { 647impl<'d> Drop for BufferedUartRx<'d> {
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index d2fb85ee3..2d801e6bf 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -539,6 +539,11 @@ 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 set_baudrate(self.info, self.kernel_clock, baudrate)
546 }
542} 547}
543 548
544/// Wait until transmission complete 549/// Wait until transmission complete
@@ -1014,6 +1019,11 @@ impl<'d, M: Mode> UartRx<'d, M> {
1014 } 1019 }
1015 Ok(()) 1020 Ok(())
1016 } 1021 }
1022
1023 /// Set baudrate
1024 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
1025 set_baudrate(self.info, self.kernel_clock, baudrate)
1026 }
1017} 1027}
1018 1028
1019impl<'d, M: Mode> Drop for UartTx<'d, M> { 1029impl<'d, M: Mode> Drop for UartTx<'d, M> {
@@ -1455,6 +1465,13 @@ impl<'d, M: Mode> Uart<'d, M> {
1455 pub fn send_break(&self) { 1465 pub fn send_break(&self) {
1456 self.tx.send_break(); 1466 self.tx.send_break();
1457 } 1467 }
1468
1469 /// Set baudrate
1470 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
1471 self.tx.set_baudrate(baudrate)?;
1472 self.rx.set_baudrate(baudrate)?;
1473 Ok(())
1474 }
1458} 1475}
1459 1476
1460fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> { 1477fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> {
@@ -1470,20 +1487,33 @@ fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(),
1470 Ok(()) 1487 Ok(())
1471} 1488}
1472 1489
1473fn configure( 1490fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 {
1474 info: &Info, 1491 // The calculation to be done to get the BRR is `mul * pclk / presc / baud`
1475 kernel_clock: Hertz, 1492 // To do this in 32-bit only we can't multiply `mul` and `pclk`
1476 config: &Config, 1493 let clock = pclk / presc;
1477 enable_rx: bool,
1478 enable_tx: bool,
1479) -> Result<(), ConfigError> {
1480 let r = info.regs;
1481 let kind = info.kind;
1482 1494
1483 if !enable_rx && !enable_tx { 1495 // The mul is applied as the last operation to prevent overflow
1484 return Err(ConfigError::RxOrTxNotEnabled); 1496 let brr = clock / baud * mul;
1485 } 1497
1498 // The BRR calculation will be a bit off because of integer rounding.
1499 // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul.
1500 let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
1501
1502 brr + rounding
1503}
1486 1504
1505fn set_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> {
1506 info.interrupt.disable();
1507
1508 set_usart_baudrate(info, kernel_clock, baudrate)?;
1509
1510 info.interrupt.unpend();
1511 unsafe { info.interrupt.enable() };
1512
1513 Ok(())
1514}
1515
1516fn find_and_set_brr(r: Regs, kind: Kind, kernel_clock: Hertz, baudrate: u32) -> Result<bool, ConfigError> {
1487 #[cfg(not(usart_v4))] 1517 #[cfg(not(usart_v4))]
1488 static DIVS: [(u16, ()); 1] = [(1, ())]; 1518 static DIVS: [(u16, ()); 1] = [(1, ())];
1489 1519
@@ -1515,31 +1545,14 @@ fn configure(
1515 } 1545 }
1516 }; 1546 };
1517 1547
1518 fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 { 1548 let mut found_brr = None;
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.
1534 r.cr1().modify(|w| {
1535 w.set_ue(false);
1536 });
1537
1538 #[cfg(not(usart_v1))] 1549 #[cfg(not(usart_v1))]
1539 let mut over8 = false; 1550 let mut over8 = false;
1540 let mut found_brr = None; 1551 #[cfg(usart_v1)]
1552 let over8 = false;
1553
1541 for &(presc, _presc_val) in &DIVS { 1554 for &(presc, _presc_val) in &DIVS {
1542 let brr = calculate_brr(config.baudrate, kernel_clock.0, presc as u32, mul); 1555 let brr = calculate_brr(baudrate, kernel_clock.0, presc as u32, mul);
1543 trace!( 1556 trace!(
1544 "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})", 1557 "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
1545 presc, 1558 presc,
@@ -1570,18 +1583,70 @@ fn configure(
1570 } 1583 }
1571 } 1584 }
1572 1585
1573 let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?; 1586 match found_brr {
1587 Some(brr) => {
1588 #[cfg(not(usart_v1))]
1589 let oversampling = if over8 { "8 bit" } else { "16 bit" };
1590 #[cfg(usart_v1)]
1591 let oversampling = "default";
1592 trace!(
1593 "Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
1594 oversampling,
1595 baudrate,
1596 kernel_clock.0 / brr * mul
1597 );
1598 Ok(over8)
1599 }
1600 None => Err(ConfigError::BaudrateTooLow),
1601 }
1602}
1603
1604fn set_usart_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> {
1605 let r = info.regs;
1606 r.cr1().modify(|w| {
1607 // disable uart
1608 w.set_ue(false);
1609 });
1610
1611 #[cfg(not(usart_v1))]
1612 let over8 = find_and_set_brr(r, info.kind, kernel_clock, baudrate)?;
1613 #[cfg(usart_v1)]
1614 let _over8 = find_and_set_brr(r, info.kind, kernel_clock, baudrate)?;
1615
1616 r.cr1().modify(|w| {
1617 // enable uart
1618 w.set_ue(true);
1619
1620 #[cfg(not(usart_v1))]
1621 w.set_over8(vals::Over8::from_bits(over8 as _));
1622 });
1623
1624 Ok(())
1625}
1626
1627fn configure(
1628 info: &Info,
1629 kernel_clock: Hertz,
1630 config: &Config,
1631 enable_rx: bool,
1632 enable_tx: bool,
1633) -> Result<(), ConfigError> {
1634 let r = info.regs;
1635 let kind = info.kind;
1636
1637 if !enable_rx && !enable_tx {
1638 return Err(ConfigError::RxOrTxNotEnabled);
1639 }
1640
1641 // UART must be disabled during configuration.
1642 r.cr1().modify(|w| {
1643 w.set_ue(false);
1644 });
1574 1645
1575 #[cfg(not(usart_v1))] 1646 #[cfg(not(usart_v1))]
1576 let oversampling = if over8 { "8 bit" } else { "16 bit" }; 1647 let over8 = find_and_set_brr(r, kind, kernel_clock, config.baudrate)?;
1577 #[cfg(usart_v1)] 1648 #[cfg(usart_v1)]
1578 let oversampling = "default"; 1649 let _over8 = find_and_set_brr(r, kind, kernel_clock, config.baudrate)?;
1579 trace!(
1580 "Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
1581 oversampling,
1582 config.baudrate,
1583 kernel_clock.0 / brr * mul
1584 );
1585 1650
1586 r.cr2().write(|w| { 1651 r.cr2().write(|w| {
1587 w.set_stop(match config.stop_bits { 1652 w.set_stop(match config.stop_bits {
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index a791ac2a9..560ce4e8f 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -8,7 +8,9 @@ use embassy_hal_internal::PeripheralRef;
8use embedded_io_async::ReadReady; 8use embedded_io_async::ReadReady;
9use futures_util::future::{select, Either}; 9use futures_util::future::{select, Either};
10 10
11use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx}; 11use super::{
12 clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx,
13};
12use crate::dma::ReadableRingBuffer; 14use crate::dma::ReadableRingBuffer;
13use crate::gpio::{AnyPin, SealedPin as _}; 15use crate::gpio::{AnyPin, SealedPin as _};
14use crate::mode::Async; 16use crate::mode::Async;
@@ -213,6 +215,11 @@ impl<'d> RingBufferedUartRx<'d> {
213 Either::Right(((), _)) => Ok(()), 215 Either::Right(((), _)) => Ok(()),
214 } 216 }
215 } 217 }
218
219 /// Set baudrate
220 pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
221 set_baudrate(self.info, self.kernel_clock, baudrate)
222 }
216} 223}
217 224
218impl Drop for RingBufferedUartRx<'_> { 225impl Drop for RingBufferedUartRx<'_> {
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}