16-channel, 12-bit PWM Fm I2C-bus LED controller
Diff: PCA9685.h
- Revision:
- 1:6e7731f14aac
- Parent:
- 0:1527da6e7c05
- Child:
- 2:fa75aff130cc
--- a/PCA9685.h Tue Nov 07 14:17:54 2017 +0000 +++ b/PCA9685.h Tue Nov 07 14:28:19 2017 +0000 @@ -0,0 +1,421 @@ +/** + * @brief PCA9685.h + * @details 16-channel, 12-bit PWM Fm+ I2C-bus LED controller. + * Header file. + * + * + * @return NA + * + * @author Manuel Caballero + * @date 31/October/2017 + * @version 31/October/2017 The ORIGIN + * @pre NaN. + * @warning NaN + * @pre This code belongs to AqueronteBlog ( http://unbarquero.blogspot.com ). + */ +#ifndef PCA9685_H +#define PCA9685_H + +#include "mbed.h" + + +/** + Example: + +[todo] +*/ + + +/*! + Library for the PCA9685 16-channel, 12-bit PWM Fm+ I2C-bus LED controller. +*/ +class PCA9685 +{ +public: + /** + * @brief DEFAULT ADDRESSES. NOTE: There are a maximum of 64 possible programmable addresses using the 6 hardware + * address pins. Two of these addresses, Software Reset and LED All Call, cannot be used + * because their default power-up state is ON, leaving a maximum of 62 addresses. Using + * other reserved addresses, as well as any other subcall address, will reduce the total + * number of possible addresses even further. + * + * To access to a certain address just use the following method: PCA9685_ADDRESS_0 + Counter_Address + * Ex: + * PCA9685_ADDRESS_0 + 1 = 0x40 + 1 = 0x41 ( 0b1000001 ) + * PCA9685_ADDRESS_0 + 10 = 0x40 + 10 = 0x4A ( 0b1001010 ) + * and so on... + */ + typedef enum { + PCA9685_ADDRESS_0 = ( 0x40 << 1 ) /*!< A5 A4 A3 A2 A1 A0: 000 000 */ + } PCA9685_address_t; + + +// REGISTERS + /** + * @brief REGISTER DEFINITIONS + */ + typedef enum { + MODE1 = 0x00, /*!< Mode register 1 */ + MODE2 = 0x01, /*!< Mode register 2 */ + SUBADR1 = 0x02, /*!< I2C-bus subaddress 1 */ + SUBADR2 = 0x03, /*!< I2C-bus subaddress 2 */ + SUBADR3 = 0x04, /*!< I2C-bus subaddress 3 */ + ALLCALLADR = 0x05, /*!< LED All Call I2C-bus address */ + LED0_ON_L = 0x06, /*!< LED0 output and brightness control byte 0 */ + LED0_ON_H = 0x07, /*!< LED0 output and brightness control byte 1 */ + LED0_OFF_L = 0x08, /*!< LED0 output and brightness control byte 2 */ + LED0_OFF_H = 0x09, /*!< LED0 output and brightness control byte 3 */ + LED1_ON_L = 0x0A, /*!< LED1 output and brightness control byte 0 */ + LED1_ON_H = 0x0B, /*!< LED1 output and brightness control byte 1 */ + LED1_OFF_L = 0x0C, /*!< LED1 output and brightness control byte 2 */ + LED1_OFF_H = 0x0D, /*!< LED1 output and brightness control byte 3 */ + LED2_ON_L = 0x0E, /*!< LED2 output and brightness control byte 0 */ + LED2_ON_H = 0x0F, /*!< LED2 output and brightness control byte 1 */ + LED2_OFF_L = 0x10, /*!< LED2 output and brightness control byte 2 */ + LED2_OFF_H = 0x11, /*!< LED2 output and brightness control byte 3 */ + LED3_ON_L = 0x12, /*!< LED3 output and brightness control byte 0 */ + LED3_ON_H = 0x13, /*!< LED3 output and brightness control byte 1 */ + LED3_OFF_L = 0x14, /*!< LED3 output and brightness control byte 2 */ + LED3_OFF_H = 0x15, /*!< LED3 output and brightness control byte 3 */ + LED4_ON_L = 0x16, /*!< LED4 output and brightness control byte 0 */ + LED4_ON_H = 0x17, /*!< LED4 output and brightness control byte 1 */ + LED4_OFF_L = 0x18, /*!< LED4 output and brightness control byte 2 */ + LED4_OFF_H = 0x19, /*!< LED4 output and brightness control byte 3 */ + LED5_ON_L = 0x1A, /*!< LED5 output and brightness control byte 0 */ + LED5_ON_H = 0x1B, /*!< LED5 output and brightness control byte 1 */ + LED5_OFF_L = 0x1C, /*!< LED5 output and brightness control byte 2 */ + LED5_OFF_H = 0x1D, /*!< LED5 output and brightness control byte 3 */ + LED6_ON_L = 0x1E, /*!< LED6 output and brightness control byte 0 */ + LED6_ON_H = 0x1F, /*!< LED6 output and brightness control byte 1 */ + LED6_OFF_L = 0x20, /*!< LED6 output and brightness control byte 2 */ + LED6_OFF_H = 0x21, /*!< LED6 output and brightness control byte 3 */ + LED7_ON_L = 0x22, /*!< LED7 output and brightness control byte 0 */ + LED7_ON_H = 0x23, /*!< LED7 output and brightness control byte 1 */ + LED7_OFF_L = 0x24, /*!< LED7 output and brightness control byte 2 */ + LED7_OFF_H = 0x25, /*!< LED7 output and brightness control byte 3 */ + LED8_ON_L = 0x26, /*!< LED8 output and brightness control byte 0 */ + LED8_ON_H = 0x27, /*!< LED8 output and brightness control byte 1 */ + LED8_OFF_L = 0x28, /*!< LED8 output and brightness control byte 2 */ + LED8_OFF_H = 0x29, /*!< LED8 output and brightness control byte 3 */ + LED9_ON_L = 0x2A, /*!< LED9 output and brightness control byte 0 */ + LED9_ON_H = 0x2B, /*!< LED9 output and brightness control byte 1 */ + LED9_OFF_L = 0x2C, /*!< LED9 output and brightness control byte 2 */ + LED9_OFF_H = 0x2D, /*!< LED9 output and brightness control byte 3 */ + LED10_ON_L = 0x2E, /*!< LED10 output and brightness control byte 0 */ + LED10_ON_H = 0x2F, /*!< LED10 output and brightness control byte 1 */ + LED10_OFF_L = 0x30, /*!< LED10 output and brightness control byte 2 */ + LED10_OFF_H = 0x31, /*!< LED10 output and brightness control byte 3 */ + LED11_ON_L = 0x32, /*!< LED11 output and brightness control byte 0 */ + LED11_ON_H = 0x33, /*!< LED11 output and brightness control byte 1 */ + LED11_OFF_L = 0x34, /*!< LED11 output and brightness control byte 2 */ + LED11_OFF_H = 0x35, /*!< LED11 output and brightness control byte 3 */ + LED12_ON_L = 0x36, /*!< LED12 output and brightness control byte 0 */ + LED12_ON_H = 0x37, /*!< LED12 output and brightness control byte 1 */ + LED12_OFF_L = 0x38, /*!< LED12 output and brightness control byte 2 */ + LED12_OFF_H = 0x39, /*!< LED12 output and brightness control byte 3 */ + LED13_ON_L = 0x3A, /*!< LED13 output and brightness control byte 0 */ + LED13_ON_H = 0x3B, /*!< LED13 output and brightness control byte 1 */ + LED13_OFF_L = 0x3C, /*!< LED13 output and brightness control byte 2 */ + LED13_OFF_H = 0x3D, /*!< LED13 output and brightness control byte 3 */ + LED14_ON_L = 0x3E, /*!< LED14 output and brightness control byte 0 */ + LED14_ON_H = 0x3F, /*!< LED14 output and brightness control byte 1 */ + LED14_OFF_L = 0x40, /*!< LED14 output and brightness control byte 2 */ + LED14_OFF_H = 0x41, /*!< LED14 output and brightness control byte 3 */ + LED15_ON_L = 0x42, /*!< LED15 output and brightness control byte 0 */ + LED15_ON_H = 0x43, /*!< LED15 output and brightness control byte 1 */ + LED15_OFF_L = 0x44, /*!< LED15 output and brightness control byte 2 */ + LED15_OFF_H = 0x45, /*!< LED15 output and brightness control byte 3 */ + ALL_LED_ON_L = 0xFA, /*!< load all the LEDn_ON registers, byte 0 */ + ALL_LED_ON_H = 0xFB, /*!< load all the LEDn_ON registers, byte 1 */ + ALL_LED_OFF_L = 0xFC, /*!< load all the LEDn_OFF registers, byte 0 */ + ALL_LED_OFF_H = 0xFD, /*!< load all the LEDn_OFF registers, byte 1 */ + PRE_SCALE = 0xFE, /*!< prescaler for PWM output frequency */ + TESTMODE = 0xFF /*!< defines the test mode to be entered */ + } PCA9685_registers_t; + + + +// LED Sub Call I2C-bus addresses + /** + * @brief SUBADDRESS. NOTE: At power-up, Sub Call I2C-bus addresses are disabled. PCA9685 does not send an + * ACK when E2h (R/W = 0) or E3h (R/W = 1), E4h (R/W = 0) or E5h (R/W = 1), or + * E8h (R/W = 0) or E9h (R/W = 1) is sent by the master. + */ + typedef enum { + SUBADR1_REG = ( 0xE2 << 1 ), /*!< Subaddress 1 */ + SUBADR2_REG = ( 0xE4 << 1 ), /*!< Subaddress 2 */ + SUBADR3_REG = ( 0xE8 << 1 ) /*!< Subaddress 3 */ + } PCA9685_subaddresses_t; + + + + +// Software Reset I2C-bus address + /** + * @brief SWRST. NOTE: The Software Reset address (SWRST Call) must be used with + * R/#W = logic 0. If R/#W = logic 1, the PCA9685 does not acknowledge the SWRST. + */ + typedef enum { + GENERAL_CALL_ADDRESS = ( 0x00 << 1 ), /*!< Software reset */ + SWRST = ( 0x06 << 1 ) /*!< Software reset */ + } PCA9685_software_reset_t; + + + + +// MODE REGISTER 1, MODE1 + /** + * @brief RESTART + */ + typedef enum { + MODE1_RESTART_MASK = ( 1 << 7 ), /*!< RESTART bit mask */ + MODE1_RESTART_ENABLED = ( 1 << 7 ), /*!< Restart enabled */ + MODE1_RESTART_DISABLED = ( 0 << 7 ) /*!< Restart disabled ( default ) */ + } PCA9685_mode1_restart_t; + + + /** + * @brief EXTCLK + */ + typedef enum { + MODE1_EXTCLK_MASK = ( 1 << 6 ), /*!< EXTCLK bit mask */ + MODE1_EXTCLK_ENABLED = ( 1 << 6 ), /*!< Use EXTERNAL clock */ + MODE1_EXTCLK_DISABLED = ( 0 << 6 ) /*!< Use INTERNAL clock ( default ) */ + } PCA9685_mode1_extclk_t; + + + /** + * @brief AI + */ + typedef enum { + MODE1_AI_MASK = ( 1 << 5 ), /*!< AI bit mask */ + MODE1_AI_ENABLED = ( 1 << 5 ), /*!< Auto-Increment enabled */ + MODE1_AI_DISABLED = ( 0 << 5 ) /*!< Auto-Increment disabled ( default ) */ + } PCA9685_mode1_ai_t; + + + /** + * @brief SLEEP + */ + typedef enum { + MODE1_SLEEP_MASK = ( 1 << 4 ), /*!< SLEEP bit mask */ + MODE1_SLEEP_ENABLED = ( 1 << 4 ), /*!< Low power mode. Oscillator off ( default ) */ + MODE1_SLEEP_DISABLED = ( 0 << 4 ) /*!< Normal mode */ + } PCA9685_mode1_sleep_t; + + + /** + * @brief SUB1 + */ + typedef enum { + MODE1_SUB1_MASK = ( 1 << 3 ), /*!< SUB1 bit mask */ + MODE1_SUB1_ENABLED = ( 1 << 3 ), /*!< PCA9685 responds to I2C-bus subaddress 1 */ + MODE1_SUB1_DISABLED = ( 0 << 3 ) /*!< PCA9685 does not respond to I2C-bus subaddress 1 ( default ) */ + } PCA9685_mode1_sub1_t; + + + /** + * @brief SUB2 + */ + typedef enum { + MODE1_SUB2_MASK = ( 1 << 2 ), /*!< SUB2 bit mask */ + MODE1_SUB2_ENABLED = ( 1 << 2 ), /*!< PCA9685 responds to I2C-bus subaddress 2 */ + MODE1_SUB2_DISABLED = ( 0 << 2 ) /*!< PCA9685 does not respond to I2C-bus subaddress 2 ( default ) */ + } PCA9685_mode1_sub2_t; + + + /** + * @brief SUB3 + */ + typedef enum { + MODE1_SUB3_MASK = ( 1 << 1 ), /*!< SUB1 bit mask */ + MODE1_SUB3_ENABLED = ( 1 << 1 ), /*!< PCA9685 responds to I2C-bus subaddress 3 */ + MODE1_SUB3_DISABLED = ( 0 << 1 ) /*!< PCA9685 does not respond to I2C-bus subaddress 3 ( default ) */ + } PCA9685_mode1_sub3_t; + + + /** + * @brief ALLCALL + */ + typedef enum { + MODE1_ALLCALL_MASK = ( 1 << 0 ), /*!< ALLCALL bit mask */ + MODE1_ALLCALL_ENABLED = ( 1 << 0 ), /*!< PCA9685 responds to LED All Call I2C-bus address ( default ) */ + MODE1_ALLCALL_DISABLED = ( 0 << 0 ) /*!< PCA9685 does not respond to LED All Call I2C-bus address */ + } PCA9685_mode1_allcall_t; + + + +// MODE REGISTER 2, MODE2 + /** + * @brief INVRT + */ + typedef enum { + MODE2_INVRT_MASK = ( 1 << 4 ), /*!< INVRT bit mask */ + MODE2_INVRT_ENABLED = ( 1 << 4 ), /*!< Output logic state inverted. Value to use when no external driver used. Applicable when OE = 0 */ + MODE2_INVRT_DISABLED = ( 0 << 4 ) /*!< Output logic state not inverted. Value to use when external driver used. Applicable when OE = 0. ( default ) */ + } PCA9685_mode2_invrt_t; + + + /** + * @brief OCH + */ + typedef enum { + MODE2_OCH_MASK = ( 1 << 3 ), /*!< ALLCALL bit mask */ + MODE2_OCH_OUTPUT_CHANGE_STOP_CMD = ( 0 << 3 ), /*!< Outputs change on STOP command ( default ) */ + MODE2_OCH_OUTPUT_CHANGE_ACK_CMD = ( 1 << 3 ) /*!< Outputs change on ACK */ + } PCA9685_mode2_och_t; + + + /** + * @brief OUTDRV + */ + typedef enum { + MODE2_OUTDRV_MASK = ( 1 << 2 ), /*!< OUTDRV bit mask */ + MODE2_OUTDRV_TOTEM_POLE_STRUCTURE = ( 1 << 2 ), /*!< The 16 LEDn outputs are configured with a totem pole structure ( default ) */ + MODE2_OUTDRV_OPEN_DRAIN_STRUCTURE = ( 0 << 2 ) /*!< The 16 LEDn outputs are configured with an open-drain structure */ + } PCA9685_mode2_outdrv_t; + + + /** + * @brief OUTNE + */ + typedef enum { + MODE2_OUTNE_MASK = ( 3 << 0 ), /*!< OUTNE bit mask */ + MODE2_OUTNE_LEDn_LOW = ( 0 << 0 ), /*!< When #OE = 1 (output drivers not enabled), LEDn = 0 ( default ) */ + MODE2_OUTNE_LEDn_HIGH = ( 1 << 0 ), /*!< When #OE = 1 (output drivers not enabled): LEDn = 1 when OUTDRV = 1 + LEDn = high-impedance when OUTDRV = 0 (same as OUTNE[1:0] = 10) */ + MODE2_OUTNE_LEDn_HIGH_IMPEDANCE = ( 2 << 0 ) /*!< When #OE = 1 (output drivers not enabled), LEDn = high-impedance */ + } PCA9685_mode2_outne_t; + + + + + /** + * @brief INTERNAL CONSTANTS + */ + typedef enum { + PCA9685_INTERNAL_CLOCK = 25000000, /*!< Internal clock frequency */ + PCA9685_ADC_STEPS = 4096 /*!< ADC 12-bits */ + } PCA9685_internal_parameters_t; + + + typedef enum { + PCA9685_LED0 = 0x00, /*!< LED0 channel */ + PCA9685_LED1 = 0x01, /*!< LED1 channel */ + PCA9685_LED2 = 0x02, /*!< LED2 channel */ + PCA9685_LED3 = 0x03, /*!< LED3 channel */ + PCA9685_LED4 = 0x04, /*!< LED4 channel */ + PCA9685_LED5 = 0x05, /*!< LED5 channel */ + PCA9685_LED6 = 0x06, /*!< LED6 channel */ + PCA9685_LED7 = 0x07, /*!< LED7 channel */ + PCA9685_LED8 = 0x08, /*!< LED8 channel */ + PCA9685_LED9 = 0x09, /*!< LED9 channel */ + PCA9685_LED10 = 0x0A, /*!< LED10 channel */ + PCA9685_LED11 = 0x0B, /*!< LED11 channel */ + PCA9685_LED12 = 0x0C, /*!< LED12 channel */ + PCA9685_LED13 = 0x0D, /*!< LED13 channel */ + PCA9685_LED14 = 0x0E, /*!< LED14 channel */ + PCA9685_LED15 = 0x0F /*!< LED15 channel */ + } PCA9685_led_channel_t; + + + + + + /** + * @brief INTERNAL CONSTANTS + */ + typedef enum { + PCA9685_SUCCESS = 0, + PCA9685_FAILURE = 1, + I2C_SUCCESS = 0 /*!< I2C communication was fine */ + } PCA9685_status_t; + + + + + /** Create an PCA9685 object connected to the specified I2C pins. + * + * @param sda I2C data pin + * @param scl I2C clock pin + * @param addr I2C slave address + * @param freq I2C frequency in Hz. + */ + PCA9685 ( PinName sda, PinName scl, uint32_t addr, uint32_t freq ); + + /** Delete PCA9685 object. + */ + ~PCA9685(); + + /** It resets the device by software. + */ + PCA9685_status_t PCA9685_SoftReset ( void ); + + /** It configures the mode of the device: Sleep or Normal operation mode. + */ + PCA9685_status_t PCA9685_SetMode ( PCA9685_mode1_sleep_t myMode ); + + /** It configures a new PWM frequency. + */ + PCA9685_status_t PCA9685_SetPWM_Freq ( float myNewFrequency ); + + /** It configures a new PWM duty cycle on a given LED. + */ + PCA9685_status_t PCA9685_SetPWM_DutyCycle ( PCA9685_led_channel_t myLEDchannel, uint8_t myDelay, uint8_t myPWM_DutyCycle ); + + /** It configures a new PWM duty cycle on all LEDs. + */ + PCA9685_status_t PCA9685_SetPWM_DutyCycle_AllLEDs ( uint8_t myDelay, uint8_t myPWM_DutyCycle ); + + /** It sets the LEDn ON. + */ + PCA9685_status_t PCA9685_SetLED_ON ( PCA9685_led_channel_t myLEDchannel ); + + /** It sets the LEDn OFF. + */ + PCA9685_status_t PCA9685_SetLED_OFF ( PCA9685_led_channel_t myLEDchannel ); + + /** It sets All LEDs ON. + */ + PCA9685_status_t PCA9685_SetAllLED_ON ( void ); + + /** It sets All LEDs OFF. + */ + PCA9685_status_t PCA9685_SetAllLED_OFF ( void ); + + /** It sets SUB1 mode. + */ + PCA9685_status_t PCA9685_SetSUB1 ( PCA9685_mode1_sub1_t mySUB1_mode ); + + /** It sets SUB2 mode. + */ + PCA9685_status_t PCA9685_SetSUB2 ( PCA9685_mode1_sub2_t mySUB2_mode ); + + /** It sets SUB3 mode. + */ + PCA9685_status_t PCA9685_SetSUB3 ( PCA9685_mode1_sub3_t mySUB3_mode ); + + /** It sets ALLCALL mode. + */ + PCA9685_status_t PCA9685_SetALLCALL ( PCA9685_mode1_allcall_t myALLCALL_mode ); + + /** It sets INVERT mode. + */ + PCA9685_status_t PCA9685_SetINVERT ( PCA9685_mode2_invrt_t myINVERT_mode ); + + /** It sets OCH mode. + */ + PCA9685_status_t PCA9685_SetOCH ( PCA9685_mode2_och_t myOCH_mode ); + + /** It sets OUTDRV mode. + */ + PCA9685_status_t PCA9685_SetOUTDRV ( PCA9685_mode2_outdrv_t myOUTDRV_mode ); + + + +private: + I2C i2c; + uint32_t PCA9685_Addr; +}; + +#endif