You are viewing an older revision! See the latest version
high_level_apis
I2Cサンプルブック対応クラスライブラリ:GPIOエキスパンダ,LEDコントローラ用 高水準API¶
このページについて
このページは『I2Cサンプルブック対応クラスライブラリ』の補足ページとなっています.
ここでは高水準APIを持つ GPIOエキスパンダ と LEDコントローラ 用のAPIを解説します.
I2Cサンプルブックに収められたデバイス用のクラスライブラリ全体に関する基本情報はこちらのページを参照してください.
高水準APIとは?¶
もうひとつのデバイス制御用API¶
低水準(Low level) API と 高水準(High level) API¶
I2Cサンプルブック対応の部品クラスライブラリを作成するにあたって,特にGPIOエキスパンダとLEDコントローラには,レジスタアクセスを行う低水準APIの他に,高水準APIを設けました.
ここでいう低水準・高水準とはLow level・High levelに対応した言葉です.よりハードウェアに近いインターフェースを提供するものを低水準,よりハードウェアの抽象度が高いものを高水準と呼んでいます.
低水準API¶
たとえば低水準APIでは,I2Cでアクセスするデバイス内のレジスタアクセスを行うAPIで,各レジスタ機能に対して直接的なインターフェースとなっています.
GPIOエキスパンダで,そのIOポートを入力または出力に設定する場合,各ピンが内部レジスタのどのビットに割り当てられているか,入力と出力を切り替える際は,それを行うレジスタ内における0
/1
の値が入力
/出力
のどちらに対応しているかを調べておく必要があります.また入出力が混在したIOピンの扱いも煩雑になります.
LEDコントローラのPWMの値を設定するには,デバイスとそのチャンネル番号を指定してデューティ比を与えるようなインターフェースが用意されており,ハードウェアを意識したプログラムを書かなければなりません.
低水準APIを使ったプログラム例
#include "mbed.h" #include "PCAL9555.h" PCAL9555 gpio( p28, p27, 0xE8 ); // この例の検証にPCA9539を使用したためアドレス=0xE8を使用 int main() { gpio.configure( 0xFFFF ); // 16bit分のIOピンを全て入力に設定 (全てのビット=1) printf( " 0x%04X\r\n", (int)gpio );// Print pins state gpio.configure( 0x0000 ); // 16bit分のIOピンを全て入力に設定 (全てのビット=0) int count = 0; while(1) { gpio.write( count++ ); // IOピンにcountの値を出力 (ビット順はレジスタの並び通り) } }
低水準APIの例:PCAL9555(PCA9539)をその内部の16ビットレジスタで操作
#include "mbed.h" #include "PCA9626.h" PCA9626 led_cntlr( p28, p27, 0x3E ); // SDA, SCL, Slave_address(option) #define OUTPUT_CHANNEL 0 // 出力チャンネル指定 int main() { while(1) { for ( int i = 0; i <= 100; i++ ) { led_cntlr.pwm( OUTPUT_CHANNEL, (float)i / 100.0 ); // デバイスの指定したチャンネルに正規化した値でデューティ比を指定 wait( 0.01 ); } } }
低水準APIの例:PCA9626の出力チャンネルを指定してデューティ比を与えている
低水準APIでも浮動小数型を使用
よりレジスタに近いインターフェースとして動作する低水準APIですが,デューティ比の設定には浮動小数型を用いています.
これは正規化した値を使うことで,デバイス内部のレジスタ・ビット数などを意識しないで済むようにする工夫です.
(浮動小数型の扱いは,サイズと速度の両面でオーバーヘッドを生むことになりますが,MCUには相応の余裕がありますから,ユーザはそのオーバーヘッド分をカバーして余るほどの恩恵が得られるものと考えます.もしサイズや速度の最適化が必要であれば,そのための作業を行えば良いのだと考えます)
高水準API¶
これに対しこの高水準APIは,mbed-SDKに用意されているDigitalOutやBusOut,PwmOutの使い勝手をそのままに,デバイス内部レジスタについての情報が無くても使えることを目指して作られています.
折角mbedを使っているのですから,外付けデバイスも,内部レジスタの構造やサイズ・ビットの配列順などのようなハードウェアの詳細は意識せず,mbed-SDKのAPIのように使えるととても楽になります.
これが実現できればmbedの大きな特長のひとつである「データシート無しで使える」的な機能が,外部に接続されたデバイスでも実現できることになります.
なおこの高水準APIは単独のライブラリとしてではなく,各部品クラスライブラリの内部に含まれた形で提供されます.
GPIOエキスパンダ用 高水準API¶
GPIO基本機能を提供¶
以下で解説するGPIOエキスパンダ用高水準APIは16個のIOピンを持った PCAL9555A,PCA9555(A),PCA9535(A/C),PCA9539(A/R) と,8個のIOピンを持った PCAL9554B/C,PCA9554(A),PCA9538(A) をサポートするPCAL955xクラスライブラリに含まれているAPIです.
コンポーネント・ページ
GpioDigitalOut, GpioDigitalIn, GpioDigitalInOut¶
GpioDigitalOut
はmbed-SDKのDigitalOutと同様のインターフェースを提供します.
GPIOエキスパンダのインスタンスとピン名によって,ピンのインスタンスを作成し操作することができます.
次のコードはGpioDigitalOut
を使用する最も簡単な例です.
#include "mbed.h" #include "PCAL9555.h" PCAL9555 gpio_exp( p28, p27, 0x40 ); // GPIOエキスパンダのインスタンスを作成 (接続されているI2Cバスとスレーブアドレスが指定される) GpioDigitalOut pin( gpio_exp, X0_0 ); // GpioDigitalOutのインスタンスとして「X0_0」ピンを「pin」と定義 int main() { while( 1 ) { pin = 1; // mbedのDigitalOutと同様に1を代入でHighを出力 wait( 0.2 ); pin = 0; // mbedのDigitalOutと同様に0を代入でLowを出力 wait( 0.2 ); } }
GpioDigitalOutを使用する最も簡単な例
この例を実行するには下図のようなmbedとデバイス(PCAL9555)の接続が必要です.
GpioDigitalOut pin( gpio_exp, X0_0 );
と宣言された pin
はPCAL9555の4番ピンを指します.
これによりpin
に代入された0/1の値は4番ピンのLow/Highとして出力されます.
PCAL9555とmbedの結線例.GPIOエキスパンダのピンはXn_nのように指定する
同様にmbed-SDKのDigitalIn相当のGpioDigitalIn
や,DigitalInOut相当のGpioDigitalInOut
が用意されています.
使い方はDigitalInやDigitalInOutのそれと同じです.
GPIOエキスパンダのIOピン指定について
ピン名はデータシートに合わせてP0_0〜P1_7のようにしたかったのですが,これらはmbed-SDKで使われているためX0_0〜X1_7としました.
ピン名の指定は各デバイスのチャンネル数によって制限されます.
IOピン数 | ピン指定名範囲 |
16 | X0_0〜X0_7,X1_0〜X1_7 (またはX0〜X15としても指定可能) |
8 | X0_0〜X0_7 (またはX0〜X7としても指定可能) |
GpioDigitalInOut,GpioDigitalInについて
GpioDigitalInOut
はDigitalInOutと同様にinput()
やoutput()
関数によって入出力の方向を変えることができます.
GpioDigitalInOut
,GpioDigitalIn
には現在mode関数は用意されていないため,オープンドレインや内部プルアップ/ダウンなどの機能を使う場合には低水準APIをコールしなければなりません.
APIの詳細
GpioDigitalOut,GpioDigitalIn,GpioDigitalInOut APIの詳細についてはPCAL9555xのAPIドキュメントを参照してください.
GpioBusOut, GpioBusIn, GpioBusInOut¶
GpioDigitalOut, GpioDigitalIn, GpioDigitalInOutと同様にGpioBusOut
, GpioBusIn
, GpioBusInOut
が用意されています.
これらはGpioDigitalOut, GpioDigitalIn, GpioDigitalInOutをまとめて使うためのクラスです.
GpioDigitalOut/GpioDigitalIn/GpioDigitalInOutとGpioBusOut/GpioBusIn/GpioBusInOutはインスタンスへのアクセスのたびに1回のレジスタアクセスが実行されます.
複数のピンを操作する場合は,レジスタアクセスをまとめて1回で行えるGpioBusOut/GpioBusIn/GpioBusInOutの方が効率が良くなります.
次のコードはGpioBusOutを使用する簡単な例です.変数 i
の値をピンX0_0, X0_1, X0_2, X0_3に出力します.
mbed-SDKのBusOut同様,バスとしてまとめるピンは任意です(最大16ピンまで).連番でなくても構いませんし,順番も自由です.
#include "mbed.h" #include "PCAL9555.h" // GPIOエキスパンダのインスタンスを作成 (接続されているI2Cバスとスレーブアドレスが指定される) PCAL9555 gpio_exp( p28, p27, 0x40 ); // GpioBusOutのインスタンスとして「X0_0, X0_1, X0_2, X0_3」の4つのピンをまとめて「mypins」と定義 GpioBusOut mypins( gpio_exp, X0_0, X0_1, X0_2, X0_3 ); int main() { while( 1 ) { for( int i = 0; i < 16; i++ ) { mypins = i; // mbedのBusOutと同様に値を代入すると,それに従ったピン出力が現れる wait( 0.25 ); } } }
GpioBusOutを使用する簡単な例
GPIOエキスパンダ用 高水準APIは組み合わせて使うことも可能です.
次のコードはPCAL9555のIOピンを3つのバスと1つのDigitalOutと宣言して使用した例です.
#include "mbed.h" #include "PCAL9555.h" PCAL9555 gpio( p28, p27, 0x40 ); // PCAL9555のインスタンス // 以下の4つのインスタンス宣言で // GPIOエキスパンダのIOピンを bus と DigitalOut にまとめる GpioBusIn bus_in( gpio, X0_0, X0_1, X0_2, X0_3 ); // ピン「X0_0, X0_1, X0_2, X0_3」を入力用の bus_in に GpioBusOut bus_out( gpio, X0_4, X0_5, X0_6 ); // ピン「X0_4, X0_5, X0_6」を出力用の bus_out に GpioBusInOut bus_io( gpio, X1_7, X1_6, X1_5, X1_4, X1_3, X1_2, X1_1, X1_0 ); // ピン「X1_7, X1_6, X1_5, X1_4, X1_3, X1_2, X1_1, X1_0」を入出力用の bus_io に GpioDigitalOut myled( gpio, X0_7 ); // ピン「X0_7」を入出力用の myled に:"DiditalOut"のインスタンス int main() { bus_io.input(); // bus_io を入力に設定 printf( "I/O = 0x%02X\r\n", (int)bus_io ); // bus_io のピン入力を表示 printf( "In = 0x%01X\r\n", (int)bus_in ); // bus_in のピン入力を表示 bus_io.output(); // bus_io を出力に設定 int count = 0; while(1) { bus_out = count; // カウンタ値を bus_out に出力 bus_io = count; // カウンタ値を bus_io に出力 myled = count & 0x1; // カウンタの最下位ビットを myled に出力 count++; wait( 0.1 ); } }
PCAL9555のIOピンを3つのバスと1つのDigitalOutと宣言して使用した例
上記コード例でのピンの割り当てを図示するとこのようになる
GPIOエキスパンダのIOピンを,このようにまとめて扱えるため,より管理しやすいコードを書くことができるようになります.
APIの詳細
GpioBusOut,GpioBusIn,GpioBusInOut APIの詳細についてはPCAL9555xのAPIドキュメントを参照してください.
LEDコントローラ用 高水準API¶
PwmOut同等のAPI¶
mbed-SDKのPwmOutはPWM出力を行うピンのデューティ比設定を手軽に変更できる素晴らしいAPIです.一般的なLEDコントローラはそのLED出力にPWMが出るようになっており,同様のインターフェースが使えれば便利です.
この考えに基づき,LEDコントローラ・チップの出力でもPwmOut同等のAPIを実現できるようにしたのがLedPwmOut
とLedPwmOutCC
です.
LedPwmOut¶
LedPwmOut
はGPIOエキスパンダのGpioGigitalOutのようなインターフェースを実装したPWM出力用のAPIです.
このクラスはPCA9626(24ch),PCA9622(16ch),PCA9624(8ch)のLEDコントローラをサポートするPCA962xクラスライブラリと,PCA9632(4ch) LEDコントローラをサポートするPCA9632クラスライブラリで使用することができます.
LedPwmOutクラスは,PCA962xやPCA9632クラスライブラリに含まれているため,これらのライブラリをインポートしただけでそのまま使うことができます.
実際の使い方は,下のコード例のとおりです.LEDコントローラのインスタンスを宣言しておき,ピンをL0
〜L23
の名で指定することでLedPwmOutの個別のインスタンスを作成できます.
このインスタンスに0.0〜1.0の値を与えることで,PWM出力のデューティ比が設定されます.
次のコードはPCA9626のPWM出力をLedPwmOutを介して制御する例です.
#include "mbed.h" #include "PCA9626.h" PCA9626 led_cntlr( p28, p27, 0xC4 ); // PCA9626のインスタンスを作る LedPwmOut led( led_cntlr, L0 ); // LedPwmOutのインスタンスとして「L0」ピンを「led」と定義 int main() { while( 1 ) { for( float p = 0.0f; p < 1.0f; p += 0.1f ) { led = p; // L0ピンのPWM出力デューティ比をpの値に設定 wait( 0.1 ); } } }
PCA9626のPWM出力をLedPwmOutを介して制御する例
上のコードを実行するとled
として指定されたL0ピン(LED0ピン:2番ピン)のPWM出力が変化することになります.
L0ピン(LED0ピン)のPWM出力が変化
LedPwmOut でのLEDコントローラの出力ピン指定について
ピン名はデータシートに合わせてLED0〜LED23のようにしたかったのですが,これらはmbed-SDKで使われているためL0〜L23としました.
ピン名の指定は各デバイスのチャンネル数によって制限されます.
型番 | チャンネル数 | ピン指定名範囲 |
PCA9626 | 24 | L0 〜 L23 |
PCA9622 | 16 | L0 〜 L15 |
PCA9624 | 8 | L0 〜 L7 |
PCA9632 | 4 | L0 〜 L3 |
LedPwmOut APIによるPWM周波数の変更
mbed-SDKのPwmOut APIではPWM周期を変更することが可能ですが,このAPIではサポートしていません.
PCA962xファミリでは97kHz,PCA9632では1.5625kHzにPWM周波数が固定されており変更ができないためです.
コンポーネント・ページ
コンポーネント・ページ
LedPwmOutCC¶
LedPwmOut クラスとは別に LedPwmOutCC
APIが用意されています.
このAPIは2種類のLEDコントローラ:PCA9956A(24ch),PCA9955A(16ch)をサポートするPCA995xAクラスライブラリに含まれているAPIです.
LedPwmOutCCのクラスの名は,これらのデバイスが内部に電流源を持つ「定電流(Constant Current)」出力型に由来します.
LedPwmOuCCの使い方はLedPwmOutと同じです.が,PCA9956A,PCA9955A内蔵の電流出力設定に対応するための関数が追加されています.
次のコードはPCA9956AのPWM出力をLedPwmOutCC APIを介して制御する例です.
#include "mbed.h" #include "PCA9956A.h" PCA9956A led_cntlr( p28, p27, 0xC4 ); // PCA9956Aのインスタンスを作る LedPwmOutCC led( led_cntlr, L0 ); // LedPwmOutCCのインスタンスとして「L0」ピンを「led」と定義 int main() { led.current( 0.5 ); // L0ピンの電流出力を50%に設定 while( 1 ) { for( float p = 0.0f; p < 1.0f; p += 0.1f ) { led = p; // L0ピンのPWM出力デューティ比をpの値に設定 wait( 0.1 ); } } }
PCA9956AのPWM出力をLedPwmOutCC APIを介して制御する例
上のコードを実行するとled
として指定されたL0ピン(LED0ピン:6番ピン)のPWM出力が変化することになります.
L0ピン(LED0ピン)のPWM出力が変化
LedPwmOutCC でのLEDコントローラの出力ピン指定について
ピン名はデータシートに合わせてLED0〜LED23のようにしたかったのですが,これらはmbed-SDKで使われているためL0〜L23としました.
ピン名の指定は各デバイスのチャンネル数によって制限されます.
型番 | チャンネル数 | ピン指定名範囲 |
PCA9956A | 24 | L0 〜 L23 |
PCA9955A | 16 | L0 〜 L15 |
LedPwmOutCC APIによるPWM周波数の変更
mbed-SDKのPwmOut APIではPWM周期を変更することが可能ですが,このAPIではサポートしていません.
PCA995xAファミリでは31.25kHzにPWM周波数が固定されており変更ができないためです.
コンポーネント・ページ