PCA9955 16 channel current drive(sink) LED driver class library

Dependents:   PCA9955_Hello

PCA9955.cpp

Committer:
nxp_ip
Date:
2012-08-10
Revision:
0:2e6f5ac1b29b

File content as of revision 0:2e6f5ac1b29b:

/** PCA9955 constant current LED driver control library
 *
 *  @class   PCA9955
 *  @author  NXP Semiconductors Japan
 *  @version 0.5(15-Jun-2011) (publish 10-Aug-2012)
 *
 *  Copyright: 2011 NXP Semiconductors
 *  Released under the MIT License: http://mbed.org/license/mit
 *  This is a library that controls PCA9955 a constant current LED driver
 *  Example:
 *  @code
 *  #include    "mbed.h"
 *  #include    "PCA9955.h"
 *
 *  #define     MAX_IREF    0x20
 *
 *  PCA9955     led_driver( p28, p27, 0xC0 );  // making an instance of PCA9955
 *
 *  main()
 *  {
 *      char    v[ 16 ] = { 0xFF };
 *      int     sel;
 *
 *      srand( 0 );
 *
 *      led_driver  = 0xFFFF;
 *      led_driver.set_all_intensity( v );              //  PWM
 *      led_driver.set_all_intensity( MAX_IREF, true ); //  IREF
 *
 *      while ( 1 ) {
 *          for ( sel = 0; sel < 16; sel++ ) {
 *              v[ sel ]  = (char)((float)(v[ sel ]) * 0.8);
 *          }
 *
 *          v[ rand() % 16 ]  = 0xFF;
 *
 *          led_driver.set_all_intensity( v );              //  PWM
 *          wait( 0.05 );
 *      }
 *  }
 *  @endcode
 */

#include    "mbed.h"
#include    "PCA9955.h"

PCA9955::PCA9955(
    PinName I2C_sda,
    PinName I2C_scl,
    char    I2C_address = PCA9955_ADDR
) : i2c( I2C_sda, I2C_scl ), i2c_addr( I2C_address ) {

    i2c.frequency( 400 * 1000 );
    write( init_array, sizeof( init_array[42] ) );
}

void PCA9955::set_single_individual_intensity( char port, char val, int iref ) {
    write( (command_reg)((iref ? IREF_REGISTER_START : PWM_REGISTER_START) + port), val );
}

void PCA9955::set_all_intensity( char *p, int iref ) {
    char    pwm[ PCA9955_N_OF_PORTS + 1 ] = { AUTO_INCREMENT | (iref ? IREF_REGISTER_START : PWM_REGISTER_START) };

    for ( int i = 1; i <= PCA9955_N_OF_PORTS; i++ )
        pwm[ i ]    = *p++;

    write( pwm, PCA9955_N_OF_PORTS + 1 );
}

void PCA9955::set_all_intensity( char val, int iref ) {
    char    c[ PCA9955_N_OF_PORTS ];

    for ( int i = 0; i < PCA9955_N_OF_PORTS; i++ )
        c[ i ]    = val;

    set_all_intensity( c, iref );
}

void PCA9955::get_all_intensity( char *p, int iref ) {
    read( (command_reg)(AUTO_INCREMENT | (iref ? IREF_REGISTER_START : PWM_REGISTER_START)), p, PCA9955_N_OF_PORTS );
}

void PCA9955::operator=( int c ) {
    char    a[ 1 + (PCA9955_N_OF_PORTS / 4) ]  = { AUTO_INCREMENT | LEDOUT_REGISTER_START, 0x00, 0x00, 0x00, 0x00 };
    char    out_val = 0x2;

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

    write( a, sizeof( a ) );
}

unsigned short PCA9955::fault_test( void )
{
    char    mode2_reg;

#define     FAULTTEST   0x40
    
    mode2_reg   = read( MODE2 );
    mode2_reg   = 0;
    write( MODE2, mode2_reg | FAULTTEST );
    
    while ( read( MODE2 ) & FAULTTEST )
        ;
    
    return( ((unsigned short)(read( EFLAG1 )) << 8) | read( EFLAG0 ) );
}

void PCA9955::write( char *data, int length ) {
    i2c.write( i2c_addr, data, length );
}

void PCA9955::write( command_reg reg_addr, char data ) {
    char    c[2];

    c[0]    = reg_addr;
    c[1]    = data;

    i2c.write( i2c_addr, c, 2 );
}

void PCA9955::read( command_reg reg_addr, char *data, int length ) {
    i2c.write( i2c_addr, (char *)(&reg_addr), 1, true );
    i2c.read(  i2c_addr, data, length );
}

char PCA9955::read( command_reg reg_addr ) {
    i2c.write( i2c_addr, (char *)(&reg_addr), 1, true );
    i2c.read(  i2c_addr, (char *)(&reg_addr), 1 );

    return ( reg_addr );
}

char  PCA9955::init_array[] = {
    AUTO_INCREMENT | REGISTER_START,                //  Command
    0x00, 0x05,                                     //  MODE1, MODE2
    0xAA, 0xAA, 0xAA, 0xAA,                         //  LEDOUT[3:0]
    0x80, 0x00,                                     //  GRPPWM, GRPFREQ
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //  PWM[7:0]
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //  PWM[15:8]
    0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, //  IREF[7:0]
    0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, //  IREF[15:8]
    0x08                                            //  OFFSET: 1uS offsets
};