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 Exampleο
This driver is I2C driver-independent and relies on Dependency Injection for communication. When initializing the driver, you must provide:
An I2C Write Callback: A custom function matching the pt2258_write_cb_t signature that dictates how bytes are transmitted.
A Bus Context / Device Handle: A pointer to your specific I2C device handle or transport configuration structure. The driver holds this pointer and passes it back to your callback function whenever an I2C operation is performed.
ESP-IDF Native Driverο
The following example demonstrates how to initialize the PT2258 using the native ESP-IDF v5 master driver:
#include "esp_log.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c_master.h"
#include "pt2258.h"
static const char *TAG = "main";
// Implementation of the I2C write callback matching the pt2258_write_cb_t signature
static esp_err_t pt2258_i2c_write_cb(void *handle, const uint8_t *data, size_t len)
{
// Directly use the injected native ESP-IDF device handle
return i2c_master_transmit((i2c_master_dev_handle_t)handle, data, len, -1);
}
void app_main(void)
{
// 1. Initialize the I2C master bus
i2c_master_bus_config_t bus_config = {
// ... your configuration ...
};
i2c_master_bus_handle_t bus_handle;
i2c_master_new_bus(&bus_config, &bus_handle);
// 2. Add the PT2258 device to the I2C bus (using 7-bit address)
i2c_device_config_t dev_config = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = PT2258_I2C_ADDR_0, // 0x40 (7-bit)
.scl_speed_hz = 100000, // 100 kHz Standard Mode
};
i2c_master_dev_handle_t pt2258_i2c_handle;
i2c_master_bus_add_device(bus_handle, &dev_config, &pt2258_i2c_handle);
// 3. Configure PT2258 driver settings by injecting the dependencies
pt2258_config_t pt2258_cfg = {
.write_cb = pt2258_i2c_write_cb, // Inject the specific I2C write callback
.i2c_dev_handle = pt2258_i2c_handle // Inject native device handle directly as context
};
// Crucial: Wait at least 200ms after Power-ON to ensure PT2258 stability
vTaskDelay(pdMS_TO_TICKS(200));
// 4. 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;
}
// 5. Configure and control the PT2258
// Mute channels before changing configurations to avoid audio pops
pt2258_set_mute(pt2258_handle, true);
// 6. Adjust volume (attenuation)
// Set Master Volume (All channels) to -15 dB
pt2258_set_attenuation(pt2258_handle, PT2258_CH_ALL, 15);
// Set Channel 1 specifically to -40 dB
pt2258_set_attenuation(pt2258_handle, PT2258_CH_1, 40);
// Unmute the chip to let audio pass through
pt2258_set_mute(pt2258_handle, false);
// ... your application logic ...
// 7. Clean up resources when done
pt2258_delete(&pt2258_handle);
}
ESP-ADF i2c_bus Driverο
The following example demonstrates how to initialize the PT2258 using the ESP-ADF i2c_bus:
// Define the I2C transport structure for the ESP-ADF i2c_bus, which holds the bus handle and device address
typedef struct {
i2c_bus_handle_t bus_handle;
uint8_t i2c_addr;
} pt2258_i2c_transport_t;
// Implementation of the I2C write callback matching the pt2258_write_cb_t signature
static esp_err_t pt2258_i2c_write_cb(void *handle, const uint8_t *data, size_t len)
{
pt2258_i2c_transport_t *transport = (pt2258_i2c_transport_t *)handle;
return i2c_bus_write_data(transport->bus_handle, transport->i2c_addr, (uint8_t *)data, len);
}
void app_main(void)
{
// 1. Initialize the I2C bus
i2c_config_t bus_config = {
// ... your i2c configuration ...
};
i2c_bus_handle_t i2c_bus = i2c_bus_create(I2C_NUM_0, &bus_config);
// 2. Create the I2C transport context instance
static pt2258_i2c_transport_t pt2258_i2c_transport = {
.bus_handle = i2c_bus,
.i2c_addr = PT2258_I2C_ADDR_2_8BIT // 0x88 (8-bit)
};
// 3. Configure PT2258 driver by injecting transport dependencies
pt2258_config_t pt2258_cfg = {
.write_cb = pt2258_i2c_write_cb, // Inject the specific I2C write callback
.i2c_dev_handle = &pt2258_i2c_transport // Inject the transport structure as the device handle context
};
// Crucial: Wait at least 200ms after Power-ON to ensure PT2258 stability
vTaskDelay(pdMS_TO_TICKS(200));
// 4. 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;
}
// 5. Configure and control the PT2258
// Mute channels before changing configurations to avoid audio pops
pt2258_set_mute(pt2258_handle, true);
// Set All channels to -15 dB
pt2258_set_attenuation(pt2258_handle, PT2258_CH_ALL, 15);
// Set Channel 1 specifically to -40 dB
pt2258_set_attenuation(pt2258_handle, PT2258_CH_1, 40);
// Unmute the chip to let audio pass through
pt2258_set_mute(pt2258_handle, false);
// ... your application logic ...
// 7. Clean up resources when done
pt2258_delete(&pt2258_handle);
}
Espressif IoT Solution i2c_busο
The following example demonstrates how to initialize the PT2258 using the Espressif IoT Solution i2c_bus:
#include "esp_log.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "i2c_bus.h"
#include "pt2258.h"
static const char *TAG = "main";
// Implementation of the I2C write callback matching the pt2258_write_cb_t signature
static esp_err_t pt2258_i2c_write_cb(void *handle, const uint8_t *data, size_t len)
{
// Directly use the injected native ESP-IDF device handle
return i2c_bus_write_data(handle, PT2258_I2C_ADDR_2_8BIT, (uint8_t *)data, len);
}
void app_main(void)
{
// 1. Initialize the I2C bus
const i2c_config_t bus_config = {
// ... your i2c configuration ...
};
i2c_bus_handle_t i2c_bus = i2c_bus_create(I2C_NUM_0, &bus_config);
// 2. Add the PT2258 device to the I2C bus (using 7-bit address)
i2c_bus_device_handle_t pt2258_i2c_dev_handle = i2c_bus_device_create(i2c_bus, PT2258_I2C_ADDR_2, 0);
// 3. Configure PT2258 driver by injecting transport dependencies
pt2258_config_t pt2258_cfg = {
.write_cb = pt2258_i2c_write_cb, // Inject the specific I2C write callback
.i2c_dev_handle = pt2258_i2c_dev_handle // Inject the device handle directly
};
// Crucial: Wait at least 200ms after Power-ON to ensure PT2258 stability
vTaskDelay(pdMS_TO_TICKS(200));
// 4. 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;
}
// 5. Configure and control the PT2258
// Mute channels before changing configurations to avoid audio pops
pt2258_set_mute(pt2258_handle, true);
// Set All channels to -15 dB
pt2258_set_attenuation(pt2258_handle, PT2258_CH_ALL, 15);
// Set Channel 1 specifically to -40 dB
pt2258_set_attenuation(pt2258_handle, PT2258_CH_1, 40);
// Unmute the chip to let audio pass through
pt2258_set_mute(pt2258_handle, false);
// ... your application logic ...
// 7. Clean up resources when done
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 *handle, const uint8_t *data, size_t len)ο
Type of PT2258 write function callback.
- Param handle:
[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
Enums
-
enum pt2258_ch_tο
PT2258 channel selection.
Values:
-
enumerator PT2258_CH_ALLο
Master Volume (All channels)
-
enumerator PT2258_CH_1ο
Channel 1
-
enumerator PT2258_CH_2ο
Channel 2
-
enumerator PT2258_CH_3ο
Channel 3
-
enumerator PT2258_CH_4ο
Channel 4
-
enumerator PT2258_CH_5ο
Channel 5
-
enumerator PT2258_CH_6ο
Channel 6
-
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
-
pt2258_write_cb_t write_cbο
I2C write callback function
-
void *i2c_dev_handleο
Context pointer passed to the callback (e.g. i2c_master_dev_handle_t, i2c_bus_device_handle_t)
-
pt2258_write_cb_t write_cbο