LPCXpresso base board I2C device operation examples

このページは日本語でも記載されています.日本語版はこのページ後半をご覧ください. This page is written in Japanese as well. Please find it in 2nd half of this page.

What is this?

These are sample/demo codes for the "LPCXpresso base board" operation. 
This is intened to use basic training sessions for new mbed users.

The LPCXpresso base board's schematic and user manual are available on Embedded Artist's web site.

It seems those information are available only for the users who complete the registration with a base board's serial number. 
So please find detail information for the base board on their web site.

Code:

3 programs (#1..#3) has been made as samples for this base board hands-on. Those programs will be used in each training steps.

It will explain how to access the I2C devices on the base board. 
The programs access to the I2C devices through pin28 and pin27 of mbed.

STEP1...

1st target device is an I/O port expander: PCA9532 (I2C_address:0xC0) that controls 16 LEDs on its output pins. 
First program shows the access to the PCA9532 using "I2C write" function. 
In the training session, attendee can learn how to call the i2c.write() with the I2C_address, register address and data.

program_#1..."a simple version"

_training_lpcxpresso_baseboard_led_simple

Just a straight forward implementation sample of PCA9532 control. 
It just send commands to blink the LEDs. 
The code prepares the blinking pattern in array each bytes will be stored in its PCA9532's registers (from adress 0x6 to 0x9 (LED1..4), those registers has 2 setting bits for each single registers). 
In those bit fields, the LED will be turned-ON when the bit is set as '01(binary)', and turned-OFF when both bits are cleared.

This program is using "auto address increment feature" of PCA9532. 
To set the all 16 LEDs, the program need to access 4 registers to set each byte data. 
To minimize the effort to accessing registers, PCA9532 supports to do it in a sngle I2C transaction.

The auto increment feature can be enabled by setting bit 4 as '1'of register address. 
The auto increment does concecutive following data set into registers mapped in contiguous address. 
In the sample code, transferring dara are prepared as array. First byte is for the register address 0x06 and auto increment flag. 
With this setting, following 4 bytes data will be written into registers from 0x6 to 0x9. The data are prepared in 2D array (data[2][5]). The first row (data[0]) storing patten for OFF and other (data[1]) is ON.

Refer to I2C access examples for more information about I2C access to PCA9532.

#include "mbed.h"

I2C i2c( p28, p26 );        // sda, scl

const int PCA9532_addr  = 0xC0; // define the I2C Address

const char  data[2][5]  = { { 0x16, 0x00, 0x00, 0x00, 0x00 },

                   { 0x16, 0x55, 0x55, 0x55, 0x55 } };

 

int main() {

    char    i   = 0;

    while ( 1 ) {

        i2c.write( PCA9532_addr, data[ i++ & 0x1 ], 5 );

        wait( 0.5 );

    }

}

STEP2...

he 2nd target is a light sensor: ISL29003 (I2C_address:0x88). 
The program#2 shows a sample how to read registers in the device. 
This program reads 16bit information from the light sensor and controls luminance/dimming leve of 16 LEDs.

For the I2C device reading access, please refer to the notebook page I2C access examples

In the program#2, PCA9532 interface is defined differently.
It uses C++ style interface that helps accessing the device easier. 
This will show the sample of overriding '=' operator to make simple interface to set the ilumination pattern.

class baseboard_led_array {

public:

    ...

    ...

    baseboard_led_array() {

        //  no initialization done

    }

    void operator=( int c ) {

        char        a[ 5 ]  = { 0x16, 0x00, 0x00, 0x00, 0x00 };

        const char  v       = 0x2;

        for ( int i = 0; i < 16; i++ )

            a[ (i / 4) + 1 ]  |= (((c >> i) & 0x1) ? v : 0x0) << ((i % 4) << 1);

        i2c.write( PCA9532_addr, a, 5 );

    }

    ...

    ...

};

program_#2..."a version, with light sensor"

_training_lpcxpresso_baseboard_led_w_light_sensor

I2C data read from the register should be done by two I2C transactions.

  1. 1. send (write) the device a resister address.
  2. 2. read data from the device.

This demo reads 16bit data by two transfers of one byte, for lower byte and upper byte.

Since this program access two I2C devices, to make it simpler, the light sensor is also defined as a class using C++ feature.

The classes (for PCA9532 and light sensor) are defined in main.cpp together. 
In general, it may be better if the each class are defined in each .h and .cpp files, but here, it was made like this to have simple file structure in a project and it is not intended to use the class in other projects.

class light_sensor {

public:

    ...

    ...

    operator short( void ) {

        short   v;

        char    cmd;

 

        cmd    = 0x05;

        i2c.write( ISL29003_addr, &cmd, 1 );

        i2c.read( ISL29003_addr, &cmd, 1 );

        ...

    }

STEP3...

Program#3 is just a simple derivative of #2.

To control the speed of the LED blinking, a potentiometer (POT) is used on the base board. 
The POT is connected to pin15 of mbed. So it gives mbed (pin15) the voltage adjusted by its position.

In the training session, this modification may done by attendee themselves. 
It's just adding one line for "AnalogIn" instance declarationa and modification of "wait()" function argument.

program_#3..."extended version"

next code is a sample how the code can be modified.

...

...

baseboard_led_array     ledarr;

light_sensor            sensor;

AnalogIn                ain( p15 );

 

int main() {

    unsigned long   c           = 0x00000F0F;

    while ( 1 ) {

        a_pwm   = sensor >> 6;

        ledarr.pwm0( a_pwm > 255 ? 255 : (unsigned char)a_pwm );

 

        c   <<= 1;

        c   |= c & 0x10000 ? 0x1 : 0x0;

        ledarr   = c;

        wait( (float)ain / 10.0 );    

    }

}

How to use?

The simple version (program#1) is for just import, compile and run it. User can see the 16 LEDs are blinking. In the training session the I2C interface will be explained (relation between function call and actual signal going on the I2C lines) and basic register functions of PCA9532.

The light sensor version is also for just import-->compile-->run. But when user find the program running, he/she can try to lid the light sensor's aperture.

Note:

Further modification may be possible, of course. 
When atendee runs the program, they may notice the light sensor responce speed is slow. It's because the sampling interval of the light sensor is long. 
It can be adjusted by two LSB bits in a register addressed by 0. 
If the register byte is changed from 0x80 to 0x81, the response speed will be improved. 
WIth this modification, the maximum value from light sensor will be 4 bit less, so shift operation at sonsor value reading may need to adjust accordingly.

Reference:

LPCXpresso base board
http://www.embeddedartists.com/products/lpcxpresso/xpr_base.php

mbed library - I2C
http://mbed.org/handbook/I2C

I2C access examples
http://mbed.org/users/okano/notebook/i2c-access-examples/

PCA9532
http://www.nxp.com/documents/data_sheet/PCA9532.pdf

ISL29003
http://www.intersil.com/data/fn/FN7464.pdf



これは?

LPCXpressoベースボード」を用いたサンプル/デモ・コードです.
「mbedは初めて」の人向け講習会の実習用に用意されました.

なおLPCXpressoベースボードの詳細(回路図,ユーザマニュアル)は開発/販売元のEmbeddedArtistsのWebサイトで公開されています.

これらについてはベースボードに添付されているシリアル番号を用いてユーザ登録を行うとアクセスできるようになります.詳細についてはそのWebサイトをご覧ください.

コード:

実習用として3つのプログラムを用意しました.それぞれ実習の各段階で使われることを想定しています.

これらを通してベースボード上のI2Cデバイスにアクセスする方法を解説します.ベースボード上のI2Cバスはmbedの27ピン28ピンに接続されています.

第一段階...

最初に操作してみるデバイスはI/Oエクスパンダ:PCA9532(I2Cアドレス:0xC0)です.このチップのポートには16個のLEDが接続されています.
このプログラムはI2Cのwrite関数でどのようにPCA9532にアクセスするかを示します.
実習ではI2Cアドレスを指定し,レジスタとデータがi2c.write()をコールして,どのように送られるかを見て見てみます.

プログラム_#1...「簡単バージョン」

_training_lpcxpresso_baseboard_led_simple

最も単純なPCA9532制御の例で,LED点滅のコマンドを送るだけのものです.PCA9532のレジスタに設定するLEDの点滅パターン(レジスタ・アドレスと各レジスタの設定値)はプログラム内の配列に用意されます.
各レジスタにセットされるデータは2ビット毎に分けられており,この各2ビットビットのフィールドを'(2進)01'に設定するとLED点灯,'00'にすると消灯となります.

このプログラムではPCA9532の「オート・インクリメント」機能を使っています.

16個のLEDすべてを操作するためには4つのレジスタにアクセスする必要がありますが,この個々のアクセスを別々に行うのは面倒なので,一度のI2C転送(トランザクション)にまとめることができるようにしたものです.
レジスタのアドレスを指定する際にビット4を1に設定することで「オート・インクリメント」が使えます.

オート・インクリメントはそれに続くデータを,連続したレジスタにそれぞれ設定してくれます.サンプルコードではデータが配列に用意されており,第一バイト目のにレジスタアドレスとオートインクリメントフラグが指定されています.
この設定により続く4バイトのデータが0x6から0x9のレジスタにそれぞれ書かれることになります.データは2次元の配列に用意されており,最初の行(data[0])にOFF,次の行(data[1])にONのパターンが設定されています.

I2Cを使ったPCA9532へのアクセスについてはこちらI2C access examplesもご覧ください.

#include "mbed.h"

I2C i2c( p28, p26 );        // sda, scl

const int PCA9532_addr  = 0xC0; // define the I2C Address

const char  data[2][5]  = { { 0x16, 0x00, 0x00, 0x00, 0x00 },

                   { 0x16, 0x55, 0x55, 0x55, 0x55 } };

 

int main() {

    char    i   = 0;

    while ( 1 ) {

        i2c.write( PCA9532_addr, data[ i++ & 0x1 ], 5 );

        wait( 0.5 );

    }

}

第二段階...

次のターゲットは光センサ:ISL29003(I2Cアドレス:0x88)です.

プログラム_#2ではこのチップのレジスタをどのようにデータを読み出すかを示します.このプログラムでは環境光の状態を16ビットの情報として読み出し,それによって先ほどのLEDの輝度を変化させます.
I2Cの読み出しについては次のノートページI2C access examplesを参照してください.

このプログラム_#2ではPCA9532のインターフェース(アクセス方法)に変更を加えてあります.デバイスへのアクセスを簡略化するためにC++のスタイルを用いています.この中では演算子の多重定義機能を用いてLEDの点灯パターンを代入演算で行えるようにしています.

class baseboard_led_array {

public:

    ...

    ...

    baseboard_led_array() {

        //  no initialization done

    }

    void operator=( int c ) {

        char        a[ 5 ]  = { 0x16, 0x00, 0x00, 0x00, 0x00 };

        const char  v       = 0x2;

        for ( int i = 0; i < 16; i++ )

            a[ (i / 4) + 1 ]  |= (((c >> i) & 0x1) ? v : 0x0) << ((i % 4) << 1);

        i2c.write( PCA9532_addr, a, 5 );

    }

    ...

    ...

};

プログラム_#2...「光センサ・バージョン」

_training_lpcxpresso_baseboard_led_w_light_sensor

I2Cの読み出しは2回のI2Cトランザクションで行う必要があります.

  1. 1. レジスタアドレスの送出(書き込み)
  2. 2. データの読み出し

このデモプログラムでは16ビットのデータの読み出しを2回の1バイト読み出しで行っています.

またこのプログラムでは2個のI2Cデバイスを扱うため,その操作を簡略化するために光センサもC++の機能を用いて定義されています.
これらのクラス(PCA9532と光センサ)はmain.cpp内に一緒に定義されています.一般的にクラスは別個の.hや.cppファイル内に定義されるのが良いとされていますが,このサンプルコードではプロジェクト(ファイル構成)の単純化と,他での使い回しを考えないこととし,このようにしました.

第三段階…

プログラム_#3は,#2の単純な派生版です.

LEDの点滅スピードを変更するためにベースボードの可変抵抗を使ってみます.この可変抵抗はmbedの15ピンにつながれています.このためこのツマミを回すとmbedのピン(15番)の電圧が変わります.
実習では参加者それぞれにこの派生版を作成していただきます.

実際に変更して頂くのはAnalogInインスタンスを作成する1行を追加し,wait()関数の呼び出し引数を変更するだけです.

プログラム_#3...「拡張バージョン」

次はコードをどのように変更するかの例です.

...

...

baseboard_led_array     ledarr;

light_sensor            sensor;

AnalogIn                ain( p15 );

 

int main() {

    unsigned long   c           = 0x00000F0F;

    while ( 1 ) {

        a_pwm   = sensor >> 6;

        ledarr.pwm0( a_pwm > 255 ? 255 : (unsigned char)a_pwm );

 

        c   <<= 1;

        c   |= c & 0x10000 ? 0x1 : 0x0;

        ledarr   = c;

        wait( (float)ain / 10.0 );    

    }

}

使い方:

簡単バージョン(プログラム_#1)は単純にインポートし,コンパイル,実行して動作を見ていただきます.実習ではコードを見ていただき,その動作とPCA9532の動作を確認いただきます.

光センサ・バージョンもインポート-->コンパイル-->実行で動作を確認します.センサの受光部にを指で塞ぐなどして変化を見てみます.

注意:

もちろんこの他にも変更を加えることが可能でしょう.実習の参加者の中には光センサの反応スピードが遅いと感じる方もおられると思います.
この調整は光センサのレジスタ(アドレス0)の最下位2ビットで変更できます.このレジスタは初期化時に0x80に設定されていますが0x81にすると速度が改善されます.

この変更により読み出されるセンサ値の最大値は4ビット分小さくなるので,読み出した後に行うシフト演算の値も変更すると良いでしょう.

参考資料:

LPCXpresso base board
http://www.embeddedartists.com/products/lpcxpresso/xpr_base.php

mbed library - I2C
http://mbed.org/handbook/I2C

I2C access examples
http://mbed.org/users/okano/notebook/i2c-access-examples/

PCA9532
http://www.nxp.com/documents/data_sheet/PCA9532.pdf

ISL29003
http://www.intersil.com/data/fn/FN7464.pdf


0 comments

Please log in to post a comment.