ESP32-時間調整をタイマー割り込みで実施

ESP32-delay関数(時間調整について)でAPIで時間調整をして見たが、タイマー割り込みを使ったたらどうなのかやってみた。

実装内容と結果

タイマーをカウントダウン形式で運用し、0になったら割り込みが実施されるような仕組みにした。

class TimerTest
{
private:
    // 以下2つはどのタイマーを使うかの指定
    static const timer_idx_t timerIndex_ = TIMER_0;
    static const timer_group_t timerGroup_ = TIMER_GROUP_0;

    void timerAction();

public:
    TimerTest();
    ~TimerTest();

    void begin();

    void setTimer(uint64_t value);

    void start();

    bool isUp() const;
    
    static IRAM_ATTR void timerIntr(void* user);

    static const uint32_t timerDvider_ = 16;
};
// 1秒あたりのカウント数
// 80MHz(APB周波数)/16(timerDivider_)だと5000000ULLになる。
static const uint64_t secTimerScale_ = TIMER_BASE_CLK / TimerTest::timerDvider_;
// 下のはμ秒あたりのカウント数
static const uint64_t microTimerScale_ = secTimerScale_ / 1000000;

TimerTest::TimerTest()
{
}

TimerTest::~TimerTest()
{
}

void TimerTest::timerAction()
{
    // フラグ等の設定処理
}

IRAM_ATTR void TimerTest::timerIntr(void* user)
{
    auto work = (TimerTest*)user;
    work->timerAction();
    timer_pause(TimerTest::timerGroup_, TimerTest::timerIndex_);
    timer_group_clr_intr_status_in_isr(TimerTest::timerGroup_, TimerTest::timerIndex_);
    timer_group_enable_alarm_in_isr(TimerTest::timerGroup_, TimerTest::timerIndex_);
}

void TimerTest::begin()
{
    // タイマー割り込みの初期化
    timer_config_t config = {
        .alarm_en = TIMER_ALARM_EN,
        .counter_en = TIMER_PAUSE,
        .intr_type = TIMER_INTR_LEVEL,
        .counter_dir = TIMER_COUNT_DOWN,
        .auto_reload = TIMER_AUTORELOAD_DIS,
        .divider = timerDvider_,
    }; // default clock source is APB
    timer_init(timerGroup_, timerIndex_, &config);
    timer_isr_register(timerGroup_, timerIndex_,
        TimerTest::timerIntr,(void *) this, ESP_INTR_FLAG_IRAM, nullptr);
    timer_set_alarm_value(timerGroup_, timerIndex_, 0ULL);
}

#include "soc/timer_periph.h"

void TimerTest::start()
{
    timer_start(TimerTest::timerGroup_, TimerTest::timerIndex_);
}

void TimerTest::setTimer(uint64_t value)
{
    timer_set_counter_value(timerGroup_, timerIndex_,
        value * microTimerScale_);
}

ets_delay_usと同様に、2500μ秒の設定をしタイマーをスタート。割り込みを呼び出されたときまでの時間を計測(小数点2桁目四捨五入)した。

電源管理なし 2.5ms
電源管理あり 2.5ms

基本的に、ほぼ指定した時間通りの結果となったが、μ秒単位で見た場合、電源管理ありの方が若干遅れが発生した。

ちょっとした不満点

ちょっと細かい部分を見た時、いくつか不満点がある。

  1. 若干の遅延がある。
    タイマー設定に2μ秒、割り込み発生後関数が呼び出されるまで3μ秒ほどの時間がかかる。
    ets_delay_usではほぼ設定値通りdelayがかけられるのだが、割り込みを使った場合、この遅れも考慮する必要がある。
  2. 初回関数呼び出し時に遅延が大きくなる。
    通常5μ秒ほどの遅延が、初回時のみトータルで50~60μ秒かかってしまった。
  3. 割り込み処理で複雑な処理ができない。
    これは当然そうなのだが、割り込みでフラグ等の設定をして、メインループでフラグを見て処理の続行をするなどの、処理方法を考える必要がある。

利用するケースとしては

vTaskDelayで設定可能な単位より短い時間のdelayを持たせ、かつある程度遅延に関しては許容でき、並行して何か処理をさせたいなどの場合には使えるのかもしれない。

利用できる範囲は少ないかもしれないが。

コメント

タイトルとURLをコピーしました