Files
esp32_multitrack_looper/es8388.ino
T

532 lines
13 KiB
Arduino

/*
* Copyright (c) 2021 Marcel Licence
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
* der GNU General Public License, wie von der Free Software Foundation,
* Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
* veröffentlichten Version, weiter verteilen und/oder modifizieren.
*
* Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch
* OHNE JEDE GEWÄHR,; sogar ohne die implizite
* Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
* Siehe die GNU General Public License für weitere Einzelheiten.
*
* Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
* Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
*/
/**
* @file es8388.ino
* @author Marcel Licence
* @date 22.08.2021
*
* @brief This module is used to initialize the ES8388
*
* @see ESP32 Audio Kit AC101 codec failure - Get synthesizer projects working based on ES8388 - https://youtu.be/8UB3fYPjqSk
* @see https://github.com/espressif/esp-adf/blob/master/components/audio_hal/driver/es8388/es8388.c
*/
#ifdef __CDT_PARSER__
#include <cdt.h>
#endif
#ifdef ES8388_ENABLED
/*
* http://www.everest-semi.com/pdf/ES8388%20DS.pdf
*/
#include <Wire.h>
/* ES8388 address */
//#define ES8388_ADDR 0x20 /*!< 0x22:CE=1;0x20:CE=0*/
#define ES8388_ADDR 0x10 /*!< 0x22:CE=1;0x20:CE=0*/
/* ES8388 register */
#define ES8388_CONTROL1 0x00
#define ES8388_CONTROL2 0x01
#define ES8388_CHIPPOWER 0x02
#define ES8388_ADCPOWER 0x03
#define ES8388_DACPOWER 0x04
#define ES8388_CHIPLOPOW1 0x05
#define ES8388_CHIPLOPOW2 0x06
#define ES8388_ANAVOLMANAG 0x07
#define ES8388_MASTERMODE 0x08
/* ADC */
#define ES8388_ADCCONTROL1 0x09
#define ES8388_ADCCONTROL2 0x0a
#define ES8388_ADCCONTROL3 0x0b
#define ES8388_ADCCONTROL4 0x0c
#define ES8388_ADCCONTROL5 0x0d
#define ES8388_ADCCONTROL6 0x0e
#define ES8388_ADCCONTROL7 0x0f
#define ES8388_ADCCONTROL8 0x10
#define ES8388_ADCCONTROL9 0x11
#define ES8388_ADCCONTROL10 0x12
#define ES8388_ADCCONTROL11 0x13
#define ES8388_ADCCONTROL12 0x14
#define ES8388_ADCCONTROL13 0x15
#define ES8388_ADCCONTROL14 0x16
/* DAC */
#define ES8388_DACCONTROL1 0x17
#define ES8388_DACCONTROL2 0x18
#define ES8388_DACCONTROL3 0x19
#define ES8388_DACCONTROL4 0x1a
#define ES8388_DACCONTROL5 0x1b
#define ES8388_DACCONTROL6 0x1c
#define ES8388_DACCONTROL7 0x1d
#define ES8388_DACCONTROL8 0x1e
#define ES8388_DACCONTROL9 0x1f
#define ES8388_DACCONTROL10 0x20
#define ES8388_DACCONTROL11 0x21
#define ES8388_DACCONTROL12 0x22
#define ES8388_DACCONTROL13 0x23
#define ES8388_DACCONTROL14 0x24
#define ES8388_DACCONTROL15 0x25
#define ES8388_DACCONTROL16 0x26
#define ES8388_DACCONTROL17 0x27
#define ES8388_DACCONTROL18 0x28
#define ES8388_DACCONTROL19 0x29
#define ES8388_DACCONTROL20 0x2a
#define ES8388_DACCONTROL21 0x2b
#define ES8388_DACCONTROL22 0x2c
#define ES8388_DACCONTROL23 0x2d
#define ES8388_DACCONTROL24 0x2e
#define ES8388_DACCONTROL25 0x2f
#define ES8388_DACCONTROL26 0x30
#define ES8388_DACCONTROL27 0x31
#define ES8388_DACCONTROL28 0x32
#define ES8388_DACCONTROL29 0x33
#define ES8388_DACCONTROL30 0x34
uint8_t ES8388_ReadReg(uint8_t reg)
{
Wire.beginTransmission(ES8388_ADDR);
Wire.write(reg);
Wire.endTransmission(false);
uint8_t val = 0u;
if (1 == Wire.requestFrom(uint16_t(ES8388_ADDR), uint8_t(1), true))
{
val = Wire.read();
}
Wire.endTransmission(false);
return val;
}
bool ES8388_WriteReg(uint8_t reg, uint8_t val)
{
Wire.beginTransmission(ES8388_ADDR);
Wire.write(reg);
Wire.write(val);
return 0 == Wire.endTransmission(true);
}
bool ES8388_begin(int sda, int scl, uint32_t frequency)
{
bool ok = Wire.begin(sda, scl, frequency);
// Reset all registers, readback default as sanity check
//ok &= WriteReg(CHIP_AUDIO_RS, 0x123);
delay(100);
Serial.printf("0x00: 0x%02x\n", ES8388_ReadReg(ES8388_CONTROL1));
Serial.printf("0x01: 0x%02x\n", ES8388_ReadReg(ES8388_CONTROL2));
ES8388_WriteReg(ES8388_CONTROL1, 1 << 7); /* do reset! */
ES8388_WriteReg(ES8388_CONTROL1, 0x06);
ES8388_WriteReg(ES8388_CONTROL2, 0x50);
ok &= (0x06 == ES8388_ReadReg(ES8388_CONTROL1));
ok &= (0x50 == ES8388_ReadReg(ES8388_CONTROL2));
return ok;
}
void es8388_read_all()
{
for (int i = 0; i < 53; i++)
{
uint8_t reg = 0;
reg = ES8388_ReadReg(i);
Serial.printf("Reg 0x%02x = 0x%02x\n", i, reg);
}
}
void ES8388_SetADCVOL(uint8_t unused, float vol)
{
#ifdef STATUS_ENABLED
Status_ValueChangedInt("ADC Volume /db", (vol - 1) * 97 + 0.5);
#endif
vol *= -192;
vol += 192;
uint8_t volu8 = vol;
if (volu8 > 192)
{
volu8 = 192;
}
ES8388_WriteReg(0x10, volu8); // LADCVOL
ES8388_WriteReg(0x11, volu8); // RADCVOL
}
void ES8388_SetDACVOL(uint8_t unused, float vol)
{
#ifdef STATUS_ENABLED
Status_ValueChangedInt("DAC Volume /db", (vol - 1) * 97 + 0.5);
#endif
vol *= -192;
vol += 192;
uint8_t volu8 = vol;
if (volu8 > 192)
{
volu8 = 192;
}
ES8388_WriteReg(0x1A, volu8); // LDACVOL
ES8388_WriteReg(0x1B, volu8); // RDACVOL
}
void ES8388_SetPGAGain(uint8_t unused, float vol)
{
#ifdef STATUS_ENABLED
Status_ValueChangedInt("PGA Gain /db", vol * 24 + 0.25);
#endif
vol *= 8;
uint8_t volu8 = vol;
if (volu8 > 8)
{
volu8 = 8;
}
// ES8388_ADCCONTROL1
ES8388_WriteReg(0x09, volu8 + (volu8 << 4)); // MicAmpL, MicAmpR
}
void ES8388_SetInputCh(uint8_t ch, float var)
{
if (var > 0)
{
uint8_t in;
switch (ch)
{
case 0:
in = 0;
Serial.printf("AdcCh0!\n");
break;
case 1:
in = 1;
Serial.printf("AdcCh1!\n");
break;
default:
Serial.printf("Illegal Input ch!\n");
return;
}
// ES8388_ADCCONTROL2
ES8388_WriteReg(0x0A, (in << 6) + (in << 4)); // LINSEL , RINSEL , DSSEL , DSR
#ifdef STATUS_ENABLED
Status_ValueChangedInt("ADC Ch", in);
#endif
}
}
void ES8388_SetMixInCh(uint8_t ch, float var)
{
if (var > 0)
{
uint8_t in = 0;
switch (ch)
{
case 0:
in = 0;
Serial.printf("MixCh0!\n");
break;
case 1:
in = 1;
Serial.printf("MixCh1!\n");
break;
case 2:
in = 3;
Serial.printf("MixChAMPL!\n");
break;
default:
Serial.printf("Illegal Mix Input ch!\n");
return;
}
// ES8388_DACCONTROL16
ES8388_WriteReg(0x26, in + (in << 3)); // LMIXSEL, RMIXSEL
#ifdef STATUS_ENABLED
Status_ValueChangedInt("Mix In Ch", in);
#endif
}
}
void ES8388_SetIn2OoutVOL(uint8_t unused, float vol)
{
#ifdef STATUS_ENABLED
Status_ValueChangedInt("In to out volume /db", (vol - 1) * 16 + 0.5);
#endif
vol *= -5;
vol += 7;
uint8_t volu8 = vol;
if (volu8 > 7)
{
volu8 = 7;
}
uint8_t var;
var = ES8388_ReadReg(0x27) & 0xC0;
if (volu8 == 7)
{
var &= ~ 0x40;
}
else
{
var |= 0x40;
}
ES8388_WriteReg(0x27, (volu8 << 3) + var); // LD2LO, LI2LO, LI2LOVOL
var = ES8388_ReadReg(0x2A) & 0xC0;
if (volu8 == 7)
{
var &= ~ 0x40;
}
else
{
var |= 0x40;
}
ES8388_WriteReg(0x2A, (volu8 << 3) + var); // RD2RO, RI2RO, RI2ROVOL
}
void ES8388_SetOUT1VOL(uint8_t unused, float vol)
{
#ifdef STATUS_ENABLED
Status_ValueChangedInt("OUT1VOL /db", (vol - 1) * 31 + 0.5);
#endif
vol *= 0x1E;
uint8_t volu8 = vol;
if (volu8 > 129)
{
volu8 = 129;
}
ES8388_WriteReg(0x2E, volu8); // LOUT1VOL
ES8388_WriteReg(0x2F, volu8); // ROUT1VOL
}
void ES8388_SetOUT2VOL(uint8_t unused, float vol)
{
#ifdef STATUS_ENABLED
Status_ValueChangedInt("OUT2VOL /db", (vol - 1) * 31 + 0.5);
#endif
vol *= 0x1E;
uint8_t volu8 = vol;
if (volu8 > 129)
{
volu8 = 129;
}
ES8388_WriteReg(0x30, volu8); // LOUT2VOL
ES8388_WriteReg(0x31, volu8); // ROUT2VOL
}
void ES8388_Setup()
{
Serial.printf("Connect to ES8388 codec... ");
while (not ES8388_begin(ES8388_PIN_SDA, ES8388_PIN_SCL, 400000))
{
Serial.printf("Failed!\n");
delay(1000);
}
ES8388_WriteReg(ES8388_CHIPPOWER, 0xFF); //reset and stop es8388
ES8388_WriteReg(0x00, 0x80); /* reset control port register to default */
ES8388_WriteReg(0x00, 0x06); /* restore default value */
/*
* https://dl.radxa.com/rock2/docs/hw/ds/ES8388%20user%20Guide.pdf
*/
/*
* 10.5 Power Down Sequence (To Standby Mode)
*/
ES8388_WriteReg(0x0F, 0x34); /* ADC Mute */
ES8388_WriteReg(0x19, 0x36); /* DAC Mute */
ES8388_WriteReg(0x02, 0xF3); /* Power down DEM and STM */
/*
* 10.4 The sequence for Start up bypass mode
*/
/* Set Chip to Slave Mode */
ES8388_WriteReg(0x08, 0x00);
/* Power down DEM and STM */
ES8388_WriteReg(0x02, 0x3F);
/* Set same LRCK */
ES8388_WriteReg(0x2B, 0x80);
/* Set Chip to Play&Record Mode */
ES8388_WriteReg(0x00, 0x05);
/* Power Up Analog and Ibias */
ES8388_WriteReg(0x01, 0x40);
#if 0
/*
* Power down ADC, Power up
* Analog Input for Bypass
*/
ES8388_WriteReg(0x03, 0x3F);
#else
ES8388_WriteReg(0x03, 0x3F); /* adc also on but no bias */
ES8388_WriteReg(0x03, 0x00); // PdnAINL, PdinAINR, PdnADCL, PdnADCR, PdnMICB, PdnADCBiasgen, flashLP, Int1LP
#endif
#if 0
/*
* Power Down DAC, Power up
* Analog Output for Bypass
*/
ES8388_WriteReg(0x04, 0xFC);
#else
/*
* Power up DAC / Analog Output
* for Record
*/
ES8388_WriteReg(0x04, 0x3C);
#if 1
/*
* Select Analog input channel for ADC
*/
ES8388_WriteReg(0x0A, 0x80); // LINSEL , RINSEL , DSSEL , DSR
/* Select PGA Gain for ADC analog input */
ES8388_WriteReg(0x09, 0x00); // PGA gain?
//ES8388_WriteReg(0x0C, 0x18); // DATSEL, ADCLRP, ADCWL, ADCFORMAT
//ES8388_WriteReg(0x0C, 0x40); // DATSEL, ADCLRP, ADCWL, ADCFORMAT
ES8388_WriteReg(0x0C, 0x0C); // DATSEL, ADCLRP, ADCWL, ADCFORMAT
ES8388_WriteReg(0x0D, 0x02); // ADCFsMode , ADCFsRatio
//ES8388_WriteReg(0x0D, (1<<5) + 0x03); // ADCFsMode , ADCFsRatio Hasan
//ES8388_WriteReg(0x0D, 0); // ADCFsMode , ADCFsRatio Hasan
/*
* Set ADC Digital Volume
*/
#if 1
ES8388_SetADCVOL(0, 1.0f);
#else
ES8388_WriteReg(0x10, 0x00); // LADCVOL
ES8388_WriteReg(0x11, 0x00); // RADCVOL
#endif
/* UnMute ADC */
ES8388_WriteReg(0x0F, 0x30); //
ES8388_WriteReg(0x12, 0x16);
ES8388_WriteReg(0x17, 0x18); // DACLRSWAP, DACLRP, DACWL, DACFORMAT
ES8388_WriteReg(0x18, 0x02); // DACFsMode , DACFsRatio
#endif
/*
* Set ADC Digital Volume
*/
ES8388_WriteReg(0x1A, 0x00);
ES8388_WriteReg(0x1B, 0x02);
//ES8388_WriteReg(0x1B, (1<<5) + 0x03); // ADCFsMode , ADCFsRatio Hasan
//ES8388_WriteReg(0x1B, 0); // ADCFsMode , ADCFsRatio Hasan
/* UnMute DAC */
ES8388_WriteReg(0x19, 0x32);
#endif
/*
* Setup Mixer
*/
ES8388_WriteReg(0x26, 0x09);// ES8388_WriteReg(0x26, 0x00);
ES8388_WriteReg(0x27, 0xD0); // ES8388_DACCONTROL17
ES8388_WriteReg(0x28, 0x38);
ES8388_WriteReg(0x29, 0x38);
ES8388_WriteReg(0x2A, 0xD0);
/* Set Lout/Rout Volume */
#if 1
ES8388_SetOUT1VOL(0, 1);
ES8388_SetOUT2VOL(0, 1);
#else
ES8388_WriteReg(0x2E, 0x1E);
ES8388_WriteReg(0x2F, 0x1E);
ES8388_WriteReg(0x30, 0x1E);
ES8388_WriteReg(0x31, 0x1E);
#endif
/* Power up DEM and STM */
#if 0
ES8388_WriteReg(0x02, 0xF0);
#else
ES8388_WriteReg(0x02, 0x00);
#endif
ES8388_SetInputCh(1, 1);
ES8388_SetMixInCh(2, 1);
ES8388_SetPGAGain(0, 1);
ES8388_SetIn2OoutVOL(0, 0);
Serial.printf("ES8388 setup finished!\n");
es8388_read_all();
}
#endif