目次

ESP32タイマー割込み処理

 ESP32のスケッチで、タイマー割込みを扱うとして
 MsTimer2をインクルードしても、まともな動作には
 なりませんでした。

 Arduinoは、AtmelのATmega168をベースに展開して
 きたため、ArduinoIDEであっても、EPS32のように
 CPUアーキテクチャが異なる場合、ライブラリには
 互換性がないと考えてよいでしょう。

 いろいろと調べた結果、次のスケッチでタイマー割込み
 によるLED点滅を扱うことができました。

#define LED_PINA 2
#define LED_PINB 4

#define OFF 0
#define ON  OFF+1

/* initialize timer */
hw_timer_t* xtimer = NULL ;
hw_timer_t* ytimer = NULL ;

boolean aflag ;
boolean bflag ;

byte    xcnt ;
byte    ycnt ;

void init_tim0();
void init_tim1();

/* interrupt service routine */
void IRAM_ATTR MY_TIM0_INT()
{
  aflag = ON ;
}

void IRAM_ATTR MY_TIM1_INT()
{
  bflag = ON ;
}

void setup()
{
  /* initialize PIN value and direction */
  digitalWrite(LED_PINA,LOW);
  digitalWrite(LED_PINB,LOW);
  pinMode(LED_PINA,OUTPUT);
  pinMode(LED_PINB,OUTPUT);
  /* clear flags */
  aflag = OFF ;
  bflag = OFF ;
  /* clear counters */
  xcnt = 0 ;
  ycnt = 0 ;
  /* initialize timers */
  init_tim0();
  init_tim1();
}

void loop()
{
  /* timer0 interrupt handing */
  if ( aflag == ON ) {
    /* clear event flag */
    aflag = OFF ;
    /* impress */
    digitalWrite(LED_PINA,LOW);
    if ( xcnt & ON ) { digitalWrite(LED_PINA,HIGH); }
    /* update */
    xcnt++ ;
  }
  /* timer1 interrupt handing */
  if ( bflag == ON ) {
    /* clear event flag */
    bflag = OFF ;
    /* impress */
    digitalWrite(LED_PINB,LOW);
    if ( ycnt & ON ) { digitalWrite(LED_PINB,HIGH); }
    /* update */
    ycnt++ ;
  }
}

void init_tim0()
{
  /* 80MHz / 80 = 1MHz (1us) */
  xtimer = timerBegin(0, 80, true);
  /* set period */
  timerAlarmWrite(xtimer,250000,true);
  /* attach ISR */
  timerAttachInterrupt(xtimer,&MY_TIM0_INT,true);
  /* enable timer interrupt */
  timerAlarmEnable(xtimer);
}

void init_tim1()
{
  /* 80MHz / 80 = 500kHz (2us) */
  ytimer = timerBegin(1, 160, true);
  /* set period */
  timerAlarmWrite(ytimer,500000,true);
  /* attach ISR */
  timerAttachInterrupt(ytimer,&MY_TIM1_INT,true);
  /* enable timer interrupt */
  timerAlarmEnable(ytimer);
}

 ESP32のスケッチを動かせるように、ArduinoIDEに
 必要なファイルを追加すると、タイマーを扱うのに
 利用する構造体を使えるようになります。

 構造体変数を扱うために、データ型hw_timer_tの
 利用を宣言しておきます。
 構造体変数は、メモリ中のどこかにブロックごとに
 確保されるので、NULLポインタを使い、領域だけを
 確保。

hw_timer_t* xtimer = NULL ;
hw_timer_t* ytimer = NULL ;

 hw_timer_tは、hardware timer typeの略と解釈
 すればよいでしょう。

 メモリの中に領域を確保して、後から必要な
 設定をやっていく手順でいけるよう。

 割込みハンドラは、RAMの中に置く仕様なので
 次のように、関数名の前にIRAM_ATTRをつけて
 割込み発生時に呼び出されることを宣言。

void IRAM_ATTR MY_TIM0_INT()
{
  aflag = ON ;
}

void IRAM_ATTR MY_TIM1_INT()
{
  bflag = ON ;
}

 割込みハンドラは、極力短くしたいので
 イベント通知フラグをセットするだけに
 しています。

 タイマーを使うには、以下の内容を指定。

 EPS32は、64ビットのタイマーカウンタを
 4チャネル持っています。
 また、クロックソースは、いくつか選択でき
 プリスケーラに接続されています。

 ブロック図で見ると、以下。



 リストにあるパラメータを設定するのに
 次の関数を利用。

timerBegin
timerAlarmWrite
timerAttachInterrupt
timerAlarmEnable

 各関数に関して、パラメータを絡めて理解します。

 timerBegin

  関数名から、タイマーを使うことを指定すると
  わかるはず。3パラメータを指定。
  1. チャネル番号
  2. プリスケーラ値
  3. 論理値
  戻り値は、構造体領域のエントリーアドレスなので   ポインタに代入。   次のように書けばOK。 xtimer = timerBegin(0, 80, true); ytimer = timerBegin(1, 160, true);   プリスケーラ値は、ここで指定するので   カウンタ値は、別の関数で設定します。  timerAlarmWrite   関数名から、カウンタ値を指定するのかと推定できます。   3パラメータを指定。
  1. 構造体変数のエントリーアドレス
  2. カウンタ値
  3. 論理値
  カウンタは、インクリメントかデクリメントのいずれか。   インクリメントの場合、論理値にtrueを指定。   次の設定では、インクメントで、500000になると   ゼロクリアしてから、またインクリメント動作を   します。 timerAlarmWrite(ytimer,500000,true);   図でみると、以下。   カウンタのインクリメント動作ですが、最大値と   なれば、リセットされるようになります。   カウンタのデクリメント動作は、最大値から0   まで、減少させていき0になると最大値を再度   と設定。  timerAttachInterrupt   タイマー割込みが発生したときに、動かすコード   のエントリアドレスを指定。 timerAttachInterrupt(ytimer,&MY_TIM1_INT,true);   構造体のプロパティの中に、エントリアドレスを   与えるため、割込みハンドラの関数名に、「&」   をつけて、アドレスであることを明記。  timerAlarmEnable   割込みを許可するために、この関数を使います。   パラメータは、構造体変数のエントリアドレス   とします。 timerAlarmEnable(ytimer);  動作確認は、5x5のLEDマトリクスを使いました。

目次

inserted by FC2 system