mirror of
https://github.com/arendst/Tasmota.git
synced 2026-02-20 00:32:32 +01:00
es8311 for p4 eval board (#24357)
This commit is contained in:
339
tasmota/berry/audio/es8311.be
Normal file
339
tasmota/berry/audio/es8311.be
Normal file
@@ -0,0 +1,339 @@
|
||||
# ES8311 Audio Codec Driver for Berry
|
||||
# HW: ESP32P4-EV
|
||||
# pa_power pin GPIO 53
|
||||
|
||||
|
||||
class ES8311
|
||||
var i2c
|
||||
|
||||
def init()
|
||||
import gpio
|
||||
self.i2c = tasmota.wire_scan(0x18)
|
||||
if self.i2c == nil
|
||||
log("ES8311 I2C initialization failed")
|
||||
else
|
||||
# var i2s_conf = tasmota.cmd('i2sconfig')
|
||||
# var sample_freq = i2s_conf["I2SConfig"]["Tx"]["SampleRate"]
|
||||
var sample_freq = 48000 # seems to work for every rate ???
|
||||
if self.init_codec(sample_freq, sample_freq * 128)
|
||||
self.config_microphone()
|
||||
log("ES8311 initialized successfully")
|
||||
gpio.pin_mode(53, gpio.OUTPUT)
|
||||
tasmota.add_driver(self)
|
||||
else
|
||||
log("ES8311 initialization failed")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def audio(cmd, idx, payload, raw)
|
||||
if cmd == "power"
|
||||
self.pa_power(idx ? 1 : 0)
|
||||
elif cmd == "rate"
|
||||
# ??? seems to work with any rate
|
||||
if raw[0] == 0 # tx
|
||||
self.sample_frequency_config(idx * 256, idx)
|
||||
print(f"ES8311: Set TX sample rate to {idx}Hz")
|
||||
elif raw[0] == 1 # rx
|
||||
self.sample_frequency_config(idx * 256, idx)
|
||||
print(f"ES8311: Set RX sample rate to {idx}Hz")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PA Power Control
|
||||
def pa_power(enable)
|
||||
log(f"ES8311: Setting PA GPIO 53 to {enable}",4)
|
||||
import gpio
|
||||
if enable
|
||||
gpio.digital_write(53, 1)
|
||||
else
|
||||
gpio.digital_write(53, 0)
|
||||
end
|
||||
end
|
||||
|
||||
# I2C functions
|
||||
def write_reg(reg_addr, data)
|
||||
if self.i2c.write(0x18, reg_addr, data, 1)
|
||||
return 0
|
||||
else
|
||||
log(f"Write reg {reg_addr:#04x} failed", 4)
|
||||
return -1
|
||||
end
|
||||
end
|
||||
|
||||
def read_reg(reg_addr)
|
||||
var data = self.i2c.read(0x18, reg_addr, 1)
|
||||
log(f"Read reg {reg_addr:#04x} = {data:#04x}",4)
|
||||
return data != nil ? data : -1
|
||||
end
|
||||
|
||||
# Coefficient table for clock divider
|
||||
static coeff_div = [
|
||||
# mclk, rate, pre_div, pre_multi, adc_div, dac_div, fs_mode, lrck_h, lrck_l, bclk_div, adc_osr, dac_osr
|
||||
[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]
|
||||
]
|
||||
|
||||
# Find coefficients
|
||||
def get_coeff(mclk, rate)
|
||||
for i: 0..size(self.coeff_div)-1
|
||||
if self.coeff_div[i][0] == mclk && self.coeff_div[i][1] == rate
|
||||
return i
|
||||
end
|
||||
end
|
||||
return -1
|
||||
end
|
||||
|
||||
# Configure sample frequency
|
||||
def sample_frequency_config(mclk_frequency, sample_frequency)
|
||||
var coeff = self.get_coeff(mclk_frequency, sample_frequency)
|
||||
if coeff < 0
|
||||
log(f"Error: Cannot configure sample rate: {sample_frequency}",4)
|
||||
return false
|
||||
end
|
||||
|
||||
var selected_coeff = self.coeff_div[coeff]
|
||||
|
||||
# Register 0x02
|
||||
var regv = self.read_reg(0x02)
|
||||
regv &= 0x07
|
||||
regv |= (selected_coeff[2] - 1) << 5
|
||||
regv |= selected_coeff[3] << 3
|
||||
self.write_reg(0x02, regv)
|
||||
|
||||
# Register 0x03
|
||||
var reg03 = (selected_coeff[6] << 6) | selected_coeff[10]
|
||||
self.write_reg(0x03, reg03)
|
||||
|
||||
# Register 0x04
|
||||
self.write_reg(0x04, selected_coeff[11])
|
||||
|
||||
# Register 0x05
|
||||
var reg05 = ((selected_coeff[4] - 1) << 4) | (selected_coeff[5] - 1)
|
||||
self.write_reg(0x05, reg05)
|
||||
|
||||
# Register 0x06
|
||||
regv = self.read_reg(0x06)
|
||||
regv &= 0xE0
|
||||
if selected_coeff[9] < 19
|
||||
regv |= (selected_coeff[9] - 1) << 0
|
||||
else
|
||||
regv |= selected_coeff[9] << 0
|
||||
end
|
||||
self.write_reg(0x06, regv)
|
||||
|
||||
# Register 0x07
|
||||
regv = self.read_reg(0x07)
|
||||
regv &= 0xC0
|
||||
regv |= selected_coeff[7] << 0
|
||||
self.write_reg(0x07, regv)
|
||||
|
||||
# Register 0x08
|
||||
self.write_reg(0x08, selected_coeff[8])
|
||||
log(f"Sample frequency configured: MCLK={mclk_frequency}Hz, Sample Rate={sample_frequency}Hz, Coeff Index={coeff}",4)
|
||||
return true
|
||||
end
|
||||
|
||||
# Initialize ES8311
|
||||
def init_codec(sample_freq, mclk_freq)
|
||||
log(f"Initializing ES8311 codec with sample frequency: {sample_freq}Hz and MCLK frequency: {mclk_freq}Hz",2)
|
||||
# Reset ES8311
|
||||
self.write_reg(0x00, 0x1F)
|
||||
tasmota.delay(20)
|
||||
self.write_reg(0x00, 0x00)
|
||||
self.write_reg(0x00, 0x80)
|
||||
|
||||
# Clock configuration
|
||||
var reg01 = 0x3F # Enable all clocks
|
||||
self.write_reg(0x01, reg01)
|
||||
|
||||
# Configure sample frequency
|
||||
if !self.sample_frequency_config(mclk_freq, sample_freq)
|
||||
return false
|
||||
end
|
||||
|
||||
# Configure audio format (I2S, 16-bit)
|
||||
var regv = self.read_reg(0x00)
|
||||
regv &= 0xBF;
|
||||
self.write_reg(0x00, regv)
|
||||
self.write_reg(0x09, 0x0C) # SDP In: I2S, 16-bit
|
||||
self.write_reg(0x0A, 0x0C) # SDP Out: I2S, 16-bit
|
||||
|
||||
# Enable analog circuits
|
||||
self.write_reg(0x0D, 0x01) # Enable analog circuits
|
||||
self.write_reg(0x0E, 0x02) # Enable PGA and ADC modulator
|
||||
self.write_reg(0x12, 0x00) # Enable DAC
|
||||
self.write_reg(0x13, 0x10) # Enable headphone output
|
||||
|
||||
# ADC/DAC configuration
|
||||
self.write_reg(0x1C, 0x6A) # Bypass ADC equalizer
|
||||
self.write_reg(0x37, 0x08) # Bypass DAC equalizer
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
# Set volume (0-100)
|
||||
def set_volume(volume)
|
||||
if volume < 0
|
||||
volume = 0
|
||||
elif volume > 100
|
||||
volume = 100
|
||||
end
|
||||
|
||||
var reg32
|
||||
if volume == 0
|
||||
reg32 = 0
|
||||
else
|
||||
reg32 = ((volume * 256) / 100) - 1
|
||||
end
|
||||
|
||||
self.write_reg(0x32, reg32)
|
||||
return volume
|
||||
end
|
||||
|
||||
# Read volume
|
||||
def get_volume()
|
||||
var reg32 = self.read_reg(0x32)
|
||||
if reg32 == 0
|
||||
return 0
|
||||
else
|
||||
return ((reg32 * 100) / 256) + 1
|
||||
end
|
||||
end
|
||||
|
||||
# Mute
|
||||
def mute(enable)
|
||||
var reg31 = self.read_reg(0x31)
|
||||
if enable
|
||||
reg31 |= 0x60 # Set bits 6 and 5
|
||||
else
|
||||
reg31 &= ~0x60 # Clear bits 6 and 5
|
||||
end
|
||||
self.write_reg(0x31, reg31)
|
||||
end
|
||||
|
||||
# Set microphone gain
|
||||
def set_mic_gain(gain_db) # gain_db is 0x00 to 0x07 (0dB to 42dB)
|
||||
self.write_reg(0x16, gain_db)
|
||||
end
|
||||
|
||||
# Configure microphone
|
||||
def config_microphone()
|
||||
var reg14 = 0x1A # Enable analog microphone, max PGA gain
|
||||
self.write_reg(0x17, 0xC8) # Set ADC gain
|
||||
self.write_reg(0x14, reg14)
|
||||
self.set_mic_gain(0x01) # Set microphone gain to 6dB
|
||||
end
|
||||
|
||||
# Register dump for debugging
|
||||
def register_dump()
|
||||
log("ES8311 Register Dump:",2)
|
||||
for reg: 0..0x49
|
||||
var value = self.read_reg(reg)
|
||||
log(f"REG:{reg:02X}: {value:02X}",2)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# Example
|
||||
codec = ES8311()
|
||||
codec.set_volume(75)
|
||||
codec.set_mic_gain(0x04) # Set microphone gain to (6*4 =) 24dB
|
||||
tasmota.cmd('i2sconfig {"Tx":{"SampleRate":48000,"SlotMask":1,"APLL":0,"SlotConfig":2},"Rx":{"SampleRate":32000,"Channels":1, "Mode":0}}')
|
||||
Reference in New Issue
Block a user