CQ_I2C_book


We are the team of "I2C sample book" by CQ publishing

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 levelHigh levelに対応した言葉です.よりハードウェアに近いインターフェースを提供するものを低水準,よりハードウェアの抽象度が高いものを高水準と呼んでいます.

低水準API

低水準APIでは,I2Cを介してデバイス内の各レジスタ機能に直接アクセスを行うインターフェースを提供しています.

たとえばGPIOエキスパンダでこのようなインターフェースを用いる場合,各ピンと内部レジスタのビットの対応関係や,入力と出力を切り替える際は,それを行うレジスタ内における0/1の値が入力/出力のどちらに対応しているかを意識してプログラムを書かねばなりません.また入出力が混在しすると複雑で読みにくいコードになってしまいます.

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に用意されているDigitalOutBusOutPwmOutの使い勝手をそのままに,デバイス内部レジスタについての情報が無くても使えることを目指して作られています.

折角mbedを使っているのですから,外付けデバイスも,内部レジスタの構造やサイズ・ビットの配列順などのようなハードウェアの詳細は意識せず,mbed-SDKのAPIのように使えるととても楽になります.
これが実現できればmbedの大きな特長のひとつである「データシート無しで使える」的な機能が,外部に接続されたデバイスでも実現できることになります.

なおこの高水準APIは単独のライブラリとしてではなく,各部品クラスライブラリの内部に含まれた形で提供されます.



GPIOエキスパンダ用 高水準API


GPIO基本機能を提供

以下で解説するGPIOエキスパンダ用高水準APIは16個のIOピンを持った PCAL9555APCA9555(A)PCA9535(A/C)PCA9539(A/R) と,8個のIOピンを持った PCAL9554B/CPCA9554(A)PCA9538(A) をサポートするPCAL955xクラスライブラリに含まれているAPIです.

コンポーネント・ページ

Basic operation of 16 and 8 bit GPIO expander family: PCAL9555, PCA9555, PCA9535, PCA9539, PCAL9554, PCA9554, PCA9538


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として出力されます.

http://developer.mbed.org/media/uploads/nxp_ip/xgpio16.png.pagespeed.ic.UGorDxgcYv.png
PCAL9555とmbedの結線例.GPIOエキスパンダのピンはXn_nのように指定する

同様にmbed-SDKのDigitalIn相当のGpioDigitalInや,DigitalInOut相当のGpioDigitalInOutが用意されています.
使い方はDigitalInやDigitalInOutのそれと同じです.

GPIOエキスパンダのIOピン指定について

ピン名はデータシートに合わせてP0_0P1_7のようにしたかったのですが,これらはmbed-SDKで使われているためX0_0X1_7としました.
ピン名の指定は各デバイスのチャンネル数によって制限されます.

IOピン数ピン指定名範囲
16X0_0〜X0_7,X1_0〜X1_7 (またはX0〜X15としても指定可能)
8X0_0〜X0_7 (またはX0〜X7としても指定可能)

GpioDigitalInOut,GpioDigitalInについて

GpioDigitalInOutDigitalInOutと同様にinput()output()関数によって入出力の方向を変えることができます.
GpioDigitalInOutGpioDigitalInには現在mode関数は用意されていないため,オープンドレインや内部プルアップ/ダウンなどの機能を使う場合には低水準APIをコールしなければなりません.

APIの詳細

GpioDigitalOutGpioDigitalInGpioDigitalInOut APIの詳細についてはPCAL9555xのAPIドキュメントを参照してください.


GpioBusOut, GpioBusIn, GpioBusInOut

GpioDigitalOut, GpioDigitalIn, GpioDigitalInOutと同様にGpioBusOut, GpioBusIn, GpioBusInOutが用意されています.
これらはGpioDigitalOut, GpioDigitalIn, GpioDigitalInOutをまとめて使うためのクラスです.
GpioDigitalOut/GpioDigitalIn/GpioDigitalInOutGpioBusOut/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と宣言して使用した例

/media/uploads/okano/gpiodigital_gpiobus_combination2.png
上記コード例でのピンの割り当てを図示するとこのようになる


GPIOエキスパンダのIOピンを,このようにまとめて扱えるため,より管理しやすいコードを書くことができるようになります.

APIの詳細

GpioBusOutGpioBusInGpioBusInOut APIの詳細についてはPCAL9555xのAPIドキュメントを参照してください.



LEDコントローラ用 高水準API

PwmOut同等のAPI

mbed-SDKのPwmOutはPWM出力を行うピンのデューティ比設定を手軽に変更できる素晴らしいAPIです.一般的なLEDコントローラはそのLED出力にPWMが出るようになっており,同様のインターフェースが使えれば便利です.

この考えに基づき,LEDコントローラ・チップの出力でもPwmOut同等のAPIを実現できるようにしたのがLedPwmOutLedPwmOutCCです.

LedPwmOut

LedPwmOutはGPIOエキスパンダのGpioGigitalOutのようなインターフェースを実装したPWM出力用のAPIです.
このクラスはPCA9626(24ch),PCA9622(16ch),PCA9624(8ch)のLEDコントローラをサポートするPCA962xクラスライブラリと,PCA9632(4ch) LEDコントローラをサポートするPCA9632クラスライブラリで使用することができます.

LedPwmOutクラスは,PCA962xやPCA9632クラスライブラリに含まれているため,これらのライブラリをインポートしただけでそのまま使うことができます.

実際の使い方は,下のコード例のとおりです.LEDコントローラのインスタンスを宣言しておき,ピンをL0L23の名で指定することで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)_pin
L0ピン(LED0ピン)のPWM出力が変化


LedPwmOut でのLEDコントローラの出力ピン指定について

ピン名はデータシートに合わせてLED0LED23のようにしたかったのですが,これらはmbed-SDKで使われているためL0L23としました.
ピン名の指定は各デバイスのチャンネル数によって制限されます.

型番チャンネル数ピン指定名範囲
PCA962624L0 〜 L23
PCA962216L0 〜 L15
PCA96248L0 〜 L7
PCA96324L0 〜 L3

LedPwmOut APIによるPWM周波数の変更

mbed-SDKのPwmOut APIではPWM周期を変更することが可能ですが,このAPIではサポートしていません.
PCA962xファミリでは97kHz,PCA9632では1.5625kHzにPWM周波数が固定されており変更ができないためです.

コンポーネント・ページ

コンポーネント・ページ

The PCA9632 is an I²C-bus controlled 4-bit LED driver optimized for Red/Green/Blue/Amber (RGBA) color mixing applications.


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)_pin
L0ピン(LED0ピン)のPWM出力が変化

LedPwmOutCC でのLEDコントローラの出力ピン指定について

ピン名はデータシートに合わせてLED0LED23のようにしたかったのですが,これらはmbed-SDKで使われているためL0L23としました.
ピン名の指定は各デバイスのチャンネル数によって制限されます.

型番チャンネル数ピン指定名範囲
PCA9956A24L0 〜 L23
PCA9955A16L0 〜 L15

LedPwmOutCC APIによるPWM周波数の変更

mbed-SDKのPwmOut APIではPWM周期を変更することが可能ですが,このAPIではサポートしていません.
PCA995xAファミリでは31.25kHzにPWM周波数が固定されており変更ができないためです.

コンポーネント・ページ

PCA9955B and PCA9956B are I²C-bus controlled 16-channel constant current LED driver optimized for dimming and blinking.


All wikipages