Merge branch 'feature/i2s_add_expand_function' into 'release/v3.0'
Add a new i2s feature to expand the original i2s width See merge request idf/esp-idf!2174
This commit is contained in:
commit
4e36ede3bf
2 changed files with 157 additions and 52 deletions
|
@ -41,6 +41,7 @@ static const char* I2S_TAG = "I2S";
|
||||||
ESP_LOGE(I2S_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
ESP_LOGE(I2S_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||||
return (ret); \
|
return (ret); \
|
||||||
}
|
}
|
||||||
|
#define I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated
|
||||||
#define I2S_BASE_CLK (2*APB_CLK_FREQ)
|
#define I2S_BASE_CLK (2*APB_CLK_FREQ)
|
||||||
#define I2S_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num])
|
#define I2S_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num])
|
||||||
#define I2S_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num])
|
#define I2S_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num])
|
||||||
|
@ -48,7 +49,7 @@ static const char* I2S_TAG = "I2S";
|
||||||
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
|
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
|
||||||
#define I2S_FULL_DUPLEX_SLAVE_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_SLAVE)
|
#define I2S_FULL_DUPLEX_SLAVE_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_SLAVE)
|
||||||
#define I2S_FULL_DUPLEX_MASTER_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_MASTER)
|
#define I2S_FULL_DUPLEX_MASTER_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_MASTER)
|
||||||
#define APLL_MIN_FREQ (350000000)
|
#define APLL_MIN_FREQ (250000000)
|
||||||
#define APLL_MAX_FREQ (500000000)
|
#define APLL_MAX_FREQ (500000000)
|
||||||
#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
|
#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
|
||||||
/**
|
/**
|
||||||
|
@ -198,7 +199,7 @@ static float i2s_get_apll_real_rate(int bits_per_sample, int sdm0, int sdm1, int
|
||||||
}
|
}
|
||||||
float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4);
|
float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4);
|
||||||
if (fout < APLL_MIN_FREQ || fout > APLL_MAX_FREQ) {
|
if (fout < APLL_MIN_FREQ || fout > APLL_MAX_FREQ) {
|
||||||
return 9999999;
|
return APLL_MAX_FREQ;
|
||||||
}
|
}
|
||||||
float fpll = fout / (2 * (odir+2)); //== fi2s (N=1, b=0, a=1)
|
float fpll = fout / (2 * (odir+2)); //== fi2s (N=1, b=0, a=1)
|
||||||
return fpll/(8*4*bits_per_sample); //fbck = fi2s/bck_div
|
return fpll/(8*4*bits_per_sample); //fbck = fi2s/bck_div
|
||||||
|
@ -243,7 +244,7 @@ static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, in
|
||||||
float avg;
|
float avg;
|
||||||
float min_rate, max_rate, min_diff;
|
float min_rate, max_rate, min_diff;
|
||||||
if (rate < APLL_I2S_MIN_RATE) {
|
if (rate < APLL_I2S_MIN_RATE) {
|
||||||
return ESP_FAIL;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
//check pre-define apll parameters
|
//check pre-define apll parameters
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -261,7 +262,7 @@ static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, in
|
||||||
*sdm1 = 0;
|
*sdm1 = 0;
|
||||||
*sdm2 = 0;
|
*sdm2 = 0;
|
||||||
*odir = 0;
|
*odir = 0;
|
||||||
min_diff = 99999;
|
min_diff = APLL_MAX_FREQ;
|
||||||
|
|
||||||
for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) {
|
for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) {
|
||||||
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, 255, _sdm2, 0);
|
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, 255, _sdm2, 0);
|
||||||
|
@ -272,7 +273,7 @@ static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, in
|
||||||
*sdm2 = _sdm2;
|
*sdm2 = _sdm2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
min_diff = 99999;
|
min_diff = APLL_MAX_FREQ;
|
||||||
for (_odir = 0; _odir < 32; _odir ++) {
|
for (_odir = 0; _odir < 32; _odir ++) {
|
||||||
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, 255, *sdm2, _odir);
|
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, 255, *sdm2, _odir);
|
||||||
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, 0, *sdm2, _odir);
|
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, 0, *sdm2, _odir);
|
||||||
|
@ -283,7 +284,7 @@ static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
min_diff = 99999;
|
min_diff = APLL_MAX_FREQ;
|
||||||
for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) {
|
for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) {
|
||||||
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, _sdm1, *sdm2, *odir);
|
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, _sdm1, *sdm2, *odir);
|
||||||
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, _sdm1, *sdm2, *odir);
|
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, _sdm1, *sdm2, *odir);
|
||||||
|
@ -294,7 +295,7 @@ static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
min_diff = 99999;
|
min_diff = APLL_MAX_FREQ;
|
||||||
for (_sdm0 = 0; _sdm0 < 256; _sdm0 ++) {
|
for (_sdm0 = 0; _sdm0 < 256; _sdm0 ++) {
|
||||||
avg = i2s_get_apll_real_rate(bits_per_sample, _sdm0, *sdm1, *sdm2, *odir);
|
avg = i2s_get_apll_real_rate(bits_per_sample, _sdm0, *sdm1, *sdm2, *odir);
|
||||||
if (abs(avg - rate) < min_diff) {
|
if (abs(avg - rate) < min_diff) {
|
||||||
|
@ -331,7 +332,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||||
|
|
||||||
if (clkmdiv > 256) {
|
if (clkmdiv > 256) {
|
||||||
ESP_LOGE(I2S_TAG, "clkmdiv is too large\r\n");
|
ESP_LOGE(I2S_TAG, "clkmdiv is too large\r\n");
|
||||||
return ESP_FAIL;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait all on-going writing finish
|
// wait all on-going writing finish
|
||||||
|
@ -387,7 +388,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]->tx == NULL) {
|
if (p_i2s_obj[i2s_num]->tx == NULL) {
|
||||||
ESP_LOGE(I2S_TAG, "Failed to create tx dma buffer");
|
ESP_LOGE(I2S_TAG, "Failed to create tx dma buffer");
|
||||||
i2s_driver_uninstall(i2s_num);
|
i2s_driver_uninstall(i2s_num);
|
||||||
return ESP_FAIL;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
I2S[i2s_num]->out_link.addr = (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0];
|
I2S[i2s_num]->out_link.addr = (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0];
|
||||||
|
|
||||||
|
@ -405,7 +406,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]->rx == NULL){
|
if (p_i2s_obj[i2s_num]->rx == NULL){
|
||||||
ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer");
|
ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer");
|
||||||
i2s_driver_uninstall(i2s_num);
|
i2s_driver_uninstall(i2s_num);
|
||||||
return ESP_FAIL;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
I2S[i2s_num]->rx_eof_num = (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample)/4;
|
I2S[i2s_num]->rx_eof_num = (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample)/4;
|
||||||
I2S[i2s_num]->in_link.addr = (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0];
|
I2S[i2s_num]->in_link.addr = (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0];
|
||||||
|
@ -643,6 +644,7 @@ static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, in
|
||||||
|
|
||||||
esp_err_t i2s_start(i2s_port_t i2s_num)
|
esp_err_t i2s_start(i2s_port_t i2s_num)
|
||||||
{
|
{
|
||||||
|
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||||
//start DMA link
|
//start DMA link
|
||||||
I2S_ENTER_CRITICAL();
|
I2S_ENTER_CRITICAL();
|
||||||
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
|
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
|
||||||
|
@ -664,6 +666,7 @@ esp_err_t i2s_start(i2s_port_t i2s_num)
|
||||||
|
|
||||||
esp_err_t i2s_stop(i2s_port_t i2s_num)
|
esp_err_t i2s_stop(i2s_port_t i2s_num)
|
||||||
{
|
{
|
||||||
|
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||||
I2S_ENTER_CRITICAL();
|
I2S_ENTER_CRITICAL();
|
||||||
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
|
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
|
||||||
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
|
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
|
||||||
|
@ -689,7 +692,7 @@ esp_err_t i2s_stop(i2s_port_t i2s_num)
|
||||||
I2S[i2s_num]->conf.rx_reset = 1;
|
I2S[i2s_num]->conf.rx_reset = 1;
|
||||||
I2S[i2s_num]->conf.rx_reset = 0;
|
I2S[i2s_num]->conf.rx_reset = 0;
|
||||||
I2S_EXIT_CRITICAL();
|
I2S_EXIT_CRITICAL();
|
||||||
return 0;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode)
|
esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode)
|
||||||
|
@ -1020,7 +1023,7 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
|
||||||
p_i2s_obj[i2s_num] = (i2s_obj_t*) malloc(sizeof(i2s_obj_t));
|
p_i2s_obj[i2s_num] = (i2s_obj_t*) malloc(sizeof(i2s_obj_t));
|
||||||
if (p_i2s_obj[i2s_num] == NULL) {
|
if (p_i2s_obj[i2s_num] == NULL) {
|
||||||
ESP_LOGE(I2S_TAG, "Malloc I2S driver error");
|
ESP_LOGE(I2S_TAG, "Malloc I2S driver error");
|
||||||
return ESP_FAIL;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
memset(p_i2s_obj[i2s_num], 0, sizeof(i2s_obj_t));
|
memset(p_i2s_obj[i2s_num], 0, sizeof(i2s_obj_t));
|
||||||
|
|
||||||
|
@ -1068,15 +1071,15 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
|
||||||
return i2s_set_clk(i2s_num, i2s_config->sample_rate, i2s_config->bits_per_sample, p_i2s_obj[i2s_num]->channel_num);
|
return i2s_set_clk(i2s_num, i2s_config->sample_rate, i2s_config->bits_per_sample, p_i2s_obj[i2s_num]->channel_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGE(I2S_TAG, "I2S driver already installed");
|
ESP_LOGW(I2S_TAG, "I2S driver already installed");
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
|
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
|
||||||
{
|
{
|
||||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
||||||
if (p_i2s_obj[i2s_num] == NULL) {
|
if (p_i2s_obj[i2s_num] == NULL) {
|
||||||
ESP_LOGI(I2S_TAG, "ALREADY NULL");
|
ESP_LOGI(I2S_TAG, "already uninstalled");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
i2s_stop(i2s_num);
|
i2s_stop(i2s_num);
|
||||||
|
@ -1115,10 +1118,9 @@ int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t
|
||||||
{
|
{
|
||||||
char *data_ptr;
|
char *data_ptr;
|
||||||
int bytes_can_write, bytes_writen = 0;
|
int bytes_can_write, bytes_writen = 0;
|
||||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
|
||||||
if (p_i2s_obj[i2s_num]->tx == NULL) {
|
I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_FAIL);
|
||||||
return 0;
|
I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_FAIL);
|
||||||
}
|
|
||||||
xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY);
|
xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY);
|
||||||
while (size > 0) {
|
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) {
|
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) {
|
||||||
|
@ -1144,14 +1146,73 @@ int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t
|
||||||
return bytes_writen;
|
return bytes_writen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
int src_bytes = src_bits / 8, aim_bytes = aim_bits / 8;
|
||||||
|
int 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);
|
||||||
|
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) {
|
||||||
|
if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p_i2s_obj[i2s_num]->tx->rw_pos = 0;
|
||||||
|
}
|
||||||
|
data_ptr = (char*)p_i2s_obj[i2s_num]->tx->curr_ptr;
|
||||||
|
data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos;
|
||||||
|
bytes_can_write = p_i2s_obj[i2s_num]->tx->buf_size - p_i2s_obj[i2s_num]->tx->rw_pos;
|
||||||
|
if (bytes_can_write > size) {
|
||||||
|
bytes_can_write = size;
|
||||||
|
}
|
||||||
|
tail = bytes_can_write % aim_bytes;
|
||||||
|
bytes_can_write = bytes_can_write - tail;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait)
|
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait)
|
||||||
{
|
{
|
||||||
char *data_ptr;
|
char *data_ptr;
|
||||||
int bytes_can_read, byte_read = 0;
|
int bytes_can_read, byte_read = 0;
|
||||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
|
||||||
if (p_i2s_obj[i2s_num]->rx == NULL) {
|
I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_FAIL);
|
||||||
return 0;
|
I2S_CHECK((p_i2s_obj[i2s_num]->rx), "rx NULL", ESP_FAIL);
|
||||||
}
|
|
||||||
xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY);
|
xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY);
|
||||||
while (size > 0) {
|
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) {
|
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) {
|
||||||
|
@ -1179,10 +1240,10 @@ int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_
|
||||||
{
|
{
|
||||||
int i, bytes_to_push = 0;
|
int i, bytes_to_push = 0;
|
||||||
char *data_ptr;
|
char *data_ptr;
|
||||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
|
||||||
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 (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) {
|
if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) {
|
||||||
return 0;
|
return bytes_to_push;
|
||||||
}
|
}
|
||||||
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);
|
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;
|
p_i2s_obj[i2s_num]->tx->rw_pos = 0;
|
||||||
|
@ -1201,10 +1262,10 @@ int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait)
|
||||||
{
|
{
|
||||||
int i, bytes_to_pop = 0;
|
int i, bytes_to_pop = 0;
|
||||||
char *data_ptr;
|
char *data_ptr;
|
||||||
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
|
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
|
||||||
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 (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) {
|
if (xQueueReceive(p_i2s_obj[i2s_num]->rx->queue, &p_i2s_obj[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) {
|
||||||
return 0;
|
return bytes_to_pop;
|
||||||
}
|
}
|
||||||
p_i2s_obj[i2s_num]->rx->rw_pos = 0;
|
p_i2s_obj[i2s_num]->rx->rw_pos = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,7 +208,8 @@ typedef intr_handle_t i2s_isr_handle_t;
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_FAIL Parameter error
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
|
* - ESP_FAIL IO error
|
||||||
*/
|
*/
|
||||||
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
|
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
|
||||||
|
|
||||||
|
@ -242,7 +243,8 @@ esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode);
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_FAIL Parameter error
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
|
* - ESP_ERR_NO_MEM Out of memory
|
||||||
*/
|
*/
|
||||||
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue);
|
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue);
|
||||||
|
|
||||||
|
@ -253,7 +255,7 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_FAIL Parameter error
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*/
|
*/
|
||||||
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
|
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
|
||||||
|
|
||||||
|
@ -276,10 +278,41 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
|
||||||
* Format of the data in source buffer is determined by the I2S
|
* Format of the data in source buffer is determined by the I2S
|
||||||
* configuration (see i2s_config_t).
|
* configuration (see i2s_config_t).
|
||||||
*
|
*
|
||||||
* @return Number of bytes written, or ESP_FAIL (-1) for parameter error. If a timeout occurred, bytes written will be less than total size.
|
* @return
|
||||||
|
* - Number of bytes written, if timeout occurred, bytes written will be less than the size passed.
|
||||||
|
* - ESP_FAIL Parameter error.
|
||||||
*/
|
*/
|
||||||
int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait);
|
int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, 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 src Source address to write from
|
||||||
|
*
|
||||||
|
* @param size Size of data in bytes
|
||||||
|
*
|
||||||
|
* @param src_bits Source audio bit
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read data from I2S DMA receive buffer
|
* @brief Read data from I2S DMA receive buffer
|
||||||
*
|
*
|
||||||
|
@ -293,8 +326,12 @@ int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t
|
||||||
*
|
*
|
||||||
* Format of the data in source buffer is determined by the I2S
|
* Format of the data in source buffer is determined by the I2S
|
||||||
* configuration (see i2s_config_t).
|
* 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, or ESP_FAIL (-1) for parameter error. If a timeout occurred, bytes read will be less than total size.
|
* @return
|
||||||
|
* - Number of bytes read, if timeout occurred, bytes written will be less than the size passed.
|
||||||
|
* - ESP_FAIL Parameter error.
|
||||||
*/
|
*/
|
||||||
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait);
|
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait);
|
||||||
|
|
||||||
|
@ -309,7 +346,9 @@ int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks
|
||||||
*
|
*
|
||||||
* @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 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.
|
||||||
*
|
*
|
||||||
* @return Number of bytes successfully pushed to DMA buffer, or ESP_FAIL (-1) for parameter error. Will be either zero or the size of configured sample buffer.
|
* @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);
|
int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait);
|
||||||
|
|
||||||
|
@ -324,8 +363,9 @@ int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_
|
||||||
*
|
*
|
||||||
* @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 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.
|
||||||
*
|
*
|
||||||
* @return Number of bytes successfully read from DMA buffer, or ESP_FAIL (-1) for parameter error. Byte count will be either zero or the size of the configured sample buffer.
|
* @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);
|
int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait);
|
||||||
|
|
||||||
|
@ -343,7 +383,9 @@ int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait);
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_FAIL Parameter error
|
* - 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);
|
esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate);
|
||||||
|
|
||||||
|
@ -356,7 +398,7 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate);
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_FAIL Parameter error
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*/
|
*/
|
||||||
esp_err_t i2s_stop(i2s_port_t i2s_num);
|
esp_err_t i2s_stop(i2s_port_t i2s_num);
|
||||||
|
|
||||||
|
@ -370,7 +412,7 @@ esp_err_t i2s_stop(i2s_port_t i2s_num);
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_FAIL Parameter error
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*/
|
*/
|
||||||
esp_err_t i2s_start(i2s_port_t i2s_num);
|
esp_err_t i2s_start(i2s_port_t i2s_num);
|
||||||
|
|
||||||
|
@ -383,7 +425,7 @@ esp_err_t i2s_start(i2s_port_t i2s_num);
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_FAIL Parameter error
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*/
|
*/
|
||||||
esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
|
esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
|
||||||
|
|
||||||
|
@ -402,7 +444,9 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_FAIL Parameter error
|
* - ESP_FAIL Not initialized
|
||||||
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
|
* - ESP_ERR_NO_MEM Out of memory
|
||||||
*/
|
*/
|
||||||
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch);
|
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch);
|
||||||
|
|
||||||
|
@ -413,7 +457,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
|
||||||
* @param adc_channel ADC channel index
|
* @param adc_channel ADC channel index
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_FAIL Parameter error
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*/
|
*/
|
||||||
esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel);
|
esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue