pca953x: Driver for PCA9530/PCA9533 I2C-bus LED dimmers

The PCA9530 and the PCA9533 are 2-bit and 4-bit I2C LED dimmers with open-drain outputs. Every output is controlled by two bits of the LED selector register:

Value

Meaning

00

Output is high-impedance, the LED is off and the pin can be read as an input

01

Output is driven low, the LED is on

10

Output is modulated with the rate and the duty cycle of PWM0

11

Output is modulated with the rate and the duty cycle of PWM1

The two PWM generators are shared by all outputs. The period is (prescaler + 1) / 152 seconds, between 6.6 ms and 1.684 s, and the duty cycle is PWM / 256. A short period, above roughly 100 Hz, makes the LED look dimmed; a long period makes it blink.

Everyday use needs four functions. pca953x_set_brightness() turns a LED on, dims it or turns it off, the brightness going from 0, dark, to PCA953X_BRIGHTNESS_MAX, fully lit, and the two extremes switch the output to the steady modes, so the LED does not toggle at all; pca953x_get_brightness() reports that value back; pca953x_blink() lights a LED in pulses with a period in milliseconds and a brightness on the same scale, and pca953x_get_blink() reports both.

The dimming runs at the shortest period the chip can produce, about 6.6 ms or 152 Hz, which is far above the flicker fusion threshold, so a dimmed LED looks steady rather than blinking. The two generators belong to the chip, not to the outputs, so all dimmed outputs share one brightness and all blinking outputs share one period and one brightness, the last call winning for every output that uses the same generator. Outputs that are switched on or off steadily do not depend on the generators.

The registers remain available for the cases the simple functions do not cover: the modes, the duty cycles, the prescalers and the pin levels belong to the reference below.

ESP-IDF driver for PCA9530/PCA9533 I2C-bus LED dimmers.

Copyright (c) 2026 Ruslan V. Uss unclerus@gmail.com

BSD Licensed as described in the file LICENSE

Defines

PCA953X_I2C_ADDR_PCA9530_A0_LOW

I2C addresses.

The PCA9530 has one hardware address pin (A0), and the address depends on its level. The PCA9533/01 and PCA9533/02 versions have fixed addresses. The values are 7-bit addresses, which is what the I2C driver expects; the datasheets show them as 8-bit write addresses with the extra zero bit, so 0xc0, 0xc2, 0xc4 and 0xc6 are the same addresses multiplied by two. PCA9530, A0 connected to GND

PCA953X_I2C_ADDR_PCA9530_A0_HIGH

PCA9530, A0 connected to VDD.

PCA953X_I2C_ADDR_PCA9533_01

PCA9533/01.

PCA953X_I2C_ADDR_PCA9533_02

PCA9533/02.

PCA953X_BRIGHTNESS_MAX

Fully lit brightness.

The duty cycle register holds 8 bits, so the pulses run from 0 to 255, and 256 is the extreme that leaves no low phase at all, which means the output is steady. The brightness functions accept the whole range, from 0, dark, to this value, fully lit.

Enums

enum pca953x_type_t

Device type.

The two devices share the register map and differ in the number of LED outputs: the PCA9530 has two, the PCA9533 has four.

Values:

enumerator PCA953X_TYPE_PCA9530

PCA9530, 2 LED outputs.

enumerator PCA953X_TYPE_PCA9533

PCA9533, 4 LED outputs.

enum pca953x_mode_t

LED output modes.

The values match the bits of the LED selector register.

Values:

enumerator PCA953X_MODE_OFF

Output is high-impedance, the LED is off, the pin can be read as an input.

enumerator PCA953X_MODE_ON

Output is driven low, the LED is on.

enumerator PCA953X_MODE_PWM0

Output is modulated with the rate and the duty cycle of PWM0.

enumerator PCA953X_MODE_PWM1

Output is modulated with the rate and the duty cycle of PWM1.

Functions

esp_err_t pca953x_init_desc(pca953x_t *dev, pca953x_type_t type, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio)

Initialize device descriptor.

Default SCL frequency is 400 kHz.

Parameters:
  • dev – Pointer to the device descriptor

  • type – Device type

  • addr – I2C address, one of PCA953X_I2C_ADDR_*

  • port – I2C port number

  • sda_gpio – SDA GPIO

  • scl_gpio – SCL GPIO

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_free_desc(pca953x_t *dev)

Free device descriptor.

Parameters:

dev – Pointer to the device descriptor

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if the descriptor is NULL

esp_err_t pca953x_get_mode(pca953x_t *dev, uint8_t led, pca953x_mode_t *mode)

Get the mode of an LED output.

Parameters:
  • dev – Pointer to the device descriptor

  • led – LED number, 0..1 for PCA9530, 0..3 for PCA9533

  • mode – [out] Output mode

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_set_mode(pca953x_t *dev, uint8_t led, pca953x_mode_t mode)

Set the mode of an LED output.

To use a pin as a GPIO input, set its mode to PCA953X_MODE_OFF and read it with pca953x_get_input().

Parameters:
  • dev – Pointer to the device descriptor

  • led – LED number, 0..1 for PCA9530, 0..3 for PCA9533

  • mode – Output mode

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_get_modes(pca953x_t *dev, uint8_t *ls)

Get the LED selector register.

The register holds two bits per LED output, in the same order as pca953x_set_mode() stores them.

Parameters:
  • dev – Pointer to the device descriptor

  • ls – [out] LED selector value

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_set_modes(pca953x_t *dev, uint8_t ls)

Set the LED selector register.

The reserved bits are written as they are passed, so it is safer to change the outputs one by one with pca953x_set_mode().

Parameters:
  • dev – Pointer to the device descriptor

  • ls – LED selector value

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_get_prescaler(pca953x_t *dev, uint8_t rate, uint8_t *psc)

Get the prescaler of a PWM rate.

The period of rate is (prescaler + 1) / 152 seconds, so the frequency is between 152 Hz and 0.59 Hz.

Parameters:
  • dev – Pointer to the device descriptor

  • rate – PWM rate, 0 or 1

  • psc – [out] Prescaler value

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_set_prescaler(pca953x_t *dev, uint8_t rate, uint8_t psc)

Set the prescaler of a PWM rate.

Parameters:
  • dev – Pointer to the device descriptor

  • rate – PWM rate, 0 or 1

  • psc – Prescaler value

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_get_pwm(pca953x_t *dev, uint8_t rate, uint8_t *pwm)

Get the duty cycle of a PWM rate.

Parameters:
  • dev – Pointer to the device descriptor

  • rate – PWM rate, 0 or 1

  • pwm – [out] Duty cycle, 0..255

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_set_pwm(pca953x_t *dev, uint8_t rate, uint8_t pwm)

Set the duty cycle of a PWM rate.

The duty cycle is pwm / 256. When the value is 0, the output is always high and the LED is off. When the period is short enough, above roughly 100 Hz, the LED looks dimmed instead of blinking.

Parameters:
  • dev – Pointer to the device descriptor

  • rate – PWM rate, 0 or 1

  • pwm – Duty cycle, 0..255

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

Set the period of a PWM rate in milliseconds.

The period is rounded up to the closest value the prescaler can produce, between 7 ms and 1684 ms. The function changes the prescaler only, the duty cycle is set with pca953x_set_pwm().

Parameters:
  • dev – Pointer to the device descriptor

  • rate – PWM rate, 0 or 1

  • period_ms – Requested period, milliseconds

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid or the period is out of range

Get the period of a PWM rate in milliseconds.

Parameters:
  • dev – Pointer to the device descriptor

  • rate – PWM rate, 0 or 1

  • period_ms – [out] Period, milliseconds

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_set_brightness(pca953x_t *dev, uint8_t led, uint16_t brightness)

Set the brightness of a LED.

This is the simple way to light a LED: the brightness goes from 0 to PCA953X_BRIGHTNESS_MAX, that is, from dark to fully lit. The extremes are absolute and switch the output to the steady modes, so 0 turns the LED off and 256 turns it on, without any toggling. The values in between are the duty cycle of the dimming generator, from 1/256 to 255/256 of the period.

No prescaler and no generator has to be chosen: the driver uses the fast generator and sets its period to the shortest one, about 6.6 ms or 152 Hz, which is far above the flicker fusion threshold, so the LED looks steady rather than blinking.

The chip has two duty cycle registers for all its outputs, so the outputs that are dimmed at the same time share the brightness: the last call wins for all of them. Outputs that are switched on or off steadily do not depend on the registers and can be used freely.

Parameters:
  • dev – Pointer to the device descriptor

  • led – LED number, 0..1 for PCA9530, 0..3 for PCA9533

  • brightness – Brightness, 0 to PCA953X_BRIGHTNESS_MAX

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_get_brightness(pca953x_t *dev, uint8_t led, uint16_t *brightness)

Get the brightness of a LED.

A LED that is switched off or on steadily reports 0 or PCA953X_BRIGHTNESS_MAX, a LED that blinks reports the brightness of the pulses.

Parameters:
  • dev – Pointer to the device descriptor

  • led – LED number, 0..1 for PCA9530, 0..3 for PCA9533

  • brightness – [out] Brightness, 0 to PCA953X_BRIGHTNESS_MAX

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_blink(pca953x_t *dev, uint8_t led, uint32_t period_ms, uint16_t brightness)

Blink a LED.

The function sets the period and the brightness of the pulses and switches the LED to the slow generator, so one call is enough. The period is rounded up to the closest value the prescaler can produce, between 7 ms and 1684 ms.

The brightness follows the same scale as pca953x_set_brightness(): 0 turns the LED off and PCA953X_BRIGHTNESS_MAX turns it on steadily, because a pulse that never goes low is not a pulse. The values in between blink.

As with pca953x_set_brightness(), the blinking outputs share one period and one brightness, because the chip has a single slow generator.

Parameters:
  • dev – Pointer to the device descriptor

  • led – LED number, 0..1 for PCA9530, 0..3 for PCA9533

  • period_ms – Period of the blinking, 7 to 1684 ms

  • brightness – Brightness of the pulses, 0 to PCA953X_BRIGHTNESS_MAX

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_get_blink(pca953x_t *dev, uint8_t led, uint32_t *period_ms, uint16_t *brightness)

Get the period and the brightness of a blinking LED.

Parameters:
  • dev – Pointer to the device descriptor

  • led – LED number, 0..1 for PCA9530, 0..3 for PCA9533

  • period_ms – [out] Period of the blinking, milliseconds

  • brightness – [out] Brightness of the pulses, 0 to PCA953X_BRIGHTNESS_MAX

Returns:

ESP_OK on success ESP_ERR_INVALID_STATE if the LED is not blinking ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_get_inputs(pca953x_t *dev, uint8_t *levels)

Read the state of all LED pins.

The input register reflects the levels of the pins, so it is useful for the pins that are set to PCA953X_MODE_OFF and used as GPIO inputs.

Parameters:
  • dev – Pointer to the device descriptor

  • levels – [out] Pin levels, bit n is the level of LED n, 1 is high

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

esp_err_t pca953x_get_input(pca953x_t *dev, uint8_t led, bool *level)

Read the state of a LED pin.

Parameters:
  • dev – Pointer to the device descriptor

  • led – LED number, 0..1 for PCA9530, 0..3 for PCA9533

  • level – [out] true if the pin is high

Returns:

ESP_OK on success ESP_ERR_INVALID_ARG if an argument is invalid

struct pca953x_t
#include <pca953x.h>

Device descriptor.

Public Members

i2c_dev_t i2c_dev

I2C device descriptor.

pca953x_type_t type

Device type.