diff options
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 149 | ||||
| -rw-r--r-- | examples/stm32l1/src/bin/usart.rs | 37 |
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 | ||
| 1019 | impl<'d, M: Mode> Drop for UartTx<'d, M> { | 1031 | impl<'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 | ||
| 1460 | fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> { | 1480 | fn 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 | ||
| 1493 | fn 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 | |||
| 1508 | fn 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 | |||
| 1519 | fn 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 | |||
| 1473 | fn configure( | 1607 | fn 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 | |||
| 4 | use cortex_m_rt::entry; | ||
| 5 | use defmt::*; | ||
| 6 | use embassy_stm32::usart::{Config, Uart}; | ||
| 7 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | bind_interrupts!(struct Irqs { | ||
| 11 | USART2 => usart::InterruptHandler<peripherals::USART2>; | ||
| 12 | }); | ||
| 13 | |||
| 14 | #[entry] | ||
| 15 | fn 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 | } | ||
