2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ESP32 on Rustチートシート(タイマー割込と排他制御)

Last updated at Posted at 2023-01-09

ESP32 on Rustチートシート
(タイマー割込と排他制御)

タイマー割込を行うプログラムのサンプル

割込を実装する際、ペリファラルに対して割込関数からアクセスするので、ペリフェラルをグローバル変数で宣言し、排他制御でメイン関数と割込関数の両方で書き込みを行うように実装する

サンプルコード

# Cargo.toml
[package]
name = "timer-interrupt"
version = "0.1.0"
authors = ["dai_guard"]
edition = "2021"
license = "MIT OR Apache-2.0"

[dependencies]
esp32-hal = "0.7.0"
esp-backtrace = { version = "0.4.0", features = ["esp32", "panic-handler", "print-uart"] }
esp-println = { version = "0.3.0", features = ["esp32"] }
xtensa-lx-rt = { version = "0.14.0", features = ["esp32"], optional = true }
critical-section  = "1.1.1"

[features]
default = ["rt"]
rt = ["xtensa-lx-rt"]

// main.rs
#![no_std]
#![no_main]

// 内部可変パターン
use core::cell::RefCell;
// 排他制御用のMutex
use critical_section::Mutex;

// ESP32用のHALクレート
use esp32_hal::{
    clock::ClockControl,
    pac::{self, Peripherals, TIMG0, TIMG1},
    interrupt::{self, Priority},
    prelude::*,
    timer::{Timer, Timer0, Timer1, TimerGroup},
    Rtc, IO, Delay, 
    gpio::{GpioPin, Output, PushPull, Bank0GpioRegisterAccess, InputOutputPinType}
};

use esp_backtrace as _;
// use xtensa_lx_rt;
use esp_println::println;

// グローバル変数として宣言するペリフェラルを参照する値を宣言
// 1. Mutexで宣言し排他アクセスを保証する
// 2. Optionでグローバル宣言時はNoneで初期化する
//  あとのメイン関数内でインスタンスを設定する
static TIMER00: Mutex<RefCell<Option<Timer<Timer0<TIMG0>>>>> = Mutex::new(RefCell::new(None));
static TIMER01: Mutex<RefCell<Option<Timer<Timer1<TIMG0>>>>> = Mutex::new(RefCell::new(None));
static GPIO: Mutex<RefCell<Option<GpioPin<Output<PushPull>, Bank0GpioRegisterAccess, InputOutputPinType, 4>>>> = Mutex::new(RefCell::new(None));

// ※ 使用するターゲットボードによってentryのクレートが違います
#[xtensa_lx_rt::entry]
fn main() -> ! {

    let peripherals = Peripherals::take().unwrap();
    let system = peripherals.DPORT.split();
    let clocks = ClockControl::boot_defaults(system.clock_control).freeze();

    // Disable the RTC and TIMG watchdog timers
    let mut rtc = Rtc::new(peripherals.RTC_CNTL);
    let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
    let mut wdt0 = timer_group0.wdt;
    let mut timer00 = timer_group0.timer0;
    let mut timer01 = timer_group0.timer1;
    let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
    let mut wdt1 = timer_group1.wdt;

    rtc.rwdt.disable();
    wdt0.disable();
    wdt1.disable();

    // 割込を許可する
    interrupt::enable(pac::Interrupt::TG0_T0_LEVEL, Priority::Priority2).unwrap();
    interrupt::enable(pac::Interrupt::TG0_T1_LEVEL, Priority::Priority2).unwrap();

    //GPIO4を出力として使用する
    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
    let mut led = io.pins.gpio4.into_push_pull_output();
    led.set_high().unwrap();

    // タイマーをスタートする
    timer00.start(500u64.millis());
    timer01.start(1000u64.millis());

    // 割込待ちを開始する
    timer00.listen();
    timer01.listen();

    // このクリティカルセッション内での処理はラッピングされます
    // このセッション内の処理が完了するまでは割込が発生しません
    critical_section::with(|cs| {
        TIMER00.borrow_ref_mut(cs).replace(timer00);
        TIMER01.borrow_ref_mut(cs).replace(timer01);
        GPIO.borrow_ref_mut(cs).replace(led);
    });

    loop {
    }
}

// 割込関数を宣言する
#[interrupt]
fn TG0_T0_LEVEL() {

    // このクリティカルセッション内での処理はラッピングされます
    // このセッション内の処理が完了するまでは割込が発生しません
    critical_section::with(|cs| {

        // 参照するタイマーを取得する
        let mut timer = TIMER00.borrow_ref_mut(cs);
        let timer = timer.as_mut().unwrap();
        // 参照するGPIOを取得する
        let mut led = GPIO.borrow_ref_mut(cs);
        let led = led.as_mut().unwrap();

        // I/OのHigh/Lowを切り替える
        led.toggle().unwrap();

        // 割込フラグをリセットし、タイマーを再スタートする
        if timer.is_interrupt_set() {
            timer.clear_interrupt();
            timer.start(500u64.millis());

            println!("Interrupt Level 2 - Timer0");
        }
    });
}

#[interrupt]
fn TG0_T1_LEVEL() {
    critical_section::with(|cs| {
        let mut timer = TIMER01.borrow_ref_mut(cs);
        let timer = timer.as_mut().unwrap();

        if timer.is_interrupt_set() {
            timer.clear_interrupt();
            timer.start(1000u64.millis());

            println!("Interrupt Level 2 - Timer1");
        }
    });
}

参考リンク

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?