🕰️
M5Stack LLM630 Compute Kit で I2Cのテスト
はじめに
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