Hi you all,
I’ve tried to compile various C++ examples for my muse proto but it seems those which interest me, like the bluetooth speaker one, do not compile any longer (last change to the repo: ~3 years ago). That or I’m just bad at it.
So I decided to start from scratch using the esp-idf library, using PlatformIO in vscode (using esp-wrover-kit as a board, because I’ve seen a bunch of projects doing that too).
So far all I’d like is to get some sound, whatever sound, out of that board.
Here is my source file, can you spot anything wrong?
There are no compile errors nor runtime errors… And everything seems to proceed smoothly: audio buffers are written one after the other, it’s quick… I’ve tried a bunch of different pins too, with no luck there either.
Your help would be immensely appreciated, thanks in advance for any tips you may be able to provide!
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include <math.h>
#include <vector>
#include <sstream>
#define I2S_BCLK GPIO_NUM_5
#define I2S_LRC GPIO_NUM_25
#define I2S_DOUT GPIO_NUM_26
#define I2S_DIN GPIO_NUM_35
#define BUF_SIZE 64
/** This is necessary for the linker to find the firmware's entry point */
extern "C" {
void app_main(void);
}
#define SAMPLE_RATE (44100)
#define PI (3.14159265)
i2s_chan_handle_t tx_handle;
typedef std::vector<int16_t> VectorBuffer;
VectorBuffer generate_sine_wave(
float sample_rate_Hz,
float duration_s = 1.0f,
float frequency = 440.0f,
float amplitude = 1.0f
) {
const auto samples_count = (int)(sample_rate_Hz * duration_s);
VectorBuffer buffer(samples_count);
for (int i = 0; i < samples_count - 1; i++) {
const auto sample = (int16_t)(amplitude * INT16_MAX * sin((2 * PI * i * frequency) / sample_rate_Hz));
buffer.at(i) = sample;
}
return buffer;
}
// Should play a F note for 0.1 second every second
void i2s_task(void *pvParameter) {
while (1) {
auto buffer = generate_sine_wave(
SAMPLE_RATE,
0.1f,
440.0f,
1.0f
);
ESP_LOGI("I2S_TASK", "Playing sine wave of %d samples", buffer.size());
size_t bytes_written;
for (;;) {
if (buffer.empty()) {
ESP_LOGD("I2S_TASK", "Buffer is empty, good.");
break;
}
esp_err_t e = i2s_channel_write(tx_handle, buffer.data(), buffer.size() * sizeof(int16_t), &bytes_written, portMAX_DELAY);
if (e != ESP_OK) {
ESP_LOGE("I2S_TASK", "Error writing to I2S: %d", e);
break;
}
if (bytes_written == 0) {
// this should not happen
ESP_LOGE("I2S_TASK", "No bytes written");
break;
}
ESP_LOGI("I2S_TASK", "Wrote %d bytes", bytes_written);
buffer.erase(buffer.begin(), buffer.begin() + bytes_written / sizeof(int16_t));
};
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void hello_task(void *pvParameter) {
while (1) {
ESP_LOGI("HELLO_TASK", "hello");
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}
void app_main() {
// UART configuration
const uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
// rx_flow_ctrl_thresh is irrelevant in our case because we have
// flow_ctrl set to UART_HW_FLOWCTRL_DISABLE, whatever that means
.rx_flow_ctrl_thresh = 122,
.source_clk = UART_SCLK_APB,
.flags = UART_MODE_UART,
};
uart_param_config(UART_NUM_0, &uart_config);
uart_driver_install(UART_NUM_0, 1024 * 2, 0, 0, NULL, 0);
// I2S configuration
i2s_std_config_t std_config = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
.slot_cfg = I2S_STD_PCM_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED,
.bclk = I2S_BCLK,
.ws = I2S_LRC,
.dout = I2S_DOUT,
.din = I2S_DIN,
.invert_flags = {
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
}
},
};
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
i2s_new_channel(&chan_cfg, &tx_handle, NULL);
i2s_channel_init_std_mode(tx_handle, &std_config);
i2s_channel_enable(tx_handle);
// Create the hello_task
xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL);
// Create the i2s_task
xTaskCreate(&i2s_task, "i2s_task", 2048, NULL, 5, NULL);
}
EDIT: grammar, code excerpt cleanup