如何用外设句柄清除中断?嵌入式锈

Posted

技术标签:

【中文标题】如何用外设句柄清除中断?嵌入式锈【英文标题】:How to clear interrupt with perpiheral handle? Embedded Rust 【发布时间】:2021-12-24 08:37:50 【问题描述】:

几周前,我开始学习 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 和 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返回false,为什么?

【问题讨论】:

我建议你在github.com/rust-embedded/book创建一个问题 好的,我创建了一个问题:github.com/rust-embedded/book/issues/307 【参考方案1】:

#[interrupt] 的宏属性暴露在 cortex-m-rt 而不是 cortex-m 作为书籍章节 Interrupts 文档中:

与异常类似,cortex-m-rt crate 提供了一个中断属性来声明中断处理程序。

【讨论】:

如果我添加 use cortex_m_rt::interrupt; 我遇到了 TIM3 函数的问题。即使我有use stm32g0::stm32g071::..., TIM3 行。【参考方案2】:

我按照 GitHub 问题中的说明进行操作,并且成功了。我没有正确使用Mutexinterrupt::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());
            
        
    );

【讨论】:

以上是关于如何用外设句柄清除中断?嵌入式锈的主要内容,如果未能解决你的问题,请参考以下文章

如何用SystemView分析AliOS Things

嵌入式Linux裸机开发——S5PV210中断处理流程

嵌入式定时器中断初始化

跟涛哥一起学嵌入式 第05集:一道程序改错题,测出你的嵌入式功底

目前CSDN上最全面的C语言讲解如何用更高层次编写嵌入式C代码

嵌入式数据库sqlite3进阶篇-如何用C语言操作sqlite3,一文搞懂