ATtiny1614の割り込み処理

ATtiny1614で、DS3231 RTCモジュールのアラーム信号を受け取って割り込み処理を行う。

毎記事、自身の覚書としてだけではなく、できる限り皆さんのお役に立てばと考えて拙い文章を連ねている。今回は、それに加えてもう一つ。感染症が流行している際は、不特定多数の人とできるだけ接触しないこと、手洗い・うがいといった基本的な衛生行動を怠らないこと、そして、正しい情報を正しく理解すること。本稿記載時点でなお、COVID-19は猛威を振るっている。

さて本題。Arduino(Pro Mini互換機)でDS3231 RTCモジュールのアラーム信号を受け取って割り込み処理する手順を以前の記事に記した。また、megaTinyCoreを使用すると、ATtiny1614がArduino同様に開発できることも前回の記事で示した。実際に、Lチカだけではなく、DS3231でも使用可能なDS3232のライブラリーと液晶表示器コントローラーST7032のライブラリーを使った下記スケッチがArduino(Pro Mini互換機)でもATtiny1614でも動作することを確認している。

#include <DS3232RTC.h>
#include <ST7032.h>

DS3232RTC clock;
ST7032 lcd;

void setup() {
    clock.begin();
    lcd.begin(8, 2);
    lcd.setContrast(20);
}

void loop() {
    time_t now = clock.get();
    char line[8];

    sprintf(line, "%02d-%02d-%02d", year(now)%100, month(now), day(now));
    lcd.setCursor(0, 0);
    lcd.print(line);

    sprintf(line, "%02d:%02d:%02d", hour(now), minute(now), second(now));
    lcd.setCursor(0, 1);
    lcd.print(line);

    delay(10);
}

では割り込み処理も同様に、と考えたくなるのが世の道理。ところが、attachInterrupt()関数が予期したとおりに動作しないようである。Arduino IDEでのコンパイル時に下記の警告が出ていたのも、いかにも不吉であった(関係はなかった)。

警告:ライブラリDS3232RTC-masterはアーキテクチャavrに対応したものであり、アーキテクチャmegaavrで動作するこのボードとは互換性がないかもしれません。

Web上をさまようこと数時間、何のことはない、megaTinyCoreの作者さんが丁寧な解説に加えてサンプルコードまで示してくださっていた。Well, I understand. それを基に修正したのが以下のコードである。割り込みは、「完全に非同期的に」割り込み信号を受け取れるPA6(=4番ピン)を使用した。

#include <DS3232RTC.h>
#include <avr/power.h>
#include <avr/sleep.h>

const byte ALARM_IN_USE = ALARM_1; // every second
const uint8_t MAX_ALARM_COUNT = 5; // every 5 seconds
const uint8_t INT_PIN = 2; // PA6
const uint8_t LED_PIN = 5; // PB2

volatile boolean caught_alarm = false;
uint8_t alerm_count = 0;
DS3232RTC clock;

void setup(void) {
    power_all_enable();

    pinMode(INT_PIN, INPUT_PULLUP);
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, LOW);
    /* bits 0-2: 011 = FALLING, bit 3: 1 = PULLUP */
    PORTA.PIN6CTRL = 0b00001011;

    clock.alarmInterrupt(ALARM_1, false);
    clock.alarmInterrupt(ALARM_2, false);
    clock.squareWave(SQWAVE_NONE);
    clock.oscStopped(true);
    clock.setAlarm(ALM1_EVERY_SECOND, 0, 0, 0, 1);
    clock.setAlarm(ALM2_EVERY_MINUTE, 0, 0, 0, 1);
    clock.alarm(ALARM_IN_USE);
    clock.alarmInterrupt(ALARM_IN_USE, true);
}

void loop(void) {
    if (caught_alarm) {
        caught_alarm = false;
        alerm_count++;

        if (alerm_count >= MAX_ALARM_COUNT) {
            alerm_count = 0;
            doWork();
        }

        clock.alarm(ALARM_IN_USE);
    }

    enterSleep();
}

ISR(PORTA_PORT_vect) {
    register8_t flags = PORTA.INTFLAGS;
    PORTA.INTFLAGS = flags; // clear flags; set 1 if flag = 1
    caught_alarm = true;
}

void enterSleep(void) {
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    sleep_mode();
    /* wait for alarm */
    sleep_disable();
}

void doWork(void) {
    power_all_enable();

    digitalWrite(LED_PIN, HIGH);
    delay(100);
    digitalWrite(LED_PIN, LOW);
    delay(100);
    digitalWrite(LED_PIN, HIGH);
    delay(100);
    digitalWrite(LED_PIN, LOW);
}

UPDI programmerである“jtag2updi”の使い方と配線は前回の記事を参照されたい。Arduino Pro Mini互換機経由で上記スケッチをATtiny1614に書き込んだ後、以下のとおり配線する。注意すべきは、スケッチでのピン番号と実際のピン番号とのずれである。

  • ATtiny1614の4番ピンとDS3231 RTCモジュールのSQWを繋ぐ
  • ATtiny1614の7番ピンとGNDをLチカ用LEDで繋ぐ
  • ATtiny1614の8番ピンとDS3231 RTCモジュールのSDAを繋ぐ
  • ATtiny1614の9番ピンとDS3231 RTCモジュールのSCLを繋ぐ
  • ATtiny1614の14番ピンとGNDを繋ぐ
  • ATtiny1614の1番ピンとVccを繋ぐ

相変わらず手振れのひどい動画で申し訳ない。スリープ時には約0.5 mA、動作時には約2.5 mA(RTCモジュール込み、LED無し)で動作していた。

コメント

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