如何用外围句柄清除中断?嵌入式铁锈
How to clear interrupt with perpiheral handle? Embedded Rust
几周前我开始学习 Rust Embedded。
现在我被困住了,我想向你寻求帮助。所以..
我想在我的代码中使用 TIM3 来通过 ISR 中的寄存器更改变量(在未来的外设状态)和清除(未挂起的?)中断。
在 C 中,我在 ISR 中做了类似的事情:
void TIM3_IRQHandler(void)
{
if (TIM3->SR & TIM_SR_UIF)
{
TIM3->SR &= ~(TIM_SR_UIF);
}
}
..现在我不得不在 Rust 中做这件事。
首先我展示我到目前为止所做的。
#![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());
}
})
}
我得到这个编译错误:
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
我不知道如何解决这些依赖问题。
你能告诉我我用这个 Mutex G_TIM 做的很好吗?
我的意思是我是在阅读这篇文章后这样做的:https://docs.rust-embedded.org/book/concurrency/#sharing-peripherals
我也读过这个 https://users.rust-lang.org/t/rust-embedded-stm32f303-timer-interrupt-hanging/40323 但我不想使用 hal crates。
我也在 Rust 论坛上问过:https://users.rust-lang.org/t/how-to-clear-interrupt-with-perpiheral-handle/67214
编辑:
我改为:
use cortex_m::interrupt::free;
use cortex_m::interrupt::Mutex;
use stm32g0::stm32g071::{self, Interrupt, NVIC, TIM3, interrupt};
和使用 interrupt::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());
}
});
}
我认为我的 ISR 正在循环调用。如何正确清除这个中断?
编辑:
我全部改成了TIM2。
我无法使用调试器到达行 tim2.sr.write(|w| w.uif().clear_bit());
。我觉得上面if let
returns不对,为什么?
宏属性#[interrupt]
is exposed in cortex-m-rt
not cortex-m
as book chapter Interrupts
文档:
Similarly to exceptions, the cortex-m-rt crate provides an interrupt attribute to declare interrupt handlers.
我按照 GitHub 问题中的说明进行操作并且成功了。我没有正确使用 Mutex
和 interrupt::free
。 ISR 中的 if let..
返回 false,因为在替换之前执行了中断,所以...它在中断中具有 None
的值。
这是我的代码,修复后有效。
#![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());
}
}
});
}
几周前我开始学习 Rust Embedded。 现在我被困住了,我想向你寻求帮助。所以..
我想在我的代码中使用 TIM3 来通过 ISR 中的寄存器更改变量(在未来的外设状态)和清除(未挂起的?)中断。
在 C 中,我在 ISR 中做了类似的事情:
void TIM3_IRQHandler(void)
{
if (TIM3->SR & TIM_SR_UIF)
{
TIM3->SR &= ~(TIM_SR_UIF);
}
}
..现在我不得不在 Rust 中做这件事。 首先我展示我到目前为止所做的。
#![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());
}
})
}
我得到这个编译错误:
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
我不知道如何解决这些依赖问题。 你能告诉我我用这个 Mutex G_TIM 做的很好吗? 我的意思是我是在阅读这篇文章后这样做的:https://docs.rust-embedded.org/book/concurrency/#sharing-peripherals 我也读过这个 https://users.rust-lang.org/t/rust-embedded-stm32f303-timer-interrupt-hanging/40323 但我不想使用 hal crates。
我也在 Rust 论坛上问过:https://users.rust-lang.org/t/how-to-clear-interrupt-with-perpiheral-handle/67214
编辑: 我改为:
use cortex_m::interrupt::free;
use cortex_m::interrupt::Mutex;
use stm32g0::stm32g071::{self, Interrupt, NVIC, TIM3, interrupt};
和使用 interrupt::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());
}
});
}
我认为我的 ISR 正在循环调用。如何正确清除这个中断?
编辑:
我全部改成了TIM2。
我无法使用调试器到达行 tim2.sr.write(|w| w.uif().clear_bit());
。我觉得上面if let
returns不对,为什么?
宏属性#[interrupt]
is exposed in cortex-m-rt
not cortex-m
as book chapter Interrupts
文档:
Similarly to exceptions, the cortex-m-rt crate provides an interrupt attribute to declare interrupt handlers.
我按照 GitHub 问题中的说明进行操作并且成功了。我没有正确使用 Mutex
和 interrupt::free
。 ISR 中的 if let..
返回 false,因为在替换之前执行了中断,所以...它在中断中具有 None
的值。
这是我的代码,修复后有效。
#![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());
}
}
});
}