diff options
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 46 |
1 files changed, 29 insertions, 17 deletions
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index e203336e1..255ddfd4b 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -809,45 +809,57 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | |||
| 809 | Kind::Uart => (1, 0x10, 0x1_0000), | 809 | Kind::Uart => (1, 0x10, 0x1_0000), |
| 810 | }; | 810 | }; |
| 811 | 811 | ||
| 812 | fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 { | ||
| 813 | // The calculation to be done to get the BRR is `mul * pclk / presc / baud` | ||
| 814 | // To do this in 32-bit only we can't multiply `mul` and `pclk` | ||
| 815 | let clock = pclk / presc; | ||
| 816 | |||
| 817 | // The mul is applied as the last operation to prevent overflow | ||
| 818 | let brr = clock / baud * mul; | ||
| 819 | |||
| 820 | // The BRR calculation will be a bit off because of integer rounding. | ||
| 821 | // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul. | ||
| 822 | let rounding = ((clock % baud) * mul + (baud / 2)) / baud; | ||
| 823 | |||
| 824 | brr + rounding | ||
| 825 | } | ||
| 826 | |||
| 812 | #[cfg(not(usart_v1))] | 827 | #[cfg(not(usart_v1))] |
| 813 | let mut over8 = false; | 828 | let mut over8 = false; |
| 814 | let mut found = None; | 829 | let mut found_brr = None; |
| 815 | for &(presc, _presc_val) in &DIVS { | 830 | for &(presc, _presc_val) in &DIVS { |
| 816 | let denom = (config.baudrate * presc as u32) as u64; | 831 | let brr = calculate_brr(config.baudrate, pclk_freq.0, presc as u32, mul); |
| 817 | let div = (pclk_freq.0 as u64 * mul + (denom / 2)) / denom; | ||
| 818 | trace!( | 832 | trace!( |
| 819 | "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})", | 833 | "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})", |
| 820 | presc, | 834 | presc, |
| 821 | div, | 835 | brr, |
| 822 | div >> 4, | 836 | brr >> 4, |
| 823 | div & 0x0F | 837 | brr & 0x0F |
| 824 | ); | 838 | ); |
| 825 | 839 | ||
| 826 | if div < brr_min { | 840 | if brr < brr_min { |
| 827 | #[cfg(not(usart_v1))] | 841 | #[cfg(not(usart_v1))] |
| 828 | if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { | 842 | if brr * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { |
| 829 | over8 = true; | 843 | over8 = true; |
| 830 | let div = div as u32; | 844 | r.brr().write_value(regs::Brr(((brr << 1) & !0xF) | (brr & 0x07))); |
| 831 | r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07))); | ||
| 832 | #[cfg(usart_v4)] | 845 | #[cfg(usart_v4)] |
| 833 | r.presc().write(|w| w.set_prescaler(_presc_val)); | 846 | r.presc().write(|w| w.set_prescaler(_presc_val)); |
| 834 | found = Some(div); | 847 | found_brr = Some(brr); |
| 835 | break; | 848 | break; |
| 836 | } | 849 | } |
| 837 | panic!("USART: baudrate too high"); | 850 | panic!("USART: baudrate too high"); |
| 838 | } | 851 | } |
| 839 | 852 | ||
| 840 | if div < brr_max { | 853 | if brr < brr_max { |
| 841 | let div = div as u32; | 854 | r.brr().write_value(regs::Brr(brr)); |
| 842 | r.brr().write_value(regs::Brr(div)); | ||
| 843 | #[cfg(usart_v4)] | 855 | #[cfg(usart_v4)] |
| 844 | r.presc().write(|w| w.set_prescaler(_presc_val)); | 856 | r.presc().write(|w| w.set_prescaler(_presc_val)); |
| 845 | found = Some(div); | 857 | found_brr = Some(brr); |
| 846 | break; | 858 | break; |
| 847 | } | 859 | } |
| 848 | } | 860 | } |
| 849 | 861 | ||
| 850 | let div = found.expect("USART: baudrate too low"); | 862 | let brr = found_brr.expect("USART: baudrate too low"); |
| 851 | 863 | ||
| 852 | #[cfg(not(usart_v1))] | 864 | #[cfg(not(usart_v1))] |
| 853 | let oversampling = if over8 { "8 bit" } else { "16 bit" }; | 865 | let oversampling = if over8 { "8 bit" } else { "16 bit" }; |
| @@ -857,7 +869,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | |||
| 857 | "Using {} oversampling, desired baudrate: {}, actual baudrate: {}", | 869 | "Using {} oversampling, desired baudrate: {}, actual baudrate: {}", |
| 858 | oversampling, | 870 | oversampling, |
| 859 | config.baudrate, | 871 | config.baudrate, |
| 860 | (pclk_freq.0 * mul as u32) / div | 872 | pclk_freq.0 / brr * mul |
| 861 | ); | 873 | ); |
| 862 | 874 | ||
| 863 | r.cr2().write(|w| { | 875 | r.cr2().write(|w| { |
