16-channel, 12-bit PWM Fm I2C-bus LED controller

Revision:
2:fa75aff130cc
Parent:
0:1527da6e7c05
--- a/PCA9685.cpp	Tue Nov 07 14:28:19 2017 +0000
+++ b/PCA9685.cpp	Tue Nov 07 14:52:15 2017 +0000
@@ -0,0 +1,908 @@
+/**
+ * @brief       PCA9685.h
+ * @details     16-channel, 12-bit PWM Fm+ I2C-bus LED controller.
+ *              Functions file.
+ *
+ *
+ * @return      NA
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017    The ORIGIN
+ * @pre         NaN.
+ * @warning     NaN
+ * @pre         This code belongs to AqueronteBlog ( http://unbarquero.blogspot.com ).
+ */
+
+#include "PCA9685.h"
+
+
+PCA9685::PCA9685 ( PinName sda, PinName scl, uint32_t addr, uint32_t freq )
+    : i2c          ( sda, scl )
+    , PCA9685_Addr ( addr )
+{
+    i2c.frequency( freq );
+}
+
+
+PCA9685::~PCA9685()
+{
+}
+
+
+
+/**
+ * @brief       PCA9685_SoftReset ( void )
+ *
+ * @details     It performs a software reset.
+ *
+ * @param[in]    NaN.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SoftReset.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         The device will be ready to be addressed again within
+ *              the specified bus free time ( t_BUF ).
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SoftReset   ( void )
+{
+    char         cmd   =   SWRST;
+    uint32_t     aux;
+
+
+
+    aux = i2c.write ( GENERAL_CALL_ADDRESS, &cmd, 1, false );
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetMode ( PCA9685_mode1_sleep_t )
+ *
+ * @details     It configures the device in Low power mode or in Normal operation
+ *              mode.
+ *
+ * @param[in]    myMode:            Sleep or Normal mode.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetMode.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         NaN.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetMode   ( PCA9685_mode1_sleep_t myMode )
+{
+    char     cmd[]   =   { MODE1, 0 };
+    uint32_t aux;
+
+
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], 1, true );
+    aux      =   i2c.read  ( PCA9685_Addr, &cmd[1], 1 );
+    cmd[1]  &=  ~MODE1_SLEEP_MASK;
+    cmd[1]  |=   myMode;
+
+
+    aux = i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetPWM_Freq ( float )
+ *
+ * @details     It sets a new PWM frequency.
+ *
+ * @param[in]    myNewFrequency:    New PWM frequency.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetPWM_Freq.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         This library can ONLY work with the internal clock, otherwise
+ *              PCA9685_INTERNAL_CLOCK must be changed in the header file.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetPWM_Freq ( float myNewFrequency )
+{
+    char     cmd[]       =   { MODE1, 0 };
+    char     prev_mode1  =   0;
+    uint32_t aux;
+
+
+    // The maximum PWM frequency is 1526 Hz and the minimum PWM frequency is 24 Hz.
+    if ( ( myNewFrequency < 24 ) || ( myNewFrequency > 1526 ) )
+        return   PCA9685_FAILURE;
+
+
+    // The device MUST be in SLEEP mode
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], 1, true );
+    aux      =   i2c.read  ( PCA9685_Addr, &prev_mode1, 1 );
+    cmd[1]   =   ( prev_mode1 | MODE1_SLEEP_ENABLED );
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+    // Calculate the new PWM frequency
+    if ( myNewFrequency == 24 )
+        cmd[1]   =   255;
+    else
+        cmd[1]   =   _MYROUND ( ( PCA9685_INTERNAL_CLOCK / ( PCA9685_ADC_STEPS * myNewFrequency ) ) - 1 );
+
+
+    cmd[0]   =   PRE_SCALE;
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+    // Restore the device's mode
+    cmd[0]   =   MODE1;
+    cmd[1]   =   prev_mode1;
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetPWM_DutyCycle ( PCA9685_led_channel_t , uint8_t , uint8_t )
+ *
+ * @details     It sets a new PWM duty cycle on the given LED ( channel ).
+ *
+ * @param[in]    myLEDchannel:      Chosen LED ( channel ).
+ * @param[in]    myDelay:           PWM delay.
+ * @param[in]    myPWM_DutyCycle:   PWM duty cycle.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetPWM_DutyCycle.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         Datasheet p.17 ( Example 1 and Example 2).
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetPWM_DutyCycle ( PCA9685_led_channel_t myLEDchannel, uint8_t myDelay, uint8_t myPWM_DutyCycle )
+{
+    char     cmd[]       =   { 0, 0 };
+    uint32_t myAux       =   0;
+    uint32_t aux;
+
+
+    // The range is from 0% up to 100%.
+    if ( ( myDelay > 100 ) || ( myPWM_DutyCycle > 100 ) )
+        return   PCA9685_FAILURE;
+
+
+    // Delay time cannot be 0%
+    if ( myDelay == 0 )
+        myDelay  =   1;
+
+
+    // DELAY TIME: LEDn_ON_L + LEDn_ON_H
+    myAux   =   _MYROUND ( ( myDelay / 100.0 ) * PCA9685_ADC_STEPS ) - 1;
+
+    // LEDn_ON_L
+    cmd[0]  =   LED0_ON_L + ( myLEDchannel << 2 );
+    cmd[1]  =   ( myAux & 0xFF );
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDn_ON_H
+    cmd[0]  =   LED0_ON_H + ( myLEDchannel << 2 );
+
+    if ( myPWM_DutyCycle == 100 )
+        cmd[1]  =   0x10;                                   // LEDn full ON
+    else
+        cmd[1]  =   ( ( myAux >> 8 ) & 0xFF );
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+    // LED OFF TIME: LEDn_OFF_L + LEDn_OFF_H
+    myAux  +=    _MYROUND ( ( myPWM_DutyCycle / 100.0 ) * PCA9685_ADC_STEPS );
+
+    if ( ( myDelay + myPWM_DutyCycle ) <= 100 )
+        myAux--;
+    else
+        myAux    =   ( myAux - 4096 );
+
+
+    // LEDn_OFF_L
+    cmd[0]  =   LED0_OFF_L + ( myLEDchannel << 2 );
+    cmd[1]  =   ( myAux & 0xFF );
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDn_OFF_H
+    cmd[0]  =   LED0_OFF_H + ( myLEDchannel << 2 );
+
+    if ( myPWM_DutyCycle == 0 )
+        cmd[1]  =   0x10;                                   // LEDn full OFF
+    else
+        cmd[1]  =   ( ( myAux >> 8 ) & 0xFF );
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetPWM_DutyCycle_AllLEDs ( uint8_t , uint8_t )
+ *
+ * @details     It sets a new PWM duty cycle on all LEDs ( all channels ).
+ *
+ * @param[in]    myDelay:           PWM delay.
+ * @param[in]    myPWM_DutyCycle:   PWM duty cycle.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetPWM_DutyCycle_AllLEDs.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         Datasheet p.17 ( Example 1 and Example 2).
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetPWM_DutyCycle_AllLEDs ( uint8_t myDelay, uint8_t myPWM_DutyCycle )
+{
+    char      cmd[]       =   { 0, 0 };
+    uint32_t  myAux       =   0;
+    uint32_t  aux;
+
+
+    // The range is from 0% up to 100%.
+    if ( ( myDelay > 100 ) || ( myPWM_DutyCycle > 100 ) )
+        return   PCA9685_FAILURE;
+
+
+    // Delay time cannot be 0%
+    if ( myDelay == 0 )
+        myDelay  =   1;
+
+
+    // DELAY TIME: LEDs_ON_L + LEDs_ON_H
+    myAux   =   _MYROUND ( ( myDelay / 100.0 ) * PCA9685_ADC_STEPS ) - 1;
+
+    // LEDs_ON_L
+    cmd[0]  =   ALL_LED_ON_L;
+    cmd[1]  =   ( myAux & 0xFF );
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDs_ON_H
+    cmd[0]  =   ALL_LED_ON_H;
+
+    if ( myPWM_DutyCycle == 100 )
+        cmd[1]  =   0x10;                                   // All LEDs full ON
+    else
+        cmd[1]  =   ( ( myAux >> 8 ) & 0xFF );
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+    // LED OFF TIME: LEDs_OFF_L + LEDs_OFF_H
+    myAux  +=    _MYROUND ( ( myPWM_DutyCycle / 100.0 ) * PCA9685_ADC_STEPS );
+
+    if ( ( myDelay + myPWM_DutyCycle ) <= 100 )
+        myAux--;
+    else
+        myAux    =   ( myAux - 4096 );
+
+
+    // LEDs_OFF_L
+    cmd[0]  =   ALL_LED_OFF_L;
+    cmd[1]  =   ( myAux & 0xFF );
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDs_OFF_H
+    cmd[0]  =   ALL_LED_OFF_H;
+
+    if ( myPWM_DutyCycle == 0 )
+        cmd[1]  =   0x10;                                   // All LEDs full OFF
+    else
+        cmd[1]  =   ( ( myAux >> 8 ) & 0xFF );
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+/**
+ * @brief       PCA9685_SetLED_ON ( PCA9685_led_channel_t )
+ *
+ * @details     It sets LEDn ON.
+ *
+ * @param[in]    myLEDchannel:      Chosen LED ( channel ).
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetLED_ON.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         Update on ACK requires all 4 PWM channel registers to be loaded before outputs will
+ *              change on the last ACK.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetLED_ON ( PCA9685_led_channel_t myLEDchannel )
+{
+    char     cmd[]       =   { 0, 0 };
+    uint32_t aux;
+
+
+
+    // LEDn_ON_L
+    cmd[0]  =   LED0_ON_L + ( myLEDchannel << 2 );
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDn_ON_H
+    cmd[0]  =   LED0_ON_H + ( myLEDchannel << 2 );
+    cmd[1]  =   0x10;                                       // LEDn full ON
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+    // LEDn_OFF_L
+    cmd[0]  =   LED0_OFF_L + ( myLEDchannel << 2 );
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDn_OFF_H
+    cmd[0]  =   LED0_OFF_H + ( myLEDchannel << 2 );
+    cmd[1]  =   0x00;                                       // LEDn full OFF
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetLED_OFF ( PCA9685_led_channel_t )
+ *
+ * @details     It sets LEDn OFF.
+ *
+ * @param[in]    myLEDchannel:      Chosen LED ( channel ).
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetLED_OFF.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         Update on ACK requires all 4 PWM channel registers to be loaded before outputs will
+ *              change on the last ACK.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetLED_OFF ( PCA9685_led_channel_t myLEDchannel )
+{
+    char     cmd[]       =   { 0, 0 };
+    uint32_t aux;
+
+
+
+    // LEDn_ON_L
+    cmd[0]  =   LED0_ON_L + ( myLEDchannel << 2 );
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDn_ON_H
+    cmd[0]  =   LED0_ON_H + ( myLEDchannel << 2 );
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+    // LEDn_OFF_L
+    cmd[0]  =   LED0_OFF_L + ( myLEDchannel << 2 );
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDn_OFF_H
+    cmd[0]  =   LED0_OFF_H + ( myLEDchannel << 2 );
+    cmd[1]  =   0x10;                                       // LEDn full OFF
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetAllLED_ON ( void )
+ *
+ * @details     It sets All LEDs ON.
+ *
+ * @param[in]    NaN.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetAllLED_ON.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         Update on ACK requires all 4 PWM channel registers to be loaded before outputs will
+ *              change on the last ACK.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetAllLED_ON ( void )
+{
+    char     cmd[]       =   { 0, 0 };
+    uint32_t aux;
+
+
+
+    // LEDs_ON_L
+    cmd[0]  =   ALL_LED_ON_L;
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDs_ON_H
+    cmd[0]  =   ALL_LED_ON_H;
+    cmd[1]  =   0x10;                                       // All LEDs full ON
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+    // LEDs_OFF_L
+    cmd[0]  =   ALL_LED_OFF_L;
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDs_OFF_H
+    cmd[0]  =   ALL_LED_OFF_H;
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetAllLED_OFF ( void )
+ *
+ * @details     It sets All LEDs OFF.
+ *
+ * @param[in]    NaN.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetAllLED_OFF.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         Update on ACK requires all 4 PWM channel registers to be loaded before outputs will
+ *              change on the last ACK.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetAllLED_OFF ( void )
+{
+    char     cmd[]       =   { 0, 0 };
+    uint32_t aux;
+
+
+
+    // LEDs_ON_L
+    cmd[0]  =   ALL_LED_ON_L;
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDs_ON_H
+    cmd[0]  =   ALL_LED_ON_H;
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+    // LEDs_OFF_L
+    cmd[0]  =   ALL_LED_OFF_L;
+    cmd[1]  =   0x00;                                       // Dummy value
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+    // LEDs_OFF_H
+    cmd[0]  =   ALL_LED_OFF_H;
+    cmd[1]  =   0x10;                                       // All LEDs full OFF
+
+    aux     =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetSUB1 ( PCA9685_mode1_sub1_t )
+ *
+ * @details     The device responds ( Enabled ) or not ( Disabled ) to I2C-bus subaddress 1.
+ *
+ * @param[in]    mySUB1_mode:       SUB1 Enabled/Disabled.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetSUB1.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         NaN.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetSUB1 ( PCA9685_mode1_sub1_t mySUB1_mode )
+{
+    char     cmd[]       =   { MODE1, 0 };
+    uint32_t aux;
+
+
+    // Mask SUB1 and update its value
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], 1, true );
+    aux      =   i2c.read  ( PCA9685_Addr, &cmd[1], 1 );
+    cmd[1]  &=   ~MODE1_SUB1_MASK;
+    cmd[1]  |=   mySUB1_mode;
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetSUB2 ( PCA9685_mode1_sub2_t )
+ *
+ * @details     The device responds ( Enabled ) or not ( Disabled ) to I2C-bus subaddress 2.
+ *
+ * @param[in]    mySUB2_mode:       SUB2 Enabled/Disabled.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetSUB2.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         NaN.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetSUB2 ( PCA9685_mode1_sub2_t mySUB2_mode )
+{
+    char     cmd[]       =   { MODE1, 0 };
+    uint32_t aux;
+
+
+    // Mask SUB2 and update its value
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], 1, true );
+    aux      =   i2c.read  ( PCA9685_Addr, &cmd[1], 1 );
+    cmd[1]  &=   ~MODE1_SUB2_MASK;
+    cmd[1]  |=   mySUB2_mode;
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetSUB3 ( PCA9685_mode1_sub3_t )
+ *
+ * @details     The device responds ( Enabled ) or not ( Disabled ) to I2C-bus subaddress 3.
+ *
+ * @param[in]    mySUB3_mode:       SUB3 Enabled/Disabled.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetSUB3.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         NaN.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetSUB3 ( PCA9685_mode1_sub3_t mySUB3_mode )
+{
+    char     cmd[]       =   { MODE1, 0 };
+    uint32_t aux;
+
+
+    // Mask SUB3 and update its value
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], 1, true );
+    aux      =   i2c.read  ( PCA9685_Addr, &cmd[1], 1 );
+    cmd[1]  &=   ~MODE1_SUB3_MASK;
+    cmd[1]  |=   mySUB3_mode;
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetALLCALL ( PCA9685_mode1_allcall_t )
+ *
+ * @details     The device responds ( Enabled ) or not ( Disabled ) to LED All Call I2C-bus address.
+ *
+ * @param[in]    myALLCALL_mode:    ALLCALL Enabled/Disabled.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetALLCALL.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         NaN.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetALLCALL ( PCA9685_mode1_allcall_t myALLCALL_mode )
+{
+    char     cmd[]       =   { MODE1, 0 };
+    uint32_t aux;
+
+
+    // Mask SUB3 and update its value
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], 1, true );
+    aux      =   i2c.read  ( PCA9685_Addr, &cmd[1], 1 );
+    cmd[1]  &=   ~MODE1_ALLCALL_MASK;
+    cmd[1]  |=   myALLCALL_mode;
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetINVERT ( PCA9685_mode2_invrt_t )
+ *
+ * @details     Output logic state inverted ( Enabled ) or not ( Disabled ). Value to use
+ *              when external driver used. Applicable when #OE = 0
+ *
+ * @param[in]    myINVERT_mode:     INVERT Enabled/Disabled.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetINVERT.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         NaN.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetINVERT ( PCA9685_mode2_invrt_t myINVERT_mode )
+{
+    char     cmd[]       =   { MODE2, 0 };
+    uint32_t aux;
+
+
+    // Mask SUB3 and update its value
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], 1, true );
+    aux      =   i2c.read  ( PCA9685_Addr, &cmd[1], 1 );
+    cmd[1]  &=   ~MODE2_INVRT_MASK;
+    cmd[1]  |=   myINVERT_mode;
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}
+
+
+
+
+/**
+ * @brief       PCA9685_SetOUTDRV ( PCA9685_mode2_outdrv_t )
+ *
+ * @details     It sets the 16 LEDn as open-drain or totem pole structure.
+ *
+ * @param[in]    myOUTDRV_mode:     OUTDRV mode.
+ *
+ * @param[out]   NaN.
+ *
+ *
+ * @return       Status of PCA9685_SetOUTDRV.
+ *
+ *
+ * @author      Manuel Caballero
+ * @date        7/November/2017
+ * @version     7/November/2017     The ORIGIN
+ * @pre         NaN.
+ * @warning     NaN.
+ */
+PCA9685::PCA9685_status_t  PCA9685::PCA9685_SetOUTDRV ( PCA9685_mode2_outdrv_t myOUTDRV_mode )
+{
+    char     cmd[]       =   { MODE2, 0 };
+    uint32_t aux;
+
+
+    // Mask SUB3 and update its value
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], 1, true );
+    aux      =   i2c.read  ( PCA9685_Addr, &cmd[1], 1 );
+    cmd[1]  &=   ~MODE2_OUTDRV_MASK;
+    cmd[1]  |=   myOUTDRV_mode;
+    aux      =   i2c.write ( PCA9685_Addr, &cmd[0], sizeof( cmd )/sizeof( cmd[0] ), false );
+
+
+
+
+
+    if ( aux == I2C_SUCCESS )
+        return   PCA9685_SUCCESS;
+    else
+        return   PCA9685_FAILURE;
+}