I2S sample rate not acting logically
Posted: Sun Feb 20, 2022 4:54 pm
I am attempting to generate low frequency sine waves using the I2S system and the internal DAC of the ESP32 (on ESP32-WROOM).
There are 100 samples of the sine wave in ROM that are sent to the DAC through the I2C DMA system.
The sample rate is 100 times the frequency (because there are 100 samples per cycle); however, the output frequency from GPIO25 is quite different from what is expected.
At reasonable sample rates I get frequencies from 4 to more than 20 times the expected and at very high rates (100K and above), twice the expected. What is going on here?
With the code below I see this...
There are 100 samples of the sine wave in ROM that are sent to the DAC through the I2C DMA system.
The sample rate is 100 times the frequency (because there are 100 samples per cycle); however, the output frequency from GPIO25 is quite different from what is expected.
At reasonable sample rates I get frequencies from 4 to more than 20 times the expected and at very high rates (100K and above), twice the expected. What is going on here?
With the code below I see this...
Code: Select all
expected sample rate actual
80 Hz 8000 sps 2040 Hz
100 Hz 10000 sps 1920 Hz
441 Hz 44100 sps 2020 Hz
500 Hz 50000 sps 2780 Hz
750 Hz 75000 sps 37700 Hz
1000 Hz 100000 sps 2000 Hz
2000 Hz 200000 sps 4000 Hz
4000 Hz 400000 sps 8000 Hz
8000 Hz 800000 sps 16000 Hz
Code: Select all
#include "freertos/FreeRTOS.h"
#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "driver/dac.h"
#include "driver/i2s.h"
#include <math.h>
#define AMP_DAC 255
#define I2S_NUM (i2s_port_t)0
#define NOofSAMPLESperSINE 100
/* Generated with ...
for( int i=0; i < NOofSAMPLESperSINE; i++ ) {
// sinewave peak 0xFF00FF00 to negative peak 0x00000000 - zero is 0x80008000
uint32_t usample = ((uint32_t)((sin( 2.0 * M_PI * ((double)i / NOofSAMPLESperSINE)) + 1.0) * AMP_DAC/2 + 0.5)) << 8;
sineBuffer[ i ] = (usample << 16) | usample;
}
*/
const uint32_t sineBuffer[ NOofSAMPLESperSINE ] = {
0x80008000, 0x88008800, 0x8f008f00, 0x97009700, 0x9f009f00, 0xa700a700, 0xae00ae00, 0xb600b600, 0xbd00bd00, 0xc400c400,
0xca00ca00, 0xd100d100, 0xd700d700, 0xdc00dc00, 0xe200e200, 0xe700e700, 0xeb00eb00, 0xef00ef00, 0xf300f300, 0xf600f600,
0xf900f900, 0xfb00fb00, 0xfd00fd00, 0xfe00fe00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xfe00fe00, 0xfd00fd00, 0xfb00fb00,
0xf900f900, 0xf600f600, 0xf300f300, 0xef00ef00, 0xeb00eb00, 0xe700e700, 0xe200e200, 0xdc00dc00, 0xd700d700, 0xd100d100,
0xca00ca00, 0xc400c400, 0xbd00bd00, 0xb600b600, 0xae00ae00, 0xa700a700, 0x9f009f00, 0x97009700, 0x8f008f00, 0x88008800,
0x80008000, 0x77007700, 0x70007000, 0x68006800, 0x60006000, 0x58005800, 0x51005100, 0x49004900, 0x42004200, 0x3b003b00,
0x35003500, 0x2e002e00, 0x28002800, 0x23002300, 0x1d001d00, 0x18001800, 0x14001400, 0x10001000, 0x0c000c00, 0x09000900,
0x06000600, 0x04000400, 0x02000200, 0x01000100, 0x00000000, 0x00000000, 0x00000000, 0x01000100, 0x02000200, 0x04000400,
0x06000600, 0x09000900, 0x0c000c00, 0x10001000, 0x14001400, 0x18001800, 0x1d001d00, 0x23002300, 0x28002800, 0x2e002e00,
0x35003500, 0x3b003b00, 0x42004200, 0x49004900, 0x51005100, 0x58005800, 0x60006000, 0x68006800, 0x70007000, 0x77007700
};
//Configuration for the I2S bus
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), //Mode
.sample_rate = 100000, //Sampling rate updated separately below
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // the DAC uses only top 8 bits of the MSB
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // Channel format ESP32 supports stereo only
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB, //Standard format for I2S
.intr_alloc_flags = 0, // Standard Interrupt
.dma_buf_count = 2, // Number of FIFO buffers
.dma_frame_num = 100, // Size of FIFO buffers
.use_apll = false
};
void taskFill(void *pvParameter)
{
size_t bytesWritten;
do {
i2s_write((i2s_port_t)0, (const char *)sineBuffer, NOofSAMPLESperSINE * sizeof(uint32_t), &bytesWritten, 100);
} while (true);
}
esp_err_t event_handler(void *ctx, system_event_t *event)
{
return ESP_OK;
}
void app_main(void)
{
nvs_flash_init();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
#define FREQUENCY 80
i2s_config.sample_rate = (uint32_t)round( (double)FREQUENCY * (double)NOofSAMPLESperSINE );
printf( "Sample rate: %d\t Expected freq: %d Hz\n", i2s_config.sample_rate, FREQUENCY);
ESP_ERROR_CHECK( i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL) );
ESP_ERROR_CHECK( i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN) );
TaskHandle_t xHandle;
xTaskCreate(taskFill, "fillBuffer", 1024*3, NULL, 10, &xHandle);
gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT);
int level = 0;
while (true) {
gpio_set_level(GPIO_NUM_2, level & 0x01);
level = !level;
vTaskDelay(300 / portTICK_PERIOD_MS);
}
}