【PowerMeter2020】M5StickのRTCとNTP時間精度測定した<RTC14ppm/NTP0.8ppm>

パワーメーターログは、M5StickのBlueToothを使えば8msec周期まではデータ欠落なく送信できることが確認されたので、次は、M5Stickのサンプリング周期精度を確保する検討を行います。

 

●AD変換のサンプリング時間誤差の過去の対策
2019年のパワーメーター開発は、サンプリング時間誤差で、左右クランクと母艦マイコンの3か所のクロックばらつきが累積して、トルク波形の位相が大きくずれてしまうという課題の解決でほとんどの時間をつぶしてしまいました。
結論としては、

クロック精度対策
外付水晶クロックを分周してマイコンのポートへ入れて
割り込みタイミングとしてADCに使う

【パワーメーター2019】割り込みタイマー精度測定結果<TCXOは計測の必需品>

 しかし、外付けで、TSSOPのクロック基板(DS3231と分周ICを載せた基板)を
新たに追加するのは素人配線の信頼性リスクがあります。
=>ロードバイクへ搭載するとなると実装技術的に外付け回路の振動対策などがあるので大変面倒なことになるので、2020年では、外付け無しで
M5Stick単体で可能な限りクロック精度を得る可能性の検討を行います。
M5Stick自体が振動に弱いかもしれませんが、自作回路よりはマシだと思います。
しかし、最低限のアナログ部分電池、ひずみゲージアンプなどは自作する以外にありませんのでひずみゲージ関連のパッケージングを時間と手間をかけて検討する必要があります。

 

●M5StickでRTCの精度(仕様が無い)
M5Stickには、RTCの解説がありますが、BM8563という中国製のRTCですが、中国語のマニュアルで読めないのですが、精度ppmの記述がほとんどありませんので、怪しいRTCです。日本のRTCについてEPSONが最も詳細に解説してあります。
https://www5.epsondevice.com/ja/information/support/faq_rtc/all/
典型的なRTCの仕様書では、周波数精度としてΔf/fの温度範囲によるばらつきを表記してあるのが信頼性がある製品です。例えば高精度DTCXOを使ったEPSONの
RX8900CEだと±3.4ppmを保証してます。これだと年差107秒1時間で12msecずれてしまいます。実際常温で使えば1ppm以下の性能なので、1時間で3msec程度です。

https://support.epson.biz/td/api/doc_check.php?dl=brief_RX8900CE&lang=ja

M5StickのRTCの仕様がないので、測定してみる以外にありませんので、
NTPとセットでGPS基準で測定するためにNTPもプログラムにいれます。

●NTPサーバーからの受信
NTPの解説記事
https://milestone-of-se.nesuke.com/l7protocol/ntp/ntp-summary/

4ページ目の図を切り抜かせていただきました。
インターネットのIPパケットの遅延時間とサーバーのタイムスタンプ時間の
誤差を計算して補正して正確な時刻を得られるようにする技術と理解しました。

 

NTPでもインターネット経由で遅延時間補正がはいるので数msecは誤差が発生するようです。

 

 

●M5StickCでNTPとRTCをいじってみる
下記ページにM5StickでNTPで時刻合わせをしてRTCで液晶表示するプログラムあったのでコピペでNTP用のWIFIのSSIDとパスを自分の家用に記入してコンパイルして1発で動作しました。15分で出来上がりました。作者様に感謝です。
https://lang-ship.com/blog/work/m5stickc-rtc-ntp/



液晶が壊れていてライン抜けで見ずらいですが年月日でてます

実験で使ったプログラムです。

#include <M5StickC.h>
#include <WiFi.h>
#include “time.h”const char* ssid = “e”;
const char* password = “21311610”;const char* ntpServer = “ntp.jst.mfeed.ad.jp”;
int RTC_Pin=0;//GP0
int NTP_Pin=26;//GP26
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
int t_1;
int nt,nt_1;void ntpget()
{
// Set ntp time to local
configTime(9 * 3600, 0, ntpServer);// Get local time
struct tm timeInfo;
nt_1=nt;
if (getLocalTime(&timeInfo,100)) {
nt=timeInfo.tm_sec;
if(nt!=nt_1)
{
digitalWrite(NTP_Pin,0);
delay(40);
digitalWrite(NTP_Pin,1);
}/*
//Serial.print(“NTP : “);
// Serial.println(ntpServer);
Serial.print(“NTP=”);
Serial.print(timeInfo.tm_hour);
Serial.print(“:”);
Serial.print(timeInfo.tm_min);
Serial.print(“:”);
Serial.println(timeInfo.tm_sec);
*/
}
/*
// Set RTC time
RTC_TimeTypeDef TimeStruct;
TimeStruct.Hours = timeInfo.tm_hour;
TimeStruct.Minutes = timeInfo.tm_min;
TimeStruct.Seconds = timeInfo.tm_sec;
M5.Rtc.SetTime(&TimeStruct);RTC_DateTypeDef DateStruct;
DateStruct.WeekDay = timeInfo.tm_wday;
DateStruct.Month = timeInfo.tm_mon + 1;
DateStruct.Date = timeInfo.tm_mday;
DateStruct.Year = timeInfo.tm_year + 1900;
M5.Rtc.SetData(&DateStruct);
}
*/
}
void setup() {
pinMode(RTC_Pin, OUTPUT);
pinMode(NTP_Pin, OUTPUT);
// put your setup code here, to run once:
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(40, 0, 2);
M5.Lcd.println(“RTC NTP TEST”);// connect to WiFi
Serial.printf(“Connecting to %s “, ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(“.”);
}
Serial.println(” CONNECTED”);
// Set ntp time to local
configTime(9 * 3600, 0, ntpServer);// Get local time
struct tm timeInfo;
if (getLocalTime(&timeInfo)) {
Serial.print(“NTP : “);
Serial.println(ntpServer);// Set RTC time
RTC_TimeTypeDef TimeStruct;
TimeStruct.Hours = timeInfo.tm_hour;
TimeStruct.Minutes = timeInfo.tm_min;
TimeStruct.Seconds = timeInfo.tm_sec;
M5.Rtc.SetTime(&TimeStruct);RTC_DateTypeDef DateStruct;
DateStruct.WeekDay = timeInfo.tm_wday;
DateStruct.Month = timeInfo.tm_mon + 1;
DateStruct.Date = timeInfo.tm_mday;
DateStruct.Year = timeInfo.tm_year + 1900;
M5.Rtc.SetData(&DateStruct);
}

//disconnect WiFi
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}

void loop() {
ntpget();
static const char *wd[7] = {“Sun”,”Mon”,”Tue”,”Wed”,”Thr”,”Fri”,”Sat”};

// put your main code here, to run repeatedly:
t_1=RTC_TimeStruct.Seconds;

M5.Rtc.GetTime(&RTC_TimeStruct);
M5.Rtc.GetData(&RTC_DateStruct);
//M5.Lcd.setCursor(0, 30);
//M5.Lcd.printf(“Data: %04d-%02d-%02d\n”, RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date);
//M5.Lcd.printf(“Week: %s\n”, wd[RTC_DateStruct.WeekDay]);
//M5.Lcd.printf(“Time: %02d : %02d : %02d\n”, RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);
//Serial.print(RTC_TimeStruct.Hours);
//Serial.print(“:”);
if (RTC_TimeStruct.Seconds!=t_1)
{
Serial.print(RTC_TimeStruct.Minutes);
Serial.print(“,”);
Serial.print(RTC_TimeStruct.Seconds);
Serial.print(“,”);
Serial.println(millis());
digitalWrite(RTC_Pin,0);
delay(60);
digitalWrite(RTC_Pin,1);
}

}

 

■GPS基準でRTCとNTPの時間誤差を測定

①GPS信号:黄色
秋月のみちびき対応GPSにUSBシリアルアダプタを接続して、衛星数が3個以上になったのを確認して1ppsピンをオシロにつなぐと1秒毎に100msecの凹波形がでます。
GPSは屋外でなくても窓際においておけば5個以上は衛星補足できるので時間精度OKです。

 

➁RTCピンク色とNTP水色:
上記サンプルプログラムを切り貼りして、M5StickCのGP0にRTC出力、GP26にNTP出力をDigitalwrite()してオシロに信号を送ります。

③オシロの設定
GPSの下がりエッジにトリガーをかけて、そのエッジ基準に
 RTCの下がりエッジ BXmsec 
  NTPの下がりエッジ AXmsec 
 と時間差をカーソル測定します。
スタート時点での時間差を測定してスクリーンショットに記録します。
1時間後にエッジのズレをカーソルで測定してスクリーンショットに記録します。
時間誤差:
ppm=(スタート時刻secー1時間後時刻sec)/3600 *10^6

●結果
GPS基準黄色

RTCピンク色が14.4ppm 、NTP水色が0.83ppmとなりました。
やはりNTPでも誤差が高精度のTCXO程度は発生します。
※NTPが良いのは、1秒周期で数msecズレが発生があるのですが
毎回同じずれが発生するわけでなくズレを平均すると高精度に
なる点です。毎秒毎に修正をかけているようなものですので
誤差が累積されることがないので、長時間での精度は分母が大きく
なるので、どんどん精度が上がるということです。
1秒での誤差は、最悪±10msecだったら0.01secなので1万ppmと
なってしまいますが、1時間で10msecだと0.01/3600=2.778ppm
となります。本実験では1時間で3msecなので0.83ppmです。

 

●以後
 M5StickをクランクのCPUとするためには、RTCや内臓クロックは精度が悪くて使えないことがわかりました。外部の高精度RTC DS3231を入れれば、
2ppm以下になるし、32KHzの分周タイミングをえらえるので8msec周辺でダイレクトにサンプリングクロックが得られます。しかし、外付け回路が必要となります。
NTPを使う場合は、ESP32のWIFIを使うので、BlueToothが使えなくなります。同時に切り替えながらは数msec周期では無理そうですので、外付けBlueToothを追加するかになります。
結局、外付けに何か足さないと、十分なADサンプリング周期の精度が得られないことが判りました。
発想を変えて、クランクの上死点を基準にして、1回転毎にタイマーリセットして
使えば、内臓クロックでも誤差は無視できるほど小さくなるので問題はありません。
そのほうが実用的ですが、左右クランクとシートチューブの3つのCPUにクランク上死点を1msecずれ程度のタイミングで同期させないといけません。
もう少し、じっくりと考えて同期をどうするか決めていきます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です