I found some cheap AI Thinker ESP32 Audio Kit V2.2 on AliExpress and because I was tired of all the wires I had to connect to implement my different scenarios that are possible with my Arduino Audio Tools Library, I thought it to be a good idea to buy this board.

Audio Kit

I am aware that this board, like the corresponding LyraT alternatives from Espressif are mainly used with the IDF/ADF framework, but I wanted to use it with Arduino, and that’s where the problems started: First I was so naive to just deploy one of my Bluetooth A2DP Audio sketches. It was running somehow – but there was no sound! Next I tried out the SD drive – and here again – the SD drive was not available.

I am documenting here the solutions to make things work for my V2.2 3478 Board:

The SD Card

The AI board like the LyraT boards are using some unusual pin assignments and you need to initialize SPI by indicating the correct pins.
In addition you need to make sure that the DATA3 and CMD on-board switches are in the on position:

#define PIN_AUDIO_KIT_SD_CARD_CS 13
#define PIN_AUDIO_KIT_SD_CARD_MISO 2
#define PIN_AUDIO_KIT_SD_CARD_MOSI 15
#define PIN_AUDIO_KIT_SD_CARD_CLK  14

SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO, PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);

Then when you set up the SD library you need to indicate the PIN_AUDIO_KIT_SD_CARD_CS as CS pin. That was the easy one – no let’s move to the major challenge:

Output to the Speakers

The board uses a ES8388 audio chip that is connected via I2S, so we need to use the correct I2S pin assignments. Note that these are different from the LyraT ones!

#define PIN_I2S_AUDIO_KIT_MCLK 0
#define PIN_I2S_AUDIO_KIT_BCK 27
#define PIN_I2S_AUDIO_KIT_WS 25
#define PIN_I2S_AUDIO_KIT_DATA_OUT 26
#define PIN_I2S_AUDIO_KIT_DATA_IN 35

The audio chip is responsible for routing the output or input to the correct final device and controlling the volume. The ES8388 must be programmed via I2C! In order to do this I found this solution from thaaraak which inspired me to try to convert the original ADF driver from Espressif, so that it can be used in Arduino.
Here is the necessary information for the I2C connection:

#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
#define I2C_MASTER_SCL_IO 32     
#define I2C_MASTER_SDA_IO 33    
#define ES8388_ADDR 0x10

Finally, here is a link to the ES8388 user guide.

Headphone Detection

I was testing the headphone detection with the following logic:

#define HEADPHONE_DETECT 39 

bool headphoneStatus() {
  return !gpio_get_level((gpio_num_t)HEADPHONE_DETECT);
}

If no headphone is connected the gpio_get_level() returns 1 – with a headphone the output changes to 0 – so I confirm that on this board we need to use GPIO 39.

Please note that the pin must be set up to be pulled high.

Enable Power Amplifier

The power activate pin for the speakers is identical to the LyraT boards:

#define PA_ENABLE_GPIO 21

We can use this pin together with the headphone detection pin to activate/deactivate the speaker

  void processKeys() {
    LOGI(LOG_METHOD);
    static unsigned long keys_timeout = 0;
    if (keys_timeout < millis()) {
      if (cfg.is_headphone_detection) {
        LOGI("process headphone detection");
        bool isConnected = headphoneStatus();
        bool powerActive = !isConnected;
        if (powerActive != actualPower) {
          LOGW("Headphone jack has been %s",
                   isConnected ? "inserted" : "removed");
          setPAPower(powerActive);
        }
      }
      keys_timeout = millis() + KEY_RESPONSE_TIME_MS;
    }
  }

Conclusions

I have the solution working now and I can share my Audio Player Sketch that I used for my tests. It is based on my arduino-audio-tools project:

The Arduino Audio Player Sketch

#define USE_SDFAT
#define USE_HELIX
#include "AudioTools.h"
#include "AudioLibs/AudioKit.h"

const char *startFilePath="/";
const char* ext="mp3";
AudioSourceSdFat source(startFilePath, ext, PIN_AUDIO_KIT_SD_CARD_CS);
AudioKitStream kit;
MP3DecoderHelix decoder;
AudioPlayer player(source, kit, decoder);


void setup() {
  Serial.begin(115200);
  AudioLogger::instance().begin(Serial, AudioLogger::Info);

  // setup output
  auto cfg = kit.defaultConfig(TX_MODE);
  kit.begin(cfg);

  // setup player
  player.begin();
}

void loop() {
  player.copy();
  kit.processActions();
}

Yes – I just needed to replace the I2SStream with the AudioKitStream and that’s pretty cool!
If you add the kit.processActions() in the loop you get the automatic headphone detection and volume control working.

Unfortunately the output is quite distored mainly for the loud parts. We can take care of this by reducing the signal strength (volume) that we send to the kit by adjusting the volume of the player with player.setVolume(0.7);

The full example can be found on Github

Dependencies

Disclaimer

Please note that the sketches that I am posting on this site are working at the point of time of the posting. It might be that things have changed when you read this. So please use the corresponding updated example in the Audio Tools Project if you want to try it out yourself.


4 Comments

T. H. · 8. March 2022 at 22:25

I tried this with AudioKit 2.2. with ES8388, but
a) only headphone jack insertion is detected, not removal
and
b) volume is very low for headphone and speaker. I coud fix this, but only for speaker, by changing some lines in es8388.c es8388_set_voice_volume, as depicted here: https://github.com/AI-Thinker-Open/ESP32-A1S-AudioKit/issues/26

Do you have any idea how to fix headphone jack detection and headphone volume?
I read somewhere that several AudioKit variants with ES8388 exist, using different pins for I2C/I2S, did you take this into account in your code?

    pschatzmann · 9. March 2022 at 9:05

    I am not aware that different pin variants exist for the AudioKit with ES8388. However there is a variant with the AC101 which is totally different not only with the pins. As you can see in the readme of the AudioKit project, I am supporting both – but please note that depending on the functionality you want to use you might run into different pin conflicts: e.g. on the AC101 you can’t use the headphone detection if you use the SD.
    I did not hear any issues with a low volume – on the contrary for me it was too loud. But please notice that the AudiKitStream class provides it’s own methods for managing the volume: The initial value is set to 40, but you can change this by calling the setVolume() method.

    I could reproduce your issue with the headphone detection which was introduced when I extended the button handling logic.

    For further discussions please use the issues or discussions on Github.

Vladimir Kozlov · 6. January 2022 at 13:57

Hello Phil, I just tried your library for Audio Kit and it works great! By the way, do you have any information regarding on-board microphones, i.e. sensitivity, noise level, etc.? I’m thinking about measuring sound level pressure using this board, but to calculate dB values I need some data about microphones, and there are no any info for this nor in Ai-Thinker docs, nor in Google…

    pschatzmann · 10. January 2022 at 18:52

    I haven’t used the built in microphone so far.
    Please note that the driver provides the method es8388_set_mic_gain(es_mic_gain_t gain) to control the gain.

Leave a Reply

Avatar placeholder

Your email address will not be published.