リアルタイムクロックによるマイクロコントローラシステムへの正確な計時機能の追加
要約
マイクロコントローラのMAXQ610は、バッテリバックアップされたリアルタイムクロック(RTC)を内蔵していませんが、1-Wire®ネットワークのフレキシビリティにより、DS1904 RTC iButton®をMAXQ610ベースのアプリケーションに容易に追加することができます。DS1904との通信、クロックと制御の値の設定、および時刻の値と生の計時の値との変換は、たとえアセンブリ言語を使用するとしても、MAXQ610の機能で十分に対応可能です。このアプリケーションノートでは、MAXQ610ベースのアプリケーションにRTC機能を追加する方法を説明します。このアプリケーションを実装するためのデモコードを示します。この記事で説明する原理と手法は、1-Wire通信プロトコルの駆動が可能な汎用I/O (GPIO)端子を備えた他のMAXQ®ベースのマイクロコントローラにも同様に適用することができます。
この記事の類似バージョンが「Chip Design」誌の2012年3月1日号に掲載されています。
はじめに
多くのマイクロコントローラはタイマー回路を内蔵していますが、バッテリでバックアップされたリアルタイムクロック(RTC)を内蔵しているものはわずかです。しかし多くのアプリケーションはRTCを必要としているので、1-Wireネットワークを使用すれば容易にRTCを追加することができます。この記事では、1-WireプロトコルをサポートするRTCをマイクロコントローラベースのシステムに追加する方法を説明します。必要なコードは含まれています。1-Wire通信プロトコルの駆動が可能な汎用I/O (GPIO)端子を備えた任意のマイクロコントローラにも同様に適用することができる原理と手法について説明します。
設計目標
このデモは、1-Wireインタフェースを使用して以下の操作を実行するための実装方法を示しています。
- 選択したRTCの64ビットROM IDの読取り
- RTCの始動と停止
- RTCの現在値の読取り
- RTCの新しい値の設定
また、このデモは現在のRTCの値を読取り可能な形式(すなわち、生の秒数から年/月/日/時刻の形式に変換して)で表示します。ユーザーは秒数に相当する新しい値を計算して入力するのではなく、変換後のさまざまな値(たとえば年、月、日)を1ずつ加算して時計の値を変更することができます。
日付/時刻の値を秒数で格納するすべてのアプリケーションにおいて、ゼロのベースラインを選択する必要があります。このアプリケーションの場合、そのベースラインは2000年1月1日、午前12時00分00秒であり、その値に相当する生の秒数がゼロ(00000000h)です。
システムのセットアップ
1-Wireインタフェースは、この記事にとって必須です。それによって、1-WireプロトコルをサポートするRTCを任意のマイクロコントローラに追加することができます。この例では、DS1904 RTC iButton®を使用します。RTCとの通信、クロックと制御値の設定、および生の秒数と日付の間の変換がアセンブリ言語を使用する場合でも容易なため、このアプリケーションではMAXQ610マイクロコントローラを使用します。
低電力のMAXQ610はポータブルアプリケーションに最適ですが、バッテリバックアップされたRTCを備えていません。しかし、そのGPIO端子の1つを使用することによって、このマイクロコントローラを専用のRTCに接続することができます。このマイクロコントローラ用のデモコードは、アセンブリ言語ベースのMAX-IDE環境を使用して記述されました。コードはマキシムの評価(EV)キットMAXQ610-KITで動作するように設計されています。ソースコード、プロジェクトファイル、およびその他のドキュメントがすべてダウンロード用に提供されています。
アプリケーションの実行
デモコードの実行には、以下のハードウェアが必要です。
- MAXQ610-KITのEVキット
- 5V DC電源
- シリアル-JTAGまたはUSB-JTAGインタフェースボード
- JTAGプログラミングケーブル(0.100インチのピンコネクタを備えた2 × 5リボンケーブル)
- ストレートDB9シリアルインタフェースケーブル
- 空きCOMポートまたはUSB-シリアルアダプタを備えたPC
- DS1904L-F5# RTC iButton
- DS9094F+スルーホールマウントiButtonクリップ
コードはMAXQ610のEVキットで動作します。iButtonクリップ(DS9094F+)をプロトタイピング領域に実装し、DS1904L-F5# RTC iButtonをiButtonクリップに装着します。次に、iButtonクリップからの接続を行います。
- iButtonクリップのGROUND端子(DS1904の背面のラベルのない側に接触するクリップ上部の「+」と表示されたピン)を、MAXQ610のEVキット上のGNDテストポイントの1つに接続します。
- iButtonクリップのDATA端子(DS1904の前面/ラベルのある側に接触するクリップ内側のピン)を、MAXQ610のEVキット上のポートピンP2.0 (ヘッダピンP3.1)に接続します。
また、以下のソフトウェアも必要です。
- MAXQマイクロコントローラ用のMAX-IDEアセンブリ言語開発環境
- マイクロコントローラツールキット(MTK)または「ダムターミナル」モードを備えたその他の端末エミュレータ
MAX-IDE環境の最新のインストールパッケージおよびドキュメントは、当社の「MAXQ RISCマイクロコントローラ」のページで入手可能です。
RTCのデータは1-Wireプロトコルを使用してシリアル形式で転送されます。1つのデータリードとグランドリターンのみが必要です。このRTCには、出荷時にROMにレーザー書込みされる64ビットの固有IDとバイナリカウンタとして実装されたRTC/カレンダーが内蔵されています。汚れ、湿度、および衝撃に対する耐性を備えた、高耐久性のMicroCanパッケージに実装されています。このパッケージは、プリント基板(PCB)やプラスチックキーフォブを含む、ほぼすべての物の表面に実装することができます。動作時に、このRTCは任意の電子機器またはマイクロコントローラを使用する組込みアプリケーションに、カレンダー日付、時刻/日付スタンプ、ストップウォッチ、時間メーター、インターバルタイマー、およびログブック機能を追加します。
このRTCは分解能1秒の32ビットカウンタを内蔵しており、約136年間の計時を提供します。32kHzの水晶およびバッテリを含む、クロック動作を維持するために必要なすべてのハードウェアが内部に密封されています。その結果、このデバイスは10年以上の動作寿命を備え、クロック精度は+25℃の室温において月差約±2分です。動作モード(停止または動作)およびクロックカウンタの値は、1-Wireインタフェースを使用して読み書き可能です。
1-Wireネットワークの駆動
1-Wireインタフェースは、1つのワイヤと1つのグランドリターン上で電力と通信を提供します。すなわち、マイクロコントローラは1つのポートピンを使用して1-Wireセンサーと通信することが可能です。1-Wireネットワーク上で動作する各種のセンサーやその他のコンポーネントが開発されています。
1-Wireネットワークは、1つのマスターと複数のスレーブにより、マルチドロップ構成で動作します。タイミング要件はフレキシブルなため、すべてのスレーブが最高16kbpsの通信速度でマスターと同期することが可能です。個々の1-Wireセンサーはグローバルな固有の64ビットROM IDを備えているため、1-Wireマスターはネットワーク上での物理的な位置に関係なくスレーブを個別かつ正確に選択することができます。
1-Wireラインはオープンドレインモードで動作します。マスターは(スレーブの出力が要求された場合にはスレーブも)ラインをグランドにプルダウンすることで「0」を示し、ハイにフローティングさせることによって「1」を示します。通常、この動作はラインとVCCの間にディスクリートのプルアップ抵抗を接続することによって実装されます。ポートピンに弱プルアップモードを備えたマイクロコントローラ(MAXQ610など)の場合は、単にポートピンをそのモードに戻すことによってラインがハイにフローティングされるため、外付けの抵抗は不要です。マスターおよびスレーブはラインをローに駆動するのみで、アクティブにハイに駆動することはないため、1-WireネットワークはワイヤードOR構成で動作します。この方式により、複数のスレーブが同時に1-Wireバスに送信しようとした場合のラインの衝突が防止されます。
1-Wireネットワークを駆動するために、マイクロコントローラはソフトウェアを使用して1つのピン上でタイムスロットを生成します。すべてのタイムスロットは1-Wireマスターによって開始されるため、スレーブデバイスとの通信を行っていない場合、マイクロコントローラは1-Wireラインを監視する必要はありません¹。
- リセットタイムスロットの幅は、約1msです。タイムスロットの前半は、マスター(MAXQ610)が1-Wireラインをローに維持します。タイムスロットの中間点で、マスターは1-Wireラインを解放してハイにフローティングさせます。ライン上に存在するすべての1-Wireスレーブは、これに対する応答として自分自身をリセットして、タイムスロットの後半の間ラインをプルダウンします。次にスレーブはプレゼンスパルスを生成して、ライン上に1つ以上のスレーブが存在し、通信の準備が整っていることをマスターに通知します。
- 書込みタイムスロットの幅は60µs~120µsで、1つ以上のスレーブにビット(0または1)を送信するためにマスターによって使用されます。どちらのタイプの書込みタイムスロットも、マスターが少なくとも1µsの間ラインをローに駆動することによって開始されます。1を送信する場合、次にマスターはタイムスロットの残り時間にわたってラインを解放します(ハイにフローティングさせます)。0を送信する場合、マスターはタイムスロットの最後までラインをローに維持し続けます。
- 読取りタイムスロットの幅は60µs~120µsで、スレーブデバイスからビット(0または1)を読み取るためにマスターによって使用されます。タイムスロットは、マスターが少なくとも1µsの間ラインをローに駆動することによって開始されます。次にマスターはラインを解放して、スレーブがラインをローに維持するか(0)、またはハイにフローティングさせる(1)ことができるようにします。タイムスロットの中間点で、マスターはラインのサンプリングを行い、スレーブからのビット値を読み取ります。
MAXQ610は1µs当り約12命令サイクルで動作するため(12MHzでの動作時)、ポートピン(P2.0)を使用してソフトウェアで容易に標準1-Wireプロトコルを実行することができます。読取りタイムスロットも同様に実装されます。1-Wireバス上のすべてのデータバイトは最下位ビット(LSB)から順に送信されることに注意してください。
1-Wireバス上のプルアップ抵抗の値はネットワーク上のデバイスの数に応じて変化しますが、通常は4kΩ~5kΩと規定されています。これに対して、MAXQ610のポートピンの弱プルアップ抵抗は、動作電圧に応じて15kΩ~40kΩの範囲で変化します。1-Wireバスがロー状態からハイにフローティングするための時間が過大になるのを防ぐために、このコードではP2.0を通常の弱プルアップモードに設定する前に、短時間だけバスを(P2.0を介して)通常のハイ状態に駆動することにより、バスをハイ状態に「スナッピング(空吹かし)」しています。スレーブがバスをローに駆動しようとする可能性のあるタイミングで行わない限り、この操作が原因で1-Wireバス上に混乱が生じることはありません。別の方法として、1-Wireバスに物理的な外付けプルアップ抵抗を接続して、ゼロの状態の場合は標準のローモードでポートピンを駆動し、ハイの状態の場合はトライステートモードにすることもできます。
クロックの始動、停止、および設定
1-Wireバス上には2つ以上の1-Wireデバイスが存在する可能性があるため、これらのデバイスとの通信は2段階で進められます。最初にバスマスターが通信対象の1-Wireデバイスを選択し、次に通信を開始します²。バスマスターがリセットパルスを送信したあと、1-Wireバス上のすべてのスレーブデバイスがデフォルトの非選択状態に戻ります。次にバスマスターはいくつかのコマンドを利用して、第2段階で通信を行うデバイスを選択することができます。以下のコマンドは、個々のスレーブデバイスに関連付けられた64ビットROM IDを使用します。これらのコマンドは、すべての1-Wireデバイスによってサポートされています。
Skip ROM [CCh]
この1バイトのコマンドは、バス上のすべてのスレーブデバイスをアクティブ化します。このコマンドは、1つの1-Wireデバイスのみが存在する場合、またはバスマスターがバス上のすべての1-Wireデバイスに同一のコマンドを送信する必要がある場合に役立ちます。上記のアプリケーションでは、バス上に1つのデバイス(たとえば、DS1904 RTC)のみが存在するため、バスマスター(たとえば、MAXQ610マイクロコントローラ)はRTCに対する読み書きの前に、常にこのコマンドを使用してRTCをアクティブ化しています。
Read ROM [33h]
この1バイトのコマンドは、バス上のすべてのスレーブデバイスをアクティブ化し、それぞれの64ビットROM ID値をバスマスターに返信させます。このコマンドはすべてのスレーブデバイスをアクティブ化するため、単一スレーブのシステムでのみ使用可能です。それ以外の場合、複数のスレーブデバイスが同時にそれぞれのROM ID値を送信しようしようとして、データの衝突が発生することになります。デモアプリケーションではバス上に1つのデバイス(DS1904)のみが存在するため、MAXQ610は最初にこのコマンドを使用してDS1904のROM IDを読み取っています。
Match ROM [55h]
このコマンドは、1-Wireバス上の複数のスレーブの中から1つのスレーブを選択します。バスマスターはこのコマンドの送信後に、選択するスレーブデバイスの64ビットROM IDを続けて送信します。ROM IDが一致したスレーブデバイスはこれに応答する形でアクティブ状態に移行し、バス上の他のすべてのデバイスは非アクティブ状態に移行してバスマスターからの次の1-Wireリセットを待ちます(このコマンドは、ここで説明するアプリケーションでは使用されていません)。
Search ROM [F0h]
このコマンドによって、バスマスターは発見の手順を繰り返し使用して1-Wireバス上に存在する1つ以上のスレーブデバイスのROM ID値を判定することができます³ (このコマンドは、ここで説明するアプリケーションでは使用されていません)。
クロックおよび制御の値の読取りと書込み
バスマスターがSkip ROMまたはRead ROMコマンドを使用して1-Wireスレーブデバイス(すなわち、RTC、DS1904)を選択したあと、そのデバイスはデバイス固有の1-Wireコマンドを受け取ることができます。これらのコマンド(図1)について、以下で詳細に説明します。
Read Clock [66h]
このコマンドによって、バスマスターはDS1904のデバイス制御バイトと4バイト(32ビット)のRTC値の両方を読み取ることができます。デバイス制御バイトは、RTCを駆動する32kHzの発振器が動作しているか停止しているかを特定します。下記のコードが示すように、1つのコマンドのみでデバイス制御バイトとクロックの値の両方が読み取られます。両方の値が必要ない場合でも、デバイスにクロックデータを出力させるためには先にデバイス制御バイトを読み取る必要があります。
Write Clock [99h]
Read Clockと対になるこのコマンドによって、バスマスターはデバイス制御バイトおよびDS1904の4バイトのクロックカウンタに新しい値を設定することができます。新しい値を有効にするためには、5バイトすべてを書き込んだ上で、1-Wireリセットパルスを送信する必要があることに注意してください。上記のアプリケーションコードには、最初にDS1904から5バイトのデータ(1バイトのデバイス制御と4バイトのクロックカウンタ)を読み取り、次に適切な変更を加えたデータを書き戻すことによって、デバイス制御バイトとクロックの値を個別に設定するルーチンが含まれています。

図1. これらのDS1904のクロック機能コマンドは、データシートから引用しています。
時刻と日付の値の変換
生の秒数を印字可能な形式に変換するために、アプリケーションは個々の日付/時刻フィールド(年、月、日、時、分、および秒)の値を、最も大きいフィールド(年)から降順に、個別に判定して行きます。
- 秒数 ≥ (1年当りの秒数)の間、秒数から(1年当りの秒数)を引いて年に1を加えます。
- 秒数 ≥ (1カ月当りの秒数)の間、秒数から(1カ月当りの秒数)を引いて月に1を加えます。
- 秒数 ≥ (1日当りの秒数)の間、秒数から(1日当りの秒数)を引いて日に1を加えます。
- 秒数 ≥ (1時間当りの秒数)の間、秒数から(1時間当りの秒数)を引いて時間に1を加えます。
- 秒数 ≥ 60の間、秒数から60を引いて分に1を加えます。
- 残った秒数の値が、秒フィールドになります。
バスマスターがハードウェアで除算をサポートしている場合でも、最初の2つのフィールドの値(年と月)を計算するためには、単純な除算では不十分です。これは、うるう年(年と月の値に影響)および1カ月当りの日数(月にのみ影響)の影響によって、フィールドの単位当りの秒数が変化するためです。例として、2000年(うるう年)から計算を始めてみましょう。
- (2000年における1年当りの秒数) = 366 (日) × 24 (時間/日) × 60 (分/時間) × 60 (秒/分) = 31,622,400秒です。
- 通常の年の場合は1年の日数が1日少ないため(365日)、秒数/年が(31,622,400 - 86,400) = 31,536,000に変わります。
うるう年は4年に1回のため、次のように年を計算します(この擬似コード中の項目2、3、および4は同一であることに注意してください)。
- 秒数 ≥ (うるう年1年当りの秒数)である場合は、秒数から(うるう年1年当りの秒数)を引いて年に1を加え、それ以外の場合は終了します。
- 秒数 ≥ (1年当りの秒数)の場合は、秒数から(1年当りの秒数)を引いて年に1を加え、それ以外の場合は終了します。
- 秒数 ≥ (1年当りの秒数)の場合は、秒数から(1年当りの秒数)を引いて年に1を加え、それ以外の場合は終了します。
- 秒数 ≥ (1年当りの秒数)の場合は、秒数から(1年当りの秒数)を引いて年に1を加え、それ以外の場合は終了します。
- 1行目に戻ります。
月フィールドの値も、同様の方法で計算します。
- 秒数 ≥ (1月の秒数)の場合は、秒数から(1月の秒数)を引いて月に1を加え、それ以外の場合は終了します。
- 秒数 ≥ (2月の秒数)の場合は、秒数から(2月の秒数)を引いて月に1を加え、それ以外の場合は終了します。
- 秒数 ≥ (3月の秒数)の場合は、秒数から(3月の秒数)を引いて月に1を加え、それ以外の場合は終了します。
- 残りの月についても計算を続けます。
デモの実行
デモを実行するには、アプリケーションをロードして実行してください。次に、DB9シリアルケーブルを使用して、MAXQ610のEVキットのJ1 SKTとPCのCOM1を接続してください。MTK (または他の端末エミュレータ)を起動して、COM1を38400baudでオープンしてください。最初に、次のような内容が出力されます。
@ ID: 24B91231000000B2 AC 18F83065 + 18F83065 Apr 10 2013, 02:15:01 pm + 18F83066 Apr 10 2013, 02:15:02 pm + 18F83067 Apr 10 2013, 02:15:03 pm + 18F83068 Apr 10 2013, 02:15:04 pm + 18F83069 Apr 10 2013, 02:15:05 pm
このコードの2行目には、DS1904のROM IDの値(24B91231000000B2)、デバイス制御バイト(AC)、および現在のクロックの値(18F83065)が含まれています。後続の行の「+」という値は、クロックが動作していることを示します。時刻の値が変化するたびに更新と表示が行われるため、1秒に1回の出力となります。クロックを停止するには、「-」を押下してください。その時点で、追加のキーを押下することによってクロックの値を変更することができます。
クロックをスタートさせ、自動更新を再開します。 | ||
年の値に1を加え、月および日を01/01にリセットします。 | ||
月の値に1を加え、日を01にリセットします。 | ||
日の値に1を加えます(現在の月に応じてラップアラウンドします)。 | ||
時間の値に1を加えます。 | ||
分の値に1を加えます。 | ||
秒数カウンタを00にリセットします。 | ||
秒数カウンタをゼロにして、時刻を2001年1月1日、午前12時00分00秒にリセットします。 |
参考文献
- 1-Wireのタイミング要件の詳細については、DS1904 RTCのデータシートを参照してください。
- 以下のコマンドの詳細については、DS1904のデータシートを参照してください。
- 同上、japan.maximintegrated.com/DS1904。
参考資料
1 Refer to the DS1904 RTC data sheet for more details on 1-Wire timing requirements.
2 For more details on the following commands, please refer to the DS1904 data sheet.
3 Ibid., https://www.analog.com/en/products/ds1904.html