Closed ifrew closed 2 years ago
@ifrew
Internal DAC sample is 8 bits. https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html#configuring-i2s-to-use-internal-dac-for-analog-output
The wave samples generated in the presented sketch are based on 32 bits amplitude, thus the DAC will output ZEROs most of the time.
Try out this example that generates a sine wave form using internal DAC. It'd be very easy to adapt it to an Arduino Sketch: https://github.com/infrasonicaudio/esp32-i2s-synth-example/blob/main/main/i2s_example_main.c
There is no issue with Arduino or IDF...
This is the Arduino sketch, converted from the previous IDF APP that outputs a Sine Stereo in the DAC:
/* I2S Synthesis example
This example code will output a sine wave of arbitrary frequency WAVE_FREQ_HZ
(default 235 Hz) at 44100 Hz sample rate to the internal 8-bit DAC channels of
the ESP32.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "driver/i2s.h"
#define SAMPLE_RATE (44100)
#define DMA_BUF_LEN (32)
#define DMA_NUM_BUF (2)
#define I2S_NUM ((i2s_port_t)(0))
#define WAVE_FREQ_HZ (235.0f)
#define TWOPI (6.28318531f)
#define PHASE_INC (TWOPI * WAVE_FREQ_HZ / SAMPLE_RATE)
// Accumulated phase
static float p = 0.0f;
// Output buffer (2ch interleaved)
static uint16_t out_buf[DMA_BUF_LEN * 2];
// Fill the output buffer and write to I2S DMA
static void write_buffer()
{
float samp = 0.0f;
size_t bytes_written;
for (int i=0; i < DMA_BUF_LEN; i++) {
// Scale sine sample to 0-1 for internal DAC
// (can't output negative voltage)
samp = (sinf(p) + 1.0f) * 0.5f;
// Increment and wrap phase
p += PHASE_INC;
if (p >= TWOPI)
p -= TWOPI;
// Scale to 8-bit integer range
samp *= 255.0f;
// Shift to MSB of 16-bit int for internal DAC
out_buf[i*2] = out_buf[i*2+1] = (uint16_t)samp << 8;
}
// Write with max delay. We want to push buffers as fast as we
// can into DMA memory. If DMA memory isn't transmitted yet this
// will yield the task until the interrupt fires when DMA buffer has
// space again. If we aren't keeping up with the real-time deadline,
// audio will glitch and the task will completely consume the CPU,
// not allowing any task switching interrupts to be processed.
i2s_write(I2S_NUM, out_buf, sizeof(out_buf), &bytes_written, portMAX_DELAY);
}
void setup(void)
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2,
.dma_buf_count = DMA_NUM_BUF,
.dma_buf_len = DMA_BUF_LEN,
.use_apll = false
};
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM, NULL); // Internal DAC
}
void loop()
{
write_buffer();
}
The sketch above outputs 8bits + 8bits (stereo with 16bits per sample) in the pins 25 and 26 (DAC Pins) of the ESP32. There is no output to the I2S pins...
Interesting. Looking at the implementation of i2s, it can take up to 32 bits. I was sure the underlying implementation would take care of handling the transfer to the 8 bits DAC. However, You were right about the sketch being wrong. Looking at the sine wave example you gave from IDF, when I changed the communication format to I2S_COMM_FORMAT_STAND_MSB from I2S_COMM_FORMAT_I2S the sketch I provide with 32bit Amplitude works now.
I will close this out. Thanks for the info!
I can confirm this is still broken in Arduino 2.0.4, IDF 4.4.1
Here is the sketch I used. If I change from internal DAC to PDM it works although really noisy.
Originally posted by @ifrew in https://github.com/espressif/arduino-esp32/issues/5938#issuecomment-1152838615