i2s: Introduced a brand new driver

This commit is contained in:
laokaiyao
2021-08-18 19:45:51 +08:00
parent e8d172eb87
commit 621d0aa942
71 changed files with 4934 additions and 1549 deletions

View File

@@ -1,18 +1,16 @@
/* I2S Example
This example code will output 100Hz sine wave and triangle wave to 2-channel of I2S driver
Every 5 seconds, it will change bits_per_sample [16, 24, 32] for i2s data
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* I2S Example
* This example code will output 100Hz sine wave and triangle wave to 2-channel of I2S driver
* Every 5 seconds, it will change bits_per_sample [16, 24, 32] for i2s data
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s.h"
#include "driver/i2s_controller.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "esp_log.h"
@@ -30,27 +28,31 @@
#define SAMPLE_PER_CYCLE (SAMPLE_RATE/WAVE_FREQ_HZ)
static const char* TAG = "i2s_example";
static const char *TAG = "i2s_example";
static i2s_chan_handle_t tx_handle = NULL;
static void setup_triangle_sine_waves(int bits)
{
int *samples_data = malloc(((bits+8)/16)*SAMPLE_PER_CYCLE*4);
int *samples_data = malloc(((bits + 8) / 16) * SAMPLE_PER_CYCLE * 4);
unsigned int i, sample_val;
double sin_float, triangle_float, triangle_step = (double) pow(2, bits) / SAMPLE_PER_CYCLE;
size_t i2s_bytes_write = 0;
static i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
static i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
printf("\r\nTest bits=%d free mem=%d, written data=%d\n", bits, esp_get_free_heap_size(), ((bits+8)/16)*SAMPLE_PER_CYCLE*4);
printf("\r\nTest bits=%d free mem=%d, written data=%d\n", bits, esp_get_free_heap_size(), ((bits + 8) / 16)*SAMPLE_PER_CYCLE * 4);
triangle_float = -(pow(2, bits)/2 - 1);
triangle_float = -(pow(2, bits) / 2 - 1);
for(i = 0; i < SAMPLE_PER_CYCLE; i++) {
for (i = 0; i < SAMPLE_PER_CYCLE; i++) {
sin_float = sin(i * 2 * PI / SAMPLE_PER_CYCLE);
if(sin_float >= 0)
if (sin_float >= 0) {
triangle_float += triangle_step;
else
} else {
triangle_float -= triangle_step;
}
sin_float *= (pow(2, bits)/2 - 1);
sin_float *= (pow(2, bits) / 2 - 1);
if (bits == 16) {
sample_val = 0;
@@ -59,26 +61,34 @@ static void setup_triangle_sine_waves(int bits)
sample_val += (short) sin_float;
samples_data[i] = sample_val;
} else if (bits == 24) { //1-bytes unused
samples_data[i*2] = ((int) triangle_float) << 8;
samples_data[i*2 + 1] = ((int) sin_float) << 8;
samples_data[i * 2] = ((int) triangle_float) << 8;
samples_data[i * 2 + 1] = ((int) sin_float) << 8;
} else {
samples_data[i*2] = ((int) triangle_float);
samples_data[i*2 + 1] = ((int) sin_float);
samples_data[i * 2] = ((int) triangle_float);
samples_data[i * 2 + 1] = ((int) sin_float);
}
}
ESP_LOGI(TAG, "set clock");
i2s_set_clk(I2S_NUM, SAMPLE_RATE, bits, 2);
//Using push
// for(i = 0; i < SAMPLE_PER_CYCLE; i++) {
// if (bits == 16)
// i2s_push_sample(0, &samples_data[i], 100);
// else
// i2s_push_sample(0, &samples_data[i*2], 100);
// }
// or write
ESP_LOGI(TAG, "set data bit width to %d", bits);
/* Updata clock and slot information */
slot_cfg.data_bit_width = bits;
i2s_stop_channel(tx_handle);
i2s_set_slot(tx_handle, &slot_cfg);
if (bits == 24) {
/**
* Because '24' has factor '3'
* The mclk multiple must be able to divide by '3' as well
* Otherwise the sample rate won't be accurate */
clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_384;
i2s_set_clock(tx_handle, &clk_cfg);
} else {
clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_256;
i2s_set_clock(tx_handle, &clk_cfg);
}
i2s_start_channel(tx_handle);
ESP_LOGI(TAG, "write data");
i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100);
i2s_write_channel(tx_handle, samples_data, ((bits + 8) / 16)*SAMPLE_PER_CYCLE * 4, &i2s_bytes_write, 100);
free(samples_data);
}
@@ -90,35 +100,32 @@ void app_main(void)
//using 6 buffers, we need 60-samples per buffer
//if 2-channels, 16-bit each channel, total buffer is 360*4 = 1440 bytes
//if 2-channels, 24/32-bit each channel, total buffer is 360*8 = 2880 bytes
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.dma_desc_num = 6,
.dma_frame_num = 60,
.use_apll = false,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1
i2s_gpio_config_t i2s_pin = {
.mclk = I2S_GPIO_UNUSED,
.bclk = I2S_BCK_IO,
.ws = I2S_WS_IO,
.dout = I2S_DO_IO,
.din = I2S_DI_IO
};
i2s_pin_config_t pin_config = {
.mck_io_num = I2S_PIN_NO_CHANGE,
.bck_io_num = I2S_BCK_IO,
.ws_io_num = I2S_WS_IO,
.data_out_num = I2S_DO_IO,
.data_in_num = I2S_DI_IO //Not used
};
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM, &pin_config);
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
chan_cfg.id = I2S_NUM;
i2s_new_channel(&chan_cfg, &tx_handle, NULL);
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
#if SOC_I2S_SUPPORTS_APLL
// APLL clock is more accurate when sample rate is high
clk_cfg.clk_src = I2S_CLK_APLL;
#endif
i2s_init_channel(tx_handle, &clk_cfg, &slot_cfg);
i2s_start_channel(tx_handle);
int test_bits = 16;
while (1) {
setup_triangle_sine_waves(test_bits);
vTaskDelay(5000/portTICK_PERIOD_MS);
vTaskDelay(pdMS_TO_TICKS(5000));
test_bits += 8;
if(test_bits > 32)
if (test_bits > 32) {
test_bits = 16;
}
}
}