Skip to content

Commit

Permalink
Add 24-bit mode to I2S (esp8266#7835)
Browse files Browse the repository at this point in the history
Add basic 24 bit mode to the I2S API with a i2s_set_bits() call.
By default 16b mode is still used, but if i2s_set_bits(24) is run
before i2s_begin() then the HW will drive 24-bits of data.  This
data must be left-aligned (i.e. bits 31..8) in 4-byte samples.

Fixes esp8266#5244 (the HW doesn't support 8 or 32 bits, only 16 or 24).
  • Loading branch information
earlephilhower committed Jan 23, 2021
1 parent b3fe0aa commit e0cfb5a
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 1 deletion.
17 changes: 16 additions & 1 deletion cores/esp8266/core_esp8266_i2s.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ static i2s_state_t *tx = NULL;

// Last I2S sample rate requested
static uint32_t _i2s_sample_rate;
static int _i2s_bits = 16;

// IOs used for I2S. Not defined in i2s.h, unfortunately.
// Note these are internal GPIO numbers and not pins on an
Expand All @@ -84,6 +85,14 @@ static uint32_t _i2s_sample_rate;
#define I2SI_BCK 13
#define I2SI_WS 14

bool i2s_set_bits(int bits) {
if (tx || rx || (bits != 16 && bits != 24)) {
return false;
}
_i2s_bits = bits;
return true;
}

static bool _i2s_is_full(const i2s_state_t *ch) {
if (!ch) {
return false;
Expand Down Expand Up @@ -441,7 +450,7 @@ void i2s_set_rate(uint32_t rate) { //Rate in HZ
}
_i2s_sample_rate = rate;

uint32_t scaled_base_freq = I2SBASEFREQ/32;
uint32_t scaled_base_freq = I2SBASEFREQ / (_i2s_bits * 2);
float delta_best = scaled_base_freq;

uint8_t sbd_div_best=1;
Expand Down Expand Up @@ -483,6 +492,9 @@ void i2s_set_dividers(uint8_t div1, uint8_t div2) {
// div1, div2 = Set I2S WS clock frequency. BCLK seems to be generated from 32x this
i2sc_temp |= I2SRF | I2SMR | I2SRMS | I2STMS | (div1 << I2SBD) | (div2 << I2SCD);

// Adjust the shift count for 16/24b output
i2sc_temp |= (_i2s_bits == 24 ? 8 : 0) << I2SBM;

I2SC = i2sc_temp;

i2sc_temp &= ~(I2STXR); // Release reset
Expand Down Expand Up @@ -549,6 +561,9 @@ bool i2s_rxtxdrive_begin(bool enableRx, bool enableTx, bool driveRxClocks, bool

// I2STXFMM, I2SRXFMM=0 => 16-bit, dual channel data shifted in/out
I2SFC &= ~(I2SDE | (I2STXFMM << I2STXFM) | (I2SRXFMM << I2SRXFM)); // Set RX/TX FIFO_MOD=0 and disable DMA (FIFO only)
if (_i2s_bits == 24) {
I2SFC |= (2 << I2STXFM) | (2 << I2SRXFM);
}
I2SFC |= I2SDE; // Enable DMA

// I2STXCMM, I2SRXCMM=0 => Dual channel mode
Expand Down
5 changes: 5 additions & 0 deletions cores/esp8266/i2s.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
How does this work? Basically, to get sound, you need to:
- Connect an I2S codec to the I2S pins on the ESP.
- Start up a thread that's going to do the sound output
- Call i2s_set_bits() if you want to enable 24-bit mode
- Call i2s_begin()
- Call i2s_set_rate() with the sample rate you want.
- Generate sound and call i2s_write_sample() with 32-bit samples.
Expand All @@ -42,6 +43,10 @@ speed.
extern "C" {
#endif

bool i2s_set_bits(int bits); // Set bits per sample, only 16 or 24 supported. Call before begin.
// Note that in 24 bit mode each sample must be left-aligned (i.e. 0x00000000 .. 0xffffff00) as the
// hardware shifts starting at bit 31, not bit 23.

void i2s_begin(); // Enable TX only, for compatibility
bool i2s_rxtx_begin(bool enableRx, bool enableTx); // Allow TX and/or RX, returns false on OOM error
bool i2s_rxtxdrive_begin(bool enableRx, bool enableTx, bool driveRxClocks, bool driveTxClocks);
Expand Down

0 comments on commit e0cfb5a

Please sign in to comment.