1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

driver/pca9633: add new driver

This commit is contained in:
Hendrik van Essen 2020-06-09 16:49:10 +02:00
parent d23afdda92
commit 1430ddca55
7 changed files with 935 additions and 0 deletions

View File

@ -568,6 +568,10 @@ ifneq (,$(filter opt3001,$(USEMODULE)))
USEMODULE += xtimer
endif
ifneq (,$(filter pca9633,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
endif
ifneq (,$(filter pca9685,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio
FEATURES_REQUIRED += periph_i2c

View File

@ -272,6 +272,10 @@ ifneq (,$(filter opt3001,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/opt3001/include
endif
ifneq (,$(filter pca9633,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pca9633/include
endif
ifneq (,$(filter pca9685,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pca9685/include
endif

337
drivers/include/pca9633.h Normal file
View File

@ -0,0 +1,337 @@
/*
* Copyright (C) 2020 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_pca9633 PCA9633 I2C PWM controller
* @ingroup drivers_actuators
* @brief Device driver for the NXP PCA9633
*
* @{
*
* @author Hendrik van Essen <hendrik.ve@fu-berlin.de>
* @file
*/
#ifndef PCA9633_H
#define PCA9633_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "stdbool.h"
#include "periph/i2c.h"
#include "pca9633_regs.h"
/**
* @brief Blinking period with a maximum duration of ~10.73 s
*/
#define PCA9633_BLINKING_PERIOD_MAX_MS (10625)
/**
* @brief Ration between on/ off in blinking mode is balanced.
*
* 128 = 255 / 2
*/
#define PCA9633_BLINKING_RATIO_BALANCED 128
/**
* @brief PCA9633 device initialization parameters
*/
typedef struct {
i2c_t i2c_dev; /**< I2C device */
uint16_t i2c_addr; /**< I2C address of device */
uint8_t reg_pwm_red; /**< Register for red color */
uint8_t reg_pwm_green; /**< Register for green color */
uint8_t reg_pwm_blue; /**< Register for blue color */
uint8_t reg_pwm_amber; /**< Register for amber color */
bool has_amber_channel; /**< Whether PCA9633 has fourth channel */
} pca9633_params_t;
/**
* @brief PCA9633 PWM device data structure type
*/
typedef struct {
pca9633_params_t params; /**< Device initialization parameters */
uint8_t stored_reg_ledout; /**< Stored register content of LEDOUT */
} pca9633_t;
/**
* @brief PCA9633 driver error codes
*/
typedef enum {
PCA9633_OK = 0, /**< Success */
PCA9633_ERROR_I2C = 1, /**< I2C communication error */
} pca9685_error_t;
/**
* @brief PCA9633 PWM channel definitions
*/
typedef enum {
PCA9633_PWM_CHANNEL_0 = PCA9633_REG_PWM0, /**< PWM channel 0 */
PCA9633_PWM_CHANNEL_1 = PCA9633_REG_PWM1, /**< PWM channel 1 */
PCA9633_PWM_CHANNEL_2 = PCA9633_REG_PWM2, /**< PWM channel 2 */
PCA9633_PWM_CHANNEL_3 = PCA9633_REG_PWM3, /**< PWM channel 3 */
} pca9633_pwm_channel_t;
/**
* @brief LED driver output state, LEDOUT (page 14, below table 13)
*/
typedef enum {
/**
* @brief LED driver x is off
*/
PCA9633_LDR_STATE_OFF,
/**
* @brief LED driver x is fully on (individual brightness and group
* dimming/ blinking not controlled)
*/
PCA9633_LDR_STATE_ON,
/**
* @brief LED driver x individual brightness can be controlled through its
* PWMx register
*/
PCA9633_LDR_STATE_IND,
/**
* @brief LED driver x individual brightness and group dimming/ blinking can
* be controlled through its PWMx register and the GRPPWM registers.
* If using PCA9633_LDR_STATE_IND_GRP the controller takes the
* minimum value of PWM* and GRPPWM register
*/
PCA9633_LDR_STATE_IND_GRP,
} pca9633_ldr_state_t;
/**
* @brief Auto-Increment options (page 10, table 6)
*/
typedef enum {
/**
* @brief No Auto-Increment
*/
PCA9633_AI_DISABLED,
/**
* @brief Auto-Increment for all registers. D3, D2, D1, D0 roll over to
* 0000 after the last register (1100) is accessed.
*/
PCA9633_AI_ALL,
/**
* @brief Auto-Increment for individual brightness registers only.
* D3, D2, D1, D0 roll over to 0010 after the last register (0101)
* is accessed.
*/
PCA9633_AI_IND,
/**
* @brief Auto-Increment for global control registers only. D3, D2, D1, D0
* roll over to 0110 after the last register (0111) is accessed.
*/
PCA9633_AI_GBL,
/**
* @brief Auto-Increment for individual and global control registers only.
* D3, D2, D1, D0 roll over to 0010 after the last register (0111)
* is accessed.
*/
PCA9633_AI_IND_GBL,
} pca9633_auto_inc_option_t;
/**
* @brief PCA9633 group control modes
*/
typedef enum {
/**
* @brief Control mode for blinking
*/
PCA9633_GROUP_CONTROL_MODE_BLINKING,
/**
* @brief Control mode for dimming
*/
PCA9633_GROUP_CONTROL_MODE_DIMMING,
} pca9633_group_control_mode_t;
/**
* @brief Initialization.
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] params Parameters for device initialization
*
* @return PCA9633_OK on success
* @return -PCA9633_ERROR_I2C if acquiring of I2C bus fails
* @return -EIO When slave device doesn't ACK the byte
* @return -ENXIO When no devices respond on the address sent on the bus
* @return -ETIMEDOUT When timeout occurs before device's response
* @return -EINVAL When an invalid argument is given
* @return -EOPNOTSUPP When MCU driver doesn't support the flag operation
* @return -EAGAIN When a lost bus arbitration occurs
*/
int pca9633_init(pca9633_t *dev, const pca9633_params_t *params);
/**
* @brief Turn on all LEDs. Restores settings saved at pca9633_turn_off().
*
* WARNING: If you call pca9633_turn_off() twice, without calling
* pca9633_turn_on() in between, then the restored state will be
* PCA9633_LDR_STATE_OFF!
*
* @param[in] dev Device descriptor of the PCA9633
*/
void pca9633_turn_on(pca9633_t* dev);
/**
* @brief Turn off all LEDs. Saves current settings for pca9633_turn_on().
* For power saving, see pca9633_sleep().
*
* WARNING: If you call pca9633_turn_off() twice, without calling
* pca9633_turn_on() in between, then the restored state will be
* PCA9633_LDR_STATE_OFF!
*
* @param[in] dev Device descriptor of the PCA9633
*/
void pca9633_turn_off(pca9633_t* dev);
/**
* @brief Switch to normal mode.
*
* @param[in] dev Device descriptor of the PCA9633
*/
void pca9633_wakeup(pca9633_t* dev);
/**
* @brief Switch to low power mode.
*
* @param[in] dev Device descriptor of the PCA9633
*/
void pca9633_sleep(pca9633_t* dev);
/**
* @brief Set individual PWM signal for a given channel.
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] pwm_channel PWM channel
* @param[in] pwm PWM value
*/
void pca9633_set_pwm(pca9633_t* dev,
pca9633_pwm_channel_t pwm_channel, uint8_t pwm);
/**
* @brief Set global PWM signal.
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] pwm PWM value
*/
void pca9633_set_grp_pwm(pca9633_t* dev, uint8_t pwm);
/**
* @brief Set up values for blinking mode. Blinking mode needs to be activated
* manually by calling
* pca9633_set_group_control_mode(GROUP_CONTROL_MODE_BLINKING).
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] blink_period_ms Period in ms for one blink (turning off and on).
* Maximum period possible is
* PCA9633_BLINKING_PERIOD_MAX_MS 10.73 s. All
* values above this maximum will we capped to it.
* @param[in] on_off_ratio Value between 0 and 255, where e.g. a value of
* 64 (255/4) means 1/4 of the time the LEDs are on
* and 3/4 of the time the LEDs are off.
*/
void pca9633_set_blinking(pca9633_t* dev, uint16_t blink_period_ms,
uint8_t on_off_ratio);
/**
* @brief Set PWM values for RGB.
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] r Value for red color channel
* @param[in] g Value for green color channel
* @param[in] b Value for blue color channel
*/
void pca9633_set_rgb(pca9633_t* dev, uint8_t r, uint8_t g, uint8_t b);
/**
* @brief Set PWM values for RGBA.
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] r Value for red color channel
* @param[in] g Value for green color channel
* @param[in] b Value for blue color channel
* @param[in] w Value for amber color channel
*/
void pca9633_set_rgba(pca9633_t* dev, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
/**
* @brief Set the LED driver output state for a given channel.
* There are four states:
* - PCA9633_LDR_STATE_OFF
* - PCA9633_LDR_STATE_ON
* - PCA9633_LDR_STATE_IND
* - PCA9633_LDR_STATE_IND_GRP
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] state One of the four possible states
* @param[in] pwm_channel PWM channel belonging to LDR
*/
void pca9633_set_ldr_state(pca9633_t* dev,
pca9633_ldr_state_t state,
pca9633_pwm_channel_t pwm_channel);
/**
* @brief Set the LED driver output state for all channels.
* There are four states:
* - PCA9633_LDR_STATE_OFF
* - PCA9633_LDR_STATE_ON
* - PCA9633_LDR_STATE_IND
* - PCA9633_LDR_STATE_IND_GRP
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] state One of the four possible states
*/
void pca9633_set_ldr_state_all(pca9633_t* dev, pca9633_ldr_state_t state);
/**
* @brief Set an option for auto increment.
* There are five options:
* - PCA9633_AI_DISABLED
* - PCA9633_AI_ALL
* - PCA9633_AI_IND
* - PCA9633_AI_GBL
* - PCA9633_AI_IND_GBL
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] option One of the possible five options
*/
void pca9633_set_auto_increment(pca9633_t* dev, pca9633_auto_inc_option_t option);
/**
* @brief Set the group control mode.
* There are two modes:
* - PCA9633_GROUP_CONTROL_MODE_BLINKING
* - PCA9633_GROUP_CONTROL_MODE_DIMMING
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] mode One of the two possible modes
*/
void pca9633_set_group_control_mode(pca9633_t* dev,
pca9633_group_control_mode_t mode);
#ifdef __cplusplus
}
#endif
#endif /* PCA9633_H */
/** @} */

1
drivers/pca9633/Makefile Normal file
View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2020 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_actuators
* @brief Default configuration for the PCA9633 I2C PWM controller
*
* @{
*
* @author Hendrik van Essen <hendrik.ve@fu-berlin.de>
* @file
*/
#ifndef PCA9633_PARAMS_H
#define PCA9633_PARAMS_H
#include <stdbool.h>
#include "periph/i2c.h"
#include "pca9633_regs.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @name Set default configuration parameters
* @{
*/
#ifndef PCA9633_PARAM_I2C_DEV
/** I2C device is I2C_DEV(0) */
#define PCA9633_PARAM_I2C_DEV I2C_DEV(0)
#endif
#ifndef PCA9633_PARAM_I2C_ADDR
/** I2C address of device is (0xc0 >> 1) */
#define PCA9633_PARAM_I2C_ADDR (0xc0 >> 1)
#endif
#ifndef PCA9633_PARAM_REG_PWM_RED
/** Register for red color is PCA9633_REG_PWM2 */
#define PCA9633_PARAM_REG_PWM_RED PCA9633_REG_PWM2
#endif
#ifndef PCA9633_PARAM_REG_PWM_GREEN
/** Register for green color is PCA9633_REG_PWM1 */
#define PCA9633_PARAM_REG_PWM_GREEN PCA9633_REG_PWM1
#endif
#ifndef PCA9633_PARAM_REG_PWM_BLUE
/** Register for blue color is PCA9633_REG_PWM0 */
#define PCA9633_PARAM_REG_PWM_BLUE PCA9633_REG_PWM0
#endif
#ifndef PCA9633_PARAM_REG_PWM_AMBER
/** Register for amber color is not given (0) */
#define PCA9633_PARAM_REG_PWM_AMBER 0
#endif
#ifndef PCA9633_PARAM_HAS_AMBER_CHANNEL
/** PCA9633 has no connected channel for amber (false) */
#define PCA9633_PARAM_HAS_AMBER_CHANNEL false
#endif
#ifndef PCA9633_PARAMS
#define PCA9633_PARAMS \
{ \
.i2c_dev = PCA9633_PARAM_I2C_DEV, \
.i2c_addr = PCA9633_PARAM_I2C_ADDR, \
.reg_pwm_red = PCA9633_PARAM_REG_PWM_RED, \
.reg_pwm_green = PCA9633_PARAM_REG_PWM_GREEN, \
.reg_pwm_blue = PCA9633_PARAM_REG_PWM_BLUE, \
.reg_pwm_amber = PCA9633_PARAM_REG_PWM_AMBER, \
.has_amber_channel = PCA9633_PARAM_HAS_AMBER_CHANNEL \
}
#endif /* PCA9633_PARAMS */
/**@}*/
/**
* @brief Allocate some memory to store the actual configuration
*/
static const pca9633_params_t pca9633_params[] =
{
PCA9633_PARAMS
};
#ifdef __cplusplus
}
#endif
#endif /* PCA9633_PARAMS_H */
/** @} */

View File

@ -0,0 +1,214 @@
/*
* Copyright (C) 2020 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_pca9633
* @brief Register definitions for the PCA9633 I2C PWM controller
* @author Hendrik van Essen <hendrik.ve@fu-berlin.de>
* @file
* @{
*/
#ifndef PCA9633_REGS_H
#define PCA9633_REGS_H
#ifdef __cplusplus
extern "C"
{
#endif
/* Register definitions (page 11, table 7) */
/**
* @brief Mode register 1
*/
#define PCA9633_REG_MODE1 0x00
/**
* @brief Mode register 2
*/
#define PCA9633_REG_MODE2 0x01
/**
* @brief Brightness control LED0
*/
#define PCA9633_REG_PWM0 0x02
/**
* @brief Brightness control LED1
*/
#define PCA9633_REG_PWM1 0x03
/**
* @brief Brightness control LED2
*/
#define PCA9633_REG_PWM2 0x04
/**
* @brief Brightness control LED3
*/
#define PCA9633_REG_PWM3 0x05
/**
* @brief Group duty cycle control
*/
#define PCA9633_REG_GRPPWM 0x06
/**
* @brief Group frequency
*/
#define PCA9633_REG_GRPFREQ 0x07
/**
* @brief LED output state
*/
#define PCA9633_REG_LEDOUT 0x08
/**
* @brief I2C-bus subaddress 1
*/
#define PCA9633_REG_SUBADR1 0x09
/**
* @brief I2C-bus subaddress 2
*/
#define PCA9633_REG_SUBADR2 0x0A
/**
* @brief I2C-bus subaddress 3
*/
#define PCA9633_REG_SUBADR3 0x0B
/**
* @brief LED All Call I2C-bus address
*/
#define PCA9633_REG_ALLCALLADR 0x0C
/* Bits in REG_MODE1 (page 12, table 8) */
/**
* @brief Bit for register Auto-Increment
* 0 = disabled
* 1 = enabled
*/
#define PCA9633_BIT_AI2 7
/**
* @brief Bit for Auto-Increment bit1
*/
#define PCA9633_BIT_AI1 6
/**
* @brief Bit for Auto-Increment bit0
*/
#define PCA9633_BIT_AI0 5
/**
* @brief 0 = Normal mode
* 1 = Low power mode. Oscillator off
*/
#define PCA9633_BIT_SLEEP 4
/**
* @brief 0 = PCA9633 does not respond to I2C-bus subaddress 1
* 1 = PCA9633 responds to I2C-bus subaddress 1
*/
#define PCA9633_BIT_SUB1 3
/**
* @brief 0 = PCA9633 does not respond to I2C-bus subaddress 2
* 1 = PCA9633 responds to I2C-bus subaddress 2
*/
#define PCA9633_BIT_SUB2 2
/**
* @brief 0 = PCA9633 does not respond to I2C-bus subaddress 3
* 1 = PCA9633 responds to I2C-bus subaddress 3
*/
#define PCA9633_BIT_SUB3 1
/**
* @brief 0 = PCA9633 does not respond to LED All Call I2C-bus address
* 1 = PCA9633 responds to LED All Call I2C-bus address
*/
#define PCA9633_BIT_ALLCALL 0
/* Bits in REG_MODE2 (page 12-13, table 9) */
/**
* @brief Bit for group control; 0=dimming, 1=blinking
*/
#define PCA9633_BIT_DMBLNK 5
/**
* @brief 0 = Output logic state not inverted. Value to use when no external driver used
* 1 = Output logic state inverted. Value to use when external driver used
*/
#define PCA9633_BIT_INVRT 4
/**
* @brief 0 = Outputs change on STOP command
* 1 = Outputs change on ACK
*/
#define PCA9633_BIT_OCH 3
/**
* @brief 0 = The 4 LED outputs are configured with an open-drain structure
* 1 = The 4 LED outputs are configured with a totem pole structure
*/
#define PCA9633_BIT_OUTDRV 2
/**
* @brief See PCA9633_BIT_OUTNE0
*/
#define PCA9633_BIT_OUTNE1 1
/**
* @brief 00 = When OE = 1 (output drivers not enabled), LEDn = 0.
* 01* = When OE = 1 (output drivers not enabled):
* LEDn = 1 when OUTDRV = 1
* LEDn = high-impedance when OUTDRV = 0 (same as OUTNE[1:0] = 10)
* 10 When OE = 1 (output drivers not enabled), LEDn = high-impedance.
* 11 reserved
*/
#define PCA9633_BIT_OUTNE0 0
/* Bits in REG_LEDOUT (page 14, table 13) */
/**
* @brief Lower of two bits for LDR3
*/
#define PCA9633_BIT_LDR3 6
/**
* @brief Lower of two bits for LDR2
*/
#define PCA9633_BIT_LDR2 4
/**
* @brief Lower of two bits for LDR1
*/
#define PCA9633_BIT_LDR1 2
/**
* @brief Lower of two bits for LDR0
*/
#define PCA9633_BIT_LDR0 0
#ifdef __cplusplus
}
#endif
#endif /* PCA9633_REGS_H */
/** @} */

277
drivers/pca9633/pca9633.c Normal file
View File

@ -0,0 +1,277 @@
/*
* Copyright (C) 2020 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_pca9633
* @brief Device driver for the PCA9633 I2C PWM controller
* @author Hendrik van Essen <hendrik.ve@fu-berlin.de>
* @file
* @{
*/
#include <stdio.h>
#include "pca9633.h"
#include "pca9633_regs.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief Write data to a register.
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] reg Register address to write to
* @param[in] data Data to write
*
* @return 0 on success
* @return -PCA9633_ERROR_I2C if acquiring of I2C bus fails
* @return -EIO When slave device doesn't ACK the byte
* @return -ENXIO When no devices respond on the address sent on the bus
* @return -ETIMEDOUT When timeout occurs before device's response
* @return -EINVAL When an invalid argument is given
* @return -EOPNOTSUPP When MCU driver doesn't support the flag operation
* @return -EAGAIN When a lost bus arbitration occurs
*/
static int _write_reg(pca9633_t* dev, uint8_t reg, uint8_t data);
/**
* @brief Read data from a register.
*
* @param[in] dev Device descriptor of the PCA9633
* @param[in] reg Register address to read from
* @param[out] data Byte read from given registerAddress
*
* @return 0 on success
* @return -PCA9633_ERROR_I2C if acquiring of I2C bus fails
* @return -EIO When slave device doesn't ACK the byte
* @return -ENXIO When no devices respond on the address sent on the bus
* @return -ETIMEDOUT When timeout occurs before device's response
* @return -EINVAL When an invalid argument is given
* @return -EOPNOTSUPP When MCU driver doesn't support the flag operation
* @return -EAGAIN When a lost bus arbitration occurs
*/
static int _read_reg(pca9633_t* dev, uint8_t reg, uint8_t* data);
int pca9633_init(pca9633_t *dev, const pca9633_params_t *params)
{
assert(dev);
assert(params);
dev->params = *params;
i2c_init(dev->params.i2c_dev);
int rc = _write_reg(dev, PCA9633_REG_MODE1, 0x0);
_write_reg(dev, PCA9633_REG_MODE2, 0x0);
if (rc != PCA9633_OK) {
return rc;
}
return PCA9633_OK;
}
void pca9633_wakeup(pca9633_t* dev)
{
uint8_t reg;
_read_reg(dev, PCA9633_REG_MODE1, &reg);
reg = reg & ~(1 << PCA9633_BIT_SLEEP);
_write_reg(dev, PCA9633_REG_MODE1, reg);
}
void pca9633_sleep(pca9633_t* dev)
{
uint8_t reg;
_read_reg(dev, PCA9633_REG_MODE1, &reg);
reg = reg | (1 << PCA9633_BIT_SLEEP);
_write_reg(dev, PCA9633_REG_MODE1, reg);
}
void pca9633_turn_on(pca9633_t* dev)
{
_write_reg(dev, PCA9633_REG_LEDOUT, dev->stored_reg_ledout);
}
void pca9633_turn_off(pca9633_t* dev)
{
_read_reg(dev, PCA9633_REG_LEDOUT, &dev->stored_reg_ledout);
_write_reg(dev, PCA9633_REG_LEDOUT, PCA9633_LDR_STATE_OFF);
}
void pca9633_set_pwm(pca9633_t* dev,
pca9633_pwm_channel_t pwm_channel, uint8_t pwm)
{
_write_reg(dev, pwm_channel, pwm);
}
void pca9633_set_grp_pwm(pca9633_t* dev, uint8_t pwm)
{
_write_reg(dev, PCA9633_REG_GRPPWM, pwm);
}
void pca9633_set_blinking(pca9633_t* dev, uint16_t blink_period_ms,
uint8_t on_off_ratio)
{
/* frequency of 24 Hz is used: */
uint16_t blink_period = (24 * blink_period_ms) / 1000;
if (blink_period > 255) {
blink_period = 255;
}
_write_reg(dev, PCA9633_REG_GRPFREQ, (uint8_t) blink_period);
_write_reg(dev, PCA9633_REG_GRPPWM, on_off_ratio);
}
void pca9633_set_rgb(pca9633_t* dev, uint8_t r, uint8_t g, uint8_t b)
{
pca9633_set_pwm(dev, dev->params.reg_pwm_red, r);
pca9633_set_pwm(dev, dev->params.reg_pwm_green, g);
pca9633_set_pwm(dev, dev->params.reg_pwm_blue, b);
}
void pca9633_set_rgba(pca9633_t* dev, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
pca9633_set_rgb(dev, r, g, b);
if (dev->params.has_amber_channel) {
pca9633_set_pwm(dev, dev->params.reg_pwm_amber, a);
}
}
void pca9633_set_ldr_state(pca9633_t* dev,
pca9633_ldr_state_t state, pca9633_pwm_channel_t pwm_channel)
{
uint8_t ldr_bit;
switch (pwm_channel) {
case PCA9633_PWM_CHANNEL_0:
ldr_bit = PCA9633_BIT_LDR0;
break;
case PCA9633_PWM_CHANNEL_1:
ldr_bit = PCA9633_BIT_LDR1;
break;
case PCA9633_PWM_CHANNEL_2:
ldr_bit = PCA9633_BIT_LDR2;
break;
case PCA9633_PWM_CHANNEL_3:
ldr_bit = PCA9633_BIT_LDR3;
break;
default:
return;
}
uint8_t reg;
_read_reg(dev, PCA9633_REG_LEDOUT, &reg);
/* first clear both bits of ldr */
reg = reg & ~(0b11 << ldr_bit);
/* second set new state to specified ldr */
reg |= (state << ldr_bit);
_write_reg(dev, PCA9633_REG_LEDOUT, reg);
}
void pca9633_set_ldr_state_all(pca9633_t* dev, pca9633_ldr_state_t state)
{
uint8_t reg = (state << PCA9633_BIT_LDR3)
| (state << PCA9633_BIT_LDR2)
| (state << PCA9633_BIT_LDR1)
| (state << PCA9633_BIT_LDR0);
_write_reg(dev, PCA9633_REG_LEDOUT, reg);
}
void pca9633_set_auto_increment(pca9633_t* dev, pca9633_auto_inc_option_t option)
{
uint8_t new_reg;
switch (option) {
case PCA9633_AI_ALL:
new_reg = (1 << PCA9633_BIT_AI2)
| (0 << PCA9633_BIT_AI1)
| (0 << PCA9633_BIT_AI0);
break;
case PCA9633_AI_IND:
new_reg = (1 << PCA9633_BIT_AI2)
| (1 << PCA9633_BIT_AI1)
| (0 << PCA9633_BIT_AI0);
break;
case PCA9633_AI_GBL:
new_reg = (1 << PCA9633_BIT_AI2)
| (0 << PCA9633_BIT_AI1)
| (1 << PCA9633_BIT_AI0);
break;
case PCA9633_AI_IND_GBL:
new_reg = (1 << PCA9633_BIT_AI2)
| (1 << PCA9633_BIT_AI1)
| (1 << PCA9633_BIT_AI0);
break;
case PCA9633_AI_DISABLED:
/* fall-thru */
default:
new_reg = (0 << PCA9633_BIT_AI2)
| (0 << PCA9633_BIT_AI1)
| (0 << PCA9633_BIT_AI0);
break;
}
_write_reg(dev, PCA9633_REG_MODE1, new_reg);
}
void pca9633_set_group_control_mode(pca9633_t* dev,
pca9633_group_control_mode_t mode)
{
uint8_t prev_reg;
_read_reg(dev, PCA9633_REG_MODE2, &prev_reg);
switch (mode) {
case PCA9633_GROUP_CONTROL_MODE_BLINKING:
_write_reg(dev, PCA9633_REG_MODE2, prev_reg | (1 << PCA9633_BIT_DMBLNK));
break;
case PCA9633_GROUP_CONTROL_MODE_DIMMING:
default:
_write_reg(dev, PCA9633_REG_MODE2, prev_reg & ~(1 << PCA9633_BIT_DMBLNK));
break;
}
}
int _write_reg(pca9633_t* dev, uint8_t reg, uint8_t data)
{
i2c_t i2c_dev = dev->params.i2c_dev;
if (i2c_acquire(i2c_dev) != 0) {
return -PCA9633_ERROR_I2C;
}
int rc = i2c_write_reg(i2c_dev, dev->params.i2c_addr, reg, data, 0);
i2c_release(i2c_dev);
return rc;
}
int _read_reg(pca9633_t* dev, uint8_t reg, uint8_t* data)
{
i2c_t i2c_dev = dev->params.i2c_dev;
if (i2c_acquire(i2c_dev) != 0) {
return -PCA9633_ERROR_I2C;
}
int rc = i2c_read_reg(i2c_dev, dev->params.i2c_addr, reg, data, 0);
i2c_release(i2c_dev);
return rc;
}