1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-21 10:26:06 +03:00

Add 24-bit mode to I2S (#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 #5244 (the HW doesn't support 8 or 32 bits, only 16 or 24).
This commit is contained in:
Earle F. Philhower, III 2021-01-23 14:40:29 -08:00 committed by GitHub
parent b3fe0aab19
commit e0cfb5a995
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 1 deletions

View File

@ -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
@ -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;
@ -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;
@ -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
@ -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

View File

@ -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.
@ -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);