[es8156] Add support for ES8156 audio DAC (#8085)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
Keith Burzinski 2025-01-20 21:15:18 -06:00 committed by GitHub
parent 0f4e274e52
commit 716a8b87e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 274 additions and 0 deletions

View File

@ -133,6 +133,7 @@ esphome/components/ens160_i2c/* @latonita
esphome/components/ens160_spi/* @latonita
esphome/components/ens210/* @itn3rd77
esphome/components/es7210/* @kahrendt
esphome/components/es8156/* @kbx81
esphome/components/es8311/* @kahrendt @kroimon
esphome/components/esp32/* @esphome/core
esphome/components/esp32_ble/* @Rapsssito @jesserockz

View File

View File

@ -0,0 +1,27 @@
import esphome.codegen as cg
from esphome.components import i2c
from esphome.components.audio_dac import AudioDac
import esphome.config_validation as cv
from esphome.const import CONF_ID
CODEOWNERS = ["@kbx81"]
DEPENDENCIES = ["i2c"]
es8156_ns = cg.esphome_ns.namespace("es8156")
ES8156 = es8156_ns.class_("ES8156", AudioDac, cg.Component, i2c.I2CDevice)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(ES8156),
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x08))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)

View File

@ -0,0 +1,87 @@
#include "es8156.h"
#include "es8156_const.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include <cinttypes>
namespace esphome {
namespace es8156 {
static const char *const TAG = "es8156";
// Mark the component as failed; use only in setup
#define ES8156_ERROR_FAILED(func) \
if (!(func)) { \
this->mark_failed(); \
return; \
}
void ES8156::setup() {
ESP_LOGCONFIG(TAG, "Setting up ES8156...");
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG02_SCLK_MODE, 0x04));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG20_ANALOG_SYS1, 0x2A));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG21_ANALOG_SYS2, 0x3C));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG22_ANALOG_SYS3, 0x00));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG24_ANALOG_LP, 0x07));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG23_ANALOG_SYS4, 0x00));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0A_TIME_CONTROL1, 0x01));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0B_TIME_CONTROL2, 0x01));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG11_DAC_SDP, 0x00));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG19_EQ_CONTROL1, 0x20));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0D_P2S_CONTROL, 0x14));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG09_MISC_CONTROL2, 0x00));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG18_MISC_CONTROL3, 0x00));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG08_CLOCK_ON_OFF, 0x3F));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG00_RESET, 0x02));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG00_RESET, 0x03));
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG25_ANALOG_SYS5, 0x20));
}
void ES8156::dump_config() {
ESP_LOGCONFIG(TAG, "ES8156 Audio Codec:");
if (this->is_failed()) {
ESP_LOGCONFIG(TAG, " Failed to initialize");
return;
}
}
bool ES8156::set_volume(float volume) {
volume = clamp(volume, 0.0f, 1.0f);
uint8_t reg = remap<uint8_t, float>(volume, 0.0f, 1.0f, 0, 255);
ESP_LOGV(TAG, "Setting ES8156_REG14_VOLUME_CONTROL to %u (volume: %f)", reg, volume);
return this->write_byte(ES8156_REG14_VOLUME_CONTROL, reg);
}
float ES8156::volume() {
uint8_t reg;
this->read_byte(ES8156_REG14_VOLUME_CONTROL, &reg);
return remap<float, uint8_t>(reg, 0, 255, 0.0f, 1.0f);
}
bool ES8156::set_mute_state_(bool mute_state) {
uint8_t reg13;
this->is_muted_ = mute_state;
if (!this->read_byte(ES8156_REG13_DAC_MUTE, &reg13)) {
return false;
}
ESP_LOGV(TAG, "Read ES8156_REG13_DAC_MUTE: %u", reg13);
if (mute_state) {
reg13 |= BIT(1) | BIT(2);
} else {
reg13 &= ~(BIT(1) | BIT(2));
}
ESP_LOGV(TAG, "Setting ES8156_REG13_DAC_MUTE to %u (muted: %s)", reg13, YESNO(mute_state));
return this->write_byte(ES8156_REG13_DAC_MUTE, reg13);
}
} // namespace es8156
} // namespace esphome

View File

@ -0,0 +1,51 @@
#pragma once
#include "esphome/components/audio_dac/audio_dac.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/core/component.h"
namespace esphome {
namespace es8156 {
class ES8156 : public audio_dac::AudioDac, public Component, public i2c::I2CDevice {
public:
/////////////////////////
// Component overrides //
/////////////////////////
void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override;
////////////////////////
// AudioDac overrides //
////////////////////////
/// @brief Writes the volume out to the DAC
/// @param volume floating point between 0.0 and 1.0
/// @return True if successful and false otherwise
bool set_volume(float volume) override;
/// @brief Gets the current volume out from the DAC
/// @return floating point between 0.0 and 1.0
float volume() override;
/// @brief Disables mute for audio out
/// @return True if successful and false otherwise
bool set_mute_off() override { return this->set_mute_state_(false); }
/// @brief Enables mute for audio out
/// @return True if successful and false otherwise
bool set_mute_on() override { return this->set_mute_state_(true); }
bool is_muted() override { return this->is_muted_; }
protected:
/// @brief Mutes or unmutes the DAC audio out
/// @param mute_state True to mute, false to unmute
/// @return True if successful and false otherwise
bool set_mute_state_(bool mute_state);
};
} // namespace es8156
} // namespace esphome

View File

@ -0,0 +1,68 @@
#pragma once
#include "es8156.h"
namespace esphome {
namespace es8156 {
/* ES8156 register addresses */
/*
* RESET Control
*/
static const uint8_t ES8156_REG00_RESET = 0x00;
/*
* Clock Managerment
*/
static const uint8_t ES8156_REG01_MAINCLOCK_CTL = 0x01;
static const uint8_t ES8156_REG02_SCLK_MODE = 0x02;
static const uint8_t ES8156_REG03_LRCLK_DIV_H = 0x03;
static const uint8_t ES8156_REG04_LRCLK_DIV_L = 0x04;
static const uint8_t ES8156_REG05_SCLK_DIV = 0x05;
static const uint8_t ES8156_REG06_NFS_CONFIG = 0x06;
static const uint8_t ES8156_REG07_MISC_CONTROL1 = 0x07;
static const uint8_t ES8156_REG08_CLOCK_ON_OFF = 0x08;
static const uint8_t ES8156_REG09_MISC_CONTROL2 = 0x09;
static const uint8_t ES8156_REG0A_TIME_CONTROL1 = 0x0a;
static const uint8_t ES8156_REG0B_TIME_CONTROL2 = 0x0b;
/*
* System Control
*/
static const uint8_t ES8156_REG0C_CHIP_STATUS = 0x0c;
static const uint8_t ES8156_REG0D_P2S_CONTROL = 0x0d;
static const uint8_t ES8156_REG10_DAC_OSR_COUNTER = 0x10;
/*
* SDP Control
*/
static const uint8_t ES8156_REG11_DAC_SDP = 0x11;
static const uint8_t ES8156_REG12_AUTOMUTE_SET = 0x12;
static const uint8_t ES8156_REG13_DAC_MUTE = 0x13;
static const uint8_t ES8156_REG14_VOLUME_CONTROL = 0x14;
/*
* ALC Control
*/
static const uint8_t ES8156_REG15_ALC_CONFIG1 = 0x15;
static const uint8_t ES8156_REG16_ALC_CONFIG2 = 0x16;
static const uint8_t ES8156_REG17_ALC_CONFIG3 = 0x17;
static const uint8_t ES8156_REG18_MISC_CONTROL3 = 0x18;
static const uint8_t ES8156_REG19_EQ_CONTROL1 = 0x19;
static const uint8_t ES8156_REG1A_EQ_CONTROL2 = 0x1a;
/*
* Analog System Control
*/
static const uint8_t ES8156_REG20_ANALOG_SYS1 = 0x20;
static const uint8_t ES8156_REG21_ANALOG_SYS2 = 0x21;
static const uint8_t ES8156_REG22_ANALOG_SYS3 = 0x22;
static const uint8_t ES8156_REG23_ANALOG_SYS4 = 0x23;
static const uint8_t ES8156_REG24_ANALOG_LP = 0x24;
static const uint8_t ES8156_REG25_ANALOG_SYS5 = 0x25;
/*
* Chip Information
*/
static const uint8_t ES8156_REGFC_I2C_PAGESEL = 0xFC;
static const uint8_t ES8156_REGFD_CHIPID1 = 0xFD;
static const uint8_t ES8156_REGFE_CHIPID0 = 0xFE;
static const uint8_t ES8156_REGFF_CHIP_VERSION = 0xFF;
} // namespace es8156
} // namespace esphome

View File

@ -0,0 +1,15 @@
esphome:
on_boot:
then:
- audio_dac.mute_off:
- audio_dac.mute_on:
- audio_dac.set_volume:
volume: 50%
i2c:
- id: i2c_es8156
scl: ${scl_pin}
sda: ${sda_pin}
audio_dac:
- platform: es8156

View File

@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO16
sda_pin: GPIO17
<<: !include common.yaml

View File

@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO5
sda_pin: GPIO4
<<: !include common.yaml

View File

@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO5
sda_pin: GPIO4
<<: !include common.yaml

View File

@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO16
sda_pin: GPIO17
<<: !include common.yaml

View File

@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO5
sda_pin: GPIO4
<<: !include common.yaml