Skip to content

DRAFT: Fixes for I2S #7117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 58 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
306cf89
Initial support for second I2S - not tested
PilnyTomas Aug 12, 2022
f9af615
Merge branch 'master' into i2s_fix
PilnyTomas Aug 12, 2022
d87aa62
Initial support for 24 bits per second - not tested yet!
PilnyTomas Aug 12, 2022
54e9554
SimpleTone supports all available bitrates
PilnyTomas Aug 15, 2022
481c439
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Sep 21, 2022
db32ea6
Minor changes to fix compilation errors
PilnyTomas Sep 21, 2022
f2fdca7
Remapped pins
PilnyTomas Sep 21, 2022
578e871
Changed default pins
PilnyTomas Sep 27, 2022
b376699
Added notes into README as a guide for propper documentation
PilnyTomas Sep 27, 2022
dc1769e
WIP Backup of documentation update
PilnyTomas Sep 30, 2022
adff9e1
Finished documenting header file + README.md
PilnyTomas Sep 30, 2022
26ac979
Updated pins in examples + removed skip files
PilnyTomas Oct 3, 2022
7a9fd45
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Oct 14, 2022
c7d011e
Added C3 PDM support
PilnyTomas Oct 17, 2022
b02596b
Simplified peek() - NOT tested
PilnyTomas Oct 17, 2022
0f8e9bc
Updated README.md - section describing modes
PilnyTomas Oct 17, 2022
2b04bf8
Revert "Simplified peek() - NOT tested"
PilnyTomas Oct 18, 2022
989817c
Extended mode warning and added mode text array
PilnyTomas Oct 18, 2022
fe268c8
Added new example demonstrating usage of both I2S module (not working…
PilnyTomas Oct 24, 2022
a0ab150
Changed mutex to recursive mutex
PilnyTomas Oct 25, 2022
0b38c9b
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Oct 26, 2022
d7e1228
Added missing initializers to satisfy compilier's warnings
PilnyTomas Oct 27, 2022
e96f5a9
Fix for previous commit - I2S_TDM_ACTIVE_CH
PilnyTomas Oct 27, 2022
8f6613e
First I2S tests
PilnyTomas Oct 27, 2022
5f3542c
Changed default FS pin which was accidentally set on UART TX for C3
PilnyTomas Oct 27, 2022
f67ce84
Added getI2SNum()
PilnyTomas Oct 31, 2022
0719bdc
Added function isInitialized()
PilnyTomas Oct 31, 2022
9721149
Extended begin test for slave mode + added pin setter & getter test
PilnyTomas Oct 31, 2022
2899011
Added & modified buffer functions; Renamed I2S1 to I2S_1
PilnyTomas Nov 3, 2022
d746aa2
Updated DualModule example
PilnyTomas Nov 7, 2022
de30999
Added test
PilnyTomas Nov 11, 2022
53d8f23
Updated default pins
PilnyTomas Nov 11, 2022
a3898e6
Fixed buffer calls in example
PilnyTomas Nov 11, 2022
405723a
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Nov 11, 2022
6ac821e
Added skip files for DualModule example
PilnyTomas Nov 11, 2022
27149b8
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Nov 23, 2022
85b0ea4
Renamed data parameter to sample; removed _buffer_byte_size - now usi…
PilnyTomas Nov 28, 2022
9fa388c
Added MCLK
PilnyTomas Nov 30, 2022
5f779df
Fixed constructor
PilnyTomas Nov 30, 2022
b8dcf69
fixed variable order
PilnyTomas Nov 30, 2022
51a7914
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Dec 1, 2022
70c9e26
Fixed freezing output
PilnyTomas Dec 7, 2022
6aed27f
Separated info message with doc link for each SoC
PilnyTomas Dec 7, 2022
d831f1a
Changed default MCLK pins
PilnyTomas Dec 7, 2022
9761860
Modified MCLK code and doc
PilnyTomas Dec 8, 2022
77a876e
Added note to legacy example
PilnyTomas Dec 8, 2022
653c995
Fixed input
PilnyTomas Dec 8, 2022
83f5372
changed default input pin to match with ADC support
PilnyTomas Dec 9, 2022
94a9169
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Dec 9, 2022
4af7fa3
Fixed DAC
PilnyTomas Dec 15, 2022
4d174af
Added setDMABufferSampleSize function and made few changes in README
PilnyTomas Dec 16, 2022
17caf84
Lowered I2S task priority
PilnyTomas Dec 18, 2022
b12cc18
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Dec 18, 2022
46aee1f
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Dec 27, 2022
d5cde9e
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Jun 23, 2023
3d85853
backup
PilnyTomas Jul 17, 2023
1d85571
work in progress
PilnyTomas Jul 17, 2023
b2d000a
Merge remote-tracking branch 'origin/i2s_fix' into i2s_fix
PilnyTomas Jul 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Renamed data parameter to sample; removed _buffer_byte_size - now usi…
…ng getRingBufferByteSize; reduced i2s_config.fixed_mclk
  • Loading branch information
PilnyTomas committed Nov 28, 2022
commit 85b0ea473d6f95a96aa01114ab9da3553b14219a
4 changes: 2 additions & 2 deletions libraries/I2S/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ Reads a single sample from ring buffer and keeps it available for future read (i
This function is **blocking** - if there is not enough space in ring buffer the function will wait until it can write the sample.

**Parameter:**
* **uint8_t data** The sample to be sent
* **uint8_t sample** The sample to be sent

**Returns:** 1 on successful write; 0 on error = did not write the sample to ring buffer

Expand All @@ -296,7 +296,7 @@ Please consider sending data in arrays using function `size_t write(const uint8_
This function is **blocking** - if there is not enough space in ring buffer the function will wait until it can write the sample.

**Parameter:**
**int32_t data** The sample to be sent
**int32_t sample** The sample to be sent

**Returns:** Number of written bytes, if successful the value will be equal to `bitsPerSample/8`

Expand Down
78 changes: 42 additions & 36 deletions libraries/I2S/src/I2S.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
I2SClass::I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, uint8_t sckPin, uint8_t fsPin) :
_deviceIndex(deviceIndex),
_sdPin(sdPin), // shared data pin
_inSdPin(PIN_I2S_SD_IN), // input data pin
_outSdPin(PIN_I2S_SD), // output data pin
_inSdPin(deviceIndex == 0 ? PIN_I2S_SD_IN : PIN_I2S1_SD_IN), // input data pin
_outSdPin(deviceIndex == 0 ? PIN_I2S_SD : PIN_I2S1_SD), // output data pin
_sckPin(sckPin), // clock pin
_fsPin(fsPin), // frame (word) select pin

Expand All @@ -41,8 +41,6 @@ I2SClass::I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, u
_sampleRate(0),
_mode(I2S_PHILIPS_MODE),

_buffer_byte_size(0),

_driverInstalled(false),
_initialized(false),
_callbackTaskHandle(NULL),
Expand Down Expand Up @@ -76,8 +74,8 @@ int I2SClass::_createCallbackTask(){
onDmaTransferComplete, // Function to implement the task
"onDmaTransferComplete", // Name of the task
stack_size, // Stack size in words
(void *)&_deviceIndex, // Task input parameter
2, // Priority of the task
(void *)&_deviceIndex, // Task input parameter
4, // Priority of the task
&_callbackTaskHandle // Task handle.
);
if(_callbackTaskHandle == NULL){
Expand Down Expand Up @@ -164,7 +162,7 @@ int I2SClass::_installDriver(){

if(_driveClock == false){
i2s_config.use_apll = true;
i2s_config.fixed_mclk = 512*_sampleRate;
i2s_config.fixed_mclk = 8*_sampleRate;
}

// Install and start i2s driver
Expand Down Expand Up @@ -324,11 +322,10 @@ int I2SClass::begin(int mode, int sampleRate, int bitsPerSample, bool driveClock
return 0; // ERR
}

_buffer_byte_size = _i2s_dma_buffer_frame_size * (_bitsPerSample / 8) * _I2S_DMA_BUFFER_COUNT * CHANNEL_NUMBER; // The magic "*k2" stands for number of channels which are statically set to stereo
_input_ring_buffer = xRingbufferCreate(_buffer_byte_size, RINGBUF_TYPE_BYTEBUF);
_output_ring_buffer = xRingbufferCreate(_buffer_byte_size, RINGBUF_TYPE_BYTEBUF);
_input_ring_buffer = xRingbufferCreate(getRingBufferByteSize(), RINGBUF_TYPE_BYTEBUF);
_output_ring_buffer = xRingbufferCreate(getRingBufferByteSize(), RINGBUF_TYPE_BYTEBUF);
if(_input_ring_buffer == NULL || _output_ring_buffer == NULL){
log_e("(I2S#%d) ERROR: could not create one or both internal buffers. Requested size = %d", _deviceIndex, _buffer_byte_size);
log_e("(I2S#%d) ERROR: could not create one or both internal buffers. Requested size = %d", _deviceIndex, getRingBufferByteSize());
if(!_give_mux()){ return 0; /* ERR */ }
return 0; // ERR
}
Expand Down Expand Up @@ -593,7 +590,7 @@ int I2SClass::available(){
if(!_take_mux()){ return 0; /* ERR */ }
int ret = 0;
if(_input_ring_buffer != NULL){
ret = _buffer_byte_size - (int)xRingbufferGetCurFreeSize(_input_ring_buffer);
ret = getRingBufferByteSize() - (int)xRingbufferGetCurFreeSize(_input_ring_buffer);
}
if(!_give_mux()){ return 0; /* ERR */ }
return ret;
Expand Down Expand Up @@ -766,14 +763,14 @@ size_t I2SClass::write_nonblocking(const void *buffer, size_t size){
if(!_give_mux()){ return 0; /* ERR */ }
return size;
}else{
log_w("(I2S#%d) I2S could not write all data into ring buffer!", _deviceIndex);
log_w("(I2S#%d) I2S could not write all data (%d B) into ring buffer!", _deviceIndex, size);
if(!_give_mux()){ return 0; /* ERR */ }
return 0;
}
}
} // if(_initialized)
return 0;
if(!_give_mux()){ return 0; /* ERR */ } // this should not be needed
return 0;
}

/*
Expand Down Expand Up @@ -944,7 +941,6 @@ int I2SClass::_enableReceiver(){

void I2SClass::_tx_done_routine(uint8_t* prev_item){
static bool prev_item_valid = false;
const size_t single_dma_buf_byte_size = _i2s_dma_buffer_frame_size*(_bitsPerSample/8)* CHANNEL_NUMBER;
static size_t item_size = 0;
static size_t prev_item_size = 0;
static void *item = NULL;
Expand All @@ -960,22 +956,20 @@ void I2SClass::_tx_done_routine(uint8_t* prev_item){
prev_item_size -= bytes_written;
} // prev_item_valid

if(_output_ring_buffer != NULL && (_buffer_byte_size - xRingbufferGetCurFreeSize(_output_ring_buffer) >= single_dma_buf_byte_size)){ // fill up the I2S DMA buffer
if(_output_ring_buffer != NULL && (getRingBufferByteSize() - xRingbufferGetCurFreeSize(_output_ring_buffer) >= getDMABufferByteSize())){ // fill up the I2S DMA buffer
bytes_written = 0;
item_size = 0;
if(_buffer_byte_size - xRingbufferGetCurFreeSize(_output_ring_buffer) >= _i2s_dma_buffer_frame_size*(_bitsPerSample/8)){ // don't read from almost empty buffer
item = xRingbufferReceiveUpTo(_output_ring_buffer, &item_size, pdMS_TO_TICKS(0), single_dma_buf_byte_size);
if (item != NULL){
_fix_and_write(item, item_size, &bytes_written);
if(item_size != bytes_written){ // save item that was not written correctly for later
memcpy(prev_item, (void*)&((uint8_t*)item)[bytes_written], item_size-bytes_written);
prev_item_size = item_size - bytes_written;
prev_item_offset = 0;
prev_item_valid = true;
} // save item that was not written correctly for later
vRingbufferReturnItem(_output_ring_buffer, item);
} // Check received item
} // don't read from almost empty buffer
item = xRingbufferReceiveUpTo(_output_ring_buffer, &item_size, pdMS_TO_TICKS(0), getDMABufferByteSize());
if (item != NULL){
_fix_and_write(item, item_size, &bytes_written);
if(item_size != bytes_written){ // save item that was not written correctly for later
memcpy(prev_item, (void*)&((uint8_t*)item)[bytes_written], item_size-bytes_written);
prev_item_size = item_size - bytes_written;
prev_item_offset = 0;
prev_item_valid = true;
} // save item that was not written correctly for later
vRingbufferReturnItem(_output_ring_buffer, item);
} // Check received item
} // fill up the I2S DMA buffer
if(_onTransmit){
_onTransmit();
Expand All @@ -984,16 +978,25 @@ void I2SClass::_tx_done_routine(uint8_t* prev_item){

void I2SClass::_rx_done_routine(){
size_t bytes_read = 0;
const size_t single_dma_buf_byte_size = _i2s_dma_buffer_frame_size*(_bitsPerSample/8)*CHANNEL_NUMBER;
size_t request_read = 0;

if(_input_ring_buffer != NULL){
uint8_t *_inputBuffer = (uint8_t*)malloc(single_dma_buf_byte_size);
uint8_t *_inputBuffer = (uint8_t*)malloc(getDMABufferByteSize());
size_t avail = xRingbufferGetCurFreeSize(_input_ring_buffer);
if(avail > 0){
esp_err_t ret = esp_i2s::i2s_read((esp_i2s::i2s_port_t) _deviceIndex, _inputBuffer, avail <= single_dma_buf_byte_size ? avail : single_dma_buf_byte_size, (size_t*) &bytes_read, 0);
if(_bitsPerSample == 8){ // 8-bps is received with padding as 16bits - read twice than actually needed
request_read = avail*2 <= getDMABufferByteSize() ? avail*2 : getDMABufferByteSize();
}else{
request_read = avail <= getDMABufferByteSize() ? avail : getDMABufferByteSize();
}

esp_err_t ret = esp_i2s::i2s_read((esp_i2s::i2s_port_t) _deviceIndex, _inputBuffer, request_read, &bytes_read, 0);
if(ret != ESP_OK){
log_w("(I2S#%d) i2s_read returned with error %d", _deviceIndex, ret);
}
if(request_read != bytes_read){
log_w("(I2S#%d) i2s_read read only %d bytes instead of %d requested", _deviceIndex, bytes_read, request_read);
}
_post_read_data_fix(_inputBuffer, &bytes_read);
}

Expand All @@ -1003,7 +1006,7 @@ void I2SClass::_rx_done_routine(){
} // xRingbufferSendComplete
} // if(bytes_read > 0)
free(_inputBuffer);
if (_onReceive && avail < _buffer_byte_size){ // when user callback is registered && and there is some data in ring buffer to read
if (_onReceive && avail < getRingBufferByteSize()){ // when user callback is registered && and there is some data in ring buffer to read
_onReceive();
} // user callback
}
Expand Down Expand Up @@ -1038,7 +1041,7 @@ void I2SClass::onDmaTransferComplete(void *deviceIndex){
I2S_1._onTransferComplete();
}
#endif
log_w("(I2S#%d) Deleting callback task from inside!", index);
log_w("(I2S#%d) Deleting callback task from inside!", *index);
vTaskDelete(NULL);
}

Expand All @@ -1058,10 +1061,14 @@ inline bool I2SClass::_give_mux(){
return true;
}


// Fixes data in-situ received from esp i2s driver. After fixing they reflect what was on the bus.
// input - bytes as received from i2s_read - this serves as input and output buffer
// size - number of bytes (this may be changed during operation)
// In 8 bit mode data are received as 16 bit number with LSB padded with 0s and actual data on MSB,
// this function removes the padding (shrinking the size to 1/2)
// In 16 bit mode data are received with wrong endianity, this function swaps the bytes
// In 24 bit mode - not tested if needs fixing.
// In 32 bit mode data are ok - no action is performed.
void I2SClass::_post_read_data_fix(void *input, size_t *size){
ulong dst_ptr = 0;
switch(_bitsPerSample){
Expand Down Expand Up @@ -1174,7 +1181,6 @@ void I2SClass::_fix_and_write(void *output, size_t size, size_t *bytes_written,
}
}


#if (SOC_I2S_SUPPORTS_ADC && SOC_I2S_SUPPORTS_DAC)
int I2SClass::_gpioToAdcUnit(gpio_num_t gpio_num, esp_i2s::adc_unit_t* adc_unit){
switch(gpio_num){
Expand Down
10 changes: 4 additions & 6 deletions libraries/I2S/src/I2S.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,23 +285,23 @@ class I2SClass : public Stream
* Write single sample of 8 bit size.
* This function is blocking - if there is not enough space in ring buffer the function will wait until it can write the sample.
* Parameter:
* uint8_t data The sample to be sent
* uint8_t sample The sample to be sent
* Returns: 1 on successful write; 0 on error = did not write the sample to ring buffer
* Note: This functions is used in many examples for it's simplicity, but it's use is discouraged for performance reasons.
* Please consider sending data in arrays using function `size_t write(const uint8_t *buffer, size_t size)`
*/
virtual size_t write(uint8_t data);
virtual size_t write(uint8_t sample);

/*
* Write single sample of up to 32 bit size.
* This function is blocking - if there is not enough space in ring buffer the function will wait until it can write the sample.
* Parameter:
* int32_t data The sample to be sent
* int32_t sample The sample to be sent
* Returns: Number of written bytes, if successful the value will be equal to bitsPerSample/8
* Note: This functions is used in many examples for it's simplicity, but it's use is discouraged for performance reasons.
* Please consider sending data in arrays using function `size_t write(const uint8_t *buffer, size_t size)`
*/
size_t write(int32_t);
size_t write(int32_t sample);

/*
* Write array of samples.
Expand Down Expand Up @@ -461,8 +461,6 @@ class I2SClass : public Stream
uint32_t _sampleRate;
int _mode;

uint16_t _buffer_byte_size;

bool _driverInstalled; // Is IDF I2S driver installed?
bool _initialized; // Is everything initialized (callback task, I2S driver, ring buffers)?
TaskHandle_t _callbackTaskHandle;
Expand Down