Closed harbaum closed 1 year ago
@me-no-dev Please help with triage, thanks
@harbaum - DAC only supports 8 bits sample per channel. This is the problem. Anyway, this is an IDF issue, not related to the Arduino Core directly.
You can try this:
// adjust the samples to 8bit ch1 + 8bit ch2
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // the DAC only uses 8 bits per channel
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // stereo
or
// adjust samples to 8bit single channel
.bits_per_sample = I2S_BITS_PER_SAMPLE_8BIT, // the DAC only uses 8 bits
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // mono
@SuGlider Thanks for the reply. I'll give this a try asap. However,
the example on this page: https://docs.espressif.com/projects/esp-idf/en/v4.3.5/esp32/api-reference/peripherals/i2s.html
includes this line
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, /* the DAC module will only take the 8bits from MSB */
This was the reason why I chose 16 bit.
Later on the page states:
I2S_MODE_DAC_BUILT_IN = 16
Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB
For some reason all these comments are gone in later ESP-IDF docs.
There's probably a directly relationship between arduino ESP32 board support versions (2.0.xx) and the ESP-IDF version (4.x/5.x).
This broke from 2.0.9 to 2.0.10. Where can I see what underlying ESP-IDF versions these two use?
Edit: 2.0.9 is based on ESP-IDF 4.4.4, 2.0.10 and 2.0.11 are based on 4.4.5
Some more investigation. The stereo version also crackles. So does only right and only left.
On the oscilloscope i see short spikes of the intended volume/voltage but not nearly as long as expected.
Interesting fact: I had left and right mixed in channel_format and set_dac_mode. That gave a sound on previous versions, while it IMHO shouldn't.
With 2.0.11 it only works with left/left or right/right. But still there's significant noise, which there isn't with 2.0.9 a and earlier. The example (now with right/right) gives a rectangle signal but with noticeable crackling noise. While the cracks are not extremely dominant in the rectangle version, they are very prominent in a real audio example.
Still, the example above produces noticeable crackling noises.
You can try this:
.bits_per_sample = I2S_BITS_PER_SAMPLE_8BIT, // the DAC only uses 8 bits .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // mono
Switching to 8 bits doesn't make a difference.
The distortions seen on the oscilloscope.
@harbaum - I've found what solves the issue.
Please use .use_apll = false
instead of true
.
I don't know exactly what has changed from the IDF 4.4 precompiled libraries used in the Arduino Core 2.0.9 to the Arduino Core 2.0.10.
It seems that it's nothing that has chaged in the Arduino Layer... maybe something changed in the IDF side. I'll try to quickly see if there is something in the IDF github that may justify this finding.
I couldn't see any change in https://github.com/espressif/esp-idf/blob/release/v4.4/components/driver/i2s.c that would justify such change. Maybe something changed in the components used to calculate and set the I2S source clock when it uses APLL.
Thanks for reporting! You may want to open an issue within IDF github to report this APLL issue.
@VojtechBartoska - You may want to report it directly to the I2S IDF team. Thanks!
Please use
.use_apll = false
instead oftrue
.
This seems to solve the issue for 24kHz and the resulting frequency in my demo sketch here is indeed, 24000/64 = 375Hz
But Galagino (https://github.com/harbaum/galagino) also uses 11765 Hz (as that's the frequency the Donkey Kong Arcade based its audio on). This should be 11765/64 = 183Hz. And with appl=true I really get a (crackling) 183 Hz signal. With apll=false I get 462 Hz which in turn would mean that the sample rate is 30kHz rather than the requested 11765 Hz.
Actually with apll=false I get totally odd frequencies with the above example just by changing the sample_rate. E.g.:
24000 results in 375Hz which indeed is a sample rate of 24000 Hz 20000 results in 312Hz which indeed is a sample rate of 20000 Hz 12000 results in 486Hz which actually is a sample rate of 31000 Hz 10000 results in 320Hz which actually is a sample rate of 20480 Hz 8000 results in 691Hz which actually is a sample rate of 44224Hz 6000 results in 1200Hz which actually is a sample rate of 76800Hz
So with apll=false the sample rates are messed up somehow ...
How is the sample_rate supposed to work with apll = false?
I got some better results with .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
instead of I2S_CHANNEL_FMT_ONLY_RIGHT
Using .use_apll = true
Example with 6,400 samples per second in a 64 samples per cycle (Hz) running OK.
static const i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
.sample_rate = 6400,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //I2S_CHANNEL_FMT_ONLY_RIGHT,
.intr_alloc_flags = 0,
.dma_buf_count = 4,
.dma_buf_len = 64, // 64 samples
.use_apll = true
};
Please also try it and let me know.
I got some better results with
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
instead ofI2S_CHANNEL_FMT_ONLY_RIGHT
Using.use_apll = true
... Please also try it and let me know.
It's indeed better, but still crackling. The rectangle wave seems to hide the distortions somewhat. They become much more prominent with real life audio or e.g. with a sine wave generated like this:
for(int i=0;i<64;i++)
snd_buffer[i] = (int)(0x8000 + 0x4000 * sin(i*M_PI/32))&0xff00;
Another interesting observation:
This should be a saw tooth:
for(int i=0;i<64;i++)
snd_buffer[i] = (i&15)<<8;
But on the scope it looks like this:
It looks correct if I swap every second byte like so:
for(int i=0;i<64;i++)
snd_buffer[i^1] = (i&15)<<8;
Arduino ESP32 version 2.0.9 was ESP-IDF 4.4.4 and 2.0.10 uses 4.4.5
So this problem may have been introduced in ESP-IDF 4.4.5
So this problem may have been introduced in ESP-IDF 4.4.5
It is very possible. I know that I2S has been completely refactored for the IDF 5.x
for(int i=0;i<64;i++) snd_buffer[i^1] = (i&15)<<8;
I have not put too much thinkning here, but we have to remember that ESP32 is little endian. The best way to set it may be with 2 bytes and a OR operation.
I'm taking a look at the changes from IDF 4.4.4 to 4.4.5. The main changes to I2S are the RX/TX channel format configuration for ESP32/ESP32-S2 and changes to the endianess when time division multiplexing is supported.
@SuGlider @harbaum Is this issue confirmed to be only on ESP32 or wasn't it tested in other SOCs ?
@SuGlider The ESP32 is imho the only variant supporting the DAC via I2S. So I don't think this can even happen on a different SoC.
I'll to some testing and report back my findings
@harbaum I reverted the I2S changes. I don't have a oscilloscope with me, could you test if the crackling still happens ? This binary uses a sample rate of 11765 with APLL enabled.
If the crackling still happens it might be related to changes in the ADC or clocking.
Thanks a lot. I'll try asap and report back.
I just found that I still have the test setup at my bench.
So yes, the binary you sent me gives a 186Hz square wave and I hear no crackling at all. On the scope, there are slight distortions, but that may be due to my rather simple setup.
Update:
2 options:
This is the IDF commit that introduced this issue: https://github.com/espressif/esp-idf/commit/73ca054b807557b4b9bbfc948343f1e344ba8069
Note that reverting this commit might break I2S microphones.
Board
ESP32 dev board
Device Description
DevKitC
Hardware Configuration
Speaker on GPIO25
Version
latest master (checkout manually)
IDE Name
Arduino IDE
Operating System
Linux and Windows
Flash frequency
40Mhz
PSRAM enabled
no
Upload speed
921000
Description
This demo sketch used to play a rectangle wave form on GPIO25 it works on 2.0.6 to 2.0.9
Since 2.0.10 sound is distorted and has a crackling noise overlaid. Oscilloscope shows short spikes in the rectangle signal.
Sketch
Debug Message
Other Steps to Reproduce
No response
I have checked existing issues, online documentation and the Troubleshooting Guide