aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/usart/mod.rs46
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| {