Page 1 of 1

Audio I2S ADC

Posted: Mon May 27, 2019 11:19 pm
by Zoptune
Hello,

I'm working on a project with an ESP32 involving audio input and frequency analysis.
I would like to use an external I2S ADC to have a good quality (at least 16bits @ 96khz).

Is this one (https://fr.aliexpress.com/item/32989916894.html) compatible with the ESP32 or do you see any constraint or possible issue ?
Do you have an other affordable product to advise me ?

And more generally do you have any advise for a project like this ?

Thanks

Edit : Here is the documentation I found : https://www.akm.com/akm/en/file/datasheet/AK5720VT.pdf

Re: Audio I2S ADC

Posted: Wed Aug 07, 2019 8:05 pm
by Delphium
Hello Zoptube

It IS compatible... IF configured correctly....

I have purchased this board last month and have been wrapping my head over the lack of documentation other than the AK5720VT chipset PDF, which declares that the device can be configured in a number of ways with different data formats.


[ADC - Identify Operational Modes]
After a few nights of trial and error, very much mostly error, I hooked up a digital scope to the ADC directly without the ESP32 to discover that all the clock pins were active on the ADC.
This indicates that the ADC board is working in I2S 'master' mode, and the ESP32 will need to be configured as a I2S Slave device.

With the scope hooked up, I can see clearly also that the format of the data is in 'I2S Compatible' data format and NOT the MSB Justified format.

According to Page 16 - Table 2 of the AK5720VT chipset documentation it appears that the ADC board has the chip configured to operate in 'Mode 3'.


[ADC - Test Clocks]
The ADC board has an on-board 24.576Mhz master clock, which drives the LRCK at 96Khz.
The on-board clock is connected to the MRCLK via a jumper header.
It is possible to remove the jumper header and insert an alternative clock to the MRCLK pin so that the LRCK will clock at 48Khz, 44.1Khz and 32Khz by using 12.288Mhz, 11.289Mhz or 8.192Mhz clock signals respectively.

I was able to verify this works using the signal generator built in my scope to produce the 12.288, 11.289 and 8.192Mhz clock frequencies and connect to the MRCLK of the ADC.


[ESP32 - I2S Setup]
After discovering that the ADC board outputs its own BICK and LRCK clock signals, the ESP32 must be configured in I2S Slave mode.
I use the following I2S configuration to connect to the device.

Code: Select all

 const i2s_config_t i2s_config = {
      .mode = i2s_mode_t(I2S_MODE_SLAVE | I2S_MODE_RX), // Receive, not transfer
      .sample_rate = SAMPLING_FREQUENCY,                        
      .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // The ADC outputs a 24bit number, but is padded inside a 32bit block.
      .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // output of ADC alternates L/R signals depending on when the LRCK is high/low.
      .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S), //ADC uses I2S compatible mode.
      .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,     // Interrupt level 1
      .dma_buf_count = 4,                           // number of buffers
      .dma_buf_len = 256                              // 8 samples per buffer (minimum)
  };


int sample;
void loop() {
   i2s_pop_sample(I2S_PORT, (char *)&sample, portMAX_DELAY);
   Serial.println(sample);
}

[ESP/ADC Sample Rates]
During my testing I found that reading the ADC at the 96Khz sample rate often lead to bits being shifted left or right which would cause massive spikes seen clearly viewed in a serial plotter.

I tried to write some code to check the bits on the input and shift then left or right accordingly to bring the signal back inline, this worked to some degree but I am not happy to rely on it for my audio/FFT needs.

I found that the reliability of the data captured increased as a lower sampling rate was used.
I found that this can work most reliably at 44.1Khz or less sample rates.

I have not yet determined why it is so unreliable at the 96Khz sample rate, the signal from the ADC looks very clean when viewed on the scope, I suspect that there could be some timing issue with the ESP32 accurately capturing the data, but this is only a suspicion at this time.

[ESP32 - High Frequency PWM]
Naturally I would rather not use a scope or other dedicated device to generate the MRCLK signal when not using the ADC built in clock of 24.576Mhz.
Ideally we want the ESP32 to create this high speed PWM for us!

Using the ledC.h driver library for the ESP32, it is possible to configure a high speed PWM output which may be used to drive the MRCLK at 12.288Mhz etc (SAMPLING_FREQUENCY*256).

Code: Select all

#include <driver/ledc.h>

int PWMPin = 14; 
int PWMChannel = 0;

int freq = SAMPLING_FREQUENCY*256;  //SAMPLING_FREQUENCY = 44100

//res bit depth examples:
// res = 1 / duty = 0,1 (0%, 50%)
// res = 2 / duty = 0,1,2,3 (0%, 25%, 50%, 75%)
// res = 3 / duty = 0,1,2,3,4,5,6,7
// res = 4 / duty = 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

int resolution = 1; //resolution in bits
int dutyCycle = 1; //value when using bits from resolution

void Setup_PWM(){
  // configure PWM 
  ledcSetup(PWMChannel, freq, resolution);
  
  // attach pin to be controlled
  ledcAttachPin(PWMPin, PWMChannel);

  //write PWM to output pin.
  ledcWrite(PWMChannel, dutyCycle);
}
I hope this helps.

Re: Audio I2S ADC

Posted: Thu Aug 08, 2019 8:29 am
by Delphium
While waiting for my first post to get approved, I realised I forgot something and cant currently edit it.

When the data is received from the ADC, the 24bits of data is aligned to the left of the 32bit block.
Example:- 1111 1111 1111 1111 1111 1111 0000 0000
To drop the 8 zeros at the end, I simply bitshift my values with
sample = sample >> 8; //shift the bits 8 places to the right.

The result will be 0000 0000 1111 1111 1111 1111 1111 1111.