-
I want to write a program that blinks the on-board LED of an Arduino Uno an and off every second. However, I want to do it using an ISR (Interrupt Service Routine), specifically via a Timer Overflow Interrupt. I tried to do this by translating the C code from this video to Rust, and got some inspiration from the existing This is what I came up with so far: Code/*
* A program to blink the LED on pin 13 of the Arduino
* on and of every second, using a hardware timer interrupt/
* Interrupt Service Routine (ISR).
* We use an overflow timer, meaning a variable is incremented
* every set interval, and when it overflows, the ISR is triggered.
*/
#![no_std]
#![no_main]
#![feature(abi_avr_interrupt)]
use panic_halt as _;
const CPU_CLOCKRATE: u32 = 16_000_000;
const MAX_TIMER_VALUE: u32 = 65535;
const PRESCALE_VALUE: u32 = 1024;
#[avr_device::interrupt(atmega328p)]
fn TIMER1_OVF() {
let dp = arduino_hal::Peripherals::take().unwrap();
let pins = arduino_hal::pins!(dp);
let mut led = pins.d13.into_output();
led.toggle();
if led.is_set_high() {
let _ = ufmt::uwriteln!(&mut arduino_hal::default_serial!(dp, pins, 57600), "ON");
} else {
let _ = ufmt::uwriteln!(&mut arduino_hal::default_serial!(dp, pins, 57600), "OFF");
}
let timer = dp.TC1;
timer.tcnt1.write(|register| {
register.bits(
(MAX_TIMER_VALUE - (CPU_CLOCKRATE / PRESCALE_VALUE))
.try_into()
.unwrap(),
)
});
}
#[arduino_hal::entry]
fn main() -> ! {
let dp = arduino_hal::Peripherals::take().unwrap();
let timer = dp.TC1;
timer.tcnt1.write(|register| {
register.bits(
(MAX_TIMER_VALUE - (CPU_CLOCKRATE / PRESCALE_VALUE))
.try_into()
.unwrap(),
)
});
// Prescaler: Downscale the CPU from 16MHz to 15625Hz effective clockrate
timer
.tccr1b
.write(|register| register.cs1().prescale_1024());
timer.tccr1a.write(|register| unsafe { register.bits(0) });
// Enable the timer to interrupt the CPU
timer.timsk1.write(|register| register.toie1().set_bit());
unsafe { avr_device::interrupt::enable() };
loop {}
} The code doesn't work; I think it's because the Timer Overflow doesn't trigger ("ON" and "OFF" never get printed to the console, even though console printing definitely works). Does someone know what the issue could be or how to solve it? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 8 replies
-
it's the way you used peripherals, combined with panic_halt, it won't print error like normal rust program will #[avr_device::interrupt(atmega328p)]
fn TIMER1_OVF() {
let dp = arduino_hal::Peripherals::take().unwrap(); this will panic because peripherals has already been taken you can use but the led will stay on, this is because when you call into_output on pin it will default to LOW so if you toggle once it will always end up in HIGH #[panic_handler]
fn panic(info: &PanicInfo) -> ! {
avr_device::interrupt::disable();
let dp = unsafe { arduino_hal::Peripherals::steal() };
let pins = arduino_hal::pins!(dp);
let serial = arduino_hal::default_serial!(dp, pins, 57600);
let mut writer = Writer {
u_write: serial
};
writeln!(&mut writer, "{}", info).ok();
loop {
}
}
struct Writer<T> {
u_write: T
}
impl<T: uWrite> Write for Writer<T> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.u_write.write_str(s).map_err(|x| match x {
_ => core::fmt::Error
})
}
fn write_char(&mut self, c: char) -> core::fmt::Result {
self.u_write.write_char(c).map_err(|x| match x {
_ => core::fmt::Error
})
}
} this will print error to serial however |
Beta Was this translation helpful? Give feedback.
Thanks! After juggling a bit with some types, this is my final solution:
Code