🕰️

M5Stack LLM630 Compute Kit で I2Cのテスト

2025/01/25に公開

はじめに

LLM630にはGroveポートが2つついていて、赤い方はI2Cが使用できます。
どんな感じで使えるか調べてみる覚書。

結論:使用できるアドレスは限定的だけど動いた。

ちょっと調べる

/dev/i2c-0と/dev/i2c-1が有効化されててGroveのport.Aに入ってるのはi2c-1の方。
とりあえず使えそうなアドレスは0x30~0x35,0x37,0x50~0x5fということでよいのかな。

いろいろなI2Cデバイスをつなげてみたけど、つないで範囲内にアドレス表示されたのがRTC8563だけ。
範囲内のアドレスを持ってるはずの ULTRASONIC I2C(0x57)とNCIR MLX90614(0x5A)はなぜか表示されなかった。謎。

RTC8363を使ってみる

結論から言うとsmbus2を使ってさっくりI2Cが動きました。
実行するとこんな感じ

root@m5stack-kit:/home/workspace/rtc# python3 rtc.py -jst
NTP Time (JST): 2025-01-25 14:42:10
RTC time set successfully!
root@m5stack-kit:/home/workspace/rtc# python3 rtc.py -utc
NTP Time (UTC): 2025-01-25 05:42:21
RTC time set successfully!
root@m5stack-kit:/home/workspace/rtc# python3 rtc.py -cst
NTP Time (CST): 2025-01-25 13:42:24
RTC time set successfully!

地味💦

コード

適当な作業用ディレクトリを作って作業。今回は以下の通り。
/home/workspace/rtc

ちなみに、pythonは3.10が入ってます。

root@m5stack-kit:/home/workspace/rtc# python3 --version
Python 3.10.12

コードを適当に作ってもらって動かしてみました。
必要なモジュールは以下の通り

pip install smbus2
pip install ntplib

以下のコードで動きました。

import smbus2
import ntplib
import time
from datetime import datetime, timedelta
import argparse

# I2C バス番号と RTC アドレスを指定
I2C_BUS = 1
RTC_ADDRESS = 0x51  # RTC8563 の I2C アドレス

# SMBus の初期化
bus = smbus2.SMBus(I2C_BUS)

# BCD エンコード関数
def to_bcd(value):
    return (value // 10) << 4 | (value % 10)

# RTC8563 に時刻を書き込む関数
def set_rtc_time(year, month, day, hour, minute, second):
    data = [
        to_bcd(second),
        to_bcd(minute),
        to_bcd(hour),
        to_bcd(day),
        0,  # 曜日(ここでは使用しない)
        to_bcd(month),
        to_bcd(year - 2000)  # 年は 2000 年基準
    ]
    # レジスタ 0x02 から書き込み
    bus.write_i2c_block_data(RTC_ADDRESS, 0x02, data)
    print("RTC time set successfully!")

# NTP サーバーから時刻を取得する関数
def get_ntp_time():
    try:
        # NTP クライアントの初期化
        client = ntplib.NTPClient()
        response = client.request("ntp.nict.jp", version=3)  # 日本のNTPサーバー
        utc_time = datetime.utcfromtimestamp(response.tx_time)
        return utc_time
    except Exception as e:
        print(f"Failed to get NTP time: {e}")
        return None

# タイムゾーンに合わせた時間を計算する関数
def convert_to_timezone(utc_time, timezone):
    if timezone == 'jst':
        return utc_time + timedelta(hours=9)
    elif timezone == 'pst':
        return utc_time - timedelta(hours=8)
    elif timezone == 'est':
        return utc_time - timedelta(hours=5)
    elif timezone == 'cst':
        return utc_time + timedelta(hours=8)
    elif timezone == 'utc':
        return utc_time  # UTC は変換不要
    else:
        return utc_time

# メイン処理
def synchronize_rtc_with_ntp(timezone=None):
    # NTP の現在時刻を取得
    current_time = get_ntp_time()
    if current_time:
        # タイムゾーンに合わせて時刻を変換
        if timezone:
            current_time = convert_to_timezone(current_time, timezone)
            print(f"NTP Time ({timezone.upper()}):", current_time.strftime("%Y-%m-%d %H:%M:%S"))
        else:
            print(f"NTP Time (UTC):", current_time.strftime("%Y-%m-%d %H:%M:%S"))
        
        # RTC に時刻を書き込む
        set_rtc_time(
            year=current_time.year,
            month=current_time.month,
            day=current_time.day,
            hour=current_time.hour,
            minute=current_time.minute,
            second=current_time.second
        )
    else:
        print("Failed to synchronize RTC with NTP")

# エントリーポイント
if __name__ == "__main__":
    # コマンドライン引数の解析
    parser = argparse.ArgumentParser(description="Synchronize RTC8563 with NTP server")
    parser.add_argument("-jst", action="store_true", help="Synchronize to Japan Standard Time (JST)")
    parser.add_argument("-pst", action="store_true", help="Synchronize to Pacific Standard Time (PST)")
    parser.add_argument("-est", action="store_true", help="Synchronize to Eastern Standard Time (EST)")
    parser.add_argument("-cst", action="store_true", help="Synchronize to China Standard Time (CST)")
    parser.add_argument("-utc", action="store_true", help="Synchronize to Universal Time Coordinated (UTC)")
    args = parser.parse_args()

    # 引数に応じてタイムゾーンを設定
    if args.jst:
        timezone = 'jst'
    elif args.pst:
        timezone = 'pst'
    elif args.est:
        timezone = 'est'
    elif args.cst:
        timezone = 'cst'
    elif args.utc:
        timezone = 'utc'
    else:
        timezone = None  # デフォルトは UTC
    
    # RTC を同期
    synchronize_rtc_with_ntp(timezone)

Discussion