Linux

【Zynq7】実践2.温度センサをPython+Dockerで使う【I2Cデバイス編】

1.記事一覧

記事は複数回に分けて投稿します。XilinxのARM SoC (Zynq7020SoC)で動作する、PetaLinuxを使わない素のLinuxをソースコードから構築する記事の続編です。

ZynqMP(arm64版)はこちら

エッジArm Linux構築編(Armv7)

エッジArm Linux実践編(Armv7)

2.【概要】LinuxでI2Cデバイスを使ってみる【中編】

2-1. 概要

前回はI2CデバイスのRTCをLinuxのHwclockとして使えるようにブートローダ(FSBL)の設定とカーネル再ビルド、デバイスツリー定義を行い、RTCを認識させました。中編では他に接続したI2Cの温度センサを使用した表示アプリをPythonで実装してみたいと思います。

今回使用する温度センサ(ADT7410)は秋月電子で売られているもので、Web上にサンプルコードが多く存在します。

今回開発PCでDockerを使用するため、Zynq のArm Linux側でもDockerを動かしてみたいと思います。

2-2. Pythonのパッケージ管理は仮想環境venv VS コンテナどちらにすべきか

ところで、Pythonistaの方はご存知と思いますが、パッケージバージョン管理として仮想環境Anacondaやvenvなどを使用すると思います。しかし、私はDockerコンテナを使用しています。理由を説明します。

pythonの仮想環境は今までに乱立してきた歴史があります。詳しくは以下のqiitaの参考記事がわかりやすいです。

qiita: pyenv、pyenv-virtualenv、venv、Anaconda、Pipenv。私はPipenvを使う。
qiita: 2021年のPython仮想環境〜いまやvenvを使わない理由はありません〜

正直私もPythonを久しぶりに使うときは「python 仮想環境 2020」などのWeb検索を掛けて動向や仕組み、注意点の詳細を調べるなどをしていました。昔ですが、pip、venv、Anacondaを共存させてパッケージ管理をした結果、python実行環境が破壊され修復不可能になったことがあります。UbuntuのようなPythonがOSの一部機能を担っているものだと、最悪OS再インストールする自体になるケースがありました(そもそもsystemのpythonをいじってはいけないのですが)。そのようなこともあり、仮想環境は干渉しないよう、下調べをするのが日課になったのですが、いかんせん乱立しすぎて面倒になりました。

そこで、コンテナ仮想環境に素の状態のpython3+pipを入れる方法にしました。python本体のver切替えのpyenvは使用したりしますが、ほぼ素の状態です。コンテナを消せばすべてきれいになくなります。ホストPCを汚さないのは大変嬉しいです。本格的な開発をするとメリデメは今後多く見つかってくると思いますが、経験としてとりあえずやっています。

3.環境

今回使用する環境です。

開発PCUbuntu20.04
ターゲットボードDigilent社製 Zybo z7-20
SoC:Xilinx社 Zynq7020 armv7hf (Cortex-A9×2、666MHz)
SDRAM:DDR3 1GB
u-boot:v2022.01
Linux Kernel: v5.15
RootFs:Ubuntu22.04 jammy armv7l ←注!構築時からVer上げてます。
I2C:温度センサADT7410(Analog Devices製)
秋月電子で購入しました。
秋月温度センサモジュール取説
データシート
コンテナ基盤開発PC:Docker Engine 23.0.1 x64
ターゲットボード:Docker Engine 23.0.1 armv7

後編の流れです。

  1. デバイスの配線←前回記事参照
  2. Docker Python環境の構築
  3. Pythonライブラリ(モジュール)のインストール
  4. 温度センサADT7410ライブラリの実装

4.開発環境準備

4-1. VSCodeのRemoteSSHでターゲットボードと接続

Zyboz7ボードがSSH接続できているので、”Remote Development”拡張を入れてVSCodeをボードに接続します。これを使用するとボード上でVSCodeを開いてファイル編集をしているように開発できます。やり方は説明しませんが、いくつかポイントだけ上げていきます。

【①vscode-serverが起動できないとき】
RemoteSSHはサーバ側でvscode-serverが起動し、ファイル・フォルダ編集操作を中継します。ターゲットボードに初回接続したときはボード上にvscode-serverを自動でインストールしようとします。今回自動インストール後に起動失敗したので、原因を調べました。ちなみにですが、armv7版対応しています。

SSHでターゲットボードにログインし、
~/.vscode-server/.5e805b79fcb6ba4c2d23712967df89a089da575b.log
のような.logファイルを開いて調べます。

Bash
$ less ~/.vscode-server/.5e805b79fcb6ba4c2d23712967df89a089da575b.log
"/home/zynq/.vscode-server/bin/.../node:error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directory"

libatomic.so.1が無くてNode.jsが実行できないようです。

libatomic.so.1をボード側にインストールします。これで起動しました。

Bash
zynq$ sudo apt-get install libatomic1

【②vscode-serverの負荷軽減】
ファイル変更監視が有効になったままだと、ボード側の負荷が上がります。手動更新に切替えます。以下のサイトがわかりやすいです。
【VSCode使用者注意】サーバーリソース食い散らかすマンから解放される唯一の方法

【③vscode-serverの削除】
userフォルダ以下にある、”~/.vscode-server/”を消すだけです。

4-2. Docker-Python環境の構築

コンテナ基盤のDocker Engineを構築済みと仮定します。構築方法は別記事で解説します。今回のようなLinuxカーネルをソースからビルドした環境の場合はカーネルの機能が足りない場合があるので、Dockerはすんなり動いてくれません。構築の手間がかなりかかります。

開発用コンテナイメージをbuildします。ベースイメージはdebian:stable-slimを使用します。SDRAM1GBしかありませんが、無事ゆっくりながらもビルドできました。

コンテナを起動します。コマンド例を置いておきます。--device引数でi2cのデバイスファイルをコンテナと共有します。

Bash
$ docker run -v "/home/zynq/:/home/share" --device=/dev/i2c-0:/dev/i2c-0 --name "py-sensor-app" -it "debian/sample" /bin/bash

コンテナに入り、python3とpipをインストールします。ちなみにボードのホストOSのUbuntu22.04ではpipのaptパッケージが見つからなかったですが、debian:stable-slimコンテナのaptではありました。(理由は気が向いたら調べます。ただそもそもホストOSのpythonをいじるのは良くないので)

Bash
$ sudo apt install python3 python3-pip

4-3. Pythonライブラリのインストール(smbus2)

i2cバスにアクセスするためのドライバライブラリをインストールします。
root権限が必要です。i2cのデバイスファイルopenにroot権限を使用するので、sudoをつけてライブラリのインストールパスをlocal側ではなくroot側にします。

Bash
$ sudo pip3 install smbus2

smbusはI2Cベースのプロトコルです(SystemManagementBus)。

5.温度センサから温度を読み出す

5-1. 温度センサADT7410のスペック

  • Analog Devices製
  • 測定温度範囲:±0.5℃@-40℃~+105℃(2.7V~3.6V)
  • 温度分解能:0.0078℃(16ビット設定時)/0.0625℃(13ビット設定時)
  • サンプリングモード:連続変換、1ショット、1Hzサンプリング、シャットダウン
  • 温度アラーム:高温、低温超過アラーム割込み

5-2. 初期設定値の調査

データシートを調べて初期化処理に必要な情報を集めます。(一部抜粋)

Configurationレジスタ(アドレス0x03)の初期値Default Valueを見ると、

  • Operation mode=連続AD変換モード。温度を連続してサンプリングし続ける
  • Resolution=分解能13bit。セルシウス温度で0.0625℃

とあるので、特に何も初期設定値を書き込まなくても13bitモードで温度を計測し始めていることがわかります。精密な温度測定を行いたい場合、気をつけないといけないのが温度センサ自身の発熱による温度バイアスがかかることです。連続AD変換をしていると、センサの消費電力が増え、温度測定値が少し上がります。対策として1ショットAD変換や1HzAD変換のようなモードを使用してセンサの発熱を抑える必要があります。

今回は測定精度を求めないのでサンプリングはこのままの設定値で行きます。

5-3. 温度センサ読み出しを実装

温度値が入っているレジスタは2つです。レジスタアドレス0x00,0x01で0x00がMSB(most significant byte)側です。レジスタアドレス0x00を指定して2byte読み出します。

16bitの場合は128で割った値がセルシウス温度になります。
13bitの場合は左詰めになっていて右3ビットシフトしてから16で割った値がセルシウス温度になります。

I2C転送パケットですが、I2Cスレーブアドレス、レジスタアドレス、レジスタ値の順で贈ります。

以下の機能を実装しました。使用しているモジュールはsmbus2です。

  • 温度読み出し
  • 分解能13/16bit切り替え

実行結果

ABOUT ME
sh-goto
低レイヤで遊んでいます
関連記事