196 lines
7.7 KiB
Python
196 lines
7.7 KiB
Python
# -*- coding: UTF-8 -*-
|
|
import time
|
|
from micropython import const
|
|
|
|
_ES_MODULE_ADC = const(0x01)
|
|
_ES_MODULE_DAC = const(0x02)
|
|
_ES_MODULE_ADC_DAC = const(0x03)
|
|
_ES_MODULE_LINE = const(0x04)
|
|
_BIT_LENGTH_16BITS = const(0x03)
|
|
_FMT_I2S_NORMAL = const(0x00)
|
|
_I2S_MODE_SLAVE = const(0x00)
|
|
_ADC_INPUT_LINE = const(0x01)
|
|
_DAC_OUTPUT_ALL = const(0x02)
|
|
_LCLK_DIV = const(256)
|
|
_MCLK_DIV = const(0x04)
|
|
|
|
class ES8374:
|
|
def __init__(self, i2c_bus=None, i2c_addr=0x10, gain=5, pga_en=1):
|
|
self.i2c_bus = i2c_bus
|
|
self.i2c_addr = i2c_addr
|
|
self.stop()
|
|
self.init_reg(_I2S_MODE_SLAVE, ((_BIT_LENGTH_16BITS << 4) | _FMT_I2S_NORMAL), _DAC_OUTPUT_ALL, _ADC_INPUT_LINE)
|
|
self.mic_gain(gain)
|
|
self.pga_enable(pga_en)
|
|
self.configI2SFormat(_ES_MODULE_ADC_DAC, _FMT_I2S_NORMAL)
|
|
|
|
def _readReg(self, regAddr):
|
|
return self.i2c_bus.readfrom_mem(self.i2c_addr, regAddr, 1)[0]
|
|
|
|
def _writeReg(self, regAddr, data):
|
|
self.i2c_bus.writeto_mem(
|
|
self.i2c_addr, regAddr, data.to_bytes(1, 'little'))
|
|
|
|
def init_reg(self, ms_mode, fmt, out_channel, in_channel):
|
|
self._writeReg(0x00, 0x3F) # IC Rst start
|
|
self._writeReg(0x00, 0x03) # IC Rst stop
|
|
self._writeReg(0x01, 0x7F) # IC clk on # M ORG 7F
|
|
self._writeReg(0x0f, (self._readReg(0x0F) & 0x7f) | (ms_mode << 7)) # CODEC IN I2S SLAVE MODE
|
|
|
|
self._writeReg(0x6F, 0xA0) # pll set:mode enable
|
|
self._writeReg(0x72, 0x41) # pll set:mode set
|
|
self._writeReg(0x09, 0x01) # pll set:reset on ,set start
|
|
self._writeReg(0x0C, 0x22) # pll set:k
|
|
self._writeReg(0x0D, 0x2E) # pll set:k
|
|
self._writeReg(0x0E, 0xC6) # pll set:k
|
|
self._writeReg(0x0A, 0x3A) # pll set:
|
|
self._writeReg(0x0B, 0x07) # pll set:n
|
|
self._writeReg(0x09, 0x41) # pll set:reset off ,set stop
|
|
self.i2sConfigClock()
|
|
self._writeReg(0x24, 0x08) # adc set
|
|
self._writeReg(0x36, 0x00) # dac set
|
|
self._writeReg(0x12, 0x30) # timming set
|
|
self._writeReg(0x13, 0x20) # timming set
|
|
self.configI2SFormat(_ES_MODULE_ADC, fmt)
|
|
self.configI2SFormat(_ES_MODULE_DAC, fmt)
|
|
self._writeReg(0x21, 0x50) # adc set: SEL LIN1 CH+PGAGAIN=0DB
|
|
self._writeReg(0x22, 0xFF) # adc set: PGA GAIN=0DB
|
|
self._writeReg(0x21, 0x14) # adc set: SEL LIN1 CH+PGAGAIN=18DB
|
|
self._writeReg(0x22, 0x55) # pga = +15db
|
|
# set class d divider = 33, to avoid the high frequency tone on laudspeaker
|
|
self._writeReg(0x08, 0x21)
|
|
self._writeReg(0x00, 0x80) # IC START
|
|
time.sleep(0.05)
|
|
self._writeReg(0x25, 0x00) # ADCVOLUME on
|
|
self._writeReg(0x38, 0x00) # DACVOLUME on
|
|
self._writeReg(0x14, 0x8A) # IC START
|
|
self._writeReg(0x15, 0x40) # IC START
|
|
self._writeReg(0x1A, 0xA0) # monoout set
|
|
self._writeReg(0x1B, 0x19) # monoout set
|
|
self._writeReg(0x1C, 0x90) # spk set
|
|
self._writeReg(0x1D, 0x01) # spk set
|
|
self._writeReg(0x1F, 0x00) # spk set
|
|
self._writeReg(0x1E, 0x20) # spk on
|
|
self._writeReg(0x28, 0x70) # alc set 0x70
|
|
# self._writeReg(0x26, 0x4E)# alc set
|
|
# self._writeReg(0x27, 0x10)# alc set
|
|
# self._writeReg(0x29, 0x00)# alc set
|
|
# self._writeReg(0x2B, 0x00)# alc set
|
|
self._writeReg(0x25, 0x00) # ADCVOLUME on
|
|
self._writeReg(0x38, 0x00) # DACVOLUME on
|
|
self._writeReg(0x37, 0x30) # dac set
|
|
# SEL:GPIO1=DMIC CLK OUT+SEL:GPIO2=PLL CLK OUT
|
|
self._writeReg(0x6D, 0x60)
|
|
self._writeReg(0x71, 0x05) # for automute setting
|
|
self._writeReg(0x73, 0x70)
|
|
# 0x3c Enable DAC and Enable Lout/Rout/1/2
|
|
self.configDACOutput(out_channel)
|
|
# 0x00 LINSEL & RINSEL, LIN1/RIN1 as ADC Input DSSEL,use one DS Reg11 DSR, LINPUT1-RINPUT1
|
|
self.configADCInput(in_channel)
|
|
self.voice_volume(95)
|
|
self._writeReg(0x37, 0x00) # dac set
|
|
'''
|
|
reg = self._readReg(0x1a) # disable lout
|
|
reg |= 0x08
|
|
self._writeReg(0x1a, reg)
|
|
reg &= 0xdf
|
|
self._writeReg(0x1a, reg)
|
|
self._writeReg(0x1D, 0x12) # mute speaker
|
|
self._writeReg(0x1E, 0x20) # disable class d
|
|
reg = self._readReg(0x15) # power up dac
|
|
reg &= 0xdf
|
|
self._writeReg(0x15, reg)
|
|
reg = self._readReg(0x1a) # disable lout
|
|
reg |= 0x20
|
|
self._writeReg(0x1a, reg)
|
|
reg &= 0xf7
|
|
self._writeReg(0x1a, reg)
|
|
self._writeReg(0x1D, 0x02) # mute speaker
|
|
self._writeReg(0x1E, 0xa0) # disable class d
|
|
self.voice_mute(0)
|
|
'''
|
|
|
|
def stop(self):
|
|
self.voice_mute(1)
|
|
self._writeReg(0x1a, self._readReg(0x1a) | 0x08)
|
|
self._writeReg(0x1a, self._readReg(0x1a) & 0xdf)
|
|
self._writeReg(0x1D, 0x12) # mute speaker
|
|
self._writeReg(0x1E, 0x20) # disable class d
|
|
self._writeReg(0x15, self._readReg(0x15) | 0x20)
|
|
self._writeReg(0x10, self._readReg(0x10) | 0xc0)
|
|
self._writeReg(0x21, self._readReg(0x21) | 0xc0)
|
|
|
|
def i2sConfigClock(self):
|
|
self._writeReg(0x0f, (self._readReg(0x0F) & 0xe0) | _MCLK_DIV)
|
|
# ADCFsMode,singel SPEED,RATIO=256
|
|
self._writeReg(0x06, _LCLK_DIV >> 8)
|
|
# ADCFsMode,singel SPEED,RATIO=256
|
|
self._writeReg(0x07, _LCLK_DIV & 0xFF)
|
|
|
|
def configI2SFormat(self, mode, fmt):
|
|
fmt_tmp = ((fmt & 0xf0) >> 4)
|
|
fmt_i2s = fmt & 0x0f
|
|
if (mode == _ES_MODULE_ADC or mode == _ES_MODULE_ADC_DAC):
|
|
reg = self._readReg(0x10)
|
|
reg &= 0xfc
|
|
self._writeReg(0x10, (reg | fmt_i2s))
|
|
self.setBitsPerSample(mode, 3)
|
|
|
|
if (mode == _ES_MODULE_DAC or mode == _ES_MODULE_ADC_DAC):
|
|
reg = self._readReg(0x11)
|
|
reg &= 0xfc
|
|
self._writeReg(0x11, (reg | fmt_i2s))
|
|
self.setBitsPerSample(mode, 3)
|
|
|
|
# set Bits Per Sample
|
|
def setBitsPerSample(self, mode, bit_per_smaple):
|
|
bits = bit_per_smaple & 0x0f
|
|
if (mode == _ES_MODULE_ADC or mode == _ES_MODULE_ADC_DAC):
|
|
reg = self._readReg(0x10)
|
|
reg &= 0xe3
|
|
self._writeReg(0x10, (reg | (bits << 2)))
|
|
|
|
if (mode == _ES_MODULE_DAC or mode == _ES_MODULE_ADC_DAC):
|
|
reg = self._readReg(0x11)
|
|
reg &= 0xe3
|
|
self._writeReg(0x11, (reg | (bits << 2)))
|
|
|
|
def configDACOutput(self, output):
|
|
self._writeReg(0x1d, 0x02)
|
|
reg = self._readReg(0x1c) # set spk mixer
|
|
reg |= 0x80
|
|
self._writeReg(0x1c, reg)
|
|
self._writeReg(0x1D, 0x02) # spk set
|
|
self._writeReg(0x1F, 0x00) # spk set
|
|
self._writeReg(0x1E, 0xA0) # spk on
|
|
|
|
def configADCInput(self, input):
|
|
reg = self._readReg(0x21)
|
|
reg = (reg & 0xcf) | 0x24
|
|
self._writeReg(0x21, reg)
|
|
|
|
def mic_volume(self, volume=None):
|
|
if volume is None:
|
|
return round(100 - self._readReg(0x25) * 100 / 192)
|
|
else:
|
|
self._writeReg(0x25, (100 - volume) * 192 // 100)
|
|
|
|
def voice_volume(self, volume=None):
|
|
if volume is None:
|
|
return round(100 - self._readReg(0x38) * 100 / 192)
|
|
else:
|
|
self._writeReg(0x38, (100 - volume) * 192 // 100)
|
|
|
|
def voice_mute(self, enable=None):
|
|
if enable is None:
|
|
return True if self._readReg(0x36) & 0x40 else False
|
|
else:
|
|
self._writeReg(0x36, (self._readReg(0x36) & 0xdf) | (enable << 5))
|
|
|
|
def mic_gain(self, gain):
|
|
gain_n = max(min(gain, 15), 0)
|
|
self._writeReg(0x22, (gain_n | (gain_n << 4))) # MIC PGA -3.5db ~ 24db
|
|
|
|
def pga_enable(self, enable):
|
|
self._writeReg(0x21, (self._readReg(0x21) & 0xfb) | (enable << 2)) # MIC PGA 0db or 15db
|