16-channel, 12-bit PWM Fm I2C-bus LED controller
PCA9685.cpp
- Committer:
- mcm
- Date:
- 2017-11-07
- Revision:
- 2:fa75aff130cc
- Parent:
- 0:1527da6e7c05
File content as of revision 2:fa75aff130cc:
/** * @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; }