mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 00:02:28 +00:00
Correctly handle modifying LCR register after uart enable
This commit is contained in:
parent
d1207706c0
commit
4c34132337
@ -860,6 +860,56 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
});
|
||||
}
|
||||
|
||||
fn lcr_modify<R>(f: impl FnOnce(&mut rp_pac::uart::regs::UartlcrH) -> R) -> R {
|
||||
let r = T::regs();
|
||||
|
||||
// Notes from PL011 reference manual:
|
||||
//
|
||||
// - Before writing the LCR, if the UART is enabled it needs to be
|
||||
// disabled and any current TX + RX activity has to be completed
|
||||
//
|
||||
// - There is a BUSY flag which waits for the current TX char, but this is
|
||||
// OR'd with TX FIFO !FULL, so not usable when FIFOs are enabled and
|
||||
// potentially nonempty
|
||||
//
|
||||
// - FIFOs can't be set to disabled whilst a character is in progress
|
||||
// (else "FIFO integrity is not guaranteed")
|
||||
//
|
||||
// Combination of these means there is no general way to halt and poll for
|
||||
// end of TX character, if FIFOs may be enabled. Either way, there is no
|
||||
// way to poll for end of RX character.
|
||||
//
|
||||
// So, insert a 15 Baud period delay before changing the settings.
|
||||
// 15 Baud is comfortably higher than start + max data + parity + stop.
|
||||
// Anything else would require API changes to permit a non-enabled UART
|
||||
// state after init() where settings can be changed safely.
|
||||
let clk_base = crate::clocks::clk_peri_freq();
|
||||
|
||||
let cr = r.uartcr().read();
|
||||
if cr.uarten() {
|
||||
r.uartcr().modify(|w| {
|
||||
w.set_uarten(false);
|
||||
w.set_txe(false);
|
||||
w.set_rxe(false);
|
||||
});
|
||||
|
||||
// Note: Maximise precision here. Show working, the compiler will mop this up.
|
||||
// Create a 16.6 fixed-point fractional division ratio; then scale to 32-bits.
|
||||
let mut brdiv_ratio = 64 * r.uartibrd().read().0 + r.uartfbrd().read().0;
|
||||
brdiv_ratio <<= 10;
|
||||
// 3662 is ~(15 * 244.14) where 244.14 is 16e6 / 2^16
|
||||
let scaled_freq = clk_base / 3662;
|
||||
let wait_time_us = brdiv_ratio / scaled_freq;
|
||||
embedded_hal_1::delay::DelayNs::delay_us(&mut Delay, wait_time_us);
|
||||
}
|
||||
|
||||
let res = r.uartlcr_h().modify(f);
|
||||
|
||||
r.uartcr().write_value(cr);
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
/// sets baudrate on runtime
|
||||
pub fn set_baudrate(&mut self, baudrate: u32) {
|
||||
Self::set_baudrate_inner(baudrate);
|
||||
@ -886,28 +936,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
|
||||
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
|
||||
|
||||
let cr = r.uartcr().read();
|
||||
if cr.uarten() {
|
||||
r.uartcr().modify(|w| {
|
||||
w.set_uarten(false);
|
||||
w.set_txe(false);
|
||||
w.set_rxe(false);
|
||||
});
|
||||
|
||||
// Note: Maximise precision here. Show working, the compiler will mop this up.
|
||||
// Create a 16.6 fixed-point fractional division ratio; then scale to 32-bits.
|
||||
let mut brdiv_ratio = 64 * r.uartibrd().read().0 + r.uartfbrd().read().0;
|
||||
brdiv_ratio <<= 10;
|
||||
// 3662 is ~(15 * 244.14) where 244.14 is 16e6 / 2^16
|
||||
let scaled_freq = clk_base / 3662;
|
||||
let wait_time_us = brdiv_ratio / scaled_freq;
|
||||
embedded_hal_1::delay::DelayNs::delay_us(&mut Delay, wait_time_us);
|
||||
}
|
||||
// PL011 needs a (dummy) line control register write to latch in the
|
||||
// divisors. We don't want to actually change LCR contents here.
|
||||
r.uartlcr_h().modify(|_| {});
|
||||
|
||||
r.uartcr().write_value(cr);
|
||||
Self::lcr_modify(|_| {});
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user