Skip to content

[FEATURE] Basic implementation of Arduino's I2S library #5304

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

Merged
merged 107 commits into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
185b7ef
[FEATURE] Basic implementation of Arduino's I2S library
PilnyTomas Jun 18, 2021
2aabfb7
[MAINTENANCE] Added I2S to CMakeLists
PilnyTomas Jun 18, 2021
ca6f456
[MAINTENANCE] Joined task blocking (i2s event queue + kill command)
PilnyTomas Jun 18, 2021
32043fc
Merge branch 'espressif:master' into arduino_i2s
PilnyTomas Jun 18, 2021
a3309d4
[FEATURE] Added functions to set pins for both Input and Output
PilnyTomas Jun 21, 2021
3ad6d36
[FEATURE] Added new example demonstrating usage of callbacks
PilnyTomas Jun 24, 2021
12d926f
[MAINTENANCE] Minor changes
PilnyTomas Jun 28, 2021
d7eb3f3
[BACKUP] Work in progress on overlaying buffer (crashing)
PilnyTomas Jul 7, 2021
ad2c540
[BUGFIX] Fixed data type which was causing crashes
PilnyTomas Jul 7, 2021
baff65d
[BUGFIX] Fixed usage of new buffer in read function
PilnyTomas Jul 8, 2021
f366160
[BACKUP] Latest experiments with internal buffer
PilnyTomas Jul 23, 2021
370dd9f
Merge branch 'master' into arduino_i2s
PilnyTomas Jul 28, 2021
7a64d97
[BUGFIX] Fixed merging error in CMakeLists
PilnyTomas Jul 28, 2021
ee969b8
Improved quality of playback
PilnyTomas Jul 30, 2021
5b65b5d
Reimplemented input buffer as ring buffer
PilnyTomas Aug 3, 2021
f0ebf2b
Fixed kill semaphore error; added pin getters/setters
PilnyTomas Aug 5, 2021
a86a32b
Returning accidentally removed mutex give
PilnyTomas Aug 5, 2021
97102fe
Increased DMA buffer size for better performance
PilnyTomas Aug 5, 2021
83bb448
Split begin; changed pin setups and duplex/simplex setup
PilnyTomas Aug 13, 2021
5bb5090
Initial implementation of PDM support (untested)
PilnyTomas Aug 18, 2021
1073b60
Merge branch 'master' into arduino_i2s
PilnyTomas Aug 18, 2021
fbfe7c7
Added esp-dsp in CMakeLists.txt to compile in IDF
PilnyTomas Aug 20, 2021
9cb2d3d
Pre-release changes
PilnyTomas Sep 1, 2021
3bdb4e5
Extended SimpleTone example with DAC settings
PilnyTomas Sep 2, 2021
8c8d357
Removed ArduinoSound from CMakeLists
PilnyTomas Sep 2, 2021
adb66dc
[FEATURE] Basic implementation of Arduino's I2S library
PilnyTomas Jun 18, 2021
4577331
[MAINTENANCE] Added I2S to CMakeLists
PilnyTomas Jun 18, 2021
13a988c
[MAINTENANCE] Joined task blocking (i2s event queue + kill command)
PilnyTomas Jun 18, 2021
019490c
[FEATURE] Added functions to set pins for both Input and Output
PilnyTomas Jun 21, 2021
b18cb31
[FEATURE] Added new example demonstrating usage of callbacks
PilnyTomas Jun 24, 2021
d5a66dd
[MAINTENANCE] Minor changes
PilnyTomas Jun 28, 2021
64a3bb2
[BACKUP] Work in progress on overlaying buffer (crashing)
PilnyTomas Jul 7, 2021
992c80a
[BUGFIX] Fixed data type which was causing crashes
PilnyTomas Jul 7, 2021
64bd076
[BUGFIX] Fixed usage of new buffer in read function
PilnyTomas Jul 8, 2021
635dc5a
[BACKUP] Latest experiments with internal buffer
PilnyTomas Jul 23, 2021
d84057b
Improved quality of playback
PilnyTomas Jul 30, 2021
7da54b8
Reimplemented input buffer as ring buffer
PilnyTomas Aug 3, 2021
d5a3a05
Fixed kill semaphore error; added pin getters/setters
PilnyTomas Aug 5, 2021
f95fdb6
Returning accidentally removed mutex give
PilnyTomas Aug 5, 2021
8d99a4d
Increased DMA buffer size for better performance
PilnyTomas Aug 5, 2021
8519d67
Split begin; changed pin setups and duplex/simplex setup
PilnyTomas Aug 13, 2021
b0d45ce
Initial implementation of PDM support (untested)
PilnyTomas Aug 18, 2021
f45e5ba
Added esp-dsp in CMakeLists.txt to compile in IDF
PilnyTomas Aug 20, 2021
cb6da04
Pre-release changes
PilnyTomas Sep 1, 2021
cdf3a7c
Extended SimpleTone example with DAC settings
PilnyTomas Sep 2, 2021
991f54c
Removed ArduinoSound from CMakeLists
PilnyTomas Sep 2, 2021
2270f4c
Merging CMakeLists
PilnyTomas Sep 2, 2021
9fd0042
ESP32-S2 support
PilnyTomas Sep 2, 2021
7b77310
Removed excessive I2S from CMakeLists
PilnyTomas Sep 3, 2021
b3fdeec
Variable pin for ADC
PilnyTomas Sep 20, 2021
cde002f
Fixed data types for sample_rate inconsistent with IDF i2s driver
PilnyTomas Sep 21, 2021
14e2c7f
Fixed #ifdef to #if
PilnyTomas Sep 21, 2021
2645cf4
Fixed forgotten #ifdef to #if
PilnyTomas Sep 21, 2021
545d916
Merge branch 'master' into arduino_i2s
SuGlider Sep 21, 2021
80f49da
Updated Keywords
PilnyTomas Sep 22, 2021
139aef3
GPIO to ADC conversion methods wrapped in ADC support #if
PilnyTomas Sep 22, 2021
1d481e9
Added .skip.esp32c3 files untill C3 is supported
PilnyTomas Sep 22, 2021
ca0887b
All private functions have now underscore preceeding their name
PilnyTomas Sep 22, 2021
2dfab5f
Proposed wrapping functions for thread safety
PilnyTomas Sep 22, 2021
83d5094
Small fix: Added new function as class member
PilnyTomas Sep 23, 2021
28e6947
Applied nesting locks to all public functions
PilnyTomas Sep 23, 2021
a8727ad
Added aditional checks
PilnyTomas Sep 29, 2021
b1e1387
Added thread safety example
PilnyTomas Sep 30, 2021
39372eb
Thread safety example: Added 2 tasks to use more public functions
PilnyTomas Sep 30, 2021
23e65bd
Mono channel support
PilnyTomas Oct 8, 2021
7914492
FullDuplex changed + added example
PilnyTomas Oct 11, 2021
a65dad7
Merge branch 'master' into arduino_i2s
PilnyTomas Oct 13, 2021
f61e30d
Minor changes to FullDuplex example
PilnyTomas Oct 13, 2021
ba155a5
Added support for 8 bps
PilnyTomas Oct 13, 2021
4bc2633
Moved driver install before ringbuffer init
PilnyTomas Oct 13, 2021
ea037b1
BugFix - return was called before mutex release in read
PilnyTomas Oct 13, 2021
0b66402
Changed #if constants for PDM and ADC/DAC
PilnyTomas Oct 14, 2021
660656f
BugFix: forgotten init flag rise for PDM mode during init + #if const…
PilnyTomas Oct 14, 2021
9da5942
bugfix: Changes on the i2s_set_clk and DMA size
pedrominatel Oct 21, 2021
ef1a825
bugfix: Reverted the DMA buffer and fix on the i2s_set_clk for Philli…
pedrominatel Oct 22, 2021
a56be41
Split PDM modes to mono and stereo + renamed ADC mode
PilnyTomas Oct 25, 2021
3f9458c
Modified internal initialization flags and checks
PilnyTomas Oct 25, 2021
d7f6f6e
Merge branch 'master' into arduino_i2s
PilnyTomas Oct 26, 2021
5e4c7a4
Merge branch 'master' into arduino_i2s
PilnyTomas Nov 16, 2021
0e9d34e
Single-sample writes are now blocking (same as Arduino)
PilnyTomas Nov 19, 2021
0e478b9
removed kill sempahore for callback task deletion
PilnyTomas Nov 19, 2021
4cc4e26
added few more checks
PilnyTomas Nov 19, 2021
3dfa490
Removed Callback locks
PilnyTomas Nov 22, 2021
35ec3e4
Implemented peek
PilnyTomas Nov 22, 2021
90232a9
Merge branch 'master' into arduino_i2s
PilnyTomas Nov 22, 2021
5d786e7
Bugfix - check if task exists before deleteing
PilnyTomas Nov 23, 2021
39bfd11
Added draft for unit tests
PilnyTomas Nov 25, 2021
8af5b2a
Merge branch 'arduino_i2s' of github.com:PilnyTomas/arduino-esp32 int…
PilnyTomas Nov 25, 2021
262b18e
Basic UART comm for unit tests
PilnyTomas Nov 26, 2021
0afe17c
Work In Progress on I2S data transfer
PilnyTomas Dec 2, 2021
cd2c8c8
Work In Progress on data fix function
PilnyTomas Dec 8, 2021
395fb08
Fixed WDT
PilnyTomas Jan 4, 2022
6420fad
Removed unsupported examples and unit tests
PilnyTomas Jan 6, 2022
cedff7d
Initial code polish
PilnyTomas Jan 6, 2022
a73a1a6
fixes buffer size - no noise now
SuGlider Jan 6, 2022
29b05a3
Fix free bug for 24 and 32 bps; add warning to unsupported modes
PilnyTomas Jan 6, 2022
5b98d71
Merge branch 'master' into arduino_i2s
PilnyTomas Jan 6, 2022
e1dc00e
Initial documentation of I2S lib
PilnyTomas Jan 18, 2022
e883358
Modifications to I2S doc
PilnyTomas Jan 19, 2022
d02f392
Updates and small fixes - slave mode, pins,...
PilnyTomas Jan 19, 2022
459ed79
Structure review and syntax fixes
pedrominatel Feb 1, 2022
28d6871
Merge branch 'master' into arduino_i2s
pedrominatel Feb 1, 2022
6591f5b
Fix replace() failing (#6224)
s-hadinger Feb 3, 2022
1046f59
Upload to the component registry (#6203)
magicarm22 Feb 3, 2022
bb4d902
add feather esp32 v2 and qtpy c3 board def (#6223)
ladyada Feb 3, 2022
9b066ea
Added dual antenna for WiFi (based on the ESP32-WROOM-DA module) (#6226)
pedrominatel Feb 3, 2022
5a13725
Merge branch 'espressif:master' into arduino_i2s
PilnyTomas Feb 4, 2022
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
Pre-release changes
  • Loading branch information
PilnyTomas committed Sep 1, 2021
commit 9cb2d3d14affdbfd6ca87be7d5e267aca66a4f61
239 changes: 137 additions & 102 deletions libraries/I2S/src/I2S.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include "I2S.h"
#include "freertos/semphr.h"


#define _I2S_EVENT_QUEUE_LENGTH 16
#define _I2S_DMA_BUFFER_COUNT 4 // BUFFER COUNT must be between 2 and 128
#define I2S_INTERFACES_COUNT SOC_I2S_NUM
Expand Down Expand Up @@ -94,7 +93,7 @@ I2SClass::I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t inSdPin,

int I2SClass::createCallbackTask()
{
int stack_size = 15000;
int stack_size = 10000;
if(_callbackTaskHandle == NULL){
if(_task_kill_cmd_semaphore_handle == NULL){
_task_kill_cmd_semaphore_handle = xSemaphoreCreateBinary();
Expand Down Expand Up @@ -129,9 +128,7 @@ void I2SClass::destroyCallbackTask()
}
vSemaphoreDelete(_task_kill_cmd_semaphore_handle); // delete semaphore after usage
_task_kill_cmd_semaphore_handle = NULL; // prevent usage of uninitialized (deleted) semaphore
}else{ // callback handle check
log_e("Could not destroy callback");
}
} // callback handle check
}

int I2SClass::_installDriver(){
Expand Down Expand Up @@ -187,17 +184,19 @@ int I2SClass::_installDriver(){
.dma_buf_count = _I2S_DMA_BUFFER_COUNT,
.dma_buf_len = _i2s_dma_buffer_size
};

if(ESP_OK != esp_i2s::i2s_driver_install((esp_i2s::i2s_port_t) _deviceIndex, &i2s_config, _I2S_EVENT_QUEUE_LENGTH, &_i2sEventQueue)){ // Install and start i2s driver
log_e("ERROR could not install i2s driver");
return 0; // ERR
}
if(_i2sEventQueue == NULL){
log_e("ERROR i2s driver did not create event queue");
//return 0; // ERR
}else{
log_d("DEBUG MSG i2s event queue exists");
}
// Install and start i2s driver
while(ESP_OK != esp_i2s::i2s_driver_install((esp_i2s::i2s_port_t) _deviceIndex, &i2s_config, _I2S_EVENT_QUEUE_LENGTH, &_i2sEventQueue)){
// double buffer size
log_w("WARNING i2s driver install failed; Trying to increase I2S DMA buffer size from %d to %d\n", _i2s_dma_buffer_size, 2*_i2s_dma_buffer_size);
if(2*_i2s_dma_buffer_size <= 1024){
setBufferSize(2*_i2s_dma_buffer_size);
}else if(_i2s_dma_buffer_size < 1024){
setBufferSize(1024);
}else{
log_e("ERROR i2s driver install failed");
return 0; // ERR
}
} //try installing with increasing size

if(_mode == I2S_ADC_DAC){
esp_i2s::adc_unit_t adc_unit = (esp_i2s::adc_unit_t) 1;
Expand All @@ -224,7 +223,7 @@ int I2SClass::_installDriver(){
return 1; // OK
}

int I2SClass::begin(int mode, long sampleRate, int bitsPerSample)
int I2SClass::begin(int mode, int sampleRate, int bitsPerSample)
{
// master mode (driving clock and frame select pins - output)
return begin(mode, sampleRate, bitsPerSample, true);
Expand All @@ -233,14 +232,14 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample)
int I2SClass::begin(int mode, int bitsPerSample)
{
log_e("ERROR I2SClass::begin Audio in Slave mode is not implemented for ESP\n\
Note: If it is NOT your intention to initialize in slave mode, you are probably missing <sampleRate> parameter - see the declaration below\
Note: If it is NOT your intention to initialize in slave mode, you are probably missing <sampleRate> parameter - see the declaration below\n\
\tint I2SClass::begin(int mode, long sampleRate, int bitsPerSample)");
return 0; // ERR
// slave mode (not driving clock and frame select pin - input)
//return begin(mode, 0, bitsPerSample, false);
}

int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveClock)
int I2SClass::begin(int mode, int sampleRate, int bitsPerSample, bool driveClock)
{
if(_initialized){
end();
Expand Down Expand Up @@ -279,10 +278,12 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
}

if(!_installDriver()){
_initialized = false;
return 0; // ERR
}

if(!createCallbackTask()){
_initialized = false;
return 0; // ERR
}

Expand Down Expand Up @@ -389,21 +390,11 @@ int I2SClass::setAllPins(int sckPin, int fsPin, int inSdPin, int outSdPin){
}

int I2SClass::setDuplex(){
/*
if(_inSdPin < 0 || _outSdPin < 0){
log_e("I2S cannot set Duplex - one or both pins not set\n input pin = %d\toutput pin = %d", _inSdPin, _outSdPin);
return 0; // ERR
}
*/
_state = I2S_STATE_DUPLEX;
return 1;
}

int I2SClass::setSimplex(){
if(_sdPin < 0){
log_e("I2S cannot set Simplex - shared data pin is not set\n data pin = %d", _sdPin);
return 0; // ERR
}
_state = I2S_STATE_IDLE;
return 1;
}
Expand Down Expand Up @@ -432,9 +423,15 @@ int I2SClass::getDataOutPin(){
return _outSdPin;
}

int I2SClass::_uninstallDriver(){
// TODO
return 1; // Ok
void I2SClass::_uninstallDriver(){
if(_mode == I2S_ADC_DAC){
esp_i2s::i2s_adc_disable((esp_i2s::i2s_port_t) _deviceIndex);
}
esp_i2s::i2s_driver_uninstall((esp_i2s::i2s_port_t) _deviceIndex);

if(_state != I2S_STATE_DUPLEX){
_state = I2S_STATE_IDLE;
}
}

void I2SClass::end()
Expand All @@ -443,15 +440,8 @@ void I2SClass::end()
destroyCallbackTask();

if(_initialized){

if(_mode == I2S_ADC_DAC){
esp_i2s::i2s_adc_disable((esp_i2s::i2s_port_t) _deviceIndex);
}
esp_i2s::i2s_driver_uninstall((esp_i2s::i2s_port_t) _deviceIndex);
_uninstallDriver();
_initialized = false;
if(_state != I2S_STATE_DUPLEX){
_state = I2S_STATE_IDLE;
}
}
_onTransmit = NULL;
_onReceive = NULL;
Expand Down Expand Up @@ -538,20 +528,49 @@ size_t I2SClass::write(const uint8_t *buffer, size_t size)
return write((const void*)buffer, size);
}

size_t I2SClass::write(const void *buffer, size_t size)
// blocking version of write
// TODO add timeout
size_t I2SClass::write_blocking(const void *buffer, size_t size)
{
if (_state != I2S_STATE_TRANSMITTER && _state != I2S_STATE_DUPLEX) {
if(!enableTransmitter()){
return 0; // There was an error switching to transmitter
}
}
// TODO add timeout
while(availableForWrite() < size){
yield();
}
if(pdTRUE == xRingbufferSend(_output_ring_buffer, buffer, size, 10)){
return size;
}else{
return 0;
}
}

// non-blocking version of write
size_t I2SClass::write_nonblocking(const void *buffer, size_t size)
{
if (_state != I2S_STATE_TRANSMITTER && _state != I2S_STATE_DUPLEX) {
if(!enableTransmitter()){
return 0; // There was an error switching to transmitter
}
}
if(availableForWrite() < size){
flush();
}
if(pdTRUE == xRingbufferSend(_output_ring_buffer, buffer, size, 10)){
return size;
}else{
return 0;
}
}

size_t I2SClass::write(const void *buffer, size_t size){
//return write_blocking(buffer, size);
return write_nonblocking(buffer, size);
}

int I2SClass::peek()
{
// TODO
Expand Down Expand Up @@ -596,10 +615,9 @@ int I2SClass::setBufferSize(int bufferSize)
if(bufferSize >= 8 && bufferSize <= 1024){
_i2s_dma_buffer_size = bufferSize;
if(_initialized){
end();
return begin(_mode, _sampleRate, _bitsPerSample, _driveClock);
_uninstallDriver();
return _installDriver();
}

return 1; // OK
}else{
return 0; // ERR
Expand Down Expand Up @@ -628,84 +646,101 @@ int I2SClass::enableReceiver()
return 1; // Ok
}

void I2SClass::_tx_done_routine(uint8_t* prev_item){
static bool prev_item_valid = false;
const size_t single_dma_buf = _i2s_dma_buffer_size*(_bitsPerSample/8);
static size_t item_size = 0;
static size_t prev_item_size = 0;
static void *item = NULL;
static int prev_item_offset = 0;
static size_t bytes_written;

if(prev_item_valid){ // use item from previous round
esp_i2s::i2s_write((esp_i2s::i2s_port_t) _deviceIndex, prev_item+prev_item_offset, prev_item_size, &bytes_written, 0);
if(prev_item_size == bytes_written){
prev_item_valid = false;
} // write size check
prev_item_offset = bytes_written;
prev_item_size -= bytes_written;
} // prev_item_valid

if(_buffer_byte_size - xRingbufferGetCurFreeSize(_output_ring_buffer) >= single_dma_buf){ // fill up the I2S DMA buffer
bytes_written = 0;
item_size = 0;
//if(_buffer_byte_size - xRingbufferGetCurFreeSize(_output_ring_buffer) >= _i2s_dma_buffer_size*(_bitsPerSample/8)){ // don't read from almost empty buffer
item = xRingbufferReceiveUpTo(_output_ring_buffer, &item_size, pdMS_TO_TICKS(1000), single_dma_buf);
if (item != NULL){
esp_i2s::i2s_write((esp_i2s::i2s_port_t) _deviceIndex, item, item_size, &bytes_written, 0);
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

if(_onTransmit){
_onTransmit();
} // user callback
}

void I2SClass::_rx_done_routine(){
static size_t bytes_read;
const size_t single_dma_buf = _i2s_dma_buffer_size*(_bitsPerSample/8);
uint8_t *_inputBuffer = (uint8_t*)malloc(_i2s_dma_buffer_size*4);

size_t avail = xRingbufferGetCurFreeSize(_input_ring_buffer);
esp_i2s::i2s_read((esp_i2s::i2s_port_t) _deviceIndex, _inputBuffer, avail <= single_dma_buf ? avail : single_dma_buf, (size_t*) &bytes_read, 0);
if(pdTRUE != xRingbufferSend(_input_ring_buffer, _inputBuffer, bytes_read, 0)){
log_w("I2S failed to send item from DMA to internal buffer\n");
}else{
if (_onReceive) {
_onReceive();
} // user callback
} // xRingbufferSendComplete
free(_inputBuffer);
}


void I2SClass::onTransferComplete()
{
uint8_t prev_item[_i2s_dma_buffer_size*4];
static QueueSetHandle_t xQueueSet;
const size_t single_dma_buf = _i2s_dma_buffer_size*(_bitsPerSample/8);
QueueSetMemberHandle_t xActivatedMember;
esp_i2s::i2s_event_type_t i2s_event;
size_t item_size = 0;
size_t prev_item_size = 0;
void *item = NULL;
bool prev_item_valid = false;
size_t bytes_written, bytes_read;
int prev_item_offset = 0;
uint8_t prev_item[_i2s_dma_buffer_size*4];
uint8_t _inputBuffer[_i2s_dma_buffer_size*4];

esp_i2s::i2s_event_t i2s_event;
xQueueSet = xQueueCreateSet(sizeof(i2s_event)*_I2S_EVENT_QUEUE_LENGTH + 1);
configASSERT(xQueueSet);
configASSERT(_i2sEventQueue);
xQueueAddToSet(_i2sEventQueue, xQueueSet);
xQueueAddToSet(_task_kill_cmd_semaphore_handle, xQueueSet);

while(true){
xActivatedMember = xQueueSelectFromSet(xQueueSet, portMAX_DELAY);
//xActivatedMember = xQueueSelectFromSet(xQueueSet, portMAX_DELAY); // defaul
xActivatedMember = xQueueSelectFromSet(xQueueSet, 5); // hack
// TODO try just queue receive at the timeout
if(xActivatedMember == _task_kill_cmd_semaphore_handle){
xSemaphoreTake(_task_kill_cmd_semaphore_handle, 0);
break; // from the infinite loop
}else if(xActivatedMember == _i2sEventQueue){
xQueueReceive(_i2sEventQueue, &i2s_event, 0);
if(i2s_event == esp_i2s::I2S_EVENT_TX_DONE){
if(prev_item_valid){ // use item from previous round
esp_i2s::i2s_write((esp_i2s::i2s_port_t) _deviceIndex, prev_item+prev_item_offset, prev_item_size, &bytes_written, 0);
if(prev_item_size == bytes_written){
prev_item_valid = false;
} // write size check
prev_item_offset = bytes_written;
prev_item_size -= bytes_written;
} // prev_item_valid

if(_buffer_byte_size - xRingbufferGetCurFreeSize(_output_ring_buffer) >= single_dma_buf){ // fill up the I2S DMA buffer

bytes_written = 0;
item_size = 0;
item = xRingbufferReceiveUpTo(_output_ring_buffer, &item_size, pdMS_TO_TICKS(1000), single_dma_buf);
if (item != NULL){
esp_i2s::i2s_write((esp_i2s::i2s_port_t) _deviceIndex, item, item_size, &bytes_written, 0);
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

if(_onTransmit){
_onTransmit();
} // user callback

}else if(i2s_event == esp_i2s::I2S_EVENT_RX_DONE){
size_t avail = xRingbufferGetCurFreeSize(_input_ring_buffer);
esp_i2s::i2s_read((esp_i2s::i2s_port_t) _deviceIndex, _inputBuffer, avail <= single_dma_buf ? avail : single_dma_buf, (size_t*) &bytes_read, 0);
if(pdTRUE != xRingbufferSend(_input_ring_buffer, _inputBuffer, bytes_read, 0)){
log_w("I2S failed to send item from DMA to internal buffer\n");
}else{
if (_onReceive) {
_onReceive();
} // user callback
} // xRingbufferSendComplete
} // RX Done
} // Queue set (I2S event or kill command)
//}else if(xActivatedMember == _i2sEventQueue){ // default
}else if(xActivatedMember == _i2sEventQueue || xActivatedMember == NULL){ // hack
if(uxQueueMessagesWaiting(_i2sEventQueue)){
xQueueReceive(_i2sEventQueue, &i2s_event, 0);
if(i2s_event.type == esp_i2s::I2S_EVENT_TX_DONE){
_tx_done_routine(prev_item);
}else if(i2s_event.type == esp_i2s::I2S_EVENT_RX_DONE){
_rx_done_routine();
} // RX Done
} // queue not empty
}else{
}
} // infinite loop
_callbackTaskHandle = NULL; // prevent secondary termination to non-existing task
}

void I2SClass::onDmaTransferComplete(void*)
{

I2S.onTransferComplete();
vTaskDelete(NULL);
}
Expand Down
Loading