Skip to content

Commit

Permalink
i2s can send now buffers (esp8266#5349)
Browse files Browse the repository at this point in the history
* i2s can send now buffers

* adding mono and stereo, with blocking and non blocking support

* fixing crash

* cosmetic changes

* we dont need the & 0xffff

* using unsigned integers since we'll never be using negative numbers
  • Loading branch information
aguaviva authored and devyte committed Nov 24, 2018
1 parent 19a0a0b commit cf21dfd
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 5 deletions.
74 changes: 71 additions & 3 deletions cores/esp8266/core_esp8266_i2s.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,18 @@ bool i2s_rx_is_empty() {
return _i2s_is_empty( rx );
}

static int16_t _i2s_available(const i2s_state_t *ch) {
static uint16_t _i2s_available(const i2s_state_t *ch) {
if (!ch) {
return 0;
}
return (SLC_BUF_CNT - ch->slc_queue_len) * SLC_BUF_LEN;
}

int16_t i2s_available(){
uint16_t i2s_available(){
return _i2s_available( tx );
}

int16_t i2s_rx_available(){
uint16_t i2s_rx_available(){
return _i2s_available( rx );
}

Expand Down Expand Up @@ -331,6 +331,74 @@ bool i2s_write_lr(int16_t left, int16_t right){
return i2s_write_sample(sample);
}

// writes a buffer of frames into the DMA memory, returns the amount of frames written
// A frame is just a int16_t for mono, for stereo a frame is two int16_t, one for each channel.
static uint16_t _i2s_write_buffer(int16_t *frames, uint16_t frame_count, bool mono, bool nb) {
uint16_t frames_written=0;

while(frame_count>0) {

// make sure we have room in the current buffer
if (tx->curr_slc_buf_pos==SLC_BUF_LEN || tx->curr_slc_buf==NULL) {
// no room in the current buffer? if there are no buffers available then exit
if (tx->slc_queue_len == 0)
{
if (nb) {
// if nonblocking just return the number of frames written so far
break;
}
else {
while (1) {
if (tx->slc_queue_len > 0) {
break;
} else {
optimistic_yield(10000);
}
}
}
}

// get a new buffer
ETS_SLC_INTR_DISABLE();
tx->curr_slc_buf = (uint32_t *)i2s_slc_queue_next_item(tx);
ETS_SLC_INTR_ENABLE();
tx->curr_slc_buf_pos=0;
}

//space available in the current buffer
uint16_t available = SLC_BUF_LEN - tx->curr_slc_buf_pos;

uint16_t fc = (available < frame_count) ? available : frame_count;

if (mono) {
for(uint16_t i=0;i<fc;i++){
uint16_t v = (uint16_t)(*frames++);
tx->curr_slc_buf[tx->curr_slc_buf_pos++] = (v << 16) | v;
}
}
else
{
for(uint16_t i=0;i<fc;i++){
uint16_t v1 = (uint16_t)(*frames++);
uint16_t v2 = (uint16_t)(*frames++);
tx->curr_slc_buf[tx->curr_slc_buf_pos++] = (v1 << 16) | v2;
}
}

frame_count -= fc;
frames_written += fc;
}
return frames_written;
}

uint16_t i2s_write_buffer_mono_nb(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, true); }

uint16_t i2s_write_buffer_mono(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, true, false); }

uint16_t i2s_write_buffer_nb(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, true); }

uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count) { return _i2s_write_buffer(frames, frame_count, false, false); }

bool i2s_read_sample(int16_t *left, int16_t *right, bool blocking) {
if (!rx) {
return false;
Expand Down
11 changes: 9 additions & 2 deletions cores/esp8266/i2s.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,18 @@ bool i2s_is_full();//returns true if DMA is full and can not take more bytes (ov
bool i2s_is_empty();//returns true if DMA is empty (underflow)
bool i2s_rx_is_full();
bool i2s_rx_is_empty();
int16_t i2s_available();// returns the number of samples than can be written before blocking
int16_t i2s_rx_available();// returns the number of samples than can be written before blocking
uint16_t i2s_available();// returns the number of samples than can be written before blocking
uint16_t i2s_rx_available();// returns the number of samples than can be written before blocking
void i2s_set_callback(void (*callback) (void));
void i2s_rx_set_callback(void (*callback) (void));

// writes a buffer of frames into the DMA memory, returns the amount of frames written
// A frame is just a int16_t for mono, for stereo a frame is two int16_t, one for each channel.
uint16_t i2s_write_buffer_mono(int16_t *frames, uint16_t frame_count);
uint16_t i2s_write_buffer_mono_nb(int16_t *frames, uint16_t frame_count);
uint16_t i2s_write_buffer(int16_t *frames, uint16_t frame_count);
uint16_t i2s_write_buffer_nb(int16_t *frames, uint16_t frame_count);

#ifdef __cplusplus
}
#endif
Expand Down

0 comments on commit cf21dfd

Please sign in to comment.