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の電源をオフしても稼働する。