Created
June 20, 2025 04:52
-
-
Save Staars/211633eecc471145b7e560ad1130ed9c to your computer and use it in GitHub Desktop.
WIP-Driver for ES8311
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ES8311 Audio Codec Driver - Complete Berry Implementation | |
# Converted from C implementation for Tasmota/ESP32 | |
class ES8311 | |
# Konstanten | |
# P4 Nano | |
static P4_NANO_PA_GPIO = 53 | |
static ES8311_ADDR = 0x18 | |
static FROM_MCLK_PIN = true | |
static FROM_SCLK_PIN = 0 | |
static INVERT_MCLK = 0 | |
static INVERT_SCLK = 0 | |
static IS_DMIC = 0 | |
static MCLK_DIV_FRE = 256 | |
# Vollständige Register-Definitionen | |
static ES8311_RESET_REG00 = 0x00 | |
static ES8311_CLK_MANAGER_REG01 = 0x01 | |
static ES8311_CLK_MANAGER_REG02 = 0x02 | |
static ES8311_CLK_MANAGER_REG03 = 0x03 | |
static ES8311_CLK_MANAGER_REG04 = 0x04 | |
static ES8311_CLK_MANAGER_REG05 = 0x05 | |
static ES8311_CLK_MANAGER_REG06 = 0x06 | |
static ES8311_CLK_MANAGER_REG07 = 0x07 | |
static ES8311_CLK_MANAGER_REG08 = 0x08 | |
static ES8311_SDPIN_REG09 = 0x09 | |
static ES8311_SDPOUT_REG0A = 0x0A | |
static ES8311_SYSTEM_REG0B = 0x0B | |
static ES8311_SYSTEM_REG0C = 0x0C | |
static ES8311_SYSTEM_REG0D = 0x0D | |
static ES8311_SYSTEM_REG0E = 0x0E | |
static ES8311_SYSTEM_REG10 = 0x10 | |
static ES8311_SYSTEM_REG11 = 0x11 | |
static ES8311_SYSTEM_REG12 = 0x12 | |
static ES8311_SYSTEM_REG13 = 0x13 | |
static ES8311_SYSTEM_REG14 = 0x14 | |
static ES8311_ADC_REG15 = 0x15 | |
static ES8311_ADC_REG16 = 0x16 | |
static ES8311_ADC_REG17 = 0x17 | |
static ES8311_ADC_REG1B = 0x1B | |
static ES8311_ADC_REG1C = 0x1C | |
static ES8311_DAC_REG31 = 0x31 | |
static ES8311_DAC_REG32 = 0x32 | |
static ES8311_DAC_REG37 = 0x37 | |
static ES8311_GPIO_REG44 = 0x44 | |
static ES8311_GP_REG45 = 0x45 | |
# Audio HAL Konstanten | |
static AUDIO_HAL_08K_SAMPLES = 8000 | |
static AUDIO_HAL_11K_SAMPLES = 11025 | |
static AUDIO_HAL_16K_SAMPLES = 16000 | |
static AUDIO_HAL_22K_SAMPLES = 22050 | |
static AUDIO_HAL_24K_SAMPLES = 24000 | |
static AUDIO_HAL_32K_SAMPLES = 32000 | |
static AUDIO_HAL_44K_SAMPLES = 44100 | |
static AUDIO_HAL_48K_SAMPLES = 48000 | |
# I2S Format Konstanten | |
static AUDIO_HAL_I2S_NORMAL = 0 | |
static AUDIO_HAL_I2S_LEFT = 1 | |
static AUDIO_HAL_I2S_RIGHT = 2 | |
static AUDIO_HAL_I2S_DSP = 3 | |
# Bit Length Konstanten | |
static AUDIO_HAL_BIT_LENGTH_16BITS = 16 | |
static AUDIO_HAL_BIT_LENGTH_24BITS = 24 | |
static AUDIO_HAL_BIT_LENGTH_32BITS = 32 | |
# Mode Konstanten | |
static AUDIO_HAL_MODE_MASTER = 0 | |
static AUDIO_HAL_MODE_SLAVE = 1 | |
# Module Konstanten | |
static ES_MODULE_ADC = 1 | |
static ES_MODULE_DAC = 2 | |
static ES_MODULE_ADC_DAC = 3 | |
static ES_MODULE_LINE = 4 | |
var i2c_handle | |
var dac_vol_handle | |
var coeff_div | |
var tag | |
def init() | |
self.i2c_handle = nil | |
self.dac_vol_handle = nil | |
self.tag = "ES8311" | |
self.init_coeff_table() | |
end | |
# Vollständige Clock coefficient table | |
def init_coeff_table() | |
self.coeff_div = [ | |
# mclk, rate, pre_div, pre_multi, adc_div, dac_div, fs_mode, lrck_h, lrck_l, bclk_div, adc_osr, dac_osr | |
# 8k | |
[12288000, 8000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[18432000, 8000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x05, 0xff, 0x18, 0x10, 0x20], | |
[16384000, 8000, 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[8192000, 8000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[6144000, 8000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[4096000, 8000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[3072000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[2048000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[1536000, 8000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[1024000, 8000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
# 11.025k | |
[11289600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[5644800, 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[2822400, 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[1411200, 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
# 12k | |
[12288000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[6144000, 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[3072000, 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[1536000, 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
# 16k | |
[12288000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[18432000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x20], | |
[16384000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[8192000, 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[6144000, 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[4096000, 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[3072000, 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[2048000, 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[1536000, 16000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
[1024000, 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20], | |
# 22.05k | |
[11289600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[5644800, 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[2822400, 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[1411200, 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
# 24k | |
[12288000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[18432000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[6144000, 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[3072000, 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[1536000, 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
# 32k | |
[12288000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[18432000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10], | |
[16384000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[8192000, 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[6144000, 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[4096000, 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[3072000, 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[2048000, 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[1536000, 32000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10], | |
[1024000, 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
# 44.1k | |
[11289600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[5644800, 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[2822400, 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[1411200, 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
# 48k | |
[12288000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[18432000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[6144000, 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[3072000, 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[1536000, 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
# 64k | |
[12288000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[18432000, 64000, 0x03, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10], | |
[16384000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[8192000, 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[6144000, 64000, 0x01, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10], | |
[4096000, 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[3072000, 64000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10], | |
[2048000, 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[1536000, 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0xbf, 0x03, 0x18, 0x18], | |
[1024000, 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10], | |
# 88.2k | |
[11289600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[5644800, 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[2822400, 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[1411200, 88200, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10], | |
# 96k | |
[12288000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[18432000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[6144000, 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[3072000, 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10], | |
[1536000, 96000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10] | |
] | |
end | |
# I2C Funktionen | |
def write_reg(reg_addr, data) | |
if self.i2c_handle == nil | |
return false | |
end | |
if self.i2c_handle.write(self.ES8311_ADDR, reg_addr, data, 1) | |
return 0 | |
else | |
log(f"{self.tag}: Write reg {reg_addr:#04x} failed", 4) | |
return -1 | |
end | |
end | |
def read_reg(reg_addr) | |
if self.i2c_handle == nil | |
return -1 | |
end | |
var data = self.i2c_handle.read(self.ES8311_ADDR, reg_addr, 1) | |
log(f"{self.tag}: Read reg {reg_addr:#04x} = {data:#04x}",4) | |
return data != nil ? data : -1 | |
end | |
def i2c_init() | |
self.i2c_handle = tasmota.wire_scan(self.ES8311_ADDR) | |
return self.i2c_handle != nil | |
end | |
def get_es8311_mclk_src() | |
# Board-spezifische Implementierung | |
return self.FROM_MCLK_PIN | |
end | |
# Coefficient lookup | |
def get_coeff(mclk, rate) | |
for i: 0..size(self.coeff_div)-1 | |
if self.coeff_div[i][1] == rate && self.coeff_div[i][0] == mclk | |
return i | |
end | |
end | |
return -1 | |
end | |
# Mute-Funktion | |
def mute(enable) | |
var regv = self.read_reg(self.ES8311_DAC_REG31) & 0x9f | |
if enable | |
self.write_reg(self.ES8311_DAC_REG31, regv | 0x60) | |
else | |
self.write_reg(self.ES8311_DAC_REG31, regv) | |
end | |
print(f"{self.tag}: Mute = {enable}") | |
end | |
# Suspend-Modus | |
def suspend() | |
print(f"{self.tag}: Entering suspend mode") | |
self.write_reg(self.ES8311_DAC_REG32, 0x00) | |
self.write_reg(self.ES8311_ADC_REG17, 0x00) | |
self.write_reg(self.ES8311_SYSTEM_REG0E, 0xFF) | |
self.write_reg(self.ES8311_SYSTEM_REG12, 0x02) | |
self.write_reg(self.ES8311_SYSTEM_REG14, 0x00) | |
self.write_reg(self.ES8311_SYSTEM_REG0D, 0xFA) | |
self.write_reg(self.ES8311_ADC_REG15, 0x00) | |
self.write_reg(self.ES8311_GP_REG45, 0x01) | |
end | |
# PA Power Control | |
def pa_power(enable) | |
var pa_gpio = self.get_pa_enable_gpio() | |
if pa_gpio == -1 | |
return true | |
end | |
print(f"{self.tag}: Setting PA GPIO {pa_gpio} to {enable}") | |
import gpio | |
if enable | |
gpio.digital_write(pa_gpio, 1) | |
else | |
gpio.digital_write(pa_gpio, 0) | |
end | |
return true | |
end | |
def get_pa_enable_gpio() | |
# Board-spezifische GPIO-Konfiguration | |
# Muss für spezifisches Board angepasst werden | |
return self.P4_NANO_PA_GPIO | |
end | |
# Vollständige Codec-Initialisierung | |
def codec_init(codec_cfg) | |
var ret = 0 | |
if !self.i2c_init() | |
print(f"{self.tag}: I2C initialization failed") | |
return false | |
end | |
# I2C noise immunity enhancement | |
ret &= self.write_reg(self.ES8311_GPIO_REG44, 0x08) | |
ret &= self.write_reg(self.ES8311_GPIO_REG44, 0x08) # Doppelter Write | |
# Initial register setup | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG01, 0x30) | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG02, 0x00) | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG03, 0x10) | |
ret &= self.write_reg(self.ES8311_ADC_REG16, 0x24) | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG04, 0x10) | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG05, 0x00) | |
ret &= self.write_reg(self.ES8311_SYSTEM_REG0B, 0x00) | |
ret &= self.write_reg(self.ES8311_SYSTEM_REG0C, 0x00) | |
ret &= self.write_reg(self.ES8311_SYSTEM_REG10, 0x1F) | |
ret &= self.write_reg(self.ES8311_SYSTEM_REG11, 0x7F) | |
ret &= self.write_reg(self.ES8311_RESET_REG00, 0x80) | |
# Master/Slave Mode konfigurieren | |
var regv = self.read_reg(self.ES8311_RESET_REG00) | |
var mode = codec_cfg.find("mode", self.AUDIO_HAL_MODE_SLAVE) | |
if mode == self.AUDIO_HAL_MODE_MASTER | |
print(f"{self.tag}: ES8311 in Master mode") | |
regv |= 0x40 | |
else | |
print(f"{self.tag}: ES8311 in Slave mode") | |
regv &= 0xBF | |
end | |
ret &= self.write_reg(self.ES8311_RESET_REG00, regv) | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG01, 0x3F) | |
# Clock source selection | |
var mclk_src = self.get_es8311_mclk_src() | |
regv = self.read_reg(self.ES8311_CLK_MANAGER_REG01) | |
if mclk_src == self.FROM_MCLK_PIN | |
regv &= 0x7F | |
else | |
regv |= 0x80 | |
end | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG01, regv) | |
# Sample rate konfigurieren | |
var sample_rate = codec_cfg.find("sample_rate", self.AUDIO_HAL_48K_SAMPLES) | |
var mclk_freq = sample_rate * self.MCLK_DIV_FRE | |
var coeff = self.get_coeff(mclk_freq, sample_rate) | |
if coeff < 0 | |
print(f"{self.tag}: Unable to configure sample rate {sample_rate}Hz with {mclk_freq}Hz MCLK") | |
return false | |
end | |
# Clock parameter setup | |
ret &= self.setup_clock_parameters(coeff) | |
# MCLK/SCLK inversion | |
regv = self.read_reg(self.ES8311_CLK_MANAGER_REG01) | |
if self.INVERT_MCLK | |
regv |= 0x40 | |
else | |
regv &= ~0x40 | |
end | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG01, regv) | |
regv = self.read_reg(self.ES8311_CLK_MANAGER_REG06) | |
if self.INVERT_SCLK | |
regv |= 0x20 | |
else | |
regv &= ~0x20 | |
end | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG06, regv) | |
# Final system setup | |
ret &= self.write_reg(self.ES8311_SYSTEM_REG13, 0x10) | |
ret &= self.write_reg(self.ES8311_ADC_REG1B, 0x0A) | |
ret &= self.write_reg(self.ES8311_ADC_REG1C, 0x6A) | |
if ret != 0 | |
print(f"{self.tag}: ES8311 initialize failed") | |
return false | |
end | |
# PA GPIO setup | |
self.setup_pa_gpio() | |
# Volume control initialization | |
self.init_volume_control() | |
print(f"{self.tag}: ES8311 initialized successfully") | |
return true | |
end | |
# Vollständige Clock parameter setup | |
def setup_clock_parameters(coeff) | |
var coeff_data = self.coeff_div[coeff] | |
var ret = 0 | |
# Pre-divider und multiplier setup | |
var regv = self.read_reg(self.ES8311_CLK_MANAGER_REG02) & 0x07 | |
regv |= (coeff_data[2] - 1) << 5 # pre_div | |
var datmp = 0 | |
var pre_multi = coeff_data[3] | |
if pre_multi == 1 | |
datmp = 0 | |
elif pre_multi == 2 | |
datmp = 1 | |
elif pre_multi == 4 | |
datmp = 2 | |
elif pre_multi == 8 | |
datmp = 3 | |
end | |
if self.get_es8311_mclk_src() == self.FROM_SCLK_PIN | |
datmp = 3 # DIG_MCLK = LRCK * 256 = BCLK * 8 | |
end | |
regv |= datmp << 3 | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG02, regv) | |
# ADC/DAC divider | |
regv = self.read_reg(self.ES8311_CLK_MANAGER_REG05) & 0x00 | |
regv |= (coeff_data[4] - 1) << 4 # adc_div | |
regv |= (coeff_data[5] - 1) << 0 # dac_div | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG05, regv) | |
# FS mode und ADC OSR | |
regv = self.read_reg(self.ES8311_CLK_MANAGER_REG03) & 0x80 | |
regv |= coeff_data[6] << 6 # fs_mode | |
regv |= coeff_data[10] << 0 # adc_osr | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG03, regv) | |
# DAC OSR | |
regv = self.read_reg(self.ES8311_CLK_MANAGER_REG04) & 0x80 | |
regv |= coeff_data[11] << 0 # dac_osr | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG04, regv) | |
# LRCK divider high | |
regv = self.read_reg(self.ES8311_CLK_MANAGER_REG07) & 0xC0 | |
regv |= coeff_data[7] << 0 # lrck_h | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG07, regv) | |
# LRCK divider low | |
regv = self.read_reg(self.ES8311_CLK_MANAGER_REG08) & 0x00 | |
regv |= coeff_data[8] << 0 # lrck_l | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG08, regv) | |
# BCLK divider | |
regv = self.read_reg(self.ES8311_CLK_MANAGER_REG06) & 0xE0 | |
if coeff_data[9] < 19 # bclk_div | |
regv |= (coeff_data[9] - 1) << 0 | |
else | |
regv |= coeff_data[9] << 0 | |
end | |
ret &= self.write_reg(self.ES8311_CLK_MANAGER_REG06, regv) | |
return ret | |
end | |
# Format-Konfiguration | |
def config_fmt(fmt) | |
var ret = 0 | |
var adc_iface = self.read_reg(self.ES8311_SDPOUT_REG0A) | |
var dac_iface = self.read_reg(self.ES8311_SDPIN_REG09) | |
if fmt == self.AUDIO_HAL_I2S_NORMAL | |
print(f"{self.tag}: ES8311 in I2S Format") | |
dac_iface &= 0xFC | |
adc_iface &= 0xFC | |
elif fmt == self.AUDIO_HAL_I2S_LEFT || fmt == self.AUDIO_HAL_I2S_RIGHT | |
print(f"{self.tag}: ES8311 in LJ Format") | |
adc_iface &= 0xFC | |
dac_iface &= 0xFC | |
adc_iface |= 0x01 | |
dac_iface |= 0x01 | |
elif fmt == self.AUDIO_HAL_I2S_DSP | |
print(f"{self.tag}: ES8311 in DSP-A Format") | |
adc_iface &= 0xDC | |
dac_iface &= 0xDC | |
adc_iface |= 0x03 | |
dac_iface |= 0x03 | |
else | |
dac_iface &= 0xFC | |
adc_iface &= 0xFC | |
end | |
ret &= self.write_reg(self.ES8311_SDPIN_REG09, dac_iface) | |
ret &= self.write_reg(self.ES8311_SDPOUT_REG0A, adc_iface) | |
return ret | |
end | |
# Bit length konfiguration | |
def set_bits_per_sample(bits) | |
var ret = 0 | |
var adc_iface = self.read_reg(self.ES8311_SDPOUT_REG0A) | |
var dac_iface = self.read_reg(self.ES8311_SDPIN_REG09) | |
if bits == self.AUDIO_HAL_BIT_LENGTH_16BITS | |
dac_iface |= 0x0c | |
adc_iface |= 0x0c | |
elif bits == self.AUDIO_HAL_BIT_LENGTH_24BITS | |
# 24-bit default | |
elif bits == self.AUDIO_HAL_BIT_LENGTH_32BITS | |
dac_iface |= 0x10 | |
adc_iface |= 0x10 | |
else | |
dac_iface |= 0x0c | |
adc_iface |= 0x0c | |
end | |
ret &= self.write_reg(self.ES8311_SDPIN_REG09, dac_iface) | |
ret &= self.write_reg(self.ES8311_SDPOUT_REG0A, adc_iface) | |
return ret | |
end | |
# I2S Interface konfiguration | |
def config_i2s(mode, iface) | |
var ret = 0 | |
ret = self.set_bits_per_sample(iface.find("bits", self.AUDIO_HAL_BIT_LENGTH_16BITS)) | |
ret = self.config_fmt(iface.find("fmt", self.AUDIO_HAL_I2S_NORMAL)) | |
return ret | |
end | |
# Codec control state | |
def ctrl_state(mode, ctrl_state) | |
var ret = 0 | |
var es_mode = self.ES_MODULE_DAC | |
if mode == "encode" | |
es_mode = self.ES_MODULE_ADC | |
elif mode == "line_in" | |
es_mode = self.ES_MODULE_LINE | |
elif mode == "decode" | |
es_mode = self.ES_MODULE_DAC | |
elif mode == "both" | |
es_mode = self.ES_MODULE_ADC_DAC | |
else | |
es_mode = self.ES_MODULE_DAC | |
print(f"{self.tag}: Codec mode not support, default is decode mode") | |
end | |
if ctrl_state == "start" | |
ret = self.start(es_mode) | |
else | |
print(f"{self.tag}: The codec is about to stop") | |
ret = self.stop(es_mode) | |
end | |
return ret | |
end | |
# Start function | |
def start(mode) | |
var ret = 0 | |
var adc_iface = self.read_reg(self.ES8311_SDPOUT_REG0A) & 0xBF | |
var dac_iface = self.read_reg(self.ES8311_SDPIN_REG09) & 0xBF | |
adc_iface |= 0x40 # BIT(6) | |
dac_iface |= 0x40 | |
if mode == self.ES_MODULE_LINE | |
print(f"{self.tag}: The codec es8311 doesn't support ES_MODULE_LINE mode") | |
return false | |
end | |
if mode == self.ES_MODULE_ADC || mode == self.ES_MODULE_ADC_DAC | |
adc_iface &= ~0x40 | |
end | |
if mode == self.ES_MODULE_DAC || mode == self.ES_MODULE_ADC_DAC | |
dac_iface &= ~0x40 | |
end | |
ret &= self.write_reg(self.ES8311_SDPIN_REG09, dac_iface) | |
ret &= self.write_reg(self.ES8311_SDPOUT_REG0A, adc_iface) | |
ret &= self.write_reg(self.ES8311_ADC_REG17, 0xBF) | |
ret &= self.write_reg(self.ES8311_SYSTEM_REG0E, 0x02) | |
ret &= self.write_reg(self.ES8311_SYSTEM_REG12, 0x00) | |
ret &= self.write_reg(self.ES8311_SYSTEM_REG14, 0x1A) | |
# PDM DMIC enable/disable | |
var regv = self.read_reg(self.ES8311_SYSTEM_REG14) | |
if self.IS_DMIC | |
regv |= 0x40 | |
else | |
regv &= ~0x40 | |
end | |
ret &= self.write_reg(self.ES8311_SYSTEM_REG14, regv) | |
ret &= self.write_reg(self.ES8311_SYSTEM_REG0D, 0x01) | |
ret &= self.write_reg(self.ES8311_ADC_REG15, 0x40) | |
ret &= self.write_reg(self.ES8311_DAC_REG37, 0x08) | |
ret &= self.write_reg(self.ES8311_GP_REG45, 0x00) | |
# Set internal reference signal | |
ret &= self.write_reg(self.ES8311_GPIO_REG44, 0x58) | |
return ret | |
end | |
# Stop function | |
def stop(mode) | |
self.suspend() | |
return true | |
end | |
# Volume control | |
def set_voice_volume(volume) | |
if volume < 0 || volume > 100 | |
return false | |
end | |
var reg = self.audio_codec_get_dac_reg_value(volume) | |
var res = self.write_reg(self.ES8311_DAC_REG32, reg) | |
print(f"{self.tag}: Set volume: {volume} reg_value: 0x{reg:02X}") | |
return res | |
end | |
def get_voice_volume() | |
var regv = self.read_reg(self.ES8311_DAC_REG32) | |
if regv < 0 | |
return 0 | |
end | |
if regv == self.dac_vol_handle["reg_value"] | |
return self.dac_vol_handle["user_volume"] | |
else | |
return 0 | |
end | |
end | |
# Mute control | |
def set_voice_mute(enable) | |
print(f"{self.tag}: SetVoiceMute: {enable}") | |
self.mute(enable) | |
return true | |
end | |
def get_voice_mute() | |
var res = self.read_reg(self.ES8311_DAC_REG31) | |
if res >= 0 | |
return (res & 0x20) >> 5 | |
end | |
return 0 | |
end | |
# Microphone gain | |
def set_mic_gain(gain_db) | |
return self.write_reg(self.ES8311_ADC_REG16, gain_db) | |
end | |
# Deinitialize | |
def deinit() | |
# I2C cleanup würde hier stehen | |
self.dac_vol_handle = nil | |
return true | |
end | |
# Helper functions | |
def setup_pa_gpio() | |
var pa_gpio = self.get_pa_enable_gpio() | |
if pa_gpio != -1 | |
import gpio | |
gpio.pin_mode(pa_gpio, gpio.OUTPUT) | |
self.pa_power(true) | |
end | |
end | |
def init_volume_control() | |
self.dac_vol_handle = { | |
"max_dac_volume": 32, | |
"min_dac_volume": -95.5, | |
"board_pa_gain": 0, | |
"volume_accuracy": 0.5, | |
"dac_vol_symbol": 1, | |
"zero_volume_reg": 0xBF, | |
"reg_value": 0, | |
"user_volume": 0 | |
} | |
end | |
def audio_codec_get_dac_reg_value(volume) | |
# Vereinfachte Volume-zu-Register Konvertierung | |
# 0x00: -95.5 dB, 0xBF: 0 dB, 0xFF: 32 dB | |
if volume == 0 | |
return 0x00 | |
elif volume >= 100 | |
return 0xFF | |
else | |
return int((volume * 0xBF) / 100) | |
end | |
end | |
# Debug function | |
def read_all() | |
print(f"{self.tag}: Register Dump:") | |
for i: 0..0x4A-1 | |
var reg_val = self.read_reg(i) | |
print(f"REG[0x{i:02X}] = 0x{reg_val:02X}") | |
end | |
end | |
end | |
# Default handle structure (als globale Variable) | |
var AUDIO_CODEC_ES8311_DEFAULT_HANDLE = { | |
"audio_codec_initialize": nil, | |
"audio_codec_deinitialize": nil, | |
"audio_codec_ctrl": nil, | |
"audio_codec_config_iface": nil, | |
"audio_codec_set_mute": nil, | |
"audio_codec_set_volume": nil, | |
"audio_codec_get_volume": nil, | |
"audio_codec_enable_pa": nil, | |
"audio_hal_lock": nil, | |
"handle": nil | |
} | |
# Usage example: | |
var codec = ES8311() | |
var config = {"mode": ES8311.AUDIO_HAL_MODE_SLAVE, "sample_rate": ES8311.AUDIO_HAL_48K_SAMPLES,"fmt": ES8311.AUDIO_HAL_I2S_NORMAL, "bits": ES8311.AUDIO_HAL_BIT_LENGTH_16BITS } | |
codec.codec_init(config) | |
codec.config_i2s(ES8311.AUDIO_HAL_MODE_SLAVE, config) | |
codec.set_voice_volume(30) | |
codec.start(ES8311.ES_MODULE_ADC_DAC) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment