Skip to content

Commit e0cfb5a

Browse files
Add 24-bit mode to I2S (esp8266#7835)
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).
1 parent b3fe0aa commit e0cfb5a

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

cores/esp8266/core_esp8266_i2s.cpp

+16-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ static i2s_state_t *tx = NULL;
7373

7474
// Last I2S sample rate requested
7575
static uint32_t _i2s_sample_rate;
76+
static int _i2s_bits = 16;
7677

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

88+
bool i2s_set_bits(int bits) {
89+
if (tx || rx || (bits != 16 && bits != 24)) {
90+
return false;
91+
}
92+
_i2s_bits = bits;
93+
return true;
94+
}
95+
8796
static bool _i2s_is_full(const i2s_state_t *ch) {
8897
if (!ch) {
8998
return false;
@@ -441,7 +450,7 @@ void i2s_set_rate(uint32_t rate) { //Rate in HZ
441450
}
442451
_i2s_sample_rate = rate;
443452

444-
uint32_t scaled_base_freq = I2SBASEFREQ/32;
453+
uint32_t scaled_base_freq = I2SBASEFREQ / (_i2s_bits * 2);
445454
float delta_best = scaled_base_freq;
446455

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

495+
// Adjust the shift count for 16/24b output
496+
i2sc_temp |= (_i2s_bits == 24 ? 8 : 0) << I2SBM;
497+
486498
I2SC = i2sc_temp;
487499

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

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

554569
// I2STXCMM, I2SRXCMM=0 => Dual channel mode

cores/esp8266/i2s.h

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
How does this work? Basically, to get sound, you need to:
2828
- Connect an I2S codec to the I2S pins on the ESP.
2929
- Start up a thread that's going to do the sound output
30+
- Call i2s_set_bits() if you want to enable 24-bit mode
3031
- Call i2s_begin()
3132
- Call i2s_set_rate() with the sample rate you want.
3233
- Generate sound and call i2s_write_sample() with 32-bit samples.
@@ -42,6 +43,10 @@ speed.
4243
extern "C" {
4344
#endif
4445

46+
bool i2s_set_bits(int bits); // Set bits per sample, only 16 or 24 supported. Call before begin.
47+
// Note that in 24 bit mode each sample must be left-aligned (i.e. 0x00000000 .. 0xffffff00) as the
48+
// hardware shifts starting at bit 31, not bit 23.
49+
4550
void i2s_begin(); // Enable TX only, for compatibility
4651
bool i2s_rxtx_begin(bool enableRx, bool enableTx); // Allow TX and/or RX, returns false on OOM error
4752
bool i2s_rxtxdrive_begin(bool enableRx, bool enableTx, bool driveRxClocks, bool driveTxClocks);

0 commit comments

Comments
 (0)