mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
fix i2s mix result and error code
This commit is contained in:
parent
489e98cfb7
commit
bf4184a049
@ -119,16 +119,16 @@ static esp_err_t i2s_reset_fifo(i2s_port_t i2s_num)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
inline static void gpio_matrix_out_check(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv)
|
||||
inline static void gpio_matrix_out_check(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv)
|
||||
{
|
||||
//if pin = -1, do not need to configure
|
||||
if (gpio != -1) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(gpio, GPIO_MODE_DEF_OUTPUT);
|
||||
gpio_matrix_out(gpio, signal_idx, out_inv, oen_inv);
|
||||
}
|
||||
}
|
||||
inline static void gpio_matrix_in_check(uint32_t gpio, uint32_t signal_idx, bool inv)
|
||||
}
|
||||
}
|
||||
inline static void gpio_matrix_in_check(uint32_t gpio, uint32_t signal_idx, bool inv)
|
||||
{
|
||||
if (gpio != -1) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
@ -208,24 +208,24 @@ static float i2s_get_apll_real_rate(int bits_per_sample, int sdm0, int sdm1, int
|
||||
/**
|
||||
* @brief APLL calculate function, was described by following:
|
||||
* APLL Output frequency is given by the formula:
|
||||
*
|
||||
*
|
||||
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
|
||||
* apll_freq = fout / ((o_div + 2) * 2)
|
||||
*
|
||||
*
|
||||
* The dividend in this expression should be in the range of 240 - 600 MHz.
|
||||
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
|
||||
* * sdm0 frequency adjustment parameter, 0..255
|
||||
* * sdm1 frequency adjustment parameter, 0..255
|
||||
* * sdm2 frequency adjustment parameter, 0..63
|
||||
* * o_div frequency divider, 0..31
|
||||
*
|
||||
* The most accurate way to find the sdm0..2 and odir parameters is to loop through them all,
|
||||
* then apply the above formula, finding the closest frequency to the desired one.
|
||||
*
|
||||
* The most accurate way to find the sdm0..2 and odir parameters is to loop through them all,
|
||||
* then apply the above formula, finding the closest frequency to the desired one.
|
||||
* But 256*256*64*32 = 134.217.728 loops are too slow with ESP32
|
||||
* 1. We will choose the parameters with the highest level of change,
|
||||
* With 350MHz<fout<500MHz, we limit the sdm2 from 4 to 9,
|
||||
* With 350MHz<fout<500MHz, we limit the sdm2 from 4 to 9,
|
||||
* Take average frequency close to the desired frequency, and select sdm2
|
||||
* 2. Next, we look for sequences of less influential and more detailed parameters,
|
||||
* 2. Next, we look for sequences of less influential and more detailed parameters,
|
||||
* also by taking the average of the largest and smallest frequencies closer to the desired frequency.
|
||||
* 3. And finally, loop through all the most detailed of the parameters, finding the best desired frequency
|
||||
*
|
||||
@ -236,7 +236,7 @@ static float i2s_get_apll_real_rate(int bits_per_sample, int sdm0, int sdm1, int
|
||||
* @param[out] sdm2 The sdm 2
|
||||
* @param[out] odir The odir
|
||||
*
|
||||
* @return ESP_FAIL or ESP_OK
|
||||
* @return ESP_ERR_INVALID_ARG or ESP_OK
|
||||
*/
|
||||
static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, int *sdm1, int *sdm2, int *odir)
|
||||
{
|
||||
@ -303,7 +303,7 @@ static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, in
|
||||
*sdm0 = _sdm0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -325,7 +325,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||
|
||||
if (p_i2s_obj[i2s_num] == NULL) {
|
||||
ESP_LOGE(I2S_TAG, "Not initialized yet");
|
||||
return ESP_FAIL;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
double clkmdiv = (double)I2S_BASE_CLK / (rate * factor);
|
||||
@ -401,7 +401,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
|
||||
|
||||
save_rx = p_i2s_obj[i2s_num]->rx;
|
||||
|
||||
|
||||
p_i2s_obj[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len);
|
||||
if (p_i2s_obj[i2s_num]->rx == NULL){
|
||||
ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer");
|
||||
@ -416,7 +416,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||
i2s_destroy_dma_queue(i2s_num, save_rx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
double mclk;
|
||||
@ -475,10 +475,10 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||
ESP_LOGI(I2S_TAG, "PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
|
||||
rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals);
|
||||
}
|
||||
|
||||
|
||||
I2S[i2s_num]->sample_rate_conf.tx_bits_mod = bits;
|
||||
I2S[i2s_num]->sample_rate_conf.rx_bits_mod = bits;
|
||||
|
||||
|
||||
// wait all writing on-going finish
|
||||
if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) {
|
||||
xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux);
|
||||
@ -556,21 +556,26 @@ static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma)
|
||||
int bux_idx;
|
||||
if (p_i2s_obj[i2s_num] == NULL) {
|
||||
ESP_LOGE(I2S_TAG, "Not initialized yet");
|
||||
return ESP_FAIL;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (dma == NULL) {
|
||||
return ESP_FAIL;
|
||||
ESP_LOGE(I2S_TAG, "dma is NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
for (bux_idx = 0; bux_idx < p_i2s_obj[i2s_num]->dma_buf_count; bux_idx++) {
|
||||
if (dma->desc && dma->desc[bux_idx])
|
||||
if (dma->desc && dma->desc[bux_idx]) {
|
||||
free(dma->desc[bux_idx]);
|
||||
if (dma->buf && dma->buf[bux_idx])
|
||||
}
|
||||
if (dma->buf && dma->buf[bux_idx]) {
|
||||
free(dma->buf[bux_idx]);
|
||||
}
|
||||
}
|
||||
if (dma->buf)
|
||||
if (dma->buf) {
|
||||
free(dma->buf);
|
||||
if (dma->desc)
|
||||
}
|
||||
if (dma->desc) {
|
||||
free(dma->desc);
|
||||
}
|
||||
vQueueDelete(dma->queue);
|
||||
vSemaphoreDelete(dma->mux);
|
||||
free(dma);
|
||||
@ -922,7 +927,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
|
||||
I2S[i2s_num]->conf.rx_right_first = 0;
|
||||
I2S[i2s_num]->conf.rx_slave_mod = 0; // Master
|
||||
I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1;
|
||||
|
||||
|
||||
if (i2s_config->mode & I2S_MODE_SLAVE) {
|
||||
I2S[i2s_num]->conf.rx_slave_mod = 1;//RX Slave
|
||||
}
|
||||
@ -1115,12 +1120,25 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
|
||||
}
|
||||
|
||||
int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait)
|
||||
{
|
||||
int bytes_written = 0;
|
||||
int res = 0;
|
||||
res = i2s_write(i2s_num, src, size, &bytes_written, ticks_to_wait);
|
||||
if (res != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
return bytes_written;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t i2s_write(i2s_port_t i2s_num, const char *src, size_t size, int *bytes_written, TickType_t ticks_to_wait)
|
||||
{
|
||||
char *data_ptr;
|
||||
int bytes_can_write, bytes_writen = 0;
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
|
||||
I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_FAIL);
|
||||
I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_FAIL);
|
||||
int bytes_can_write;
|
||||
*bytes_written = 0;
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||
I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG);
|
||||
I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG);
|
||||
xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY);
|
||||
while (size > 0) {
|
||||
if (p_i2s_obj[i2s_num]->tx->rw_pos == p_i2s_obj[i2s_num]->tx->buf_size || p_i2s_obj[i2s_num]->tx->curr_ptr == NULL) {
|
||||
@ -1140,40 +1158,43 @@ int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t
|
||||
size -= bytes_can_write;
|
||||
src += bytes_can_write;
|
||||
p_i2s_obj[i2s_num]->tx->rw_pos += bytes_can_write;
|
||||
bytes_writen += bytes_can_write;
|
||||
(*bytes_written) += bytes_can_write;
|
||||
}
|
||||
xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux);
|
||||
return bytes_writen;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
int i2s_write_expand(i2s_port_t i2s_num, const char *src, int size, int src_bits, int aim_bits, TickType_t ticks_to_wait)
|
||||
esp_err_t i2s_write_expand(i2s_port_t i2s_num, const char *src, int size, int src_bits, int aim_bits, int *bytes_written, TickType_t ticks_to_wait)
|
||||
{
|
||||
char *data_ptr;
|
||||
int bytes_can_write, bytes_writen = 0, tail;
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
|
||||
I2S_CHECK((size > 0), "size must greater than zero", ESP_FAIL);
|
||||
I2S_CHECK((aim_bits * size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_FAIL);
|
||||
I2S_CHECK((aim_bits >= src_bits), "aim_bits musn't less than src_bits", ESP_FAIL);
|
||||
I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_FAIL);
|
||||
int bytes_can_write, tail;
|
||||
int src_bytes, aim_bytes, zero_bytes;
|
||||
*bytes_written = 0;
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||
I2S_CHECK((size > 0), "size must greater than zero", ESP_ERR_INVALID_ARG);
|
||||
I2S_CHECK((aim_bits * size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG);
|
||||
I2S_CHECK((aim_bits >= src_bits), "aim_bits musn't less than src_bits", ESP_ERR_INVALID_ARG);
|
||||
I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG);
|
||||
if (src_bits < I2S_BITS_PER_SAMPLE_8BIT || aim_bits < I2S_BITS_PER_SAMPLE_8BIT) {
|
||||
ESP_LOGE(I2S_TAG,"bits musn't be less than 8, src_bits %d aim_bits %d", src_bits, aim_bits);
|
||||
return ESP_FAIL;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (src_bits > I2S_BITS_PER_SAMPLE_32BIT || aim_bits > I2S_BITS_PER_SAMPLE_32BIT) {
|
||||
ESP_LOGE(I2S_TAG,"bits musn't be greater than 32, src_bits %d aim_bits %d", src_bits, aim_bits);
|
||||
return ESP_FAIL;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if ((src_bits == I2S_BITS_PER_SAMPLE_16BIT || src_bits == I2S_BITS_PER_SAMPLE_32BIT) && (size % 2 != 0)) {
|
||||
ESP_LOGE(I2S_TAG,"size must be a even number while src_bits is even, src_bits %d size %d", src_bits, size);
|
||||
return ESP_FAIL;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (src_bits == I2S_BITS_PER_SAMPLE_24BIT && (size % 3 != 0)) {
|
||||
ESP_LOGE(I2S_TAG,"size must be a multiple of 3 while src_bits is 24, size %d", size);
|
||||
return ESP_FAIL;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
int src_bytes = src_bits / 8, aim_bytes = aim_bits / 8;
|
||||
int zero_bytes = aim_bytes - src_bytes;
|
||||
|
||||
src_bytes = src_bits / 8;
|
||||
aim_bytes = aim_bits / 8;
|
||||
zero_bytes = aim_bytes - src_bytes;
|
||||
xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY);
|
||||
size = size * aim_bytes / src_bytes;
|
||||
ESP_LOGD(I2S_TAG,"aim_bytes %d src_bytes %d size %d", aim_bytes, src_bytes, size);
|
||||
@ -1196,23 +1217,36 @@ int i2s_write_expand(i2s_port_t i2s_num, const char *src, int size, int src_bits
|
||||
memset(data_ptr, 0, bytes_can_write);
|
||||
for (int j = 0; j < bytes_can_write; j += (aim_bytes - zero_bytes)) {
|
||||
j += zero_bytes;
|
||||
memcpy(&data_ptr[j], &src[bytes_writen], aim_bytes - zero_bytes);
|
||||
bytes_writen += (aim_bytes - zero_bytes);
|
||||
memcpy(&data_ptr[j], (const char *)(src + *bytes_written), aim_bytes - zero_bytes);
|
||||
(*bytes_written) += (aim_bytes - zero_bytes);
|
||||
}
|
||||
size -= bytes_can_write;
|
||||
p_i2s_obj[i2s_num]->tx->rw_pos += bytes_can_write;
|
||||
}
|
||||
xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux);
|
||||
return bytes_writen;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait)
|
||||
{
|
||||
int bytes_read = 0;
|
||||
int res = 0;
|
||||
res = i2s_read(i2s_num, dest, size, &bytes_read, ticks_to_wait);
|
||||
if (res != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
return bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t i2s_read(i2s_port_t i2s_num, char* dest, size_t size, int *bytes_read, TickType_t ticks_to_wait)
|
||||
{
|
||||
char *data_ptr;
|
||||
int bytes_can_read, byte_read = 0;
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
|
||||
I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_FAIL);
|
||||
I2S_CHECK((p_i2s_obj[i2s_num]->rx), "rx NULL", ESP_FAIL);
|
||||
int bytes_can_read;
|
||||
*bytes_read = 0;
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||
I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG);
|
||||
I2S_CHECK((p_i2s_obj[i2s_num]->rx), "rx NULL", ESP_ERR_INVALID_ARG);
|
||||
xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY);
|
||||
while (size > 0) {
|
||||
if (p_i2s_obj[i2s_num]->rx->rw_pos == p_i2s_obj[i2s_num]->rx->buf_size || p_i2s_obj[i2s_num]->rx->curr_ptr == NULL) {
|
||||
@ -1231,19 +1265,33 @@ int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks
|
||||
size -= bytes_can_read;
|
||||
dest += bytes_can_read;
|
||||
p_i2s_obj[i2s_num]->rx->rw_pos += bytes_can_read;
|
||||
byte_read += bytes_can_read;
|
||||
(*bytes_read) += bytes_can_read;
|
||||
}
|
||||
xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux);
|
||||
return byte_read;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait)
|
||||
{
|
||||
int i, bytes_to_push = 0;
|
||||
int bytes_push = 0;
|
||||
int res = 0;
|
||||
res = i2s_write_sample(i2s_num, sample, &bytes_push, ticks_to_wait);
|
||||
if (res != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
return bytes_push;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t i2s_write_sample(i2s_port_t i2s_num, const char *sample, int *sample_write, TickType_t ticks_to_wait)
|
||||
{
|
||||
int i;
|
||||
char *data_ptr;
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
|
||||
*sample_write = 0;
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||
if (p_i2s_obj[i2s_num]->tx->rw_pos == p_i2s_obj[i2s_num]->tx->buf_size || p_i2s_obj[i2s_num]->tx->curr_ptr == NULL) {
|
||||
if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) {
|
||||
return bytes_to_push;
|
||||
return *sample_write;
|
||||
}
|
||||
ESP_LOGD(I2S_TAG, "rw_pos: %d, buf_size: %d, curr_ptr: %d", p_i2s_obj[i2s_num]->tx->rw_pos, p_i2s_obj[i2s_num]->tx->buf_size, (int)p_i2s_obj[i2s_num]->tx->curr_ptr);
|
||||
p_i2s_obj[i2s_num]->tx->rw_pos = 0;
|
||||
@ -1252,20 +1300,34 @@ int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_
|
||||
data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos;
|
||||
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num; i++) {
|
||||
*data_ptr++ = *sample++;
|
||||
bytes_to_push ++;
|
||||
(*sample_write) += 1;
|
||||
}
|
||||
p_i2s_obj[i2s_num]->tx->rw_pos += bytes_to_push;
|
||||
return bytes_to_push;
|
||||
p_i2s_obj[i2s_num]->tx->rw_pos += (*sample_write);
|
||||
return ESP_OK;
|
||||
|
||||
}
|
||||
|
||||
int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait)
|
||||
{
|
||||
int i, bytes_to_pop = 0;
|
||||
int bytes_pop = 0;
|
||||
int res = 0;
|
||||
res = i2s_read_sample(i2s_num, sample, &bytes_pop, ticks_to_wait);
|
||||
if (res != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
return bytes_pop;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t i2s_read_sample(i2s_port_t i2s_num, char *sample, int *sample_read, TickType_t ticks_to_wait)
|
||||
{
|
||||
int i;
|
||||
*sample_read = 0;
|
||||
char *data_ptr;
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
|
||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||
if (p_i2s_obj[i2s_num]->rx->rw_pos == p_i2s_obj[i2s_num]->rx->buf_size || p_i2s_obj[i2s_num]->rx->curr_ptr == NULL) {
|
||||
if (xQueueReceive(p_i2s_obj[i2s_num]->rx->queue, &p_i2s_obj[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) {
|
||||
return bytes_to_pop;
|
||||
return *sample_read;
|
||||
}
|
||||
p_i2s_obj[i2s_num]->rx->rw_pos = 0;
|
||||
}
|
||||
@ -1273,15 +1335,16 @@ int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait)
|
||||
data_ptr += p_i2s_obj[i2s_num]->rx->rw_pos;
|
||||
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample; i++) {
|
||||
*sample++ = *data_ptr++;
|
||||
bytes_to_pop++;
|
||||
(*sample_read) += 1;
|
||||
}
|
||||
if (p_i2s_obj[i2s_num]->channel_num == 2) {
|
||||
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample; i++) {
|
||||
*sample++ = *data_ptr++;
|
||||
bytes_to_pop++;
|
||||
(*sample_read) += 1;
|
||||
}
|
||||
}
|
||||
|
||||
p_i2s_obj[i2s_num]->rx->rw_pos += p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
|
||||
return bytes_to_pop;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -262,42 +262,55 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
|
||||
/**
|
||||
* @brief Write data to I2S DMA transmit buffer.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* This function is deprecated. Use 'i2s_write' instead.
|
||||
* This definition will be removed in a future release.
|
||||
*
|
||||
* @param src Source address to write from
|
||||
* @return
|
||||
* - The amount of bytes written, if timeout, the result will be less than the size passed in.
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait) __attribute__ ((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Write data to I2S DMA transmit buffer.
|
||||
*
|
||||
* @param size Size of data in bytes
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
|
||||
* @param src Source address to write from
|
||||
*
|
||||
* @param size Size of data in bytes
|
||||
*
|
||||
* @param[out] bytes_written Number of bytes written, if timeout, the result will be less than the size passed in.
|
||||
*
|
||||
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
|
||||
* many ticks pass without space becoming available in the DMA
|
||||
* transmit buffer, then the function will return (note that if the
|
||||
* data is written to the DMA buffer in pieces, the overall operation
|
||||
* may still take longer than this timeout.) Pass portMAX_DELAY for no
|
||||
* timeout.
|
||||
*
|
||||
* Format of the data in source buffer is determined by the I2S
|
||||
* configuration (see i2s_config_t).
|
||||
*
|
||||
* @return
|
||||
* - Number of bytes written, if timeout occurred, bytes written will be less than the size passed.
|
||||
* - ESP_FAIL Parameter error.
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait);
|
||||
esp_err_t i2s_write(i2s_port_t i2s_num, const char *src, size_t size, int *bytes_written, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Write data to I2S DMA transmit buffer while expanding the number of bits per sample. For example, expanding 16-bit PCM to 32-bit PCM.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param src Source address to write from
|
||||
* @param src Source address to write from
|
||||
*
|
||||
* @param size Size of data in bytes
|
||||
* @param size Size of data in bytes
|
||||
*
|
||||
* @param src_bits Source audio bit
|
||||
* @param src_bits Source audio bit
|
||||
*
|
||||
* @param aim_bits Bit wanted, no more than 32, and must be greater than src_bits
|
||||
* @param aim_bits Bit wanted, no more than 32, and must be greater than src_bits
|
||||
*
|
||||
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
|
||||
* @param[out] bytes_written Number of bytes written, if timeout, the result will be less than the size passed in.
|
||||
*
|
||||
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
|
||||
* many ticks pass without space becoming available in the DMA
|
||||
* transmit buffer, then the function will return (note that if the
|
||||
* data is written to the DMA buffer in pieces, the overall operation
|
||||
@ -308,67 +321,106 @@ int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t
|
||||
* configuration (see i2s_config_t).
|
||||
*
|
||||
* @return
|
||||
* - Number of bytes written, if timeout occurred, bytes written will be less than the size passed.
|
||||
* - ESP_FAIL Parameter error.
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
int i2s_write_expand(i2s_port_t i2s_num, const char *src, int size, int src_bits, int aim_bits, TickType_t ticks_to_wait);
|
||||
esp_err_t i2s_write_expand(i2s_port_t i2s_num, const char *src, int size, int src_bits, int aim_bits, int *bytes_written, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Read data from I2S DMA receive buffer
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* This function is deprecated. Use 'i2s_read' instead.
|
||||
* This definition will be removed in a future release.
|
||||
*
|
||||
* @param dest Destination address to read into
|
||||
* @return
|
||||
* - The amount of bytes read, if timeout, bytes read will be less than the size passed in
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait) __attribute__ ((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Read data from I2S DMA receive buffer
|
||||
*
|
||||
* @param size Size of data in bytes
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param ticks_to_wait RX buffer wait timeout in RTOS ticks. If this many ticks pass without bytes becoming available in the DMA receive buffer, then the function will return (note that if data is read from the DMA buffer in pieces, the overall operation may still take longer than this timeout.) Pass portMAX_DELAY for no timeout.
|
||||
* @param dest Destination address to read into
|
||||
*
|
||||
* @param size Size of data in bytes
|
||||
*
|
||||
* @param[out] bytes_read Number of bytes read, if timeout, bytes read will be less than the size passed in.
|
||||
*
|
||||
* @param ticks_to_wait RX buffer wait timeout in RTOS ticks. If this many ticks pass without bytes becoming available in the DMA receive buffer, then the function will return (note that if data is read from the DMA buffer in pieces, the overall operation may still take longer than this timeout.) Pass portMAX_DELAY for no timeout.
|
||||
*
|
||||
* Format of the data in source buffer is determined by the I2S
|
||||
* configuration (see i2s_config_t).
|
||||
* @note If the built-in ADC mode is enabled, we should call i2s_adc_start and i2s_adc_stop around the whole reading process,
|
||||
* to prevent the data getting corrupted.
|
||||
*
|
||||
* @return
|
||||
* - Number of bytes read, if timeout occurred, bytes written will be less than the size passed.
|
||||
* - ESP_FAIL Parameter error.
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait);
|
||||
esp_err_t i2s_read(i2s_port_t i2s_num, char* dest, size_t size, int *bytes_read, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Push (write) a single sample to the I2S DMA TX buffer.
|
||||
* @brief Write a single sample to the I2S DMA TX buffer.
|
||||
*
|
||||
* This function is deprecated. Use 'i2s_write_sample' instead.
|
||||
* This definition will be removed in a future release.
|
||||
*
|
||||
* @return
|
||||
* - Number of bytes successfully pushed to DMA buffer, will be either zero or the size of configured sample buffer
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait) __attribute__ ((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Write a single sample to the I2S DMA TX buffer.
|
||||
*
|
||||
* Size of the sample is determined by the channel_format (mono or stereo)) & bits_per_sample configuration (see i2s_config_t).
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param sample Pointer to buffer containing sample to write. Size of buffer (in bytes) = (number of channels) * bits_per_sample / 8.
|
||||
* @param sample Pointer to buffer containing sample to write. Size of buffer (in bytes) = (number of channels) * bits_per_sample / 8.
|
||||
*
|
||||
* @param ticks_to_wait Push timeout in RTOS ticks. If space is not available in the DMA TX buffer within this period, no data is written and function returns 0.
|
||||
* @param[out] sample_write Number of bytes successfully pushed to DMA buffer, will be either zero or the size of configured sample buffer.
|
||||
*
|
||||
* @param ticks_to_wait Timeout in RTOS ticks. If space is not available in the DMA TX buffer within this period, no data is written and function returns 0.
|
||||
*
|
||||
* @return
|
||||
* - Number of bytes successfully pushed to DMA buffer, will be either zero or the size of configured sample buffer.
|
||||
* - ESP_FAIL Parameter error.
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait);
|
||||
esp_err_t i2s_write_sample(i2s_port_t i2s_num, const char *sample, int *sample_write, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Pop (read) a single sample from the I2S DMA RX buffer.
|
||||
* @brief Read a single sample from the I2S DMA RX buffer.
|
||||
*
|
||||
* This function is deprecated. Use 'i2s_read_sample' instead.
|
||||
* This definition will be removed in a future release.
|
||||
*
|
||||
* @return
|
||||
* - Number of bytes successfully read from DMA buffer, will be either zero or the size of configured sample buffer
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait) __attribute__ ((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Read a single sample from the I2S DMA RX buffer.
|
||||
*
|
||||
* Size of the sample is determined by the channel_format (mono or stereo)) & bits_per_sample configuration (see i2s_config_t).
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param sample Buffer sample data will be read into. Size of buffer (in bytes) = (number of channels) * bits_per_sample / 8.
|
||||
* @param sample Buffer sample data will be read into. Size of buffer (in bytes) = (number of channels) * bits_per_sample / 8.
|
||||
*
|
||||
* @param ticks_to_wait Pop timeout in RTOS ticks. If a sample is not available in the DMA buffer within this period, no data is read and function returns zero.
|
||||
* @param[out] sample_read Number of bytes successfully read from DMA buffer, will be either zero or the size of configured sample buffer.
|
||||
*
|
||||
* @param ticks_to_wait Timeout in RTOS ticks. If a sample is not available in the DMA buffer within this period, no data is read and function returns zero.
|
||||
*
|
||||
* @return
|
||||
* - Number of bytes successfully read from DMA buffer, will be either zero or the size of configured sample buffer.
|
||||
* - ESP_FAIL Parameter error.
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait);
|
||||
|
||||
esp_err_t i2s_read_sample(i2s_port_t i2s_num, char *sample, int *sample_read, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Set sample rate used for I2S RX and TX.
|
||||
@ -384,7 +436,6 @@ int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait);
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_FAIL I2s is not initialized
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate);
|
||||
@ -431,7 +482,7 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
|
||||
|
||||
/**
|
||||
* @brief Set clock & bit width used for I2S RX and TX.
|
||||
*
|
||||
*
|
||||
* Similar to i2s_set_sample_rates(), but also sets bit width.
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
@ -441,10 +492,9 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
|
||||
* @param bits I2S bit width (I2S_BITS_PER_SAMPLE_16BIT, I2S_BITS_PER_SAMPLE_24BIT, I2S_BITS_PER_SAMPLE_32BIT)
|
||||
*
|
||||
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO)
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Not initialized
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
|
@ -56,7 +56,8 @@ void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
||||
|
||||
void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len)
|
||||
{
|
||||
i2s_write_bytes(0, (const char *)data, len, portMAX_DELAY);
|
||||
int i2s_write_len;
|
||||
i2s_write(0, (const char *)data, len, &i2s_write_len, portMAX_DELAY);
|
||||
if (++m_pkt_cnt % 100 == 0) {
|
||||
ESP_LOGE(BT_AV_TAG, "audio data pkt cnt %u", m_pkt_cnt);
|
||||
}
|
||||
@ -124,7 +125,7 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
sample_rate = 48000;
|
||||
}
|
||||
i2s_set_clk(0, sample_rate, 16, 2);
|
||||
|
||||
|
||||
ESP_LOGI(BT_AV_TAG, "configure audio player %x-%x-%x-%x\n",
|
||||
a2d->audio_cfg.mcc.cie.sbc[0],
|
||||
a2d->audio_cfg.mcc.cie.sbc[1],
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
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.)
|
||||
|
||||
@ -29,11 +29,12 @@ static void setup_triangle_sine_waves(int bits)
|
||||
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;
|
||||
int i2s_bytes_write = 0;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
for(i = 0; i < SAMPLE_PER_CYCLE; i++) {
|
||||
sin_float = sin(i * PI / 180.0);
|
||||
if(sin_float >= 0)
|
||||
@ -56,7 +57,7 @@ static void setup_triangle_sine_waves(int bits)
|
||||
samples_data[i*2] = ((int) triangle_float);
|
||||
samples_data[i*2 + 1] = ((int) sin_float);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
i2s_set_clk(I2S_NUM, SAMPLE_RATE, bits, 2);
|
||||
@ -68,12 +69,12 @@ static void setup_triangle_sine_waves(int bits)
|
||||
// i2s_push_sample(0, &samples_data[i*2], 100);
|
||||
// }
|
||||
// or write
|
||||
i2s_write_bytes(I2S_NUM, (const char *)samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, 100);
|
||||
|
||||
i2s_write(I2S_NUM, (const char *)samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100);
|
||||
|
||||
free(samples_data);
|
||||
}
|
||||
void app_main()
|
||||
{
|
||||
{
|
||||
//for 36Khz sample rates, we create 100Hz sine wave, every cycle need 36000/100 = 360 samples (4-bytes or 8-bytes each sample)
|
||||
//depend on bits_per_sample
|
||||
//using 6 buffers, we need 60-samples per buffer
|
||||
@ -82,7 +83,7 @@ void app_main()
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = 16,
|
||||
.bits_per_sample = 16,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
|
||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||
.dma_buf_count = 6,
|
||||
@ -106,7 +107,7 @@ void app_main()
|
||||
test_bits += 8;
|
||||
if(test_bits > 32)
|
||||
test_bits = 16;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
8
examples/peripherals/i2s_adc_dac/main/app_main.c
Executable file → Normal file
8
examples/peripherals/i2s_adc_dac/main/app_main.c
Executable file → Normal file
@ -199,6 +199,7 @@ void example_i2s_adc_dac(void*arg)
|
||||
example_i2s_init();
|
||||
int i2s_read_len = EXAMPLE_I2S_READ_LEN;
|
||||
int flash_wr_size = 0;
|
||||
int i2s_bytes_read = 0;
|
||||
|
||||
//2. Record audio from ADC and save in flash
|
||||
#if RECORD_IN_FLASH_EN
|
||||
@ -206,7 +207,7 @@ void example_i2s_adc_dac(void*arg)
|
||||
uint8_t* flash_write_buff = (uint8_t*) calloc(i2s_read_len, sizeof(char));
|
||||
while (flash_wr_size < FLASH_RECORD_SIZE) {
|
||||
//read data from I2S bus, in this case, from ADC.
|
||||
i2s_read_bytes(EXAMPLE_I2S_NUM, (char*) i2s_read_buff, i2s_read_len, portMAX_DELAY);
|
||||
i2s_read(EXAMPLE_I2S_NUM, (char*) i2s_read_buff, i2s_read_len, &i2s_bytes_read, portMAX_DELAY);
|
||||
example_disp_buf((uint8_t*) i2s_read_buff, 64);
|
||||
//save original data from I2S(ADC) into flash.
|
||||
esp_partition_write(data_partition, flash_wr_size, i2s_read_buff, i2s_read_len);
|
||||
@ -221,6 +222,7 @@ void example_i2s_adc_dac(void*arg)
|
||||
|
||||
uint8_t* flash_read_buff = (uint8_t*) calloc(i2s_read_len, sizeof(char));
|
||||
uint8_t* i2s_write_buff = (uint8_t*) calloc(i2s_read_len, sizeof(char));
|
||||
int i2s_write_len = 0;
|
||||
while (1) {
|
||||
|
||||
//3. Read flash and replay the sound via DAC
|
||||
@ -231,7 +233,7 @@ void example_i2s_adc_dac(void*arg)
|
||||
//process data and scale to 8bit for I2S DAC.
|
||||
example_i2s_adc_data_scale(i2s_write_buff, flash_read_buff, FLASH_SECTOR_SIZE);
|
||||
//send data
|
||||
i2s_write_bytes(EXAMPLE_I2S_NUM, (char*) i2s_write_buff, FLASH_SECTOR_SIZE, portMAX_DELAY);
|
||||
i2s_write(EXAMPLE_I2S_NUM, (char*) i2s_write_buff, FLASH_SECTOR_SIZE, &i2s_write_len, portMAX_DELAY);
|
||||
printf("playing: %d %%\n", rd_offset * 100 / flash_wr_size);
|
||||
}
|
||||
#endif
|
||||
@ -244,7 +246,7 @@ void example_i2s_adc_dac(void*arg)
|
||||
while (offset < tot_size) {
|
||||
int play_len = ((tot_size - offset) > (4 * 1024)) ? (4 * 1024) : (tot_size - offset);
|
||||
int i2s_wr_len = example_i2s_dac_data_scale(i2s_write_buff, (uint8_t*)(audio_table + offset), play_len);
|
||||
i2s_write_bytes(EXAMPLE_I2S_NUM, (const char*) i2s_write_buff, i2s_wr_len, portMAX_DELAY);
|
||||
i2s_write(EXAMPLE_I2S_NUM, (const char*) i2s_write_buff, i2s_wr_len, &i2s_write_len, portMAX_DELAY);
|
||||
offset += play_len;
|
||||
example_disp_buf((uint8_t*) i2s_write_buff, 32);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user