2
0
Эх сурвалжийг харах

fix spdif for s3 and remove one override

SPDIF on esp32 was partly incorrect due to word ordering and required i2s_hal override. This is not needed anymore as the "mistery" of SPDIF hack has been properly sorted out
philippe44 1 жил өмнө
parent
commit
55053d5941

+ 2 - 2
components/_override/CMakeLists.txt

@@ -1,6 +1,6 @@
 if(IDF_TARGET STREQUAL esp32 AND IDF_VERSION_MAJOR EQUAL 4 AND IDF_VERSION_MINOR LESS 4)
     set(lib_dir ${build_dir}/esp-idf)
-    set(driver esp32/i2s.c esp32/i2s_hal.c)
+    set(driver esp32/i2s.c)
     string(REPLACE ".c" ".c.obj" driver_obj "${driver}")
 
     idf_component_register( SRCS ${driver}
@@ -20,5 +20,5 @@ if(IDF_TARGET STREQUAL esp32 AND IDF_VERSION_MAJOR EQUAL 4 AND IDF_VERSION_MINOR
                 VERBATIM
     )
 else()
-    message(STATUS "==> NO I2S LIBRARY OVERRIDE, SPDIF MIGHT NOT WORK <==")
+    message(STATUS "==> NO OVERRIDE <==")
 endif()

+ 0 - 275
components/_override/esp32/i2s_hal.c

@@ -1,275 +0,0 @@
-// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// The HAL layer for I2S (common part)
-
-#include "soc/soc.h"
-#include "soc/soc_caps.h"
-#include "hal/i2s_hal.h"
-
-#define I2S_TX_PDM_FP_DEF  960   // Set to the recommended value(960) in TRM
-#define I2S_RX_PDM_DSR_DEF 0
-
-void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits)
-{
-    if (bits <= I2S_BITS_PER_SAMPLE_16BIT) {
-        i2s_ll_set_tx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
-    } else {
-        i2s_ll_set_tx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 2 : 3);
-    }
-    i2s_ll_set_tx_chan_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
-#if SOC_I2S_SUPPORTS_DMA_EQUAL
-    i2s_ll_set_tx_dma_equal(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
-#endif
-}
-
-void i2s_hal_set_rx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits)
-{
-    if (bits <= I2S_BITS_PER_SAMPLE_16BIT) {
-        i2s_ll_set_rx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
-    } else {
-        i2s_ll_set_rx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 2 : 3);
-    }
-    i2s_ll_set_rx_chan_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
-#if SOC_I2S_SUPPORTS_DMA_EQUAL
-    i2s_ll_set_rx_dma_equal(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
-#endif
-}
-
-void i2s_hal_set_in_link(i2s_hal_context_t *hal, uint32_t bytes_num, uint32_t addr)
-{
-    i2s_ll_set_in_link_addr(hal->dev, addr);
-    i2s_ll_set_rx_eof_num(hal->dev, bytes_num);
-}
-
-#if SOC_I2S_SUPPORTS_PDM
-void i2s_hal_tx_pdm_cfg(i2s_hal_context_t *hal, uint32_t fp, uint32_t fs)
-{
-    i2s_ll_tx_pdm_cfg(hal->dev, fp, fs);
-}
-
-void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, uint32_t *fp, uint32_t *fs)
-{
-    i2s_ll_get_tx_pdm(hal->dev, fp, fs);
-}
-
-void i2s_hal_rx_pdm_cfg(i2s_hal_context_t *hal, uint32_t dsr)
-{
-    i2s_ll_rx_pdm_cfg(hal->dev, dsr);
-}
-
-void i2s_hal_get_rx_pdm(i2s_hal_context_t *hal, uint32_t *dsr)
-{
-    i2s_ll_get_rx_pdm(hal->dev, dsr);
-}
-#endif
-
-void i2s_hal_set_clk_div(i2s_hal_context_t *hal, int div_num, int div_a, int div_b, int tx_bck_div, int rx_bck_div)
-{
-    i2s_ll_set_clkm_div_num(hal->dev, div_num);
-    i2s_ll_set_clkm_div_a(hal->dev, div_a);
-    i2s_ll_set_clkm_div_b(hal->dev, div_b);
-    i2s_ll_set_tx_bck_div_num(hal->dev, tx_bck_div);
-    i2s_ll_set_rx_bck_div_num(hal->dev, rx_bck_div);
-}
-
-void i2s_hal_set_tx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits)
-{
-    i2s_ll_set_tx_bits_mod(hal->dev, bits);
-}
-
-void i2s_hal_set_rx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits)
-{
-    i2s_ll_set_rx_bits_mod(hal->dev, bits);
-}
-
-void i2s_hal_reset(i2s_hal_context_t *hal)
-{
-    // Reset I2S TX/RX module first, and then, reset DMA and FIFO.
-    i2s_ll_reset_tx(hal->dev);
-    i2s_ll_reset_rx(hal->dev);
-    i2s_ll_reset_dma_in(hal->dev);
-    i2s_ll_reset_dma_out(hal->dev);
-    i2s_ll_reset_rx_fifo(hal->dev);
-    i2s_ll_reset_tx_fifo(hal->dev);
-}
-
-void i2s_hal_start_tx(i2s_hal_context_t *hal)
-{
-    i2s_ll_start_out_link(hal->dev);
-    i2s_ll_start_tx(hal->dev);
-}
-
-void i2s_hal_start_rx(i2s_hal_context_t *hal)
-{
-    i2s_ll_start_in_link(hal->dev);
-    i2s_ll_start_rx(hal->dev);
-}
-
-void i2s_hal_stop_tx(i2s_hal_context_t *hal)
-{
-    i2s_ll_stop_out_link(hal->dev);
-    i2s_ll_stop_tx(hal->dev);
-}
-
-void i2s_hal_stop_rx(i2s_hal_context_t *hal)
-{
-    i2s_ll_stop_in_link(hal->dev);
-    i2s_ll_stop_rx(hal->dev);
-}
-
-void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_config_t *i2s_config)
-{
-    switch (i2s_config->communication_format) {
-        case I2S_COMM_FORMAT_STAND_MSB:
-            if (i2s_config->mode & I2S_MODE_TX) {
-                i2s_ll_set_tx_format_msb_align(hal->dev);
-            }
-            if (i2s_config->mode & I2S_MODE_RX) {
-                i2s_ll_set_rx_format_msb_align(hal->dev);
-            }
-            break;
-        case I2S_COMM_FORMAT_STAND_PCM_SHORT:
-            if (i2s_config->mode & I2S_MODE_TX) {
-                i2s_ll_set_tx_pcm_long(hal->dev);
-            }
-            if (i2s_config->mode & I2S_MODE_RX) {
-                i2s_ll_set_rx_pcm_long(hal->dev);
-            }
-            break;
-        case I2S_COMM_FORMAT_STAND_PCM_LONG:
-            if (i2s_config->mode & I2S_MODE_TX) {
-                i2s_ll_set_tx_pcm_short(hal->dev);
-            }
-            if (i2s_config->mode & I2S_MODE_RX) {
-                i2s_ll_set_rx_pcm_short(hal->dev);
-            }
-            break;
-        default: //I2S_COMM_FORMAT_STAND_I2S
-            if (i2s_config->mode & I2S_MODE_TX) {
-                i2s_ll_set_tx_format_philip(hal->dev);
-            }
-            if (i2s_config->mode & I2S_MODE_RX) {
-                i2s_ll_set_rx_format_philip(hal->dev);
-            }
-            break;
-    }
-}
-
-void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config)
-{
-    //reset i2s
-    i2s_ll_reset_tx(hal->dev);
-    i2s_ll_reset_rx(hal->dev);
-
-    //reset dma
-    i2s_ll_reset_dma_in(hal->dev);
-    i2s_ll_reset_dma_out(hal->dev);
-
-    i2s_ll_enable_dma(hal->dev);
-
-    i2s_ll_set_lcd_en(hal->dev, 0);
-    i2s_ll_set_camera_en(hal->dev, 0);
-
-    i2s_ll_set_dscr_en(hal->dev, 0);
-
-    i2s_ll_set_tx_chan_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left
-    i2s_ll_set_tx_fifo_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1); // 0-right&left channel;1-one channel
-    i2s_ll_set_tx_mono(hal->dev, 0);
-
-    i2s_ll_set_rx_chan_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left
-    i2s_ll_set_rx_fifo_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1); // 0-right&left channel;1-one channel
-    i2s_ll_set_rx_mono(hal->dev, 0);
-
-    i2s_ll_set_dscr_en(hal->dev, 1); //connect dma to fifo
-
-    i2s_ll_stop_tx(hal->dev);
-    i2s_ll_stop_rx(hal->dev);
-
-    if (i2s_config->mode & I2S_MODE_TX) {
-		int order = i2s_config->bits_per_sample == 32 ? 0 : 1;
-        i2s_ll_set_tx_msb_right(hal->dev, order);
-        i2s_ll_set_tx_right_first(hal->dev, ~order);
-
-        i2s_ll_set_tx_slave_mod(hal->dev, 0); // Master
-        i2s_ll_set_tx_fifo_mod_force_en(hal->dev, 1);
-
-        if (i2s_config->mode & I2S_MODE_SLAVE) {
-            i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave
-        }
-    }
-
-    if (i2s_config->mode & I2S_MODE_RX) {
-        i2s_ll_set_rx_msb_right(hal->dev, 0);
-        i2s_ll_set_rx_right_first(hal->dev, 0);
-        i2s_ll_set_rx_slave_mod(hal->dev, 0); // Master
-        i2s_ll_set_rx_fifo_mod_force_en(hal->dev, 1);
-
-        if (i2s_config->mode & I2S_MODE_SLAVE) {
-            i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
-        }
-    }
-
-#if SOC_I2S_SUPPORTS_PDM
-    if (!(i2s_config->mode & I2S_MODE_PDM)) {
-        i2s_ll_set_rx_pdm_en(hal->dev, 0);
-        i2s_ll_set_tx_pdm_en(hal->dev, 0);
-    } else {
-        if (i2s_config->mode & I2S_MODE_TX) {
-            i2s_ll_tx_pdm_cfg(hal->dev, I2S_TX_PDM_FP_DEF, i2s_config->sample_rate/100);
-        }
-        if(i2s_config->mode & I2S_MODE_RX) {
-            i2s_ll_rx_pdm_cfg(hal->dev, I2S_RX_PDM_DSR_DEF);
-        }
-        // PDM mode have nothing to do with communication format configuration.
-        return;
-    }
-#endif
-
-#if SOC_I2S_SUPPORTS_ADC_DAC
-    if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
-        if (i2s_config->mode & I2S_MODE_DAC_BUILT_IN) {
-            i2s_ll_build_in_dac_ena(hal->dev);
-        }
-        if (i2s_config->mode & I2S_MODE_ADC_BUILT_IN) {
-            i2s_ll_build_in_adc_ena(hal->dev);
-            i2s_ll_set_rx_chan_mod(hal->dev, 1);
-            i2s_ll_set_rx_fifo_mod(hal->dev, 1);
-            i2s_ll_set_rx_mono(hal->dev, 0);
-        }
-        // Buildin ADC and DAC have nothing to do with communication format configuration.
-        return;
-    }
-#endif
-
-    i2s_hal_format_config(hal, i2s_config);
-}
-
-void i2s_hal_enable_master_mode(i2s_hal_context_t *hal)
-{
-    i2s_ll_set_tx_slave_mod(hal->dev, 0); //MASTER Slave
-    i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
-}
-
-void i2s_hal_enable_slave_mode(i2s_hal_context_t *hal)
-{
-    i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave
-    i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
-}
-
-void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num)
-{
-    //Get hardware instance.
-    hal->dev = I2S_LL_GET_HW(i2s_num);
-}

+ 17 - 1
components/squeezelite/equalizer.c

@@ -63,7 +63,7 @@ static const float loudness_envelope_coefficients[EQ_BANDS][POLYNOME_COUNT] = {
 /****************************************************************************************
  * calculate loudness gains
  */
-static void calculate_loudness(void) {      
+static void calculate_loudness(void) {
 	for (int i = 0; i < EQ_BANDS; i++) {
 		for (int j = 0; j < POLYNOME_COUNT && equalizer.loudness != 0; j++) {
 			equalizer.loudness_gain[i] +=
@@ -109,29 +109,36 @@ void equalizer_close(void) {
  * change sample rate
  */
 void equalizer_set_samplerate(uint32_t samplerate) {
+#if BYTES_PER_FRAME == 4
     if (equalizer.samplerate != samplerate) equalizer_close();
     equalizer.samplerate = samplerate;
     equalizer.update = true;
 
     LOG_INFO("equalizer sample rate %u", samplerate);
+#else
+    LOG_INFO("no equalizer with 32 bits samples");
+#endif
 }
 
 /****************************************************************************************
  * get volume update and recalculate loudness according to
  */
 void equalizer_set_volume(unsigned left, unsigned right) {
+#if BYTES_PER_FRAME == 4
 	equalizer.volume = (left + right) / 2;
     // do classic dB conversion and scale it 0..100
 	if (equalizer.volume) equalizer.volume = log2(equalizer.volume);
 	equalizer.volume = equalizer.volume / 16.0 * 100.0;
 	calculate_loudness();
     equalizer.update = true;
+#endif
 }
 
 /****************************************************************************************
  * change gains from LMS
  */
 void equalizer_set_gain(int8_t *gain) {
+#if BYTES_PER_FRAME == 4
     char config[EQ_BANDS * 4 + 1] = { };
 	int n = 0;
 
@@ -145,12 +152,16 @@ void equalizer_set_gain(int8_t *gain) {
 	equalizer.update = true;
 
     LOG_INFO("equalizer gain %s", config);
+#else
+    LOG_INFO("no equalizer with 32 bits samples");
+#endif
 }
 
 /****************************************************************************************
  * change loudness from LMS
  */
 void equalizer_set_loudness(uint8_t loudness) {
+#if BYTES_PER_FRAME == 4
     // update loudness gains as a factor of loudness and volume
 	equalizer.loudness = loudness / 100.0;
     calculate_loudness();
@@ -161,12 +172,16 @@ void equalizer_set_loudness(uint8_t loudness) {
     equalizer.update = true;
 
     LOG_INFO("loudness %u", (unsigned) loudness);
+#else
+    LOG_INFO("no equalizer with 32 bits samples");
+#endif
 }
 
 /****************************************************************************************
  * process equalizer
  */
 void equalizer_process(uint8_t *buf, uint32_t bytes) {
+#if BYTES_PER_FRAME == 4    
 	// don't want to process with output locked, so take the small risk to miss one parametric update
 	if (equalizer.update) {
         equalizer.update = false;
@@ -198,4 +213,5 @@ void equalizer_process(uint8_t *buf, uint32_t bytes) {
 	if (equalizer.handle) {
 		esp_equalizer_process(equalizer.handle, buf, bytes, equalizer.samplerate, 2);
 	}
+#endif    
 }

+ 16 - 18
components/squeezelite/output_i2s.c

@@ -583,15 +583,11 @@ static void output_thread_i2s(void *arg) {
 			i2s_set_sample_rates(CONFIG_I2S_NUM, spdif.enabled ? i2s_config.sample_rate * 2 : i2s_config.sample_rate);
 			i2s_zero_dma_buffer(CONFIG_I2S_NUM);
 
-#if BYTES_PER_FRAME == 4		
             equalizer_set_samplerate(output.current_sample_rate);
-#endif			
 		}
 		
-#if BYTES_PER_FRAME == 4		
 		// run equalizer
 		equalizer_process(obuf, oframes * BYTES_PER_FRAME);
-#endif		
 
 		// we assume that here we have been able to entirely fill the DMA buffers
 		if (spdif.enabled) {
@@ -600,7 +596,7 @@ static void output_thread_i2s(void *arg) {
 			// need IRAM for speed but can't allocate a FRAME_BLOCK * 16, so process by smaller chunks
 			while (count < oframes) {
 				size_t chunk = min(SPDIF_BLOCK, oframes - count);
-				spdif_convert((ISAMPLE_T*) obuf + count * 2, chunk, (u32_t*) spdif.buf, &spdif.count);
+				spdif_convert((ISAMPLE_T*) obuf + count * 2, chunk, (u32_t*) spdif.buf, &spdif.count);              
 				i2s_write(CONFIG_I2S_NUM, spdif.buf, chunk * 16, &obytes, portMAX_DELAY);
 				bytes += obytes / (16 / BYTES_PER_FRAME);
 				count += chunk;
@@ -709,12 +705,16 @@ static const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least
 
 /* 
  SPDIF is supposed to be (before BMC encoding, from LSB to MSB)				
-	PPPP AAAA  SSSS SSSS  SSSS SSSS  SSSS VUCP				
- after BMC encoding, each bits becomes 2 hence this becomes a 64 bits word. The
- the trick is to start not with a PPPP sequence but with an VUCP sequence to that
- the 16 bits samples are aligned with a BMC word boundary. Note that the LSB of the
- audio is transmitted first (not the MSB) and that ESP32 libray sends R then L, 
- contrary to what seems to be usually done, so (dst) order had to be changed
+    0....  1...   191..  0
+    BLFMRF MLFWRF MLFWRF BLFMRF (B,M,W=preamble-4, L/R=left/Right-24, F=Flags-4)
+    each xLF pattern is 32 bits 
+	PPPP AAAA  SSSS SSSS  SSSS SSSS  SSSS VUCP (P=preamble, A=auxiliary, S=sample-20bits, V=valid, U=user data, C=channel status, P=parity)
+ After BMC encoding, each bit becomes 2 hence this becomes a 64 bits word. The parity
+ is fixed by changing AAAA bits so that VUPC does not change. Then then trick is to 
+ start not with a PPPP sequence but with an VUCP sequence to that the 16 bits samples
+ are aligned with a BMC word boundary. Input buffer is left first => LRLR...
+ The I2S interface must output first the B/M/W preamble which means that second
+ 32 bits words must be first and so must be marked right channel. 
 */
 static void IRAM_ATTR spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) {
 	register u16_t hi, lo, aux;
@@ -729,7 +729,6 @@ static void IRAM_ATTR spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, s
 		// invert if last preceeding bit is 1
 		lo ^= ~((s16_t)hi) >> 16;
 		// first 16 bits
-		*dst++ = ((u32_t)lo << 16) | hi;		
 		aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
 #else
 		hi  = spdif_bmclookup[(u8_t)(*src >> 24)];
@@ -738,39 +737,38 @@ static void IRAM_ATTR spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, s
 		// invert if last preceeding bit is 1
 		lo ^= ~((s16_t)hi) >> 16;
 		// first 16 bits
-		*dst++ = ((u32_t)lo << 16) | hi;		
 		// we use 20 bits samples as we need to force parity
 		aux = spdif_bmclookup[(u8_t)(*src++ >> 12)];
 		aux = (u8_t) (aux ^ (~((s16_t)lo) >> 16));
 		aux |= (0xb3 ^ (((u16_t)((s8_t)aux)) >> 9)) << 8;
 #endif	
 		
-		// VUCP-Bits: Valid, Subcode, Channelstatus, Parity = 0
-		// As parity is always 0, we can use fixed preambles
+		// set special preamble every 192 iteration
 		if (++cnt > 191) {
 			*dst++ =  VUCP | (PREAMBLE_B << 16 ) | aux; //special preamble for one of 192 frames
 			cnt = 0;
 		} else {
 			*dst++ = VUCP | (PREAMBLE_M << 16) | aux;
-		}
+		}     
+        // now write sample's 16 low bits
+        *dst++ = ((u32_t)lo << 16) | hi;		
 
 		// then do right channel, no need to check PREAMBLE_B
 #if BYTES_PER_FRAME == 4		
 		hi  = spdif_bmclookup[(u8_t)(*src >> 8)];
 		lo  = spdif_bmclookup[(u8_t) *src++];
 		lo ^= ~((s16_t)hi) >> 16;
-		*dst++ = ((u32_t)lo << 16) | hi;
 		aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
 #else
 		hi  = spdif_bmclookup[(u8_t)(*src >> 24)];
 		lo  = spdif_bmclookup[(u8_t)(*src >> 16)];
 		lo ^= ~((s16_t)hi) >> 16;
-		*dst++ = ((u32_t)lo << 16) | hi;
 		aux = spdif_bmclookup[(u8_t)(*src++ >> 12)];
 		aux = (u8_t) (aux ^ (~((s16_t)lo) >> 16));
 		aux |= (0xb3 ^ (((u16_t)((s8_t)aux)) >> 9)) << 8;
 #endif	
 		*dst++ = VUCP | (PREAMBLE_W << 16) | aux;
+        *dst++ = ((u32_t)lo << 16) | hi;
 	}
 	
 	*count = cnt;