Few weeks ago I started to learn Rust Embedded. Now I'm stuck, and I would like to ask you for help. So..
I wanted to use TIM3 in my code to change variable (in future peripheral state) and clear (unpend?) interrupt via registers inside ISR.
In C I did something like this inside ISR:
void TIM3_IRQHandler(void)
{
if (TIM3->SR & TIM_SR_UIF)
{
TIM3->SR &= ~(TIM_SR_UIF);
}
}
..and now I'm stuck to do this in Rust. At first I show what I've done so far.
#![no_std]
#![no_main]
use panic_halt as _;
use cortex_m_rt::entry;
use core::{cell::RefCell};
use core::ops::DerefMut;
use cortex_m::interrupt::{self, Mutex};
use stm32g0::stm32g071::{self, Interrupt, NVIC, TIM3};
static G_TIM: Mutex<RefCell<Option<stm32g071::TIM3>>> =
Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let p = stm32g071::Peripherals::take().unwrap();
let rcc_r = &p.RCC;
let timer_r = &p.TIM3;
let tim3 = p.TIM3;
unsafe {
NVIC::unmask(Interrupt::TIM3);
};
rcc_r.apbenr1.write(|w| w.tim3en().set_bit());
prepare_timer3(timer_r);
interrupt::free(|cs| {
G_TIM.borrow(cs).replace(Some(tim3))
});
loop {
}
}
fn prepare_timer3(tim3_r_handle: &TIM3) {
tim3_r_handle.cr1.write(|w| w.cen().clear_bit());
tim3_r_handle.psc.write(|w| unsafe { w.psc().bits(16000) });
tim3_r_handle.arr.write(|w| unsafe { w.arr_l().bits(100) });
tim3_r_handle.egr.write(|w| w.ug().set_bit());
tim3_r_handle.dier.write(|w| w.uie().set_bit());
tim3_r_handle.cr1.write(|w| w.cen().set_bit());
}
#[interrupt]
fn TIM3() {
interrupt::free(|cs| {
if let Some(ref mut tim3) = G_TIM.borrow(cs).borrow_mut().deref_mut() {
tim3.sr.write(|w| w.uif().clear_bit());
}
})
}
And I get this compilation error:
error: cannot find attribute `interrupt` in this scope
--> src/main.rs:51:3
|
51 | #[interrupt]
| ^^^^^^^^^
|
= note: consider importing one of these items:
cortex_m_rt::interrupt
crate::stm32g071::interrupt
stm32g0::stm32g071::interrupt
note: `interrupt` is imported here, but it is a module, not an attribute
--> src/main.rs:10:27
|
10 | use cortex_m::interrupt::{self, Mutex};
| ^^^^
error: could not compile `blink-nucleo-g0` due to previous error
I have problem how to resolve those dependency problem. Could you tell me also that what I did with this Mutex G_TIM is fine? I mean I did this after read this article: https://docs.rust-embedded.org/book/concurrency/#sharing-peripherals I also read this https://users.rust-lang.org/t/rust-embedded-stm32f303-timer-interrupt-hanging/40323 but I don't want to use hal crates.
I asked at Rust forum too: https://users.rust-lang.org/t/how-to-clear-interrupt-with-perpiheral-handle/67214
EDIT: I changed to:
use cortex_m::interrupt::free;
use cortex_m::interrupt::Mutex;
use stm32g0::stm32g071::{self, Interrupt, NVIC, TIM3, interrupt};
and usage of interrupt::free to free.
#[interrupt]
fn TIM2() {
free(|cs| {
if let Some(ref mut tim2) = G_TIM.borrow(cs).borrow_mut().deref_mut() {
tim2.sr.write(|w| w.uif().clear_bit());
}
});
}
I think that my ISR is invkoing in loop. How to clear this interrupt properly?
EDIT:
I changed whole to TIM2.
I cannot reach line tim2.sr.write(|w| w.uif().clear_bit());
with debugger. I think above if let
returns false, why?
I followed instructions in GitHub issue and it worked. I wasn't using Mutex
and interrupt::free
properly. if let..
in ISR was returning false because interrupt was exectued before replace so... it has value of None
in interrupt.
This is my code that works, after fix.
#![no_std]
#![no_main]
use panic_halt as _;
use core::cell::RefCell;
use core::ops::DerefMut;
use cortex_m::interrupt::free;
use cortex_m::interrupt::Mutex;
use cortex_m_rt::entry;
use stm32g0::stm32g071::{self, interrupt, Interrupt, NVIC};
static G_TIM: Mutex<RefCell<Option<stm32g071::TIM2>>> = Mutex::new(RefCell::new(None));
static G_GPIOA: Mutex<RefCell<Option<stm32g071::GPIOA>>> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let p = stm32g071::Peripherals::take().unwrap();
let gpioa = &p.GPIOA;
let rcc_r = &p.RCC;
// enable Clock for GPIOA
rcc_r.iopenr.modify(|_, w| w.iopaen().set_bit());
let tim2 = p.TIM2;
// Nucleo G071RB LED so need to set as output
gpioa.moder.modify(|_, w| unsafe { w.moder5().bits(0b01) });
rcc_r.apbenr1.write(|w| w.tim2en().set_bit());
free(|cs| {
tim2.cr1.write(|w| w.cen().clear_bit());
tim2.psc.write(|w| unsafe { w.psc().bits(16000) });
tim2.arr.write(|w| unsafe { w.arr_l().bits(1000) });
tim2.egr.write(|w| w.ug().set_bit());
tim2.dier.write(|w| w.uie().set_bit());
tim2.cr1.write(|w| w.cen().set_bit());
G_TIM.borrow(cs).replace(Some(tim2));
});
// NVIC unmask interrupt
unsafe {
NVIC::unmask(Interrupt::TIM2);
};
let gpioa = p.GPIOA;
free(|cs| {
G_GPIOA.borrow(cs).replace(Some(gpioa));
});
let mut increment = 0;
loop {
increment += 1;
if increment > 1000 {
increment = 0;
}
}
}
#[interrupt]
fn TIM2() {
free(|cs| {
if let Some(ref mut tim2) = G_TIM.borrow(cs).borrow_mut().deref_mut() {
tim2.sr.write(|w| w.uif().clear_bit());
}
});
free(|cs| {
if let Some(ref mut gpioa) = G_GPIOA.borrow(cs).borrow_mut().deref_mut() {
if gpioa.odr.read().odr5().bit_is_set() {
gpioa.odr.modify(|_, w| w.odr5().clear_bit());
} else {
gpioa.odr.modify(|_, w| w.odr5().set_bit());
}
}
});
}