Modified the brr calculation to be fully 32-bit
This commit is contained in:
parent
2687008242
commit
a5484cd119
@ -809,45 +809,57 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
|
|||||||
Kind::Uart => (1, 0x10, 0x1_0000),
|
Kind::Uart => (1, 0x10, 0x1_0000),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 {
|
||||||
|
// The calculation to be done to get the BRR is `mul * pclk / presc / baud`
|
||||||
|
// To do this in 32-bit only we can't multiply `mul` and `pclk`
|
||||||
|
let clock = pclk / presc;
|
||||||
|
|
||||||
|
// The mul is applied as the last operation to prevent overflow
|
||||||
|
let brr = clock / baud * mul;
|
||||||
|
|
||||||
|
// The BRR calculation will be a bit off because of integer rounding.
|
||||||
|
// Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul.
|
||||||
|
let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
|
||||||
|
|
||||||
|
brr + rounding
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(usart_v1))]
|
#[cfg(not(usart_v1))]
|
||||||
let mut over8 = false;
|
let mut over8 = false;
|
||||||
let mut found = None;
|
let mut found_brr = None;
|
||||||
for &(presc, _presc_val) in &DIVS {
|
for &(presc, _presc_val) in &DIVS {
|
||||||
let denom = (config.baudrate * presc as u32) as u64;
|
let brr = calculate_brr(config.baudrate, pclk_freq.0, presc as u32, mul);
|
||||||
let div = (pclk_freq.0 as u64 * mul + (denom / 2)) / denom;
|
|
||||||
trace!(
|
trace!(
|
||||||
"USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
|
"USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
|
||||||
presc,
|
presc,
|
||||||
div,
|
brr,
|
||||||
div >> 4,
|
brr >> 4,
|
||||||
div & 0x0F
|
brr & 0x0F
|
||||||
);
|
);
|
||||||
|
|
||||||
if div < brr_min {
|
if brr < brr_min {
|
||||||
#[cfg(not(usart_v1))]
|
#[cfg(not(usart_v1))]
|
||||||
if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
|
if brr * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
|
||||||
over8 = true;
|
over8 = true;
|
||||||
let div = div as u32;
|
r.brr().write_value(regs::Brr(((brr << 1) & !0xF) | (brr & 0x07)));
|
||||||
r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
|
|
||||||
#[cfg(usart_v4)]
|
#[cfg(usart_v4)]
|
||||||
r.presc().write(|w| w.set_prescaler(_presc_val));
|
r.presc().write(|w| w.set_prescaler(_presc_val));
|
||||||
found = Some(div);
|
found_brr = Some(brr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
panic!("USART: baudrate too high");
|
panic!("USART: baudrate too high");
|
||||||
}
|
}
|
||||||
|
|
||||||
if div < brr_max {
|
if brr < brr_max {
|
||||||
let div = div as u32;
|
r.brr().write_value(regs::Brr(brr));
|
||||||
r.brr().write_value(regs::Brr(div));
|
|
||||||
#[cfg(usart_v4)]
|
#[cfg(usart_v4)]
|
||||||
r.presc().write(|w| w.set_prescaler(_presc_val));
|
r.presc().write(|w| w.set_prescaler(_presc_val));
|
||||||
found = Some(div);
|
found_brr = Some(brr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let div = found.expect("USART: baudrate too low");
|
let brr = found_brr.expect("USART: baudrate too low");
|
||||||
|
|
||||||
#[cfg(not(usart_v1))]
|
#[cfg(not(usart_v1))]
|
||||||
let oversampling = if over8 { "8 bit" } else { "16 bit" };
|
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:
|
|||||||
"Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
|
"Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
|
||||||
oversampling,
|
oversampling,
|
||||||
config.baudrate,
|
config.baudrate,
|
||||||
(pclk_freq.0 * mul as u32) / div
|
pclk_freq.0 / brr * mul
|
||||||
);
|
);
|
||||||
|
|
||||||
r.cr2().write(|w| {
|
r.cr2().write(|w| {
|
||||||
|
Loading…
Reference in New Issue
Block a user