Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UARTE: turning uarte off and on again on nrf9160 hangs indefinitely #381

Open
folkertdev opened this issue Feb 17, 2022 · 0 comments
Open

Comments

@folkertdev
Copy link
Contributor

folkertdev commented Feb 17, 2022

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 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());
        }

cc @diondokter

folkertdev added a commit to folkertdev/nrf-hal that referenced this issue Feb 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant