本章では、Armadillo-400 シリーズのハードウェア機能をカスタマイズする方法について説明します。 2.1.1. コンソールとして別のシリアルインターフェースを使用するArmadillo-400シリーズは、標準状態でシリアルインターフェース1(CON3)をコンソールとして使用します。コンソールには、起動ログやカーネルメッセージなどが出力されるため、標準の設定ではシリアルインターフェース1に外部機器を接続して使用するといったことはできません。ここでは、コンソールとして別のシリアルインターフェースを使用する方法について説明します。例として、コンソールをシリアルインターフェース2(CON9_3、CON9_5)に変更します。 第1部「起動の仕組み」でも説明したように、コンソールに文字を表示するプログラムには、ブートローダー、Linuxカーネル、ユーザーランドアプリケーションプログラムの3種類があります。 まず、ブートローダーの起動ログとカーネルメッセージを出力する先を変更します。カーネルメッセージの出力先は、カーネルパラメータのconsole オプションで指定できます。カーネルパラメータは、ブートローダーのsetenvコマンドで設定します。ブートローダーは、console オプションが指定されている場合、それと同じシリアルインターフェースに起動ログを出力します。 カーネルパラメータを設定するには、Armadilloを保守モードで起動して、図2.1「コンソールをシリアルインターフェース2に変更する」のように、使用するシリアルデバイスのデバイスファイル名を入力します。シリアルインターフェースとデバイスファイルの対応は、「Armadillo-400シリーズ ソフトウェアマニュアル」の「UART」の章を参照してください。 現在のカーネルパラメータは、setenvコマンドを引数なしで実行することで確認できます。また、カーネルパラメータの指定を解除し、標準状態にもどすには、clearenvコマンドを使用します。 console=ttymxc2,115200 を指定した状態で起動すると、起動ログやカーネルメッセージなどはシリアルインターフェース2に出力されるようになります。但し、ログインプロンプトはまだシリアルインターフェース1に出力されます。
ログインプロンプトをシリアルインターフェース2に表示するには、/etc/inittab と/etc/securetty を修正する必要があります。標準の、Atmark Distで作成したユーザーランドの場合、/etc/inittab は図2.4「標準のinittab」のようになっています。3行目のttymxc1をttymxc2に変更すると、ログインプロンプトをシリアルインターフェース2に表示するようになります。また、/etc/securetty は図2.5「標準のsecuretty」のようになっています。ttymxc2 を追加すると、シリアルインターフェース2に表示されたログインプロンプトから、rootユーザーでログインできるようになります。 inittab やsecuretty を変更するには、ユーザーランドを再構築する必要があります。第1部「Atmark Distを使ったルートファイルシステムの作成」などを参照し、使用するプロダクト用に基本的な設定をして、一度ビルドしたAtmark Distを用意してください。そして、atmark-dist/vendors/AtmarkTechno/プロダク
ト名 /etc/inittab とatmark-dist/vendors/AtmarkTechno/プロダク
ト名 /etc/securetty を図2.6「ログインプロンプトをシリアルインターフェース2にしたinittab」、図2.7「シリアルインターフェース2からのrootログインを許可したsecuretty」に示すように修正してユーザーランドをビルドし、作成されたルートファイルシステムイメージ(romfs.img.gz)をArmadilloのフラッシュメモリのユーザーランド領域に書き込んでください。Armadilloを再起動すると、ログインプロンプトもシリアルインターフェース2に表示されるようになります。
ユーザーランドをDebian GNU/Linuxで構築している場合は、/etc/inittab のログインプロンプトに関連する部分は図2.8「Armadillo-400シリーズ用Debian GNU/Linuxのinittab(抜粋)」のようになっています。ログインプロンプトをシリアルインターフェース2に出力するには、ttymxc1をttymxc2に変更します。また、securetty は、図2.9「Armadillo-400シリーズ用Debian GNU/Linuxのsecuretty(抜粋)」のようになっているので、ttymxc2を追加します。 実際の製品においては、コンソールが使える事自体が問題となる場合もあるでしょう。コンソールへの出力を止めるのも、「コンソールとして別のシリアルインターフェースを使用する」と同様の手順で行うことができます。 コンソールへの出力を止めるには、カーネルパラメータのconsole にnone を指定します。 また、/etc/inittab のgettyに関する行は、削除するかコメントアウトします。/etc/securetty に関する設定は、ログインプロンプトを表示しなければ関係ないので、そのままで構いません[]。 Armadillo-400 シリーズでは、CON11とCON14にI2Cバスが出ており、外部のデバイスと接続することができます。Armadillo-400 シリーズLCD拡張ボードやArmadillo-400 シリーズRTCオプションモジュール、Armadillo-400シリーズWLANモジュールでは、I2Cバスにリアルタイムクロックを接続しています。ここでは、I2CバスにA/Dコンバーターを接続する方法を紹介します。 使用するソフトウェア、デバイスは以下のとおりです。 - Linuxカーネル: linux-3.14-at4 以降
- A/Dコンバーター: PCF8591(NXP社製)
I2C(Inter Integrated Circuit)は、IC間のデータ転送に使われる2線式の通信方式です。正式にはI2Cと記述し、I-squared-C(アイ・スクエアド・シー)と読みます。[] I2Cではシリアルデータライン(SDA)とシリアルクロック(SCL)の2本の信号線のみを使用して通信をおこないます。この2本の信号線に複数のデバイスを接続し、バスを構成することができます。I2Cバスに接続するデバイスの出力段はオープンドレイン(またはオープンコレクタ)とし、信号線はプルアップします。そのため、全てのデバイスがHighを出力しているときだけ信号線はHighとなり、どれかひとつのデバイスがLowを出力すると信号線はLowとなります[]。 I2Cバスに接続されたデバイスは、その役割によってマスタとスレーブに分かれます。マスタとスレーブは、一つのI2Cバスにそれぞれ複数接続することができます。通信は必ずマスタが開始し、バスに接続されたスレーブとデータのやりとりを行います。スレーブはそれぞれ固有のアドレスを持っており、マスタはアドレスを指定することで通信をおこなうスレーブを特定します。Armadillo-400シリーズは、I2Cマスタとなることができます。 I2Cでは、1クロックにつき1bitのデータの転送を行います。そのため、データ転送速度はクロックの速度によって決まります。I2Cにはいくつかのモードがあり、モードごとに転送速度の上限が決まっています。標準モードでは0から100kbit/sec、ファーストモードでは400kbit/secまで、ハイスピードモードでは3.4Mbit/secまでとなっています。Armadillo-400シリーズは、ファーストモードまで対応しています。 データの転送はクロックに同期して行われます。クロックは転送を開始するマスタが生成します。SCLがHighの時にSDAをHighからLowに変化させることで転送が開始されます。これをスタートコンディションと呼びます。また、SCLがHighの時にSDAをLowからHighに変化させることでデータの転送を終了します。これをストップコンディションといいます。スタートコンディションとストップコンディションの発行は、必ずマスターによって行われます。 I2Cでは、1回の転送で複数のバイトを送受信することができます。各バイトの長さは必ず8bitになります。データは最上位ビット(MSB)から順に送信されます。SCLがHighの時のSDAのレベルによって、論理が0(SDA=Low)か1(SDA=High)かが決定します。SCLがHighの間、SDAのレベルは一定でなければなりません。SDAのレベルを変更できるのは、SCLがLowの時だけです。 各バイト(8bit)の転送ごとに、アクノリッジ(ACK)が必要になります。受信側は、正常に通信がおこなえている場合、アクノリッジ信号として、SDAをLowにします。アクノリッジ信号としてSDAをHighにすることで、送信側にデータの終了を知らせることができます。 今回使用するA/DコンバーターPCF8591は、以下の特長を持ちます。 - 単一電源(2.5Vから6V)動作
- I2C接続
- 3つのハードウェアピンでアドレス指定可能
- オンチップ サンプルアンドホールド回路
- 8bit分解能逐次比較型A/D入力×4
- 8bit分解能D/A×1
Armadillo-400シリーズと、A/Dコンバーターとの接続を図2.14「I2C接続A/Dコンバーター回路図」に示します。Armadillo-400シリーズのCON14から出ているI2C2にPCF8591を接続します。アドレスを指定するA0、A1、A2ピンは全てプルダウンしておきます。AIN0からAIN3ピンがアナログ入力ピンです。アナログ入力にかかる電圧を、20kΩの可変抵抗で変えられるようにしています。リファレンス電圧VREFに電源電圧と同じ3.3Vを入力しているため、0Vから3.3Vの範囲のアナログ入力を8bit(256段階)のデジタル値に変換します。 PCF8591は内部にレジスタを持っており、レジスタの値を変更することで、デバイスの機能を変更することができます。レジスタへの書き込みは、図2.15「PCF8591通信フォーマット(コントロールバイト書き込み)」に示すフォーマットにしたがっておこないます。 まず、マスタがスタートコンディションを発行し、アドレスバイトを送信します。スレーブからのACKが返ってきたら、続いてコントロールバイトを送信します。再びスレーブからのACKが返ってきたら、ストップコンディションを発行して、レジスタへの書き込みを完了します。 アドレスバイトのフォーマットを図2.16「PCF8591通信フォーマット(アドレスバイト)」に示します。上位7bitでスレーブのアドレスを指定します。A2、A1、A0は、それぞれPCF8591のA2、A1、A0ピンのレベルに対応した値とします。今回の例では全てプルダウンしたので、A2、A1、A0は全て0を指定します。書き込み転送の場合は、R/W*を0とします。 コントロールバイトのフォーマットを図2.17「PCF8591通信フォーマット(コントロールバイト)」に示します。AOEはアナログ出力有効の場合、1を指定します。AISEL1とAISEL0で、どのようにアナログ入力ピンを使用するか指定します。シングルエンド(方線接地)入力×4とする場合は0b00、ディファレンシャル(差動)入力×3とする場合は0b01、シングルエンド入力×2+ディファレンシャル入力×1とする場合は0b10、ディファレンシャル入力×2とする場合は0b11となります。AINCはオートインクリメント有効の時、1を指定します。CH1とCH0にはアナログ入力に使用するチャンネルを指定します。今回の例では、AOE、AISEL1、AISEL0、AINCを全て0とします。 PCF8591からデータを読み出すと、CHで指定したチャンネルの値を得ることができます。データの読み出しは、図2.18「PCF8591通信フォーマット(データバイト読み出し)」に示すフォーマットでおこないます。 まず、マスタがスタートコンディションを発行し、アドレスバイトを送信します。スレーブはアドレスバイトへのACKを返し、続いてデータバイトを送信します。マスタはデータバイトを受信したあと、続けてデータが欲しい場合はACKを返します。データバイトの受信を終了したい場合はNACKを返し、ストップコンディションを発行します。 アドレスバイトのフォーマットは、R/W*が1になる以外、コントロールバイト書き込みの場合と同じです。 データバイトのフォーマットを図2.19「PCF8591通信フォーマット(データバイト)」に示します。PCF8591では、アクノリッジ信号のトレイリングエッジで、指定されたチャンネルの入力電圧がサンプルされ、データバイトの送信中にA/D変換がおこなわれます。そのため、データバイトで転送される値は、一つ前のデータバイト送信中に変換された値となります。なお、パワーオンリセット後の最初のデータバイトで転送される値は、0x80となります。 一般的に、I2C接続のデバイスをLinuxシステムで使用する場合、I2Cスレーブデバイス用のデバイスドライバーを作成して、デバイスの制御をおこないます。今回は、PCF8591専用のデバイスドライバーを作成するのではなく、汎用のi2cdevドライバーを使用することにします。i2cdevドライバーを使用すると、デバイスファイルインターフェースを経由して、ユーザーランドで動作するアプリケーションプログラムからデバイスの制御をおこなうことができます。Armadillo-400シリーズでは、標準のカーネルでi2cdevドライバーが有効になっているため、特に何も設定しなくとも使用可能です。 i2cdevドライバーでは、/dev/i2c-N (N は0から始まる数値文字)デバイスファイルに対して、open/close/read/write/ioctlシステムコールを発行することで、I2Cデバイスの制御をおこないます。Armadillo-400シリーズで使用できるデバイスファイルを表2.1「I2Cバスとデバイスファイルの対応」に示します。 表2.1 I2Cバスとデバイスファイルの対応 I2Cバス | コネクタ | デバイスファイル |
---|
I2C1 | なし[] | /dev/i2c-0
| I2C2 | CON14 | /dev/i2c-1
| I2C3 | CON11 | /dev/i2c-2
|
アプリケーションプログラムでI2Cデバイスの制御をおこなうには、まず、デバイスファイルをオープンします。 デバイスをオープンした後、通信を行うスレーブデバイスを特定するため、スレーブデバイスのアドレスを設定します。これには、ioctlシステムコールを使用します。I2C_SLAVEなどのi2cdevを使用する際に必要となる定義は、<linux/i2c-dev.h> で定義されています。 I2Cスレーブデバイスとのデータ転送をおこなうには、単純にread/writeシステムコールを実行するだけです。スタート/ストップコンディションの発行、アドレスバイトの生成と送信、アクノリッジの処理などは、全てドライバーがおこなってくれるので、アプリケーションプログラム側ではそれらを意識する必要はありません。 i2cdevドライバーに関する詳しい情報は、linux-3.14-at[version] /Documentation/i2c/dev-interface を参照してください。 Armadillo-400 シリーズでは、CON9をSPIバスとして使用することができます。ここでは、SPIバスにA/Dコンバータを接続する方法を紹介します。 使用するソフトウェア、デバイスは以下のとおりです。 - Linuxカーネル: linux-3.14-at4 以降
- A/Dコンバーター: MCP3204(Microchip社製)
SPI(Serial Peripheral Interface)は、IC間のデータ転送に使われる4線式の通信方式です。SPIでは、シリアルクロック(SCLK)、マスタアウトプット/スレーブインプット(MOSI)、マスタインプット/スレーブアウトプット(MISO)、スレーブセレクト(SS)の4本の信号線を使用して通信をおこないます。これらの信号線に、複数のデバイスを接続してバスを構成することができます。 SPIバスに接続されたデバイスは、その役割によってマスタとスレーブに分かれます。SPIでは、1つのバスに1つのマスタと複数のスレーブを接続できます。通信は必ずマスタが開始し、バスに接続されたスレーブとデータのやりとりを行います。マスタは、通信をおこなうスレーブをSS信号によって特定します。そのため、通常、スレーブ1つにつき1本のSS信号を接続します。Armadillo-400シリーズは、SPIマスタとなることができます。 SPIでは、1クロックにつき1bitのデータ転送をおこないます。そのため、データ転送速度はクロックの速度によって決まります。Armadillo-400シリーズは、約16MHzまで対応できます。 データの転送は、マスタがSS信号をアサートすることで開始されます。SCLK信号に同期して、マスターからスレーブへのデータをMOSIに出力し、スレーブからマスタへのデータをMISOから入力します。データの入出力をおこなう線が分かれているため、全二重の通信をおこなうことができます。一度の転送で送受信できるビット数はデバイスごとに異なり、SPIプロトコルとしての制限はありません。 SPIでは、クロックのポラリティとフェーズを指定できます。それぞれの設定をCPOLとCPHAで表します。 CPOL=0: クロックを出力していないときSCLKをLowに保ちます。 - CPHA=0: クロックの立ち上がりでデータをラッチします。
- CPHA=1: クロックの立ち下がりでデータをラッチします。
CPOL=1: クロックを出力していないときSCLKをHighに保ちます。 - CPHA=0: クロックの立ち下がりでデータをラッチします。
- CPHA=1: クロックの立ち上がりでデータをラッチします。
CPOLとCPHAの組み合わせを、SPIモードで表現する場合もあります。 表2.2 SPIモード モード | CPOL | CPHA |
---|
0 | 0 | 0 | 1 | 0 | 1 | 2 | 1 | 0 | 3 | 1 | 1 |
今回使用するA/DコンバーターMCP3204は、以下の特長を持ちます。 - 単一電源(2.7Vから5.5V)動作
- SPI接続
- サンプリング速度 最大100ksps(Vdd=5V時)、50ksps(Vdd=2.7V時)
- オンチップ サンプルアンドホールド
- 12bit分解能逐次比較型A/D入力×4
Armadillo-400シリーズと、A/Dコンバーターとの接続を図2.30「SPI接続A/Dコンバーター回路図」に示します。Armadillo-400シリーズのCON9から出ているCSPI3にMCP3204を接続します。SS信号には、CSPI3のSS0を使用します。AIN0からAIN3ピンがアナログ入力ピンです。アナログ入力にかかる電圧を、20kΩの可変抵抗で変えられるようにしています。リファレンス電圧VREFに電源電圧と同じ3.3Vを入力しているため、0Vから3.3Vの範囲のアナログ入力を12bit(4096段階)のデジタル値に変換します。 MCP3204は、SPIモード0(CPOL=0、CPHA=0)またはSPIモード3(CPOL=1、CPHA=1)で通信をおこないます。MCP3204の通信フォーマットを図2.31「MCP3204通信フォーマット」に示します。 MOSIから1を出力することで、転送の開始をMCP3204に指示します。SGL/DIFF*、D2、D1、D0の組み合わせにより、A/D変換をおこなうチャンネルを指定します。D0以降、MOSIから出力されるデータは意味を持ちません。 表2.3 MCP3204チャンネル指定 SGL/DIFF* | D2[] | D1 | D0 | 入力構成 | チャンネル |
---|
1 | d.c. | 0 | 0 | シングルエンド | CH0 | 1 | d.c. | 0 | 1 | シングルエンド | CH1 | 1 | d.c. | 1 | 0 | シングルエンド | CH2 | 1 | d.c. | 1 | 1 | シングルエンド | CH3 | 0 | d.c. | 0 | 0 | ディファレンシャル | CH0=IN+、CH1=IN- | 0 | d.c. | 0 | 1 | ディファレンシャル | CH0=IN-、CH1=IN+ | 0 | d.c. | 1 | 0 | ディファレンシャル | CH2=IN+、CH3=IN- | 0 | d.c. | 1 | 1 | ディファレンシャル | CH2=IN-、CH3=IN+ |
MCP3204は、11番目のクロックの上昇部でアナログ入力のサンプリングを開始し、次のクロックの下降部で完了します。A/D変換結果は、B11からB0に出力されます。 一般的に、SPI接続のデバイスをLinuxシステムで使用する場合、SPIスレーブデバイス用のデバイスドライバーを作成して、デバイスの制御をおこないます。今回は、MCP3204専用のデバイスドライバーを作成するのではなく、汎用のspidevドライバーを使用することにします。spidevドライバーを使用すると、デバイスファイルインターフェースを経由して、ユーザーランドで動作するアプリケーションプログラムからデバイスの制御をおこなうことができます。Armadillo-400シリーズでは、標準のカーネルではspidevドライバーが有効になっていないため、spidevを使用するにはカーネルの設定を変更する必要があります。 spidevドライバーでは、/dev/spidevN .M (N 、M は0から始まる数値文字)デバイスファイルに対して、open/close/read/write/ioctlシステムコールを発行することで、SPIデバイスの制御をおこないます。Armadillo-400シリーズで使用できるデバイスファイルを表2.4「SPIバスとデバイスファイルの対応」に示します。 表2.4 SPIバスとデバイスファイルの対応 SPIバス | コネクタ | デバイスファイル |
---|
CSPI1 | CON9 | /dev/spidev0.M (M は0または1)
| CSPI3 | CON9 | /dev/spidev2.M (M は0、1、2、3のいずれか)
|
アプリケーションプログラムでSPIデバイスの制御をおこなうには、まず、デバイスファイルをオープンします。 ioctlシステムコールにより、SPIの設定を変更することができます。 - SPI_IOC_RD_MODE, SPI_IOC_WR_MODE: 読み出しまたは書き込み時に使用するSPIモードを設定します。
- SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST: 読み出しまたは書き込み時にLSBから転送するか、MSBから転送するか設定します。
- SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD: 1回の読み出しまたは書き込みで転送するビット数を設定します。
- SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ: 読み出しまたは書き込みの最大転送速度を設定します。
read/writeシステムコールを使用すると、半二重通信をおこなうことができます。全二重通信をおこなうには、ioctlシステムコールのSPI_IOC_MESSAGE(N)メッセージを使用します。SPI_IOC_MESSAGE(N)の使用方法は、サンプルプログラムで解説します。 spidevドライバーに関する詳しい情報は、linux-3.14-at[version] /Documentation/spi/spidev を参照してください。 Armadillo-400シリーズの標準のカーネルでは、SPIドライバーは有効になっていません。そのため、SPIマスタドライバーとspidevドライバーが有効になったカーネルを作成する必要があります。 まず、カーネルのソースコードアーカイブを取得します。ここでは、Armadilloサイトからダウンロードしてくることにします。 次にArmadillo-400シリーズの標準コンフィギュレーションを適用します。 続いて、menuconfigを使用して、図2.36「SPIドライバーを有効にする」及び図2.37「SPIに使用するピンを指定する」に示すようにカーネルコンフィギュレーションを変更します。 また、カーネルのソースコードにも一部修正が必要になります。SPIスレーブデバイスドライバーを使用するには、spi_board_infoを登録する必要があります。spi_board_infoの登録は、linux-3.14-at[version] /arch/arm/mach-imx/armadillo4x0_extif.c でおこなっています。armadillo4x0_spi2_board_infoを、図2.38「CSPI3、SS0をspidevで使用する修正」に示すように修正してください。 コンフィギュレーションの変更と、ソースの修正をおこなったら、カーネルをビルドします。 正常にビルドが完了すると、linux-3.14-at[version] /linux.bin.gz にカーネルイメージが作成されます。linux.bin.gzをArmadilloのフラッシュメモリのカーネル領域に書き込んでください。 Armadillo-400シリーズでは、CON9 2ピンとCON9 26ピンを1-Wireバスとして使用することができます。ここでは、1-Wireバスに温度センサICを接続する方法を紹介します。 使用するソフトウェア、デバイスは以下のとおりです。 - Linuxカーネル: linux-3.14-at4 以降
- 温度センサ: DS18B20(MAXIM社製)
1-Wireは、IC間のデータ転送に使われる1線式の通信方式です。最低限、1本の信号線と接地線の2本だけでバスを構成することができます。このとき、電力は信号線から得ます。なお、電源線を別途用意し、3線で構成することもできます。1-Wireバスに接続されたデバイスの出力段はオープンドレインとし、信号線はプルアップします。 1-Wireバスに接続されたデバイスは、その役割によってマスタとスレーブに分かれます。1-Wireでは、1つのバスに1つのマスタと複数のスレーブを接続できます。通信は必ずマスタが開始し、バスに接続されたスレーブとデータのやりとりを行います。スレーブデバイスは、チップごとに固有な64bitのROM IDを持っており、マスタはROM IDを指定することで通信をおこなうスレーブを特定します。Armadillo-400シリーズは、1-Wireマスタとなることができます。 1-Wireでは、クロック信号がないため、タイムスロットに基づいてデータの転送をおこないます。マスタからスレーブに値を書き込む場合、マスタからローパルスを出力します。パルスの立ち下がりエッジでスレーブ内の単安定マルチバイブレーターが開始し、立ち下がりエッジから約30μsecの時点でサンプリングをおこないます。そのため、マスタは1を書き込む場合は1から15μsecの短いローパルスを出力し、0を書き込む場合は60μsecの長いローパルスを出力します。 スレーブからの値を読み出す場合、まず、マスタがローパルス1から15μsecの短いローパルスを出力します。スレーブ側は、1を送信したい場合何もしません。0を送信したい場合、60μsecの間信号線をローに引っ張ります。マスタは、立ち下がりエッジから30μsecの時点でサンプリングをおこない、スレーブからの出力をサンプリングします。 なお、タイムスロットにはスタンダード(1タイムスロット60μsec)とオーバードライブ(1タイムスロット8μsec)の二つがあります。上記の説明はスタンダードの場合のタイミングです。 マスターとスレーブ間でのデータ転送は3つのシーケンスでおこないます。3つのシーケンスは、リセットシーケンス、ROMコマンドシーケンス、ファンクションシーケンスの順番に実行されます。 リセットシーケンスでは、まず、マスタがリセットパルスを出力します。1-Wireバスにスレーブが接続されている場合、スレーブはプレゼンスパルスを出力します。 ROMコマンドシーケンスでは、マスタが8bitのROMコマンドを出力した後、64bitのROM IDを出力します。ROM IDの先頭8bitはデバイス種類を示すファミリーコードです。続く48bitがシリアルナンバーになっています。最後の8bitはCRCです。ROMコマンドには次のものがあります。 - SEARCH ROM(0xF0): バスに接続されているスレーブデバイスのROM IDを得ることができます。1回のSEARCH ROMコマンドで1つのデバイスのROM IDを特定することができます。
- READ ROM(0x33): バスに接続されているスレーブデバイスが一つだけの場合、SEARCH ROMコマンドの代わりにREAD ROMコマンドを使用して、ROM IDを得ることができます。
- MATCH ROM(0x55): MATCH ROMコマンドでマスタが出力したROM IDに一致したスレーブデバイスが、続くファンクションコマンドに応答します。それ以外のデバイスは、次のリセットシーケンスを待ちます。
- SKIP ROM(0xcc): SKIP ROMコマンドに続いて送信されたファンクションコマンドは、バスに接続されているスレーブデバイス全てに同時に適用されます。
ファンクションシーケンスは、スレーブデバイスごとに異なります。基本的には、マスタが8bitのフォワードコマンド出力した後、データの読み出しまたは書き込みをおこないます。 今回使用する温度センサDS18B20は、以下の特長を持ちます。 - 単一電源(3.0Vから5.5V)動作
- 電源は信号線から供給可能
- 外部部品不要
- 温度計測範囲-55℃から+125℃
- 分解能9bitから12bit
- 変換時間750msec(最大12bit時)
DS18B20のファンクションコマンドには以下のものがあります。 - CONVERT T(0x44): このコマンドにより、温度変換がおこなわれます。変換結果は、DS18B20の内蔵2バイトレジスタに格納されます。
- WRITE SCRATCHPAD(0x48): DS18B20の内蔵メモリに書き込みをおこないます。書き込むデータは3バイト長で、TH、TL、Configuration Registerの順番に送信します。
- READ SCRATCHPAD(0xbe): DS18B20の内蔵メモリを読み出します。読み出すデータのバイト数は最大9バイトです。途中で、マスタからリセットパルスを送信することで、データの読み出しを中断できます。
DS18B20内蔵レジスタは次のようになっています。 表2.5 DS18B20内蔵レジスタ バイト | 内容 |
---|
0 | Temperature Register LSB | 1 | Temperature Register MSB | 2 | TH or User Byte 1 | 3 | TL or User Byte 2 | 4 | Configuration Register | 5 | Reserved (0xff) | 6 | Reserved | 7 | Reserved (0x10) | 8 | CRC |
DS18B20の温度センサ分解能は、Configuration Registerの5bit目と6ビット目で決まります。それ以外のConfiguration Registerのビットは内部的に使用され、上書きすることはできません。 表2.6 DS18B20温度センサ分解能 BIT 6 | BIT 5 | 分解能 |
---|
0 | 0 | 9 bit | 0 | 1 | 10 bit | 1 | 0 | 11 bit | 1 | 1 | 12 bit[] |
Temperature Registerのフォーマットは次のようになっています。温度は摂氏で格納されています。12ビット分解能の場合は、BIT10からBIT0全てのビットが有効です。11ビット分解能の場合、BIT0が不定となります。10ビット、9ビット分解能の場合も同様です。BIT15からBIT11は、温度が正の場合0、負の場合1となります。 一般的に、1-Wire接続のデバイスをLinuxシステムで使用する場合、1-Wireスレーブデバイス用のデバイスドライバーを作成して、デバイスの制御をおこないます。今回は、1-Wireスレーブデバイスドライバーの「Thermal family implementation」を使用します。 「Thermal family implementation」を使用すると、1-Wireバスに接続された温度センサデバイスを自動で検出し、sysfs経由で温度データの読み出しを可能にします。 /sys/devices/w1_bus_master1/ が、1-Wireに関連するsysfsディレクトリです。「Thermal family implementation」が有効になっていて、スレーブデバイスが検出されると、28-0000022e2355 のようにデバイスのROM ID に対応したディレクトリが作成されます。その中のw1_slave を読み出すと、ドライバーはCONVERT Tコマンドを実行したあとREAD SCRATCHPADコマンドを実行し、DS18B20の内蔵レジスタを表示します。「crc=xx YES」でCRCが一致したことを表します。また、「t=28250」は温度(摂氏)を1000倍した値を示します。1度の読み出しで、2回分の変換結果を表示します。
Armadillo-400シリーズの標準のカーネルでは、1-Wireドライバーは有効になっていません。そのため、1-Wireマスタドライバーと「Thermal familyimplementation」ドライバーが有効になったカーネルを作成する必要があります。 まず、カーネルのソースコードアーカイブを取得します。ここでは、Armadilloサイトからダウンロードしてくることにします。 次にArmadillo-400シリーズの標準コンフィギュレーションを適用します。 続いて、menuconfigを使用して、図2.55「1-Wireドライバーを有効にする」に示すようにカーネルコンフィギュレーションを変更します。 コンフィギュレーションの変更をおこなったら、カーネルをビルドします。 正常にビルドが完了すると、linux-3.14-at[version] /linux.bin.gz にカーネルイメージが作成されます。linux.bin.gzをArmadilloのフラッシュメモリのカーネル領域に書き込んでください。 図2.50「1-Wire接続温度センサ回路図」に示すようにArmadilloとDS18B20を接続してからArmadilloを起動し、図2.51「1-Wire接続温度センサドライバーの使用例」に示す手順で動作確認をおこなってください。 Armadillo-400 シリーズでは、CON14をCANバスとして使用することができます。ここでは、Armadillo同士をCANで接続する方法を紹介します。 使用するソフトウェア、デバイスは以下のとおりです。 - Linuxカーネル: linux-3.14-at4 以降
- ユーザーランド: Atmark Dist v20151026 以降
- ネットワークおよびトラッフィック制御ツール: iproute2 (Atmark Distに含まれるもの)
- CAN通信プログラム: can-utils (Atmark Distに含まれるもの)
- CANトランシーバー: AMIS-42673(ON Semiconductor社製)
CAN(Controller Area Network)は、機器間のデータ転送に使われる、2線差動電圧式の通信方式です。差動電圧式を採用しているため耐ノイズ性に優れる点や、エラー検出方法と検出後の動作が明確化されているといった特長から、比較的信頼性の求められるネットワークに用いられます。 CANでは、CAN+とCAN-の2本の信号線間の電圧差を変化させることで通信をおこないます。この2本の信号線に複数のノード(機器)を接続し、バスを構成します。CANの物理的な仕様に関連する規格には、通信速度が125kbpsまでの低速CAN(ISO1159-2)、通信速度125kbpsから1Mbpsの高速CAN(ISO11898-2)など様々なものがあります。一般的にCANのノードは、物理層の処理をおこなうCANトランシーバとその後のデータ処理をおこなうCANコントローラから構成されます。今回の例では、CANコントローラはi.MX25内蔵のFlexCANコントローラを使用し、CANトランシーバにはISO 11898-2に対応したAMIS-42673を使用します。 CANプロトコルでは、CAN+とCAN-間の電圧差を、RS-232C通信のようにあらかじめ決められた通信速度(ビットレート)に従って変化させることで、データの転送をおこないます。転送される各ビットは、ドミナントかリセッシブのいずれかの状態を取ります。高速CANでは、CAN+とCAN-の電圧差がある場合ドミナント、無い場合リセッシブとなります。通常、ドミナントを論理0、リセッシブを論理1として扱います。CANはマルチマスタ構成のため、複数のデバイスが同時に通信をおこない、バス上でデータの衝突がおこる場合があります。この場合、どれか一つのノードがドミナントを出力していた場合、バスの状態はドミナントとなります(ドミナントがリセッシブに対して優先される)。CANでは、この特性を利用して調停をおこないます。 データの転送は、フレームという単位でおこないます。フレームには、表2.7「CANプロトコルフレーム」に示す4つの種類があります。 表2.7 CANプロトコルフレーム 名称 | 機能 |
---|
データフレーム | データを送信する。 | リモートフレーム | データフレームを要求する。 | オーバーロードフレーム | 前回のフレーム処理が完了していないことを通知する。 | エラーフレーム | エラーが発生したことを通知する。 |
データフレームとリモートフレームを合わせて、メッセージフレームといいます。CANでは、ノードごとのアドレスというものはなく、その代わりにそれぞれのメッセージが固有なID(識別子、Identifier)を持っています。受信ノードは、IDによって、自分が処理すべきメッセージかどうか判断します。メッセージに含まれるIDの長さによって、メッセージフレームには標準フォーマット(11bit長)と拡張フォーマット(29bit長)の2種類の形式があります。 データフレームの形式を図2.57「CANプロトコル(データフレーム)」に示します。上の線はリセッシブを、下の線はドミナントを意味します。データフレームは、データを送信するノードがバスをドミナントにすることから始まります。これをスタート・オブ・フレーム(SOF)と呼びます。SOFに続き、アービトレーションフィールド(ARBI)、コントロールフィールド(CONT)、データフィールド(DATA)、CRCフィールド(CRC)が順に送信されます。続いて、受信ノードはACKフィールド(ACK)を送信します。最後に、7ビット分バスをリセッシブに保ちエンド・オブ・フレーム(EOF)とします。 アービトレーションフィールドは、標準フォーマットか拡張フォーマットかによって異なります。標準フォーマットの場合、11bitのIDを送信したあと、リモート・トランスミッション・リクエスト・ビット(RTR)にドミナントを送信します。拡張フォーマットの場合、11bitのベースID(BASE ID)を送信したあと、代替リモート・リクエスト・ビット(SRR)、アイデンティファイヤ・エクステンション・ビット(IDE)として、2bit分バスをリセッシブに保ちます。続いて、18bitの拡張ID(Ext ID)を送信したあと、RTRにドミナントを送信します。 | CANプロトコルのバリエーション |
---|
CANプロトコルには、バージョン2.0Aと2.0Bの2つがあります。プロトコルバージョン2.0Aでは、標準フォーマットしか扱うことができません。もし拡張フォーマットのフレームを受信した場合、エラーフレームを送信します。プロトコルバージョン2.0Bパッシブでは、拡張フォーマットの送信はできませんが、拡張フォーマットを受信しても、無視します。プロトコルバージョン2.0Bアクティブでは、拡張フォーマットの送受信が可能です。 Armadillo-400シリーズは、プロトコルバージョン2.0Bアクティブに対応しています。 |
コントロールフィールドは、最初の2ビットが予約ビットとなっており、常にドミナントとします。続く4bitのデータ長コード(DLC)に送信するデータのバイト数を送信します。そのため、データフィールドは0から8バイト(64bit)長となります。 CRCフィールドのCRCシーケンス(CRC sequence)には、SOFからデータフィールドまでのCRC(Cyclic Redundancy Check)を送信します。CRCフィールドの区切りを示すCRCデリミタとして、1bit分リセッシブとします。 受信ノードは、受信したメッセージのCRCが一致した場合、ACKスロット(ACK slot)でドミナントを送信します。ACKスロットでバスがドミナントとなることで、送信ノードは少なくとも一つの受信ノードがデータフィールドを正常に受信できたことを確認できます。ACKスロットに続いて、ACKフィールドの区切りを示すACKデリミタ(ACK delimiter)として、1bit分リセッシブとします。 リモートフレームは、データフレームの要求に使用されます。リモートフレームを受信したノードは、リモートフレームで指定されたIDと同じIDのメッセージを返信します。リモートフレームの形式を、図2.58「CANプロトコル(リモートフレーム)」に示します。RTRをリセッシブにして、データフィールドが無い以外、データフレームと同じです。DLCは、リモートフレームへの返信として帰ってくるデータフレームのデータ長と同一にします。 メッセージフレームのアービトレーションフィールドという名前は、このフィールド送信中にバスの調停をおこなうことに由来します。同時に複数のノードがメッセージの送信を開始した場合、バスの衝突が発生します。送信ノードは、各ビットでバスの状態を確認し、もし自身がリセッシブを送信したにも関わらず、バスがドミナントとなっていた場合、以後の送信を中止します。そのため、より小さなIDが優先して送信されます。また、RTRにより、リモートフレームよりもデータフレームが優先されます。 オーバーロードフレームとエラーフレームは、一般にCANコントローラによって自動で処理されます。そのため、ここでは説明を割愛します。 | 同期とビット・スタッフィング・ルール |
---|
CANでは、ビットレートに従ってデータの送受信をおこなうため、ノードごとのクロックに誤差がある場合、タイミングが少しずつずれていきます。これを補正するため、バスがリセッシブからドミナントへ変化するとき、タイミングの同期をおこないます。 しかし、リセッシブやドミナントだけが続いた場合、この同期が行われないことになります。そこで、ビット・スタッフィング・ルールが適用されます。これは、同じ状態が5bit連続した場合、反対の状態のビット(スタッフビット)を一つ送信するルールです。このルールにより、一定期間内に必ず同期が行われることを保証しています。 なお、ビット・スタッフィング・ルールの処理はCANコントローラで自動で行われるため、ユーザー側は通常それを意識することはありません。 |
Armadillo-400シリーズとCANトランシーバーとを接続する回路図を、図2.59「CAN接続回路図」に示します。ArmadilloのCON14から出ているCAN2を使用します。CANトランシーバーには、AMIS-42673(ON Semiconductor社製)を使用します。LM2731YMF(National Semiconductor社製)は、3.3Vから5Vを生成するスイッチングコンバーターです。CON9 2ピン(GPIO3_17)で出力のON/OFFを切り替えることができます。 Armadillo-400シリーズ同士を接続する場合は、次のように接続してください。3つ以上のArmadilloを接続しても構いません。 Armadillo-400シリーズのCAN機能は、SocketCANフレームワークを使用して実装されています。SocketCANでは、通常のネットワークデバイスと同様に、socketインターフェースを用いてデータの送受信を行います。 CAN通信をおこなうプログラムは、TCP/IPなどを用いたネットワークプログラムと同様に記述できます。図2.61「CANソケットのオープン」に、CAN通信用のソケットをオープンし、can0インターフェースに関連付けるコード例を示します。プロトコルファミリーには、PF_CANを指定します。プロトコルには、ローソケットプロトコル(CAN_RAW)または、ブロードキャストマネージャ(BCM)を指定します。bindシステムコールでCANインターフェースとソケットを関連付けます。 以降の処理は、通常のネットワークプログラムと同様です。CANメッセージの送受信には、read/writeシステムコールや、send/sendto/sendmsgシステムコール、recv/recvfrom/recvmsgシステムコールを使用できます。 SocketCANに関する詳しい情報は、linux-3.14-at[version] /Documentation/networking/can.txt を参照してださい。 SocketCANフレームワークでは、sysfsインターフェースを用いて、CAN通信に関わる設定をおこないます。CAN2を使用する場合、/sys/devices/platform/FlexCAN.1/ 以下のファイルを使用します。使用可能なsysfsファイルの一覧は、「Armadillo-400シリーズ ソフトウェアマニュアル」の「CAN」を参照してください。 通常のSocketCANフレームワークには無い、Armadillo-400シリーズ独自の拡張として、リモートフレームのサポートを追加しています。set_resframe ファイルに、ID #DATA という形式で値を書き込むと、対応するIDのリモートフレームワークを受信した場合、自動でデータフレームを返信します。 Armadillo-400シリーズの標準のカーネルでは、CANドライバーは有効になっていません。そのため、CANドライバーが有効になったカーネルを作成する必要があります。 まず、カーネルのソースコードアーカイブを取得します。ここでは、Armadilloサイトからダウンロードしてくることにします。 次にArmadillo-400シリーズの標準コンフィギュレーションを適用します。 続いて、menuconfigを使用して、図2.65「CANドライバーを有効にする」及び図2.66「CANに使用するピンを指定する」に示すようにカーネルコンフィギュレーションを変更します。 コンフィギュレーションの変更と、ソースの修正をおこなったら、カーネルをビルドします。 正常にビルドが完了すると、linux-3.14-at[version] /linux.bin.gz にカーネルイメージが作成されます。linux.bin.gzをArmadilloのフラッシュメモリのカーネル領域に書き込んでください。 CANの通信速度設定は ipコマンドを使用します。ipコマンドは Atmark Distのユーザーランドコンフィギュレーションで iproute2を選択する[]事で組み込む事が可能です。 第1部の「Atmark Distを使ったルートファイルシステムの作成」などを参照し、使用するプロダクト用に基本的な設定をして一度ビルドしたAtmark Distを用意してください。Atmark Distのユーザーランドコンフィギュレーションで以下の項目にチェックを入れます。 Atmark Distには、CAN通信プログラムのサンプルとしてcan-utilsが含まれています。can-utilsには、一つのメッセージを送信するcansend、複数のメッセージを連続して送信するcangen、受信したメッセージを表示するcandumpがあります。今回は、これらを使用してCANの動作確認をおこなうことにします。 can-utilsを使用可能にするには、Atmark Distのユーザーランドコンフィギュレーションで以下の項目にチェックを入れます。 これらを選択した状態でユーザーランドをビルドし、作成されたルートファイルシステムイメージ(romfs.img.gz)をArmadilloのフラッシュメモリのユーザーランド領域に書き込んでください。 実際に、CANバスを通じてArmadillo同士で通信をおこなう手順を説明します。 まず、通信速度を設定します。通信速度は送受信をおこなうノード全てで一致している必要があるので、それぞれのArmadilloでおこなってください。 通信速度はipコマンドで設定します。以下の例では通信速度を125kbpsに設定しています。 次に、CANインターフェースを有効にします。これも、それぞれのArmadilloで実行します。 CANメッセージを受信するArmadilloで、candumpを実行しておきます。 別のArmadilloでcansendを実行すると、一つのメッセージを送信できます。図2.73「CANメッセージの送信」の例では、ID=0x5a5、データ=0x01234567を送信しています。 candumpコマンドを実行している受信側のArmadilloでは、メッセージを受信すると図2.74「CANメッセージの受信結果」に示しすような表示が得られます。 また、cangenを実行すると、連続したメッセージを送信できます。オプションにCANインターフェース名だけを指定した場合、cangenはアドレス、データ共にランダムな値を送信します。 candumpを実行している受信側のArmadilloでは、図2.76「連続したCANメッセージの受信」に示すような受信結果が得られます。 | |
|