コンテンツにスキップ

RTC・Bluetooth

1.RTC

1.1. RTCの概要

RTCの正式名称は「Real-Time Clock」で、リアルタイムクロックチップを意味します。リアルタイムクロックチップは、ピンを通じて外部に時間の読み書きインターフェースを提供し、通常は独立したバッテリーで駆動されます。これにより、外部システムの電源が切れた場合でも、チップ回路が正常に動作し、時間が正確に刻まれることを保証します。クロックチップによって内部メカニズムは異なりますが、Linuxシステムのドライバは異なるクロックチップの操作の詳細をカプセル化し、アプリケーションに統一された時間操作インターフェースを提供しています。

1.1.1 開発ボードのRTCリソース

EASY EAI Nano-TBには、デフォルトでRTC回路が【搭載されていません】。ベースボードでRTC機能をサポートしたい場合は、当社のRTCモジュールを使用して【拡張】することができます。

開発ボードのRTCリソース

開発ボードのRTCリソース

RTC拡張の具体的な手順:

【まず】ベースボードの【電源を切り】、モジュールを【表を上にして】ベースボードの40PINインターフェースに挿入します。詳細は下図をご参照ください。

開発ボードのRTCリソース

開発ボードのRTCリソース

しっかりと挿入した後、【電源を入れます】。 lsコマンドを使用して、RTCチップがシステムに認識されているか確認できます。

Terminal window
ls /dev/rtc\*

開発ボードのRTCリソース

開発ボードのRTCリソース

ドライバが正常にロードされたことを確認した後、以下のコマンドでドライバにアクセスし、RTCチップの全情報を読み取ることができます。

Terminal window
cat /proc/driver/rtc

開発ボードのRTCリソース

開発ボードのRTCリソース

1.1.2 RTC時間の読み書き

ここには、RTCチップクロックとシステムクロックの2つのクロックが関与します。RTCクロックの手動管理の本質は、クロックの同期です(システムクロックをRTCチップクロックに同期させるか、RTCチップクロックをシステムクロックに同期させるかのいずれかです)。

システムクロック:

システムクロックの本質は64ビットの整数であり、この整数は現在のEpochTimeとの時間差(秒単位)を表し、タイムスタンプと呼ばれます。このクロックはCPUメインチップのタイマーによって維持され、CPUの電源が切れると時間情報は失われます。オペレーティングシステムのクロックコマンドはdate です。

Terminal window
date # システム時間の照会
date -s "2023-09-20 11:18:00" # システム時間の変更

💡 注意 :Epoch Time 特定の時間を指します。1970年1月1日0時0分0秒です。現在が1970年1月1日0時0分0秒からN秒経過していると仮定すると、Linuxシステム内での時間値はNとなります。

RTCチップクロック: RTCチップ内部で維持されている時間です。システムの電源が切れた後は、バッテリーによって電力が供給されます。そのため、システムの電源が切れてもRTC時間は正常に進み続けます。RTCチップクロックの役割は、Linuxが稼働していない時でも時間情報を保持することです。

チップクロックからシステムクロックへの同期:

Terminal window
sudo hwclock --hctosys

システムクロックからチップクロックへの同期(または sudo hwclock -w)

Terminal window
sudo hwclock --systohc

システムクロックに同期させず、RTCチップクロックのみを照会したい場合は、以下のコマンドを使用します。

Terminal window
sudo hwclock -r

チップクロックからシステムクロックへの同期:

チップクロックからシステムクロックへの同期:

1.1.3 システムクロックの読み書き

本ドキュメントでは【RTCクロック】**に重点を置いて説明しています。

1.1.4 タイムゾーンと時刻同期サービス

  • タイムゾーン: 【RTCクロック】と【システムクロック】はどちらもUTC時間を使用しています。異なる地域で使用される時間については、タイムゾーンの影響を考慮する必要があります。

  • 時刻同期サービス: 【RTCクロック】は手動で操作できるだけでなく、時刻同期サービスの影響も受けます。

1.2. クイックスタート

1.2.1 開発環境の準備

PC側のUbuntuシステムで runスクリプトを実行し、EASY-EAIコンパイル環境に入ります。詳細は以下の通りです。

Terminal window
cd ~/develop_environment

1.2.2 ソースコードのダウンロードとサンプルのコンパイル

まず、仮想マシンのバックグラウンドターミナルで以下のコマンドを実行し、周辺機器サンプルソースコードの管理ディレクトリを作成します:

Terminal window
cd /opt
mkdir -p EASY-EAI-Nano-TB/demo

サンプルプログラムをダウンロードします:

例えば、サンプルプログラムを「PC\D:」(指定はありません。ユーザーの任意の場所で構いません)にダウンロードします。

その後、ダウンロードしたサンプルを仮想マシンのファイルシステムにコピーします。手順は下図をご参照ください。

ソースコードのダウンロードとサンプルのコンパイル

ソースコードのダウンロードとサンプルのコンパイル

最後に、該当するサンプルのディレクトリに移動してコンパイル操作を実行します。具体的なコマンドは以下の通りです:

Terminal window
cd EASY-EAI-Nano-TB/demo/12_RTC
./build.sh

💡 注意 :依存ライブラリはボード上に配置されているため、クロスコンパイル中は/mnt のマウントを維持する必要があります。

ソースコードのダウンロードとサンプルのコンパイル

ソースコードのダウンロードとサンプルのコンパイル

コンパイルが成功すると、Release ディレクトリに test-rtcという実行可能プログラムが生成され、開発ボードの /userdata/ディレクトリに自動的に配置されます。

1.2.3 サンプルの実行

シリアルポートデバッグまたはSSH経由でボードのバックグラウンドにアクセスし、サンプルが配置されているディレクトリに移動します:

Terminal window
cd /userdata

サンプルの実行

サンプルの実行

以下のコマンドを実行してサンプルを起動します。

Terminal window
sudo ./test-rtc

実行結果は以下の通りです。

サンプルの実行

サンプルの実行

1.3. C言語での使用例

RTCのC言語での使用例です。コードのパスは 12_RTC/test-rtc/main.c です。コーディングの参考にしてください。以下のコードは、RTCクロックの読み書き操作のフローを示しています:

int main(int argc, char const *argv[]){
const char *strDateTime = "2023-09-21 15:22:37";
// 文字列をtm構造体タイプの時間情報に変換する
struct tm tm = {0};
strptime(strDateTime, "%Y-%m-%d %H:%M:%S", &tm);
// RTCデバイスを開く
int rtc_fd = open("/dev/rtc0", O_RDWR);
if (rtc_fd < 0) {
perror("open RTC device /dev/rtc0 faild.");
close(rtc_fd);
return -1;
}
printf("---パラメータ設定前の日時---\n");
system("date");
/*** 1. ネットワーク時刻同期サービスを停止 ***/
system("systemctl stop ntp.service");
/*** 2. 事前に設定した時間を【RTCクロック】に書き込む ***/
struct rtc_time rtc_tm;
rtc_tm.tm_sec = tm.tm_sec;
rtc_tm.tm_min = tm.tm_min;
rtc_tm.tm_hour = tm.tm_hour;
rtc_tm.tm_mday = tm.tm_mday;
rtc_tm.tm_mon = tm.tm_mon;
rtc_tm.tm_year = tm.tm_year;
if (ioctl(rtc_fd, RTC_SET_TIME, &rtc_tm) < 0) {
perror("set data time to rtc0");
perror("RTC時間の設定に失敗しました");
close(rtc_fd);
return -1;
}
/*** 3. 【RTCクロック】を【システムクロック】に同期させる ***/
// 先ほど書き込んだRTCクロックパラメータを読み出す
if (ioctl(rtc_fd, RTC_RD_TIME, &rtc_tm) < 0) {
perror("RTC時間の読み取りに失敗しました");
close(rtc_fd);
return -1;
}
close(rtc_fd);
tm.tm_sec = rtc_tm.tm_sec;
tm.tm_min = rtc_tm.tm_min;
tm.tm_hour = rtc_tm.tm_hour;
tm.tm_mday = rtc_tm.tm_mday;
tm.tm_mon = rtc_tm.tm_mon;
tm.tm_year = rtc_tm.tm_year;
struct timeval tv;
tv.tv_sec = mktime(&tm);
tv.tv_usec = 0;
// システムクロックに時間を同期
if(0 != settimeofday(&tv, (struct timezone *)0)){
perror("システム時間の設定に失敗しました");
}
printf("---パラメータ設定後の日時---\n");
system("date");
return 0;

2.Bluetooth

2.1. Bluetoothの概要

Bluetoothプロトコルスタックにおいて、Bluetoothのデータ転送には主に2つのプロトコルが使用されます。SPP(クラシックBluetoothシリアルポートプロトコル)とBLE(Bluetooth Low Energy プロトコル)です。

  • シングルモードBluetoothモジュール: SPPまたはBLEのいずれか一方のみをサポートします。

  • デュアルモードBluetoothモジュール: SPPとBLEの両方を同時にサポートします。

EASY-EAI-Nano-TBで採用されているBluetoothモジュールはDB37であり、これは【BLEプロトコルのみをサポートする】【シングルモード】のBluetoothモジュールです。

2.1.1 BlueZ

BlueZは現在最も成熟したオープンソースのBluetoothプロトコルスタックであり、GNU General Public License (GPL)に基づいてリリースされたオープンソースプロジェクトです。Linux公式のBluetoothプロトコルスタックとなっており(Linux2.4.6からLinuxカーネルの一部となっています)、主要なLinuxディストリビューションで広く応用されています。 つまり、「Linux上でどのようにBluetoothを使用するか?」=「どのようにBlueZを使用するか?」と理解して差し支えありません。

具体的に言うと、BlueZはLinuxが公式にサポートするオープンソースのBluetoothプロトコルスタック処理ツールセットであり、以下のツールが含まれています: bccmd, bluemoon, bluetoothctl, bluetoothd, btattach, btmon, ciptool, hciattach, hciconfig, hcidump, hcitool, hex2hcd, l2ping, l2test, mpris-proxy, rctest, rfcomm, sdptool。

2.1.2 事前準備

まず、BlueZをインストールします。

Terminal window
apt-get install bluez

BlueZが正常にインストールされたか確認します:

Terminal window
bluetoothctl -v

以下のようにバージョン番号が出力されれば、BlueZは正常にインストールされています。

事前準備

事前準備

hciconfigツールを利用することで、Bluetoothデバイスが正常に動作しているか確認できます。

Terminal window
hciconfig -a

事前準備

事前準備

2.2. Bluetoothツール

hci*系のツールは一般的にBluetoothプロトコルスタックのHCI層を直接操作するために使用されますが、新しいバージョンのBlueZツールセットでは徐々にメンテナンスされなくなっています。現在、Bluetoothデバイスを操作するための主流ツールは、bluetoothdおよび bluetoothctl です。

2.2.1 bluetoothd

これはBluetoothドライバを管理するための【アプリケーション層】のサービスであり、基本的には起動しておくだけで問題ありません。psコマンドを使用して、バックグラウンドで起動しているか確認できます:

Terminal window
sudo ps -ef \| grep -i bluetoothd

bluetoothd

bluetoothd

Ubuntuシステムでは、このプロセスを手動で起動・停止する必要はありません。systemctlサービスを通じて bluetoothd を管理します。bluetoothdサービスの起動/停止およびステータス確認のコマンドは以下の通りです:

Terminal window
sudo systemctl status bluetooth.service ## bluetoothdサービスのステータスを確認
sudo systemctl start bluetooth.service ## bluetoothdサービスを起動(再起動後は状態が保存されません)
sudo systemctl stop bluetooth.service ## bluetoothdサービスを停止(再起動後は状態が保存されません)
sudo systemctl enable bluetooth.service ## サービスを有効化(デバイス再起動後、bluetoothdが自動起動します)
sudo systemctl disable bluetooth.service ## サービスを無効化(デバイス再起動後、bluetoothdは自動起動しません)

2.2.2 bluetoothctl

D-Busを介して bluetoothd とやり取りするツールであり、bluetoothdサービスのクライアントに相当します。bluetoothctl は bluetoothdを介して間接的にBluetoothハードウェアを操作します。bluetoothctlにはシェルインタラクション機能が内蔵されており、コマンドラインで直接 bluetoothctlツールを実行すると、このツールの内部シェルに入ることができます。

bluetoothctl

bluetoothctl

helpと入力すると、このツールでサポートされているコマンドを確認できます。

bluetoothctl

bluetoothctl

Bluetoothチップの電源を入れるコマンド:

Terminal window
power on

Bluetoothチップの電源を入れるコマンド:

Bluetoothチップの電源を入れるコマンド:

advertiseサブメニューに入る: チップの名前を変更し、他のBluetoothマスター(ホスト)からスキャンして発見できるようにします。

Terminal window
menu advertise
name EASY-EAI-Nano-TB

advertiseサブメニューに入る:

advertiseサブメニューに入る:

その後、back コマンドで上位メニューに戻ります:

Terminal window
back

2.3. BLEプロトコル通信

BLE (Bluetooth Low Energy) はGATTに基づいています。

2.3.1 開発ボードをマスター(ホスト)とする場合

まず、【スマートフォン】のBluetoothデバッグアシスタントアプリを【スレーブとして設定】します:スレーブモードをオンにし、アドバタイズ(ブロードキャスト)を開始します。

開発ボードをマスター(ホスト)とする場合

開発ボードをマスター(ホスト)とする場合

次に、開発ボード側(bluetoothctl 内)で【スキャンの開始】【スキャンの停止】【デバイスの接続】を行います。

スキャンの開始:

Terminal window
scan on

ターゲットデバイスを発見した後、スキャンを停止:

Terminal window
scan off

スキャンされたデバイスを一覧表示(MACアドレスを見つける):

Terminal window
devices

ターゲットデバイスとのペアリング、信頼(Trust)、接続:

Terminal window
pair xx:xx:xx:xx:xx:xx
trust xx:xx:xx:xx:xx:xx
connect xx:xx:xx:xx:xx:xx

Bluetooth接続が成功した後、Bluetoothマスター(開発ボード)で gatt サブメニューに入ります:

Terminal window
menu gatt

キャラクタリスティック属性を確認:

Terminal window
list-attributes

(【BLEデバッグアシスタントアプリ】から、fff1 は【スレーブの送信】用、fff2 は【スレーブの受信】用であることがわかります)

スレーブ送信のキャラクタリスティック属性は以下の通りです:

Terminal window
Characteristic (Handle 0x0000)
/org/bluez/hci0/dev_78_C3_C4_C4_94_8D/service002f/char0030
0000fff1-0000-1000-8000-00805f9b34fb
Unknown

スレーブ受信のキャラクタリスティック属性は以下の通りです:

Terminal window
Characteristic (Handle 0x0000)
/org/bluez/hci0/dev_78_C3_C4_C4_94_8D/service002f/char0034
0000fff2-0000-1000-8000-00805f9b34fb
Unknown
2.3.1.1 マスター受信、スレーブ送信

まず、fff1 を選択します。

Terminal window
select-attribute /org/bluez/hci0/dev_78_C3_C4_C4_94_8D/service002f/char0030

次に、通知(notify)をオンにします。

Terminal window
notify on

マスター受信、スレーブ送信

マスター受信、スレーブ送信

その後、アプリを操作して、1ByteのHexデータを開発ボードへ送信します。

マスター受信、スレーブ送信 )

マスター受信、スレーブ送信

2.3.1.2 マスター送信、スレーブ受信

属性を fff2 に変更して選択します。

Terminal window
select-attribute /org/bluez/hci0/dev_78_C3_C4_C4_94_8D/service002f/char0034

その後、write 操作を実行します。

Terminal window
write 0x67

最終的に、アプリ上で開発ボードから送信されたデータを受信できます。

マスター送信、スレーブ受信

マスター送信、スレーブ受信

2.3.2 開発ボードをスレーブとする場合

サンプルプログラムをダウンロードします:

例えば、サンプルプログラムを「PC\D:」(指定はありません。ユーザーの任意の場所で構いません)にダウンロードします。

その後、bluetooth-gatt フォルダを開発ボードに転送し、開発ボードで新しいターミナルを開いて、gatt-server サービス(【マスター】と通信するためのアプリケーション)をコンパイルして実行します。

開発ボードをスレーブとする場合

開発ボードをスレーブとする場合

開発ボードをスレーブとする場合

開発ボードをスレーブとする場合

再び bluetoothctl に戻り、以下のコマンドを実行してBluetoothアドバタイズを開始します:

Terminal window
advertise on

開発ボードをスレーブとする場合

開発ボードをスレーブとする場合

【BLEデバッグアシスタントアプリ】を使用して、開発ボードのBluetoothをスキャンし、接続します。

開発ボードをスレーブとする場合

開発ボードをスレーブとする場合

2.3.2.1 マスター受信、スレーブ送信

【BLEデバッグアシスタントアプリ】から開発ボードのデータを読み取ります。

マスター受信、スレーブ送信

マスター受信、スレーブ送信

上記の操作を実行すると、開発ボード上の gatt-server に以下の情報が出力されます:

マスター受信、スレーブ送信

マスター受信、スレーブ送信

2.3.2.2 マスター送信、スレーブ受信

【BLEデバッグアシスタントアプリ】から開発ボードへデータを送信します。

マスター送信、スレーブ受信

マスター送信、スレーブ受信

開発ボード上の gatt-server は以下の情報を受信します:

マスター送信、スレーブ受信

マスター送信、スレーブ受信