RTC用に外部クロック32kHzを使う(Arduino編)

ESP32 IDF環境での ”外付32kHzの発振器を使ったRTC製作例” ー> RTC用に外部クロック32kHzを使う。同じ事がArduino環境で出来ないか試して見ました。

使用した回路

RTC用に外部クロック32kHzを使うと同じ回路を使用しました。

Webで関連ソフトを探す

Webを参考に下記のプログラムを作成しました。

test.ino

#include <soc/rtc.h>
#include <ESP32Time.h>
#include "esp_deep_sleep.h"

#define uS_TO_S_FACTOR 1000000ULL  
#define TIME_TO_SLEEP  5        
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)

ESP32Time rtc;

void wakeup_reason() 
{
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();
  if(wakeup_reason == ESP_SLEEP_WAKEUP_TIMER) Serial.println("Wakeup caused by timer");
  else Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
  
  print_slow_clock_source();
              
  rtc_clk_32k_bootstrap(10);
  rtc_clk_32k_bootstrap(10);
  rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
  rtc_clk_32k_enable(true);

  uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);

  if (cal_32k == 0) Serial.println("32K XTAL OSC has not started up");
  else Serial.println("32K XTAL OSC Calibrated");

  print_slow_clock_source();
}

void print_slow_clock_source() 
{
  rtc_slow_freq_t slow_clk = rtc_clk_slow_freq_get();
  Serial.print("Slow clk source: ");
  switch(slow_clk) 
  {
    case RTC_SLOW_FREQ_RTC: Serial.println("Internal 150kHz"); break;
    case RTC_SLOW_FREQ_32K_XTAL: Serial.println("External 32kHz"); break;
    case RTC_SLOW_FREQ_8MD256: Serial.println("Internal 8MHz");
  }
}

void setup() 
{
  Serial.begin(115200);

  wakeup_reason();
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

  Serial.println("Going to sleep now");
  print_slow_clock_source();
  esp_deep_sleep_start();
}

const float factor = (1 << 19) * 1000.0f;
static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
{
    const uint32_t cal_count = 1000;
    uint32_t cali_val;

    printf("%s:\n", name);
    for (int i = 0; i < 10; ++i)
    {
        printf("calibrate (%d): ", i);
        cali_val = rtc_clk_cal(cal_clk, cal_count);
        printf("%.3f kHz\n", factor / (float)cali_val);
    }
    return cali_val;
}

void loop() 
{
  
}
  • 以下の関数がキーの様です
    • 21行:rtc_clk_32k_bootstrap(10); 
      • 32kHzの発振器を発振させるのに必要は関数と思われる
    • 23行:rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
      • RTCの発振器を32kHzにセットする関数
    • 24行:rtc_clk_32k_enable(true);
      • 32kHzを有効にする関数
  • 外部クロックを起動後キャリブレーションを行う。
  • プログラムは5秒間隔でDeepSleepを繰り返します。
  • 要所で現在の有効発振器をprint_slow_clock_source();で表示させています。

rtc_clk_32k_bootstrap()を何回か実行した後、rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL)、rtc_clk_32k_enable(true);を行えば外部32kHzが使える様です。ただこの条件でも起動しない例をWebで見かけました。取り敢えずプログラムを実行すると以下の様にモニターに出力されました。結果はDeepSleepから復帰しませんでした。

monitor

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:10944
load:0x40080400,len:6388
entry 0x400806b4
Wakeup was not caused by deep sleep: 0
Slow clk source: Internal 150kHz
RTC_CAL_32K_XTAL:
calibrate (0): 32.636 kHz
calibrate (1): 32.766 kHz
calibrate (2): 32.767 kHz
calibrate (3): 32.766 kHz
calibrate (4): 32.767 kHz
calibrate (5): 32.766 kHz
calibrate (6): 32.767 kHz
calibrate (7): 32.766 kHz
calibrate (8): 32.767 kHz
calibrate (9): 24.092 kHz
32K XTAL OSC Calibrated
Slow clk source: External 32kHz
Going to sleep now
Slow clk source: External 32kHz

  • 14行:Slow clk source: Internal 150kHz。 
    • 起動直後は内部発振器150kHzが選択されています。この後32kHzの発振器が起動します。
  • 15行:ここでキャリブレーションを行う。
    • 10回のキャリブレーションを行っていますが、大体32kHz位の値を返すのですが最後が24.092となっています。不十分な値です。
  • 27行:Slow clk source: External 32kHz
    • 外部クロックに切り替わった様に見えますが、実際にはクロックが発振していない様です。
    •  ー>キャリブレーションで正しい値を返していない為
  • 29行:Slow clk source: External 32kHz
    • DeepSleepに入る直前でもう一度クロックを確認すると、32kHzが起動していると返して来ますが、DeepSleepから復帰しません。
    • クロックが発振していないと思われます。

このESP32は発振しないグループの様です。

チップのバージョン

チップのバージョンが3以下では外部発振器の発振に不具合が有る事を思い出しました。そこで使っているチップのバージョンを確認しました。以下はコンパイル後Arduinoに出力された表示の一部です。4行目にrevision 1 と有ります。発振に問題の有るバーションです。

monitor

esptool.py v3.0-dev
Serial port /dev/ttyACM0
Connecting........__
Chip is ESP32-D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: c8:f0:9e:a6:b2:30
Uploading stub...
Running stub...
Stub running...

RTC用に外部クロック32kHzを使うではこれについてmenuconfigで対応しました。ただArduinoで同様の対応の仕方が分かりません。今回はこれで諦めました。

最後に

Webで起動した人、しない人がいるのは使用しているチップのバージョンの関係と思われます。バージョン3以上のESP32で確かめたい所ですが手持ちが有りません。バージョン3以上を手にいれたら確認してみます。

追記

今回バージョン3以上のESP32が手に入りました。バージョンは下記の通り ” v3.1” です

monitor

esptool.py v4.6
Serial port /dev/ttyUSB0
Connecting....
Chip is ESP32-D0WD-V3 (revision v3.1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: 1c:69:20:ea:e5:a0
Uploading stub...
Running stub...

前回から時間が経っているのが原因か分かりませんが前回のプログラムではコンパイルでエラーが出ました。エラーの内容は、”esp_deep_sleep.h”が無いとの事。Webで確認すると ”esp_deep_sleep.h” はあるバージョンから ”esp_sleep.h” になったと有ったのでそこを変更したらエラーはなくなりました。

test.ino

#include <soc/rtc.h>
#include <ESP32Time.h>
#include "esp_sleep.h"

#define uS_TO_S_FACTOR 1000000ULL  
#define TIME_TO_SLEEP  5        
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)

ESP32Time rtc;

void wakeup_reason() 
{
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();
  if(wakeup_reason == ESP_SLEEP_WAKEUP_TIMER) Serial.println("Wakeup caused by timer");
  else Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
  
  print_slow_clock_source();
              
  rtc_clk_32k_bootstrap(10);
  rtc_clk_32k_bootstrap(10);
  rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
  rtc_clk_32k_enable(true);

  uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);

  if (cal_32k == 0) Serial.println("32K XTAL OSC has not started up");
  else Serial.println("32K XTAL OSC Calibrated");

  print_slow_clock_source();
}

void print_slow_clock_source() 
{
  rtc_slow_freq_t slow_clk = rtc_clk_slow_freq_get();
  Serial.print("Slow clk source: ");
  switch(slow_clk) 
  {
    case RTC_SLOW_FREQ_RTC: Serial.println("Internal 150kHz"); break;
    case RTC_SLOW_FREQ_32K_XTAL: Serial.println("External 32kHz"); break;
    case RTC_SLOW_FREQ_8MD256: Serial.println("Internal 8MHz");
  }
}

void setup() 
{
  Serial.begin(115200);

  wakeup_reason();
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

  Serial.println("Going to sleep now");
  print_slow_clock_source();
  esp_deep_sleep_start();
}

const float factor = (1 << 19) * 1000.0f;
static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
{
    const uint32_t cal_count = 1000;
    uint32_t cali_val;

    printf("%s:\n", name);
    for (int i = 0; i < 10; ++i)
    {
        printf("calibrate (%d): ", i);
        cali_val = rtc_clk_cal(cal_clk, cal_count);
        printf("%.3f kHz\n", factor / (float)cali_val);
    }
    return cali_val;
}

void loop() 
{
  
}

出力結果は以下の通り、

monitor

ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1448
load:0x40078000,len:14844
ho 0 tail 12 room 4
load:0x40080400,len:4
load:0x40080404,len:3356
entry 0x4008059c
Wakeup was not caused by deep sleep: 0
Slow clk source: Internal 150kHz
RTC_CAL_32K_XTAL:
calibrate (0): 32.767 kHz
calibrate (1): 32.767 kHz
calibrate (2): 32.767 kHz
calibrate (3): 32.767 kHz
calibrate (4): 32.768 kHz
calibrate (5): 32.767 kHz
calibrate (6): 32.768 kHz
calibrate (7): 32.767 kHz
calibrate (8): 32.768 kHz
calibrate (9): 32.767 kHz
32K XTAL OSC Calibrated
Slow clk source: External 32kHz
Going to sleep now
Slow clk source: External 32kHz
ets Jul 29 2019 12:21:46

rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1448
load:0x40078000,len:14844
ho 0 tail 12 room 4
load:0x40080400,len:4
load:0x40080404,len:3356
entry 0x4008059c
Wakeup caused by timer
Slow clk source: Internal 150kHz
RTC_CAL_32K_XTAL:
calibrate (0): inf kHz
calibrate (1): inf kHz
calibrate (2): inf kHz
calibrate (3): 32.761 kHz
calibrate (4): 32.767 kHz
calibrate (5): 32.768 kHz
calibrate (6): 32.767 kHz
calibrate (7): 32.768 kHz
calibrate (8): 32.767 kHz
calibrate (9): 32.768 kHz
32K XTAL OSC Calibrated
Slow clk source: External 32kHz
Going to sleep now
Slow clk source: External 32kHz
ets Jul 29 2019 12:21:46

想定通り5秒間隔でDeepSleepを繰り返しています。ちゃんと外部発振器が発信している様です。バージョン3以上であれば外部32kHz発振器が使える様です。

<<Before

Next>>