A feature complete driver for the PCA9952/55 LED driver from NXP.

Dependents:   PCA9955_HelloWorld

PCA9955.h

Committer:
neilt6
Date:
2013-11-08
Revision:
4:6ca7ab31c5fb
Parent:
3:84571acc16a1
Child:
5:7ad949955db8

File content as of revision 4:6ca7ab31c5fb:

/* PCA9952/55 Driver Library
 * Copyright (c) 2013 Neil Thiessen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef PCA9955_H
#define PCA9955_H

#include "mbed.h"

/** PCA9952/55 class.
 *  Used for controlling a PCA9952/55 constant current LED driver connected via I2C.
 *
 * Example:
 * @code
 * #include "mbed.h"
 * #include "PCA9955.h"
 *
 * //Create a PCA9955 object using the LED All Call address
 * PCA9955 driver(p28, p27, PCA9955::ADDRESS_ALL);
 *
 * int main()
 * {
 *     //Try to open the PCA9955
 *     if (driver.open()) {
 *         printf("Device detected!\n");
 *
 *         //Reset the device
 *         //NOTE: This might reset other I2C devices as well!
 *         driver.reset();
 *
 *         //Set all of the output states to PWM mode
 *         driver.allOutputStates(PCA9955::OUTPUT_PWM);
 *
 *         //Set all of the output currents to maximum
 *         driver.allOutputCurrents(1.0);
 *
 *         while (1) {
 *             //Generate a breathing effect on all of the outputs
 *             for (float i = 0.0f; i < 360.0f; i += 0.1f) {
 *                 driver = 0.5 * (sinf(i * 3.14159265f / 180.0f) + 1);
 *             }
 *         }
 *     } else {
 *         error("Device not detected!\n");
 *     }
 * }
 * @endcode
 */
class PCA9955
{
public:
    /** Represents the different I2C address possibilities for the PCA9952/55
     */
    enum Address {
        ADDRESS_0 = (0x60 << 1),    /**< A[3:0] pins = 0000 */
        ADDRESS_1 = (0x61 << 1),    /**< A[3:0] pins = 0001 */
        ADDRESS_2 = (0x62 << 1),    /**< A[3:0] pins = 0010 */
        ADDRESS_3 = (0x63 << 1),    /**< A[3:0] pins = 0011 */
        ADDRESS_4 = (0x64 << 1),    /**< A[3:0] pins = 0100 */
        ADDRESS_5 = (0x65 << 1),    /**< A[3:0] pins = 0101 */
        ADDRESS_6 = (0x66 << 1),    /**< A[3:0] pins = 0110 */
        ADDRESS_7 = (0x67 << 1),    /**< A[3:0] pins = 0111 */
        ADDRESS_8 = (0x68 << 1),    /**< A[3:0] pins = 1000 (not available on PCA9952) */
        ADDRESS_9 = (0x69 << 1),    /**< A[3:0] pins = 1001 (not available on PCA9952) */
        ADDRESS_10 = (0x6A << 1),   /**< A[3:0] pins = 1010 (not available on PCA9952) */
        ADDRESS_11 = (0x6B << 1),   /**< A[3:0] pins = 1011 (not available on PCA9952) */
        ADDRESS_12 = (0x6C << 1),   /**< A[3:0] pins = 1100 (not available on PCA9952) */
        ADDRESS_13 = (0x6D << 1),   /**< A[3:0] pins = 1101 (not available on PCA9952) */
        ADDRESS_14 = (0x6E << 1),   /**< A[3:0] pins = 1110 (not available on PCA9952) */
        ADDRESS_15 = (0x6F << 1),   /**< A[3:0] pins = 1111 (not available on PCA9952) */
        ADDRESS_ALL = (0x70 << 1),  /**< The default LED All Call address */
        ADDRESS_SUB = (0x76 << 1)   /**< The default subaddress for 16-channel LED drivers */
    };

    /** Represents the different outputs of the PCA9952/55
     */
    enum Output {
        OUTPUT_0 = 0,   /**< LED output 0 */
        OUTPUT_1 = 1,   /**< LED output 1 */
        OUTPUT_2 = 2,   /**< LED output 2 */
        OUTPUT_3 = 3,   /**< LED output 3 */
        OUTPUT_4 = 4,   /**< LED output 4 */
        OUTPUT_5 = 5,   /**< LED output 5 */
        OUTPUT_6 = 6,   /**< LED output 6 */
        OUTPUT_7 = 7,   /**< LED output 7 */
        OUTPUT_8 = 8,   /**< LED output 8 */
        OUTPUT_9 = 9,   /**< LED output 9 */
        OUTPUT_10 = 10, /**< LED output 10 */
        OUTPUT_11 = 11, /**< LED output 11 */
        OUTPUT_12 = 12, /**< LED output 12 */
        OUTPUT_13 = 13, /**< LED output 13 */
        OUTPUT_14 = 14, /**< LED output 14 */
        OUTPUT_15 = 15  /**< LED output 15 */
    };

    /** Represents the power mode of the PCA9952/55
     */
    enum PowerMode {
        POWER_NORMAL,   /**< Oscillator is enabled */
        POWER_SHUTDOWN  /**< Oscillator is disabled */
    };

    /** Represents the output change mode of the PCA9952/55
     */
    enum OutputChangeMode {
        OUTPUT_CHANGE_ON_STOP,  /**< Outputs change on STOP command */
        OUTPUT_CHANGE_ON_ACK    /**< Outputs change on ACK */
    };

    /** Represents the group control mode of the PCA9952/55
     */
    enum GroupMode {
        GROUP_DIMMING,  /**< Group control = dimming */
        GROUP_BLINKING  /**< group control = blinking */
    };

    /** Represents the individual driver output states of the PCA9952/55
     */
    enum OutputState {
        OUTPUT_OFF,         /**< LED driver x is off (default power-up state) */
        OUTPUT_ON,          /**< LED driver x is fully on (individual brightness and group dimming/blinking not controlled) */
        OUTPUT_PWM,         /**< LED driver x individual brightness can be controlled through its PWMx register */
        OUTPUT_PWM_GRPPWM   /**< LED driver x individual brightness and group dimming/blinking can be controlled through its PWMx register and the GRPPWM registers */
    };

    /** Represents the fault test flags for the PCA9952/55
     */
    enum FaultFlags {
        FAULT_OUTPUT_0 = (1 << 0),      /**< LED output 0 is either open or shorted */
        FAULT_OUTPUT_1 = (1 << 1),      /**< LED output 1 is either open or shorted */
        FAULT_OUTPUT_2 = (1 << 2),      /**< LED output 2 is either open or shorted */
        FAULT_OUTPUT_3 = (1 << 3),      /**< LED output 3 is either open or shorted */
        FAULT_OUTPUT_4 = (1 << 4),      /**< LED output 4 is either open or shorted */
        FAULT_OUTPUT_5 = (1 << 5),      /**< LED output 5 is either open or shorted */
        FAULT_OUTPUT_6 = (1 << 6),      /**< LED output 6 is either open or shorted */
        FAULT_OUTPUT_7 = (1 << 7),      /**< LED output 7 is either open or shorted */
        FAULT_OUTPUT_8 = (1 << 8),      /**< LED output 8 is either open or shorted */
        FAULT_OUTPUT_9 = (1 << 9),      /**< LED output 9 is either open or shorted */
        FAULT_OUTPUT_10 = (1 << 10),    /**< LED output 10 is either open or shorted */
        FAULT_OUTPUT_11 = (1 << 11),    /**< LED output 11 is either open or shorted */
        FAULT_OUTPUT_12 = (1 << 12),    /**< LED output 12 is either open or shorted */
        FAULT_OUTPUT_13 = (1 << 13),    /**< LED output 13 is either open or shorted */
        FAULT_OUTPUT_14 = (1 << 14),    /**< LED output 14 is either open or shorted */
        FAULT_OUTPUT_15 = (1 << 15)     /**< LED output 15 is either open or shorted */
    };

    /** Create a PCA9952/55 object connected to the specified I2C pins with the specified I2C slave address
     *
     * @param sda The I2C data pin.
     * @param scl The I2C clock pin.
     * @param addr The I2C slave address (defaults to ADDRESS_0).
     */
    PCA9955(PinName sda, PinName scl, Address addr = ADDRESS_0);

    /** Create a PCA9952/55 object connected to the specified I2C pins with a custom I2C slave address
     *
     * @param sda The I2C data pin.
     * @param scl The I2C clock pin.
     * @param addr The custom I2C slave address (a modified subaddress or LED All Call address).
     */
    PCA9955(PinName sda, PinName scl, int addr);

    /** Probe for the PCA9952/55 and configure Auto-Increment if present
     *
     * @returns
     *   'true' if the device exists on the bus,
     *   'false' if the device doesn't exist on the bus.
     */
    bool open();

    /** Issue an SWRST call to reset the PCA9952/55
     * @warning This might reset other I2C devices as well!
     */
    void reset();

    /** Determine whether the LED All Call address is enabled on the PCA9952/55
     *
     * @returns Whether or not the LED All Call address is enabled.
     */
    bool allCallEnabled();

    /** Set whether the LED All Call address is enabled on the PCA9952/55
     *
     * @param enabled Whether or not the LED All Call address is enabled.
     */
    void allCallEnabled(bool enabled);

    /** Determine whether subaddress 3 is enabled on the PCA9952/55
     *
     * @returns Whether or not subaddress 3 is enabled.
     */
    bool subCall3Enabled();

    /** Set whether subaddress 3 is enabled on the PCA9952/55
     *
     * @param enabled Whether or not subaddress 3 is enabled.
     */
    void subCall3Enabled(bool enabled);

    /** Determine whether subaddress 2 is enabled on the PCA9952/55
     *
     * @returns Whether or not subaddress 2 is enabled.
     */
    bool subCall2Enabled();

    /** Set whether subaddress 2 is enabled on the PCA9952/55
     *
     * @param enabled Whether or not subaddress 2 is enabled.
     */
    void subCall2Enabled(bool enabled);

    /** Determine whether subaddress 1 is enabled on the PCA9952/55
     *
     * @returns Whether or not subaddress 1 is enabled.
     */
    bool subCall1Enabled();

    /** Set whether subaddress 1 is enabled on the PCA9952/55
     *
     * @param enabled Whether or not subaddress 1 is enabled.
     */
    void subCall1Enabled(bool enabled);

    /** Get the current power mode of the PCA9952/55
     *
     * @returns The current power mode as a PowerMode enum.
     */
    PCA9955::PowerMode powerMode();

    /** Set the power mode of the PCA9952/55
     *
     * @param mode The new power mode as a PowerMode enum.
     */
    void powerMode(PowerMode mode);

    /** Get the current output change mode of the PCA9952/55
     *
     * @returns The current output change mode as an OutputChangeMode enum.
     */
    PCA9955::OutputChangeMode outputChangeMode();

    /** Set the output change mode of the PCA9952/55
     *
     * @param mode The new output change mode as an OutputChangeMode enum.
     */
    void outputChangeMode(OutputChangeMode mode);

    /** Get the current group control mode of the PCA9952/55
     *
     * @returns The current group control mode as a GroupMode enum.
     */
    PCA9955::GroupMode groupMode();

    /** Set the group control mode of the PCA9952/55
     *
     * @param mode The new group control mode as a GroupMode enum.
     */
    void groupMode(GroupMode mode);

    /** Determine whether or not the PCA9952/55 is overheating
     *
     * @returns
     *   'true' if the device is currently disabled due to overheating,
     *   'false' if the device is functioning normally.
     */
    bool overTemp();

    /** Get the specified output's state
     *
     * @param output The output to check.
     *
     * @returns The output's current state as an OutputState enum.
     */
    PCA9955::OutputState outputState(Output output);

    /** Set the specified output's state
     *
     * @param output The output to change.
     * @param state The new output state as an OutputState enum.
     */
    void outputState(Output output, OutputState state);

    /** Get the current group control duty cycle of the PCA9952/55 in percent
     *
     * @returns The current group control duty cycle as a float (0.0 to 1.0).
     */
    float groupDuty();

    /** Set the group control duty cycle of the PCA9952/55 in percent
     *
     * @param duty The new group control duty cycle as a float (0.0 to 1.0).
     */
    void groupDuty(float duty);

    /** Get the current group control duty cycle of the PCA9952/55
     *
     * @returns The current group control duty cycle as an unsigned char (0 to 255).
     */
    char groupDuty_char();

    /** Set the group control duty cycle of the PCA9952/55
     *
     * @param duty The new group control duty cycle as an unsigned char (0 to 255).
     */
    void groupDuty_char(char duty);

    /** Get the current group control blink period of the PCA9952/55 in seconds
     *
     * @returns The current group control blink period in seconds (0.067 to 16.8).
     */
    float groupBlinkPeriod();

    /** Set the current group control blink period of the PCA9952/55 in seconds
     *
     * @param period The new group control blink period in seconds (0.067 to 16.8).
     */
    void groupBlinkPeriod(float period);

    /** Get the current group control blink period of the PCA9952/55
     *
     * @returns The current group control blink period as an unsigned char (0 to 255).
     */
    char groupBlinkPeriod_char();

    /** Set the current group control blink period of the PCA9952/55
     *
     * @param period The new group control blink period as an unsigned char (0 to 255).
     */
    void groupBlinkPeriod_char(char period);

    /** Get the specified output's duty cycle in percent
     *
     * @param output The output to check.
     *
     * @returns The output's current duty cycle as a float (0.0 to 1.0).
     */
    float outputDuty(Output output);

    /** Set the specified output's duty cycle in percent
     *
     * @param output The output to change.
     * @param duty The new output duty cycle as a float (0.0 to 1.0).
     */
    void outputDuty(Output output, float duty);

    /** Get the specified output's duty cycle
     *
     * @param output The output to check.
     *
     * @returns The output's current duty cycle as an unsigned char (0 to 255).
     */
    char outputDuty_char(Output output);

    /** Set the specified output's duty cycle
     *
     * @param output The output to change.
     * @param duty The new output duty cycle as an unsigned char (0 to 255).
     */
    void outputDuty_char(Output output, char duty);

    /** Get the specified output's current reference in percent
     *
     * @param output The output to check.
     *
     * @returns The output's current reference as a float (0.0 to 1.0).
     */
    float outputCurrent(Output output);

    /** Set the specified output's current reference in percent
     *
     * @param output The output to change.
     * @param iref The new output current reference as a float (0.0 to 1.0).
     */
    void outputCurrent(Output output, float iref);

    /** Get the specified output's current reference
     *
     * @param output The output to check.
     *
     * @returns The output's current reference as an unsigned char (0 to 255).
     */
    char outputCurrent_char(Output output);

    /** Set the specified output's current reference
     *
     * @param output The output to change.
     * @param iref The new output current reference as an unsigned char (0 to 255).
     */
    void outputCurrent_char(Output output, char iref);

    /** Get the turn-on delay between LEDn outputs
     *
     * @returns The turn-on delay between LEDn outputs in clocks (0 to 15 - 125ns per clock).
     */
    char outputDelay();

    /** Set the specified output's current reference
     *
     * @param clocks The turn-on delay between LEDn outputs in clocks (0 to 15 - 125ns per clock).
     */
    void outputDelay(char clocks);

    /** Get subaddress 1
     *
     * @returns The current I2C subaddress 1.
     */
    char subCall1Addr();

    /** Set subaddress 1
     *
     * @param addr The new I2C subaddress 1.
     */
    void subCall1Addr(char addr);

    /** Get subaddress 2
     *
     * @returns The current I2C subaddress 2.
     */
    char subCall2Addr();

    /** Set subaddress 2
     *
     * @param addr The new I2C subaddress 2.
     */
    void subCall2Addr(char addr);

    /** Get subaddress 3
     *
     * @returns The current I2C subaddress 3.
     */
    char subCall3Addr();

    /** Set subaddress 3
     *
     * @param addr The new I2C subaddress 3.
     */
    void subCall3Addr(char addr);

    /** Get the LED All Call address
     *
     * @returns The current LED All Call address.
     */
    char allCallAddr();

    /** Set the LED All Call address
     *
     * @param addr The new LED All Call address.
     */
    void allCallAddr(char addr);

    /** Set all of the output states to the same state
     *
     * @param state The new output state for all outputs.
     */
    void allOutputStates(OutputState state);

    /** Read all of the output duty cycles into an array as percents
     *
     * @param duties Pointer to any array for 16 duty cycles as floats (0.0 to 1.0).
     */
    void getOutputDuties(float* duties);

    /** Set all of the output duty cycles to the same value in percent
     *
     * @param duty The new duty cycle for all outputs as a float (0.0 to 1.0).
     */
    void allOutputDuties(float duty);

    /** Set all of the output duty cycles from an array of percents
     *
     * @param duties Pointer to any array of 16 duty cycles as floats (0.0 to 1.0).
     */
    void allOutputDuties(float* duties);

    /** Read all of the output duty cycles into an array
     *
     * @param duties Pointer to any array for 16 duty cycles as unsigned chars (0 to 255).
     */
    void getOutputDuties_char(char* duties);

    /** Set all of the output duty cycles to the same value
     *
     * @param duty The new duty cycle for all outputs as an unsigned char (0 to 255).
     */
    void allOutputDuties_char(char duty);

    /** Set all of the output duty cycles from an array
     *
     * @param duties Pointer to any array of 16 duty cycles as unsigned chars (0 to 255).
     */
    void allOutputDuties_char(char* duties);

    /** Read all of the output current references into an array as percents
     *
     * @param irefs Pointer to any array for 16 current references as floats (0.0 to 1.0).
     */
    void getOutputCurrents(float* irefs);

    /** Set all of the output current references to the same value in percent
     *
     * @param iref The new current reference for all outputs as a float (0.0 to 1.0).
     */
    void allOutputCurrents(float iref);

    /** Set all of the output current references from an array of percents
     *
     * @param irefs Pointer to any array of 16 current references as floats (0.0 to 1.0).
     */
    void allOutputCurrents(float* irefs);

    /** Read all of the output current references into an array
     *
     * @param irefs Pointer to any array for 16 current references as unsigned chars (0 to 255).
     */
    void getOutputCurrents_char(char* irefs);

    /** Set all of the output current references to the same value
     *
     * @param iref The new current reference for all outputs as an unsigned char (0 to 255).
     */
    void allOutputCurrents_char(char iref);

    /** Set all of the output current references from an array
     *
     * @param irefs Pointer to any array of 16 current references as unsigned chars (0 to 255).
     */
    void allOutputCurrents_char(char* irefs);

    /** Perform a fault test on all enabled outputs
     *
     * @returns The fault test flags as FaultFlags enum values OR'd together.
     */
    unsigned short faultTest();

#ifdef MBED_OPERATORS
    /** A shorthand for allOutputDuties()
     *
     * @param value The new duty cycle for all outputs as a float (0.0 to 1.0).
     */
    PCA9955& operator=(float value);
#endif

private:
    //I2C register addresses
    enum Register {
        REG_MODE1       = 0x00,
        REG_MODE2       = 0x01,
        REG_LEDOUT0     = 0x02,
        REG_LEDOUT1     = 0x03,
        REG_LEDOUT2     = 0x04,
        REG_LEDOUT3     = 0x05,
        REG_GRPPWM      = 0x08,
        REG_GRPFREQ     = 0x09,
        REG_PWM0        = 0x0A,
        REG_PWM1        = 0x0B,
        REG_PWM2        = 0x0C,
        REG_PWM3        = 0x0D,
        REG_PWM4        = 0x0E,
        REG_PWM5        = 0x0F,
        REG_PWM6        = 0x10,
        REG_PWM7        = 0x11,
        REG_PWM8        = 0x12,
        REG_PWM9        = 0x13,
        REG_PWM10       = 0x14,
        REG_PWM11       = 0x15,
        REG_PWM12       = 0x16,
        REG_PWM13       = 0x17,
        REG_PWM14       = 0x18,
        REG_PWM15       = 0x19,
        REG_IREF0       = 0x22,
        REG_IREF1       = 0x23,
        REG_IREF2       = 0x24,
        REG_IREF3       = 0x25,
        REG_IREF4       = 0x26,
        REG_IREF5       = 0x27,
        REG_IREF6       = 0x28,
        REG_IREF7       = 0x29,
        REG_IREF8       = 0x2A,
        REG_IREF9       = 0x2B,
        REG_IREF10      = 0x2C,
        REG_IREF11      = 0x2D,
        REG_IREF12      = 0x2E,
        REG_IREF13      = 0x2F,
        REG_IREF14      = 0x30,
        REG_IREF15      = 0x31,
        REG_OFFSET      = 0x3A,
        REG_SUBADR1     = 0x3B,
        REG_SUBADR2     = 0x3C,
        REG_SUBADR3     = 0x3D,
        REG_ALLCALLADR  = 0x3E,
        REG_RESERVED1   = 0x3F,
        REG_RESERVED2   = 0x40,
        REG_RESERVED3   = 0x41,
        REG_PWMALL      = 0x42,
        REG_IREFALL     = 0x43,
        REG_EFLAG0      = 0x44,
        REG_EFLAG1      = 0x45,
        REG_AUTO_INC    = 0x80
    };

    //Member variables
    I2C m_I2C;
    const int m_ADDR;

    //Internal functions
    char read(char reg);
    void write(char reg, char data);
    void readMulti(char startReg, char* data, int length);
    void writeMulti(char* data, int length);
};

#endif