pt2258 (I2C Driver)ο
ESP-IDF component driver for the PT2258 6-channel electronic volume controller with I2C interface. This component provides a fully decoupled interface to interact with the PT2258 using a user-defined I2C write callback. This architecture ensures out-of-the-box compatibility with any I2C bus implementation β including the native ESP-IDF drivers, the distinct i2c_bus implementations from ESP-ADF and ESP-IoT-Solution, or completely custom wrappers β effectively eliminating framework and driver conflicts in audio projects.
Featuresο
6-channel volume control: Individual attenuation control for each channel plus master volume.
Fine-grained attenuation: 0 to 79 dB in 1 dB steps.
Global mute: Chip-level mute control for all channels.
Multiple I2C addresses: Up to 4 configurable addresses via hardware pins.
Transport Independent: Easily integrates into any project by injecting your own I2C write function.
Hardware Specifications & Timingο
For details, see the PT2258 datasheet.
I2C Addressingο
The PT2258 supports up to 4 selectable I2C addresses via the hardware configuration of the CODE1 (Pin 17) and CODE2 (Pin 4) pins. This allows you to daisy-chain up to 4 chips on a single I2C bus.
CODE1 (Pin 17) |
CODE2 (Pin 4) |
8-bit Address (Datasheet) |
C Macro Definition (8-bit) |
7-bit Address |
C Macro Definition (7-bit) |
|---|---|---|---|---|---|
GND (0) |
GND (0) |
0x80 |
|
0x40 |
|
GND (0) |
VCC (1) |
0x84 |
|
0x42 |
|
VCC (1) |
GND (0) |
0x88 |
|
0x44 |
|
VCC (1) |
VCC (1) |
0x8C |
|
0x46 |
|
Critical Hardware Considerationsο
Important
Power-On Stabilization Delay
After power-up, the PT2258 requires a stabilization period. You must wait at least 200 ms before transmitting any I2C signals. Initiating communication early can lock up the chipβs internal logic, requiring a hard power cycle.
Warning
Uninitialized Register Silence
The PT2258 does not load default volume values on boot. While pt2258_create() automatically clears internal registers, you must explicitly set an attenuation value for each channel. Unconfigured channels will likely output no audio.
Usageο
Tip
Out-of-the-box Ecosystem Adapters
To avoid writing boilerplate callback functions manually, you can use one of the plug-and-play initialization adapters tailored for your specific workflow:
π ESP-IDF v5 Native I2C Master Adapter β GitHub Β· ESP Registry
π ESP-ADF i2c_bus Adapter β GitHub Β· ESP Registry
If you are using these adapters, you can skip the manual dependency injection setup below.
This driver is I2C bus realization-independent and relies on Dependency Injection for communication. When initializing the driver, you must provide:
A Bus Context / Device Handle: A pointer to your specific I2C device handle or transport configuration structure (
transport_ctx). The driver holds this pointer and passes it back to your callback function whenever an I2C operation is performed.An I2C Write Callback: A custom function matching the
pt2258_write_cb_tsignature that dictates how bytes are transmitted.An Optional Cleanup Callback: A custom function matching the
pt2258_cleanup_cb_tsignature to free memory if the transport context was allocated dynamically.
I2C Write Callback Functionο
The callback function must match the following signature:
typedef esp_err_t (*pt2258_write_cb_t)(void *transport, const uint8_t *data, size_t len);
handle: A pointer to your I2C device handle or transport configuration structure.data: A pointer to the data to be written.len: The length of the data to be written.Returns:
ESP_OKon success, or an error code on failure.
Example for native ESP-IDF v5 I2C Bus master driver:
static esp_err_t _i2c_write_cb(void *transport, const uint8_t *data, size_t len)
{
// Directly use the ESP-IDF native I2C master driver to write data into the PT2258
return i2c_master_transmit((i2c_master_dev_handle_t)transport, data, len, -1);
}
Example for Espressif-IoT-Solution i2c_bus driver:
static esp_err_t _i2c_write_cb(void *transport, const uint8_t *data, size_t len)
{
// Use the Espressif-IoT Solution I2C driver to write data into the PT2258
return i2c_bus_write_data(transport, PT2258_I2C_ADDR_2_8BIT, (uint8_t *)data, len);
}
Usage in ESP-ADFο
If youβre using the driver from ESP-ADFβs embedded i2c_bus driver, in addition to providing the callback function, you must also provide a custom transport layer. The transport layer is a structure that contains the I2C bus handle and the I2C address. This structure is injected into the driver as the bus context during initialization.
typedef struct {
i2c_bus_handle_t bus_handle; // I2C bus handle
uint8_t i2c_addr; // I2C address
} pt2258_i2c_transport_t;
static esp_err_t _i2c_write_cb(void *transport, const uint8_t *data, size_t len)
{
pt2258_i2c_transport_t *transport = (pt2258_i2c_transport_t *)transport;
// Function i2c_bus_write_data is provided by the ESP-ADF i2c_bus driver to write data to the I2C device
return i2c_bus_write_data(transport->bus_handle, transport->i2c_addr, (uint8_t *)data, len);
}
Initializationο
After defining the callback function (and if needed, the transport structure), you need to initialize the PT2258 driver by injecting dependencies.
// ... Your existing I2C bus initialization and device handle creation code ...
// If using ESP-ADF i2c_bus driver, instead of device handle, define the transport structure
#if USE_ESP_ADF_I2C_BUS
static pt2258_i2c_transport_t pt2258_i2c_dev_handle = {
.bus_handle = &i2c_bus_handle,
.i2c_addr = PT2258_I2C_ADDR_2_8BIT
};
#endif
// Configure PT2258 driver
pt2258_config_t pt2258_cfg = {
.transport_ctx = &pt2258_i2c_dev_handle, // Inject the I2C device handle context or transport structure
.write_cb = _i2c_write_cb, // Inject the specific I2C write callback
};
// Crucial: Wait at least 200ms after Power-ON to ensure PT2258 stability
vTaskDelay(pdMS_TO_TICKS(200));
// 3. Create the PT2258 driver instance
pt2258_handle_t pt2258_handle;
esp_err_t err = pt2258_create(&pt2258_cfg, &pt2258_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to create PT2258 driver: %s", esp_err_to_name(err));
return;
}
Controlο
After the driver is created, you can control the PT2258 by calling API functions, for example:
// Mute all channels
pt2258_set_mute(pt2258_handle, true);
// Set the attenuation for channel 1 to 10dB
pt2258_set_attenuation(pt2258_handle, PT2258_CH_1, 10);
// Set the attenuation for all channels to 22dB
pt2258_set_attenuation(pt2258_handle, PT2258_CH_ALL, 22);
See API documentation for more details.
Deleteο
To delete the PT2258 driver instance:
pt2258_delete(&pt2258_handle);
API Referenceο
PT2258 I2C Addresses (8-bit) as in the Datasheet
-
PT2258_I2C_ADDR_0_8BITο
Pins: CODE1=0, CODE2=0
-
PT2258_I2C_ADDR_1_8BITο
Pins: CODE1=0, CODE2=1
-
PT2258_I2C_ADDR_2_8BITο
Pins: CODE1=1, CODE2=0
-
PT2258_I2C_ADDR_3_8BITο
Pins: CODE1=1, CODE2=1
PT2258 I2C Addresses (7-bit)
-
PT2258_I2C_ADDR_0ο
7-bit address: 0x40 (pins: CODE1=0, CODE2=0)
-
PT2258_I2C_ADDR_1ο
7-bit address: 0x42 (pins: CODE1=0, CODE2=1)
-
PT2258_I2C_ADDR_2ο
7-bit address: 0x44 (pins: CODE1=1, CODE2=0)
-
PT2258_I2C_ADDR_3ο
7-bit address: 0x46 (pins: CODE1=1, CODE2=1)
PT2258 Operational Constants
-
PT2258_MIN_ATTENUATIONο
Minimum attenuation of PT2258(0 dB)
-
PT2258_MAX_ATTENUATIONο
Maximum attenuation of PT2258(-79 dB, silence)
-
PT2258_TOTAL_CHANNELSο
Total number of channels on the PT2258 (6)
Typedefs
-
typedef void *pt2258_handle_tο
Type of PT2258 device handle.
-
typedef esp_err_t (*pt2258_write_cb_t)(void *transport, const uint8_t *data, size_t len)ο
Type of PT2258 write function callback.
- Param transport:
[in] Context pointer (e.g. device descriptor, transport context)
- Param data:
[in] Pointer to data buffer to write
- Param len:
[in] Number of bytes to write
- Return:
esp_err_t ESP_OK on success, error code otherwise
-
typedef void (*pt2258_cleanup_cb_t)(void *transport)ο
Type of PT2258 cleanup function callback.
- Param transport:
[in] Context pointer (e.g. device descriptor, transport context)
Enums
-
enum pt2258_ch_tο
PT2258 channel selection.
Values:
-
enumerator PT2258_CH_ALLο
Master Volume (All channels)
-
enumerator PT2258_CH_1ο
Channel 1 (pins 1->20)
-
enumerator PT2258_CH_2ο
Channel 2 (pins 2->19)
-
enumerator PT2258_CH_3ο
Channel 3 (pins 3->18)
-
enumerator PT2258_CH_4ο
Channel 4 (pins 8->13)
-
enumerator PT2258_CH_5ο
Channel 5 (pins 9->12)
-
enumerator PT2258_CH_6ο
Channel 6 (pins 10->11)
-
enumerator PT2258_CH_ALLο
Functions
-
esp_err_t pt2258_create(const pt2258_config_t *cfg, pt2258_handle_t *handle)ο
Create PT2258 device handle.
- Parameters:
cfg β [in] Pointer to the hardware configuration structure
handle β [out] Pointer to the device handle
- Returns:
ESP_OK: Success
ESP_ERR_INVALID_ARG: If cfg or handle is NULL
ESP_ERR_NO_MEM: If memory allocation failed
-
esp_err_t pt2258_delete(pt2258_handle_t *handle)ο
Delete PT2258 device handle.
- Parameters:
handle β [in] Pointer to the device handle pointer (will be set to NULL on success)
- Returns:
ESP_OK: Success
ESP_ERR_INVALID_ARG: Invalid handle
-
esp_err_t pt2258_clear_registers(pt2258_handle_t handle)ο
Clear all internal registers of the PT2258 (System Reset)
- Parameters:
handle β [in] PT2258 device handle
- Returns:
ESP_OK: Success
ESP_ERR_INVALID_ARG: If handle is NULL
Others: I2C transfer error codes
-
esp_err_t pt2258_set_attenuation(pt2258_handle_t handle, pt2258_ch_t ch, uint8_t attenuation_db)ο
Directly set attenuation in dB for a specific channel or ALL channels.
- Parameters:
handle β [in] PT2258 device handle
ch β [in] Channel number: PT2258_CH_ALL for ALL channels (Master), PT2258_CH_1-PT2258_CH_6 for CH1-CH6
attenuation_db β [in] Attenuation value from 0 dB (max volume) to 79 dB (silence)
- Returns:
ESP_OK: Success
ESP_ERR_INVALID_ARG: If handle is NULL or ch number is out of bounds (> 6)
Others: I2C transfer error codes
-
esp_err_t pt2258_set_mute(pt2258_handle_t handle, bool mute)ο
Global Mute control on the chip level.
- Parameters:
handle β [in] PT2258 device handle
mute β [in] true to mute, false to unmute
- Returns:
ESP_OK: Success
ESP_ERR_INVALID_ARG: If handle is NULL
Others: I2C transfer error codes
-
struct pt2258_config_tο
- #include <pt2258.h>
PT2258 Configuration Structure.
Public Members
-
void *transport_ctxο
Opaque context pointer passed to callbacks (e.g., custom transport struct, or native I2C device handle)
-
pt2258_write_cb_t write_cbο
Write callback function
-
pt2258_cleanup_cb_t cleanup_cbο
Optional callback to free transport_ctx dynamic memory during driver destruction
-
void *transport_ctxο