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

Files at this revision

API Documentation at this revision

Comitter:
mcm
Date:
Tue Nov 07 14:52:15 2017 +0000
Parent:
1:6e7731f14aac
Child:
3:f69f4e2c35b6
Commit message:
The function file is ready to test

Changed in this revision

PCA9685.cpp Show annotated file Show diff for this revision Revisions of this file
PCA9685.h Show annotated file Show diff for this revision Revisions of this file
--- 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;
+}
--- a/PCA9685.h	Tue Nov 07 14:28:19 2017 +0000
+++ b/PCA9685.h	Tue Nov 07 14:52:15 2017 +0000
@@ -332,6 +332,24 @@
     } PCA9685_status_t;
 
 
+// MACRO: round function
+#define _MYROUND( x ) ({        \
+        uint32_t aux_pre;       \
+        float    aux_x;         \
+                                \
+        aux_x    =   (x);       \
+        aux_pre  =   (x);       \
+        aux_x   -=   aux_pre;   \
+        aux_x   *=   10;        \
+                                \
+        if ( aux_x >= 5 )       \
+            aux_pre++;          \
+                                \
+        aux_pre;                \
+        })
+
+
+
 
 
     /** Create an PCA9685 object connected to the specified I2C pins.