Skip to content

Critical section causes unexpected behaviour in --release mode #505

Closed
@gregoryholder

Description

@gregoryholder

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    compiler-bugNot a bug in avr-hal, but a bug in the rust compiler/LLVM

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions