RTC用に外部クロック32kHzを使う

WebでESP32でRTCを用いた製作事例を検索するとRTCモジュールのDS3231 RTC等を用いたものを良く見かけます。元々ESP32は150kHzのRC発振器を内蔵してます。これを使えば追加のモジュール無しでRTCが出来るのですが、使わないのは発振器がRCの為温度等でばらつく為でしょうか。ESP32のマニュアルにはRTC用の発振器と以下の用に記述されています。

今回は上記2番目の32kHzの外部発振器を用いたRTCを試してみたいと思います。

32kHz発振器の配線

マニュアルによると下記の様に配線すれば良い様です。

  • GPIO32/33を使用
  • 発振器の両端をつなぐ抵抗は5から10Mを使用。チップのバージョンがV3なら省略可能
  • 2のコンデンサですが、12pFが推奨値の様です。

今回製作した回路は手持ちに抵抗は1MΩ、コンデンサは20pFしか無かったのでそれらで代用しています。

検証用のプログラム

確認用のプログラムとして下記を使用します。

test.c

#include <stdio.h>
#include <sys/time.h>
#include "esp_sleep.h"
#include <soc/rtc.h>

//#define CONFIG_ESP32_RTC_XTAL_CAL_RETRY 100000
RTC_DATA_ATTR struct timeval sleep_enter_time;

void app_main(void)
{
    struct timeval now;
    int sleep_time_ms;
    const int wakeup_time_sec = 5;

    gettimeofday(&now, NULL);
    sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000;

    switch (esp_sleep_get_wakeup_cause()) 
    {
        case ESP_SLEEP_WAKEUP_TIMER: 
            printf("Wake up from timer. Time spent in deep sleep: %dms\n", sleep_time_ms);
            break;

        default:
            printf("Not a deep sleep reset\n");
    }

  	rtc_slow_freq_t slow_clk = rtc_clk_slow_freq_get();
  	printf("Slow clk source: ");
  	switch(slow_clk) 
  	{
    	case RTC_SLOW_FREQ_RTC: printf("Internal 150kHz\n"); break;
    	case RTC_SLOW_FREQ_32K_XTAL: printf("External 32kHz\n"); break;
    	case RTC_SLOW_FREQ_8MD256: printf("Internal 8MHz\n"); break;
    	default : printf("NONE\n");
  	}

    printf("Enabling timer wakeup, %ds\n", wakeup_time_sec);
    ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000));
  	esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);

    printf("Entering deep sleep\n");
    // get deep sleep enter time
    gettimeofday(&sleep_enter_time, NULL);
    // enter deep sleep
    esp_deep_sleep_start();
}
  • RTCタイマーを用いたDeepSleepのプログラム
  • 5秒に1回タイマーから割り込みを発生。
  • 立ち上がり直後にSleepしていた時間を表示する。

コンパイルと実行

32kHz 外部クロックを使用する為には、menuconfigでの設定が必要です。

Component config -> Hardware Settings -> RTC Clock Config ー> RTC clock source (External 32kHz crystal)と進むと下記の画面になります。

ここで、上から2番目の (X) External 32kHz crystal を選択。これをセーブしてコンパイル書き込みを行います。

32kHzクロックが起動しない

問題無くコンパイル実行出来るのですがどうも外部32kHz発振器は認識されていない様です。モニターには以下のコメントが表示されます。

問題のコメントはこれ 

 W (1105) clk: 32 kHz XTAL not found, switching to internal 150 kHz oscillator 

32kHzが見つからなかったので150kHzを使用している様です。

マニュアルにこんな記述が

別のマニュアルにこんな記述が有りました。

  • revision ECO3以前のものは32kHzのクリスタルを駆動するのにパワー不足となる事が有る。
  • これを解決方としてMethod1とMethod2が有る。
  • Method1はほぼ、解決される(完全では無い)
  • Method2は完全に解決されるが、Touchpadが使用出来なくなる。

このESP32のバージョンは上記モニター出力の下から4行目位に表示されている様に1.0です。

   I (1156) cpu_start: Chip rev:   v1.0 

ECO3は多分バージョン3.0の事だと思います。つまりこのESP32は32kHzの発振機使うにはMethod1/2設定する必要が有ると言うことです。

Method1/2は何処?

menuconfigの中に有りました。Component config > Hardware Settings > RTC Clock Configと進んだ画面に 

Additional current for external 32kHz crystal (None)と言う項目が有りますこの下にMethod1/2が有りました。

Method1を試したのですが動きませんでした。Method2を選択します。一個戻ってこの画面で下2行の設定も必要です。

これらについてマニュアルに以下の上に有ります。

  • 32kHzのクリスタルを使うなら以下を推奨
    • Number of cycles for RTC_SLOW_CLK calibration は3000以上
    • Number of attempts to repeat 32k XTAL calibration は1以上

幾つか試したのですが以下の設定で動きました。

  • Number of cycles for RTC_SLOW_CLK calibration: 変更無し。
  • Number of attempts to repeat 32k XTAL calibration: 10

再トライ

コンパイルして実行して下さい。今度は32kHzの発振器が見つかりませんのコメントが出ません。

ちなみにDeepSleep間の時間測定ですが、5408msと設定の5秒より0.408秒長い値となりました。一見精度が悪い様に思えたのですが、これは多分起動時に32kHzのキャリブレーションを行っている為と思われます。何度もDeepSleepを行った結果、各所要時間は最後の桁が8が9になる位の違いしか有りませんでした。かなり精度は良い様です。

最後に

これでRTCモジュールを使わなくても32kHzの発振器とコンデンサ、抵抗でRTCを使う事が出来るように成りました。

ESP32にはRTC用に内部RC発振器、32kHz外部発振器、RTCモジュールが有り、各々は以下の様に使い分けるのが良いでしょうか。

  • 内蔵RC発振器:精度を必要としないRTC場合。価格が安い。(不可部品無し)
  • 外部32kHz:比較的安く精度の高いRTCを行える。発振器とコンデンサ 抵抗が必要
  • RTCモジュール: 価格は高い。精度は外部32kHzと同等。最大のメリット:ESP32の電源をオフしても稼働する。

<<Before

Next>>