How to play a sine wave sound
Posted: Fri Sep 20, 2019 7:00 pm
I'm having massive trouble playing a simple sine wave sound through I2S and the DAC. I've attached an audio amplifier and a loudspeaker to pin 25. I try to make it work with Arduino. The problems I have are around understanding the code. The samples I could find just do something but it's not what I need and I can't bring it there. The ESP documentation is very minimal and there are no examples available.
* Why can't bits_per_sample be 8 bits? It shows me an error message for the invalid value.
* What are the specifics of communication_format? What is MSB? Do I need I2S? How are the bits and bytes aligned in the buffer?
* What is dma_buf_count for?
* What length can dma_buf_len be? Can I align it with my sine wave frequency period?
The output I get is either the wrong frequency (I'm at double the programmed frequency now) or total random garbage. This all doesn't make any sense. Also I get all harmonics in the output signal, so it's not a sine wave that's playing. The sound sounds like a square wave but the osciloscope shows a stepped sine wave.
Here's parts of my code. It has grown by trying so it's not in a good shape now. I need a solution to play and stop the sound at any time, starting and stopping at output level 0 (in the range from 0 to 2, instead of -1 to 1, because I don't have negative voltage).
* Why can't bits_per_sample be 8 bits? It shows me an error message for the invalid value.
* What are the specifics of communication_format? What is MSB? Do I need I2S? How are the bits and bytes aligned in the buffer?
* What is dma_buf_count for?
* What length can dma_buf_len be? Can I align it with my sine wave frequency period?
The output I get is either the wrong frequency (I'm at double the programmed frequency now) or total random garbage. This all doesn't make any sense. Also I get all harmonics in the output signal, so it's not a sine wave that's playing. The sound sounds like a square wave but the osciloscope shows a stepped sine wave.
Here's parts of my code. It has grown by trying so it's not in a good shape now. I need a solution to play and stop the sound at any time, starting and stopping at output level 0 (in the range from 0 to 2, instead of -1 to 1, because I don't have negative voltage).
Code: Select all
#include "driver/i2s.h"
int maxPhase = 55; // Should make 800 Hz, gives 1600 Hz and all of the harmonics as well
// I2S configuration
int i2s_num = 0; // I2S port number
i2s_config_t i2s_config =
{
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = 0, // Default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = maxPhase * 4,
.use_apll = false
};
float pi2 = 6.283185;
uint8_t buffer[i2s_config.dma_buf_len];
void setup()
{
// Initialize I2S with configurations above
i2s_driver_install((i2s_port_t)i2s_num, &i2s_config, 0, NULL);
i2s_set_dac_mode(I2S_DAC_CHANNEL_RIGHT_EN); // Pin 25
int phase = maxPhase * 0.75;
while (true)
{
int i;
for (i = 0; i < maxPhase;)
{
float rad = (float)phase / maxPhase * pi2;
uint8_t sample = (sin(rad) + 1) * 30; // Full amplitude: 127
buffer[i++] = 0; // unused right channel
buffer[i++] = 0; // unused right channel
buffer[i++] = sample; // high byte?
buffer[i++] = 0; // low byte (unused)
phase++;
if (phase >= maxPhase) phase = 0;
}
size_t bytesWritten;
i2s_write((i2s_port_t)i2s_num, buffer, i2s_config.dma_buf_len * sizeof(uint8_t), &bytesWritten, 0);
}
}
void loop()
{
}