To save power, we want to disable the uarte peripheral inbetween writes. We have recently upgraded the hal, and this has stopped working. Only the first write to uart works, any subsequent write hangs indefinitely.
Code
Full runnable example is available here. Note that the branch name is uarte-on-off-bug. A simple cargo run --bin hello should flash and run the whole program (SPM is included).
use nrf9160_hal as hal;
use hal::gpio::Level;
use hal::uarte;
use core::fmt::Write;
#[cortex_m_rt::entry]
fn main() -> ! {
let p = hal::pac::Peripherals::take().unwrap();
let pins0 = hal::gpio::p0::Parts::new(p.P0_NS);
let pins = hal::uarte::Pins {
rxd: pins0.p0_05.into_floating_input().degrade(),
txd: pins0.p0_06.into_push_pull_output(Level::High).degrade(),
cts: None,
rts: None,
};
let device = p.UARTE0_NS;
// init 1
let mut uart = hal::Uarte::new(
device,
pins,
uarte::Parity::EXCLUDED,
uarte::Baudrate::BAUD115200,
);
write!(uart, "write 1\r\n").unwrap();
write!(uart, "write 2\r\n").unwrap();
// deinit 1
let (device, pins) = uart.free();
device.events_txstopped.reset();
device.tasks_stoptx.write(|w| w.tasks_stoptx().trigger());
while device.events_txstopped.read().bits() == 0 {
cortex_m::asm::nop();
}
device.enable.write(|w| w.enable().disabled());
// init 2
let mut uart = hal::Uarte::new(
device,
pins,
uarte::Parity::EXCLUDED,
uarte::Baudrate::BAUD115200,
);
write!(uart, "write 3\r\n").unwrap();
nrf9160_rust_starter::exit()
}
Actual output
terminal
folkertdev@folkertdev ~/t/d/nrf9160-rust-starter (uarte-on-off-bug)> cargo run --bin hello
Finished dev [optimized + debuginfo] target(s) in 0.01s
Running `probe-run --chip nRF9160_xxAA target/thumbv8m.main-none-eabi/debug/hello`
(HOST) INFO flashing program (9 pages / 36.00 KiB)
(HOST) INFO success!
────────────────────────────────────────────────────────────────────────────────
^C────────────────────────────────────────────────────────────────────────────────
stack backtrace:
0: core::ptr::read_volatile
at /rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/core/src/ptr/mod.rs:1054:14
1: vcell::VolatileCell<T>::get
at /home/folkertdev/.cargo/registry/src/github.com-1ecc6299db9ec823/vcell-0.1.3/src/lib.rs:33:18
2: nrf9160_pac::generic::Reg<REG>::read
at /home/folkertdev/.cargo/registry/src/github.com-1ecc6299db9ec823/nrf9160-pac-0.11.0/src/generic.rs:65:19
3: nrf_hal_common::uarte::Uarte<T>::write
at /home/folkertdev/.cargo/registry/src/github.com-1ecc6299db9ec823/nrf-hal-common-0.15.0/src/uarte.rs:185:15
4: <nrf_hal_common::uarte::Uarte<T> as core::fmt::Write>::write_str
at /home/folkertdev/.cargo/registry/src/github.com-1ecc6299db9ec823/nrf-hal-common-0.15.0/src/uarte.rs:460:13
5: <&mut W as core::fmt::Write>::write_str
at /rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/core/src/fmt/mod.rs:193:9
6: core::fmt::write
at /rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/core/src/fmt/mod.rs:1187:9
7: core::fmt::Write::write_fmt
at /rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/core/src/fmt/mod.rs:187:6
8: hello::__cortex_m_rt_main
at src/bin/hello.rs:57:5
9: main
at src/bin/hello.rs:13:1
10: Reset
(HOST) INFO device halted by user
uart output:
write 1
write 2
Expected output
write 1
write 2
write 3
Extra info
We suspect this is a problem with the workaround for nRF9160 - anomaly 23. Specifically, our code works when we comment out this block in apply_workaround_for_enable_anomaly (uarte.rs).
// NB Safety: This is taken from Nordic's driver -
// https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 {
self.0.enable.write(|w| w.enable().enabled());
self.0.tasks_stoprx.write(|w| unsafe { w.bits(1) });
let mut workaround_succeded = false;
// The UARTE is able to receive up to four bytes after the STOPRX task has been triggered.
// On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured
// (resulting in 12 bits per data byte sent), this may take up to 40 ms.
for _ in 0..40000 {
// NB Safety: This is taken from Nordic's driver -
// https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 {
workaround_succeded = true;
break;
} else {
// Need to sleep for 1us here
}
}
if !workaround_succeded {
// panic!("Failed to apply workaround for UART");
}
let errors = self.0.errorsrc.read().bits();
// NB Safety: safe to write back the bits we just read to clear them
self.0.errorsrc.write(|w| unsafe { w.bits(errors) });
// self.0.enable.write(|w| w.enable().disabled());
}
Problem
To save power, we want to disable the uarte peripheral inbetween writes. We have recently upgraded the hal, and this has stopped working. Only the first write to uart works, any subsequent write hangs indefinitely.
Code
Full runnable example is available here. Note that the branch name is
uarte-on-off-bug
. A simplecargo run --bin hello
should flash and run the whole program (SPM is included).Actual output
terminal
uart output:
Expected output
Extra info
We suspect this is a problem with the workaround for
nRF9160 - anomaly 23
. Specifically, our code works when we comment out this block inapply_workaround_for_enable_anomaly
(uarte.rs).cc @diondokter