Page 1 of 1

I2S sample rate not acting logically

Posted: Sun Feb 20, 2022 4:54 pm
by michaelk
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...

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);
    }
}

Re: I2S sample rate not acting logically

Posted: Thu Mar 31, 2022 2:52 am
by cmiller9
I am having the exact same issue. I can see no logical pattern to the actual vs requested sample rates. Most confusing.