電池が切れた時のrtcの振る舞いについて

製品に電源を入れた際、電池が切れている場合に電池切れをユーザーに教えるために、Qtで作成したアプリ上で電池切れの表示をする必要があります。
起動時のシステム時刻がデフォルトに戻った場合に電池切れと判断しようと思っていましたが、実際に電池を抜いて電源を入れると、システム時刻はデフォルトではなく、最後に電源を落とす前の時刻が表示されました。
以上のことから、電池切れ状態で最後に電源切る前の時刻と次回起動時の時刻に差がほとんどないため、作成したアプリからは電池切れの判断が難しいと思っています。
作成したアプリから電池切れの判断を行うために、何かいい方法はありませんか?

tdx-infoの出力内容は下記の通りです。

Software summary

Bootloader: U-Boot

Kernel version: 5.15.129-6.5.0-devel+git.6f8fd49366db #1 SMP PREEMPT Fri Dec 22 11:15:52 UTC 2023
Kernel command line: root=PARTUUID=577cc89f-02 ro rootwait console=tty1 console=ttymxc2,115200 consoleblank=0 earlycon
Distro name: NAME=“TDX Wayland with XWayland”
Distro version: VERSION_ID=6.5.0-devel-20240327230744-build.0
Distro variant: -
Hostname: verdin-imx8mp-15230634

Hardware info

HW model: Toradex Verdin iMX8M Plus on Verdin Development Board

Toradex version: 0063 V1.1B
Serial number: 15230634
Processor arch: aarch64

Hi, I’m the Toradex AI Assistant.

I might make mistakes. Our support team will step in if needed. If I answered your question, please tick the “Solution” checkbox. For follow-up questions to me, please use @ToradexAI in your post.

Did you like my answer? :+1: :-1:


こんにちは、ご質問ありがとうございます。

Verdin iMX8M PlusモジュールのSecure Real-Time Clock(RTC)では、RTCのバックアップ電池が切れても、起動時に最後のシステム時刻が維持されているように見えることがあります。これはRTC制御の設計に起因しており、時刻だけで電池切れを検出するのは確かに難しい状況です。

電池切れをQtアプリケーションで確実に検出したい場合、以下の方法をお試しください。

1. RTC電源管理レジスタのフラグ確認

i.MX8M PlusのRTCは、電池抜けなどの状態変化を示すフラグを持っています。これらのフラグは、"power-on reset"や"battery low"状況を示します。Linuxでは、通常、/dev/rtc0を通じてRTCデバイスへアクセスできます。
たとえば、hwclockコマンドでRTCにアクセスしたり、QtからはC/C++でioctl()システムコールを使ってRTCの状態情報を得ることができます。

コード例: /dev/rtc0から電源復帰フラグを読む

#include <linux/rtc.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    int fd = open("/dev/rtc0", O_RDONLY);
    if (fd < 0) {
        perror("open");
        return 1;
    }
    unsigned long data = 0;
    if (ioctl(fd, RTC_RD_STATUS, &data) == 0) {
        printf("RTC Status Reg: 0x%lx\n", data);
        // dataの該当ビットで電池切れを判断
    } else {
        perror("ioctl");
    }
    close(fd);
    return 0;
}

2. VCC_BACKUP電圧状態の参照

回路設計によりますが、VCC_BACKUPの電圧状態をシステム側で取得できる場合、例えばIIO(Industrial I/O)デバイスや特定のADC経由で電圧値を取得し、電池切れかどうかを判断できます。

3. システム起動ログの確認

起動時のdmesgログやjournalctlで、RTCが"power loss detected"などといった電源異常イベントを出力していないかも合わせてチェックできます。


まとめ
Qtアプリで電池切れ判定をするには、単純な時刻の値の比較ではなく、RTCデバイスの状態レジスタ(特に「power-on reset」「battery low」フラグ)をC/C++コードで読んで、電池切れかどうかを判断する方法が確実です。

詳細なRTCレジスタの意味とマッピングは、Verdin iMX8M Plusの資料やNXPのi.MX8M Plusリファレンスマニュアルの「RTC」章を参照してください。

Verdin iMX8M Plus Module - Documentation

ご不明な点がありましたら、またご質問ください。

Best regards, Toradex AI Assistant.

@fmt_mika

いつもお世話になっております。
Toradex Japanのアルバロです。
お問い合わせいただきありがとうございます。

ご質問の中で「電池を抜いて」とご記載いただいておりますが、こちらの「電池」は、
・RTC(RX8130)のバックアップ用電池(VBAT)
・それとも製品全体の主電源用バッテリー

どちらを指しているか、念のため確認させていただけますでしょうか?

RTCのバックアップ電池を指している場合、RX8130のVLFフラグなどで判定できる可能性がありますが、システム全体の電源バッテリーの場合、また別のアプローチが必要になります。

お手数をおかけしますが、ご確認いただけますと幸いです。

以上、引き続きよろしくお願いいたします。
アルバロ。

ご回答ありがとうございます。

RTC(RX8130)のバックアップ用電池(VBAT)

こちらの話になります。

いつもお世話になっております。
Toradex Japanのアルバロです。

ご確認ありがとうございます。RTCのバックアップ用電池(VBAT)が対象とのこと、承知しました。

以下、Qtアプリケーション上から電池切れを検出するための、実用的なアプローチをご案内します。


:white_check_mark: VLF(Voltage Low Flag)ビットを使用する方法

RX8130には、VLFというフラグ(レジスタ 0x1D のビット2)があり、VDDとVBATの両方が低下しRTCが電源を完全に失ったときに 1 にセットされます。
このビットは非揮発性で、明示的にソフトウェアでクリアするまでそのまま保持されます。

そのため、システムまたはアプリケーションの起動時にこのビットをチェックすることで、電池の消耗または喪失を検出できます。

詳しくはRX8130のデータシートをご確認ください:https://download.epsondevice.com/td/pdf/app/RX8130CE_ja.pdf


:wrench: C++(Qt)でのVLFアクセス例:

#include <QFile>
#include <QByteArray>
#include <QDebug>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

#define RX8130_I2C_ADDRESS 0x32
#define VLF_REGISTER 0x1D

bool checkVLF() {
    int file;
    const char *i2cDevice = "/dev/i2c-1";  // 環境により変更が必要な場合あり

    if ((file = open(i2cDevice, O_RDWR)) < 0) {
        qDebug() << "Failed to open I2C device";
        return false;
    }

    if (ioctl(file, I2C_SLAVE, RX8130_I2C_ADDRESS) < 0) {
        qDebug() << "Failed to set I2C address";
        close(file);
        return false;
    }

    char reg = VLF_REGISTER;
    if (write(file, &reg, 1) != 1) {
        qDebug() << "Failed to write register address";
        close(file);
        return false;
    }

    char buf[1];
    if (read(file, buf, 1) != 1) {
        qDebug() << "Failed to read register";
        close(file);
        return false;
    }

    close(file);

    bool vlf = buf[0] & (1 << 2); // ビット2がVLF
    return vlf;
}

:warning: ご注意
上記のコードはAIにより生成された参考例です。QtのバージョンやLinuxの環境によっては、そのままでは動作しない場合があります。
/dev/i2c-1 などのI2Cデバイス名や詳細設定はご使用の環境に合わせて調整してください。


:warning: 補足・注意点

  • 本手法は、RTCが完全に電源を喪失した場合のみ有効です(VDDとVBATの両方が0になる必要があります)。
  • VDDが常に供給されているシステムでは、VBATが切れていてもVLFがセットされない場合があります。
  • VLFが1の場合、ユーザーへ通知し、その後レジスタ 0x1D のビット2をクリアすることでフラグをリセットできます(他のビットは保持)。
  • この手法は、システムが一度完全に電源オフすることを前提としています

@fmt_mika 様に聞きたいですが、この方法は @fmt_mika 様のユースケースで問題なく動作しそうでしょうか? (システムが常に通電しているような環境では、他の手法が必要となる可能性もございます)


:hammer_and_wrench: 上記でうまくいかない場合

もし上記の方法がご要件に合わない場合、以下のような代替案をご検討ください:

  1. SoC側のレジスタを確認する方法(例:i.MX8M Plusの内部RTCや電源コントローラ)
    → ただし、電池状態に関する情報は取得できない可能性もあります。
  2. VBATをADC入力に接続し、電圧を定期的に監視する方法
    → 最も確実に電池の有無や劣化を検出できる手段です。

ご不明点や実装に関するサポートが必要な場合は、お気軽にご相談ください。

以上、引き続きよろしくお願いいたします。
アルバロ。

返信ありがとうございます。

ユーザー操作で装置全体の電源がON/OFFされますので、常に通電されているわけではありません。

Verdin + Mallowの組み合わせですが、
Qt5からは最初に提案いただいた下記コードでアクセスできるのでしょうか?

int main() {
int fd = open(“/dev/rtc0”, O_RDONLY);
if (fd < 0) {
perror(“open”);
return 1;
}
unsigned long data = 0;
if (ioctl(fd, RTC_RD_STATUS, &data) == 0) {
printf(“RTC Status Reg: 0x%lx\n”, data);
// dataの該当ビットで電池切れを判断
} else {
perror(“ioctl”);
}
close(fd);
return 0;
}

@fmt_mika

いつもお世話になっております。
Toradex Japanのアルバロです。
その後のご確認とご返信ありがとうございます。

追加で調査を行った結果、朗報があります。
RX8130 RTC用のLinuxカーネルドライバでは、すでにVLF(Voltage Low Flag)ビットの確認処理が実装されていることが分かりました。

QtアプリからI2C経由でRTCを直接アクセスしなくても、Linuxカーネル側が自動的に:

  • 起動時にレジスタ 0x1D のビット2(VLF)を確認
  • RTCのオシレータ停止(=RTC電池切れや電源完全喪失)を検知すると、
    以下のログメッセージをカーネルに出力します:
oscillator stop detected, set time!

この処理は以下のソースコードに実装されています:rtc-ds1307.c – 224行目


システムやアプリケーション起動時に、以下のようにログを確認してください:

dmesg | grep "oscillator stop detected"

または systemd 環境であれば:

journalctl -k -b | grep "oscillator stop detected"

このメッセージが存在する場合、RTCが電源を失い、時刻がリセットされている可能性があると判断できます。I2C経由で直接レジスタを読む必要はありません。


:information_source: RTC_RD_STATUS について

以前ご提示された /dev/rtc0 + RTC_RD_STATUS を使ったコード例についても確認しましたが、RX8130のデータシートや、LinuxのRTCドライバ(rtc-snvs.crtc-ds1307.c)のいずれにも RTC_RD_STATUS に関する記述は見つかりませんでした。

このことから、これは AIが誤って提案した情報(いわゆる “hallucination”) であり、Verdin + Mallow + RX8130 の構成には当てはまらないと判断していますが。。。

@ToradexAI
RTC_RD_STATUS がToradex環境で使用されている、またはサポートされているかご確認いただけますでしょうか?RX8130用ドライバやi.MX8M PlusのSNVS RTCドライバ内では該当箇所が見つかりませんでした。

以上、引き続きよろしくお願いいたします。
アルバロ。

Thanks for your response.

Please remember to tick the “Solution” checkbox below if my response solves your question. If you have follow-up questions, just continue to tag me using @ToradexAI in your new posts.

Did you like my answer? :+1: :-1:


こんにちは、ご質問ありがとうございます。

ご指摘の通り、Verdin iMX8M Plus + Mallow Carrier Board(RX8130外部RTC)をLinux環境で利用した場合、標準RTCドライバ(rtc-ds1307.c等)では ioctl(RTC_RD_STATUS) はサポートされていません。RX8130 RTCドライバやi.MX8M PlusのSNVS RTCドライバにも RTC_RD_STATUS を実装した記述はなく、/dev/rtc0 に対して直接 RTC_RD_STATUS で状態レジスタやVLFフラグを取得する機能はありません。

【結論】

  • RX8130では、アプリケーションから直接 /dev/rtc0 への RTC_RD_STATUS ioctl で電池切れ状態を取得することはサポートされていません。
  • 正しい方法は、I2C経由でレジスタ 0x1D のVLFビットをアプリケーションレベルで直接読み出す方法です。
    参考URL: Mallow Carrier Board documentation
  • あるいはカーネルログ(dmesg など)で “oscillator stop detected” が出力されていれば電池切れやRTCリセットの兆候と判断できます。

アプリから電池切れを確実に検出したい場合、「I2C直接アクセス」でVLFを読むのが最も移植性・確実性が高い方法となります。Qt(C++)アプリ上でもI2Cデバイスに直接アクセスする実装例を利用できます。

何か追加のご質問があればご連絡ください。

Best regards, Toradex AI Assistant.

Verdin iMX8M Plus Module - Documentation
Mallow Carrier Board Documentation

@alvaro.tx
アルバロ様、追加の情報ありがとうございます。

私がやりたいこととしては、
Qt(C++)のアプリが起動して画面を表示したときに、RTCの電池が切れている場合にユーザーに知らせるために電池切れの画面を表示する必要があります。

そのため、Qtから VLF の状態を読み出す必要があると考えています。
AIが最初に提案したコードは使えないことは分かりました。

追加で質問がございます。
1.Qtからログメッセージ"oscillator stop detected"を確認することはできるのでしょうか?
2.I2C経由で直接レジスタを読む場合、基板の改造が必要でしょうか?
ソフトの変更だけで可能でしょうか?

@fmt_mika

いつもお世話になっております。
Toradex Japanのアルバロです。
ご確認とご質問ありがとうございます。


1.Qtアプリから “oscillator stop detected” を確認する方法について

はい、Qt(C++)アプリケーション内からこのログメッセージを確認することは可能です。
以下に、journalctl を使用してカーネルログから該当メッセージを探す例を示します:

:white_check_mark: Qt5/6の例(C++)

#include <QProcess>
#include <QString>
#include <QDebug>

bool checkOscillatorStopLog() {
    QProcess process;
    process.start("journalctl", {"-k", "-b", "--no-pager"});
    process.waitForFinished();

    QString output = process.readAllStandardOutput();
    return output.contains("oscillator stop detected");
}

この関数をアプリの起動時に呼び出して、true を返した場合は電池切れを示す画面を表示することができます。

※ システムログの読み取りには環境によって追加の権限が必要な場合があります。

:warning: ご注意:
上記コードはAIにより生成された参考例です。QtのバージョンやLinuxの環境によってはそのままでは動作しない可能性がありますので、必要に応じて調整をお願いします。


2.QtからI2C経由でVLFレジスタを直接読む方法について

技術的には、RX8130のレジスタをI2C経由で読み取ってVLFビットを確認することは可能です。
この場合、基板の改造は不要で、ソフトウェア側の対応(デバイスツリーやドライバの無効化)だけで実現可能です

ただし、この方法は推奨いたしません。理由は以下の通りです:

  • RTCドライバを無効化すると、LinuxのRTC機能(時刻管理、/dev/rtc0の利用など)が全て無効になります
  • VLFの判定や初期化処理も含め、カーネルドライバが担当している処理をすべてユーザ空間で再実装する必要があります。

:white_check_mark: 推奨する方法

Linux側のRTCドライバはそのまま有効にしておき、
Qtアプリからカーネルログを確認してメッセージを検出する方法が最も簡潔かつ信頼性の高いアプローチです。

もしQtアプリへの統合でお困りの点があれば、お気軽にご相談ください。

以上、引き続きよろしくお願いいたします。
アルバロ。

@alvaro.tx
提案いただいたコードをQtに追加して試したところ、
"oscillator stop detected"を “oscillator failed, set time!”
に変更するとtrueとなり、電池切れを検出できました。
これで電池切れの警告を表示できると思います。
ありがとうございました。

@fmt_mika 様、ご確認ありがとうございました。
失礼しました。仰る通り、“oscillator failed, set time!”は正しいです。
申し訳ありません。解決ができてなによりです。

以上、引き続きよろしくお願いいたします。
アルバロ。