When I run this it appears that every two entries are swapped when they are output to the DAC as shown with the following oscilloscope trace from the DAC output. When I swap every other two entries (with the compiler define SWAP_WORDS) the output looks correct. What is going on? Am I doing something wrong? It is interesting to note that the output is correct if I configure I2S for two channel operation, enable both DAC outputs, and load each sample twice (one for each channel).
The code is as follows (entire IDF project attached - compiled with IDF v4.4.4)
Code: Select all
[Codebox=c file=i2s_dac.c]
#include <stdio.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "driver/i2s.h"
/* Enable to swap 16-bit words as a kludge work-around */
//#define SWAP_WORDS
/* Prepare for 32 sample values */
#define NUM_SINE_SAMPLES 32
/* Sine Wave Sample */
const int16_t sine_data_frame[NUM_SINE_SAMPLES] = {
6392, 12539, 18204, 23169, 27244, 30272, 32137, 32767, 32137,
30272, 27244, 23169, 18204, 12539, 6392, 0, -6393, -12540,
-18205, -23170, -27245, -30273, -32138, -32767, -32138, -30273, -27245,
-23170, -18205, -12540, -6393, -1,
};
esp_err_t app_main(void)
{
int16_t i2s_write_buf[512];
size_t bytes_to_write;
size_t bytes_written;
size_t samples_to_write;
// configure i2s
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
.sample_rate = 16000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.intr_alloc_flags = 0,
.dma_buf_count = 2,
.dma_buf_len = 512,
.use_apll = 1,
.tx_desc_auto_clear = 0,
};
// install and start i2s driver
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
// init DAC pad
i2s_set_dac_mode(I2S_DAC_CHANNEL_RIGHT_EN); // RIGHT is DAC 1: GPIO25, LEFT is DAC 2: GPIO26
// Load the sine wave into the buffer
samples_to_write = 8 * NUM_SINE_SAMPLES;
bytes_to_write = 2 * samples_to_write;
#ifdef SWAP_WORDS
for (int i=0; i<samples_to_write; i+=2) {
// Swap every 2 entries in the sine table when writing to the i2s buffer
// WHY DOES THIS WORK???
i2s_write_buf[i] = sine_data_frame[(i+1) % NUM_SINE_SAMPLES] + 0x8000;
i2s_write_buf[i+1] = sine_data_frame[i % NUM_SINE_SAMPLES] + 0x8000;
}
#else
for (int i=0; i<samples_to_write; i++) {
// Offset signed value by 0x8000 to make unsigned for single-ended DAC output
i2s_write_buf[i] = sine_data_frame[i % NUM_SINE_SAMPLES] + 0x8000;
}
#endif
// Output the buffer forever
while (1) {
i2s_write(I2S_NUM_0, i2s_write_buf, bytes_to_write, &bytes_written, portMAX_DELAY);
if (bytes_written != bytes_to_write) {
printf("tried to write %d, actually wrote %d", bytes_to_write, bytes_written);
}
}
return ESP_OK;
}
[/Codebox]