Closed
Description
I've come across inconsistent behavior when attempting to output a u64
to serial using ufmt
from within a critical section.
Originally this came up because I was using a modified version of a print!
macro from #115, and I was noticing that my interrupts would stop after a few iterations.
Edit: this is with the --release
flag. Removing it seems to solve the issue, although I'd still be curious to know why.
(near)Minimal test-case:
#![no_std]
#![no_main]
#![feature(abi_avr_interrupt)]
use core::cell::Cell;
use avr_device::interrupt::Mutex;
use panic_halt as _;
use arduino_hal::prelude::*;
#[arduino_hal::entry]
fn main() -> ! {
let dp = arduino_hal::Peripherals::take().unwrap();
let pins = arduino_hal::pins!(dp);
let mut serial = arduino_hal::default_serial!(dp, pins, 57600);
let tc0 = dp.TC0;
tc0.tccr0a.write(|w| w.wgm0().ctc());
tc0.ocr0a.write(|w| w.bits(255));
tc0.tccr0b.write(|w| w.cs0().prescale_1024());
tc0.timsk0.write(|w| w.ocie0a().set_bit());
unsafe {
avr_device::interrupt::enable();
}
loop {
let counter = avr_device::interrupt::free(|cs| {
INT_COUNTER.borrow(cs).get()
});
let int_en = avr_device::interrupt::is_enabled();
// unnessesary `free` section to replicate the `print!` macro
avr_device::interrupt::free(|_| {
ufmt::uwriteln!(serial, "Counter: {}, interrupts enabled: {}", counter, int_en).unwrap_infallible();
});
arduino_hal::delay_ms(100);
}
}
static INT_COUNTER : Mutex<Cell<u64>> = Mutex::new(Cell::new(0)); // doesn't work
// static INT_COUNTER : Mutex<Cell<u32>> = Mutex::new(Cell::new(0)); // works ??
#[avr_device::interrupt(atmega328p)]
unsafe fn TIMER0_COMPA() {
let cs = avr_device::interrupt::CriticalSection::new();
let counter_cell = INT_COUNTER.borrow(cs);
let counter = counter_cell.get();
counter_cell.set(counter + 1);
}
Which outputs:
[...]
Programmed target/avr-atmega328p/release/minimal.elf
Console /dev/ttyACM1 at 57600 baud
CTRL+C to exit.
Counter: 0, interrupts enabled: true
Counter: 6, interrupts enabled: true
Counter: 12, interrupts enabled: false
Counter: 12, interrupts enabled: false
Counter: 12, interrupts enabled: false
[...]
Changing inner type
If I change INT_COUNTER
's inner type to u32
, or I don't print the counter, interrupts stay enabled and the counter correctly increments.
[...]
Programmed target/avr-atmega328p/release/minimal.elf
Console /dev/ttyACM1 at 57600 baud
CTRL+C to exit.
Counter: 0, interrupts enabled: true
Counter: 6, interrupts enabled: true
Counter: 12, interrupts enabled: true
Counter: 19, interrupts enabled: true
Counter: 25, interrupts enabled: true
Counter: 32, interrupts enabled: true
[...]
Adding a condition
Even stranger still, if I add a condition to whether I print the counter (with u64
), IT STARTS WORKING AGAIN...
avr_device::interrupt::free(|_| {
// this makes it work again
if counter > 100 {
ufmt::uwriteln!(serial, "Counter: {}, interrupts enabled: {}", counter, int_en).unwrap_infallible();
}
});
[...]
Programmed target/avr-atmega328p/release/minimal.elf
Console /dev/ttyACM1 at 57600 baud
CTRL+C to exit.
Counter: 103, interrupts enabled: true
Counter: 110, interrupts enabled: true
Counter: 116, interrupts enabled: true
Counter: 123, interrupts enabled: true
Counter: 129, interrupts enabled: true
Counter: 136, interrupts enabled: true
[...]
Any advice would be appreciated :)
Dependencies
[dependencies]
panic-halt = "0.2.0"
ufmt = "0.2.0"
nb = "1.1.0"
embedded-hal = "1.0.0"
avr-device = "0.5.4"
[dependencies.arduino-hal]
git = "https://github.com/rahix/avr-hal"
rev = "e312e6e1620bd09470afee71e6590da0ba96f369"
features = ["arduino-uno"]
Tested on uno
and mega2560
.