I2C access examples

Information

Japanese version available in lower half of this page.
このページの後半に日本語版が用意されています.

I2C access examples

I2C device register access examples (using PCA9532 and ISL29003)

Information

This page has been written as a supplement for LPCXpresso base board I2C device operation examples.

write

I2C class "write()" function sends I2C address and data on I2C bus.
The write function takes 3 arguments: slave_address, pointer to an array and length of the array.
With those parameters, the mbed SDK manages multiple bytes transfer automatically. The function will be returned when the transfer completed.

Following code and figure are showing 3 bytes data (0x16, 0x55 and 0x55) are written into a slave device which as address of 0xC0.

Warning!

The I2C 7 bit address should be given a MSB justified byte data.
For instance, if the slave device has address of '1100000' (7 bit binary), it should be given as '0xC0'. In this notation, the LSB doesn't need to be cared. The 8th bit after 7 bit slave address should be read or write bit and it is provided (overwritten) by mbed-SDK (inside of the write function).

If you are familiar to the LSB justified representation and want to use it in your program, it may be good idea to use it with 1 bit left shift operation like '(0x60 << 1)'.

#include "mbed.h"

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

int main() {
    char    data[3];

    data[0]   = 0x16;
    data[1]   = 0x55;
    data[2]   = 0x55;

    i2c.write( 0xC0, data, 3 );
}


http://mbed.org/media/uploads/okano/i2c_write_3bytes.png

Information

The program is accessing 2 registers (8bit registers) in PCA9532 to control its 16 ports. Basic register access of this chip requires two byte data after slave address. This two byte data should be register address and data for the register.
This operation is simple but having big over head. Because with this format, one register write needs whole I2C transfer each time.

To minimize this overhead, PCA9532 supports 'auto address increment' access.
When specifying the register address, set a flag on bit 4. With this setting, the auto increment is enabled then consecutive following data are set into registers in contiguous addresses.

In the sample code, transferring data are prepared as array. First byte is for the register address 0x06 and auto increment flag.
With this setting, following 2 bytes data will be written into registers of 0x6 and 0x7.

Information

The function returns zero when the transfer done successfully. It returns non-zero if the transfer got error such as NACK from slave or arbitration lost.

read

To read a register, it needs to be done by two I2C transfers.

1st transfer is "write" to specify the register address.
2nd is read from the register.

Next sample is a function that execute those two transfers and returns read 8 bit information.

short read_sensor_lower_8bit( void )
{
    char    v;
    char    cmd;

    cmd    = 0x05;

    i2c.write( 0x88, &cmd, 1 );
    i2c.read( 0x88, &v, 1 );

    return( v );
}



http://mbed.org/media/uploads/okano/i2c_read_1byte.png

Information

Almost I2C compatible devices can read the register with this sequence but some may not.
Those devices needs to have "repeated-START condition" instead of "STOP and START".
Each write and read functions generates STOP conditions at the end of transfer. To disable this STOP condition generation, you can use optional 4th argument for the functions.

same_as_previous_sample

    i2c.write( 0x88, &cmd, 1 );  //  generates "STOP condition" at the end of write transfer. 
    i2c.read( 0x88, &v, 1 );

how_to_connect_transfers_by_repeated-START_condition

    i2c.write( 0x88, &cmd, 1, true );  //  no "STOP condition" generated 
    i2c.read( 0x88, &v, 1 );           //  "START condition" for this transfer becomes a "repeated-START" condition

reference:

LPCXpresso base board I2C device operation examples
http://mbed.org/users/okano/notebook/lpcxpresso-base-board-i2c-device-operation-example/

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

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

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

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

I2C-bus specification and user manual
http://www.nxp.com/documents/user_manual/UM10204.pdf

update info

  • 03-May-2010 : 1st version (in HTML)
  • 12-Sep-2014 : converted to Wiki format and some words are added
  • 14-Sep-2014 : some modifications done. Japanese version added





I2Cアクセス例

I2C デバイスのレジスタ・アクセスの例 (PCA9532 と ISL29003での例)

Information

このノートページはLPCXpresso base boardの操作例の補足として書かれました

書き込み (write)

I2Cクラスの"write()"はI2CにI2Cアドレスとデータを送出する関数です.
このwrite関数は3つの引数をとります:スレーブ・アドレス,配列へのポインタ,そして配列の長さです.
これらのパラメータ(引数)を与えることにより,mbedSDKは複数バイトの転送を自動的に実行します.関数は転送の完了後に戻ってきます.

次の例は,3バイトのデータ(0x16, 0x55 and 0x55)を,アドレスが0xC0のスレーブ・デバイスに書き込むものです

Warning!

I2Cの7ビット・アドレスは「前詰め(MSB justified)」で指定します.
たとえばもしアドレスが'1100000' (7ビットの2進値)ならば,それを'0xC0'とします.この時の最後のビット(LSB)は気にしないで構いません.スレーブ・アドレスの7bitの次,8番目のビットは書き込みまたは読み出し指定のビットであり,mbed-SDKの関数(この場合はwrite関数)がこのビットを上書きします.

もし後詰め(LSB justified)の表現に慣れており,それを1ビットシフトした表記に直すのが面倒ならば,「'(0x60 << 1)'」と書くのもひとつの方法です.

#include "mbed.h"

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

int main() {
    char    data[3];

    data[0]   = 0x16;
    data[1]   = 0x55;
    data[2]   = 0x55;

    i2c.write( 0xC0, data, 3 );
}


http://mbed.org/media/uploads/okano/i2c_write_3bytes.png

Information

プログラムはPCA9532の16個のポートを制御するために2つのレジスタ(8ビット・レジスタ)にアクセスしています. このチップの基本的なレジスタ・アクセスは,スレーブ・アドレスと2バイトのデータ転送で行われます.2バイトのデータはレジスタ・アドレスとそこに書き込むデータです.
この転送は単純ですが非効率的です.なぜならこのやり方では,ひとつのレジスタ書き込みごとにI2Cの転送全部を行わなければならないからです.

これを効率的に行うためにPCA9532には「オート・アドレス・インクリメント」が用意されています.
レジスタ・アドレスの指定の際に4ビット目のフラグを立てておきます.この設定でオート・インクリメントが有効となり,以降のデータを連続したレジスタに書き込んで行くことができます.

コード例では転送するデータを配列として用意しています.
1バイト目はレジスタ・アドレスに0x06を指定し,さらに「オート・アドレス・インクリメント」のフラグが立てられています(0x16 == 0x06 | 0x10).
この設定により続く2バイトのデータはそれぞれ0x6と0x7のレジスタに書き込まれます.

Information

この関数は戻り値を持ちます.転送が成功すれば0が返ります.もしNACKやアービトレーション・ロストなどの問題が発生すると0でない値が返ります.

読み出し(read)

レジスタを読むには2つの転送を使います.

最初の転送は書き込み(write)転送で,読み出す対象のレジスタ・アドレスを指定ます.
2番目がレジスタの読み出しです.

次の例は,この2つの転送を行い,読みだした8ビットのデータを返す関数です.

short read_sensor_lower_8bit( void )
{
    char    v;
    char    cmd;

    cmd    = 0x05;

    i2c.write( 0x88, &cmd, 1 );
    i2c.read( 0x88, &v, 1 );

    return( v );
}



http://mbed.org/media/uploads/okano/i2c_read_1byte.png

Information

I2C互換のほとんどのデバイスでこのような読み出し方法が使えますが,例外も存在します.
そのようなデバイスでは各転送の間に「STOPコンディションとSTARTコンディション」の代わりに「リピーテッドSTARTコンディション」が必要だったりします.
writeとreadの関数は,転送の最後にSTOPコンディションを発生させます.このSTOPコンディションを発生させないようにするために,4番目のオプション引数を与えることができるようになっています.

same_as_previous_sample

    i2c.write( 0x88, &cmd, 1 );  //  書き込み転送の最後にSTOPコンディションを発生させる 
    i2c.read( 0x88, &v, 1 );

how_to_connect_transfers_by_repeated-START_condition

    i2c.write( 0x88, &cmd, 1, true );  //  STOPコンディションが発生しない 
    i2c.read( 0x88, &v, 1 );           //  この転送のSTARTコンディションは「リピーテッドSTARTコンディション」となる

参考

LPCXpresso base board I2C device operation examples
http://mbed.org/users/okano/notebook/lpcxpresso-base-board-i2c-device-operation-example/

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

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

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

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

I2C-bus specification and user manual
http://www.nxp.com/documents/user_manual/UM10204.pdf

更新情報

  • 03-May-2010 : 1st version (in HTML)
  • 12-Sep-2014 : converted to Wiki format and some words are added
  • 14-Sep-2014 : some modifications done. Japanese version added


Report
16 Sep 2013

Nice!

I had been stumped getting I2C to work, but this example got me straightened out.

Thanks!

3 comments on I2C access examples:

06 Jul 2015

Hi, I've tried your code and it works. However, how can I read multiple registers? For example, I want to read registers from 0x28 to 0x2D ?

Thanks.

17 Jul 2015

Abil Fida wrote:

Hi, I've tried your code and it works. However, how can I read multiple registers? For example, I want to read registers from 0x28 to 0x2D ?

Sorry for slow reply.

Method of the multiple register access is not scope of I2C specification.
The method is defined in each slave device datasheet.


Please let me show an example.
Next picture is a diagram from PCA9532 datasheet.
/media/uploads/okano/pca9532_ai_flag.png

This defines a usage of Control register. This data should be given after the slave address in write transfer which specifies accessing target (register address).
The field of B0 to B3 is used to set the target but if the AI (Auto Increment) bit is set, consecutive data access is done with register address increment.
So, on this device, it providing the multiple register access method as its feature.

Next code is a sample to write 4 bytes data using AI bit on the PCA9532.

#include "mbed.h"

I2C i2c( p28, p27 );

#define     SLAVE_ADDRESS           0xC0

#define     REGISTER_ADDRESS        0x06
#define     AUTO_INCREMENT_FLAG     0x10

int main()
{
    //  4 bytes data writing into registers 0x06 to 0x09

    char    data[ 5 ]   = {
        AUTO_INCREMENT_FLAG | REGISTER_ADDRESS, // register address with AI flag
        0xAA,
        0xBB,
        0xCC,
        0xDD
    };

    i2c.write( SLAVE_ADDRESS, data, sizeof( data ) );
}



For the 4 bytes reading, it can be done like next sample.

#include "mbed.h"

I2C i2c( p28, p27 );

#define     SLAVE_ADDRESS           0xC0

#define     REGISTER_ADDRESS        0x06
#define     AUTO_INCREMENT_FLAG     0x10

int main()
{
    //  4 bytes data reading from registers 0x06 to 0x09

    char    comm    = AUTO_INCREMENT_FLAG | REGISTER_ADDRESS; // register address with AI flag
    char    data[ 4 ];
    
    i2c.write( SLAVE_ADDRESS, &comm, 1 );
    i2c.read( SLAVE_ADDRESS, data, sizeof( data ) );
}


But again, the multiple register accessing method is defined in each devices.
No common way is exist. Please find it on datasheet.

11 Sep 2017

説明ありがとうございます。

Please log in to post comments.