5252void setup_i2s ();
5353bool i2s_write_stereo_samples_i16 (const int16_t * fl_sample , const int16_t * fr_sample , const int buffLen );
5454bool i2s_write_stereo_samples_buff (const float * fl_sample , const float * fr_sample , const int buffLen );
55+ bool i2s_write_stereo_samples_buff_dual (const float * fl_sample , const float * fr_sample , const int buffLen , uint8_t codec_num );
56+ bool i2s_write_stereo_samples_i16_dual (const int16_t * fl_sample , const int16_t * fr_sample , const int buffLen , uint8_t codec_num );
5557void i2s_read_stereo_samples_buff (float * fl_sample , float * fr_sample , const int buffLen );
5658void i2s_read_stereo_samples_buff (int16_t * fl_sample , int16_t * fr_sample , const int buffLen );
59+ void i2s_read_stereo_samples_buff_dual (float * fl_sample , float * fr_sample , const int buffLen , uint8_t codec_num );
60+ void i2s_read_stereo_samples_i16_dual (int16_t * fl_sample , int16_t * fr_sample , const int buffLen , uint8_t codec_num );
5761
5862#endif /* ML_SYNTH_INLINE_DECLARATION */
5963
@@ -139,6 +143,10 @@ union sampleTUNT
139143
140144const i2s_port_t i2s_port_number = I2S_NUM_0 ;
141145
146+ #ifdef DUAL_CODEC_ENABLED
147+ const i2s_port_t i2s_port_number_secondary = I2S_NUM_1 ;
148+ #endif
149+
142150/*
143151 * please refer to https://www.hackster.io/janost/audio-hacking-on-the-esp8266-fa9464#toc-a-simple-909-drum-synth-0
144152 * for the following implementation
@@ -510,6 +518,70 @@ i2s_config_t i2s_configuration =
510518};
511519#endif
512520
521+ #ifdef DUAL_CODEC_ENABLED
522+ /* Secondary I2S configuration for dual codec setup */
523+ i2s_config_t i2s_configuration_secondary =
524+ {
525+ .mode = (i2s_mode_t )(I2S_MODE_SLAVE | I2S_MODE_TX | I2S_MODE_RX ),
526+ .sample_rate = SAMPLE_RATE * I2S_OVERSAMPLE ,
527+ #ifdef SAMPLE_SIZE_32BIT
528+ .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT ,
529+ #endif
530+ #ifdef SAMPLE_SIZE_24BIT
531+ .bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT ,
532+ #endif
533+ #ifdef SAMPLE_SIZE_16BIT
534+ .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT ,
535+ #endif
536+ .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT ,
537+ #ifdef ARDUINO_RUNNING_CORE
538+ #ifdef MAX_98357A_ENABLED
539+ .communication_format = I2S_COMM_FORMAT_STAND_PCM_LONG ,
540+ #else
541+ .communication_format = I2S_COMM_FORMAT_STAND_I2S ,
542+ #endif
543+ #else
544+ .communication_format = (i2s_comm_format_t )(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB ),
545+ #endif
546+ .intr_alloc_flags = 0 ,
547+ .dma_buf_count = 2 ,
548+ .dma_buf_len = SAMPLE_BUFFER_SIZE ,
549+ #ifdef I2S_USE_APLL
550+ .use_apll = true,
551+ #else
552+ .use_apll = false,
553+ #endif
554+
555+ #ifdef ARDUINO_RUNNING_CORE
556+ .tx_desc_auto_clear = true,
557+ .fixed_mclk = 0 ,
558+ #ifdef I2S_MCLK_MULTIPLE_DEFAULT
559+ .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT ,
560+ #else
561+ .mclk_multiple = I2S_MCLK_MULTIPLE_256 ,
562+ #endif
563+ #ifdef SAMPLE_SIZE_16BIT
564+ .bits_per_chan = I2S_BITS_PER_CHAN_16BIT ,
565+ #endif
566+ #ifdef SAMPLE_SIZE_24BIT
567+ .bits_per_chan = I2S_BITS_PER_CHAN_24BIT ,
568+ #endif
569+ #ifdef SAMPLE_SIZE_32BIT
570+ .bits_per_chan = I2S_BITS_PER_CHAN_32BIT ,
571+ #endif
572+ #endif
573+
574+ #if SOC_I2S_SUPPORTS_TDM
575+ .chan_mask = I2S_CHANNEL_STEREO ,
576+ .total_chan = 0 ,
577+ .left_align = 0 ,
578+ .big_edin = 0 ,
579+ .bit_order_msb = 0 ,
580+ .skip_msk = 0 ,
581+ #endif
582+ };
583+ #endif
584+
513585
514586#ifdef I2S_NODAC
515587#ifdef ESP8266
@@ -535,6 +607,40 @@ i2s_pin_config_t pins =
535607};
536608#endif /* (defined I2S_BCLK_PIN) && (defined I2S_WCLK_PIN) && (defined I2S_DOUT_PIN) */
537609
610+ #ifdef DUAL_CODEC_ENABLED
611+ #if (defined I2S_DOUT_PIN_SECONDARY ) || (defined I2S_DIN_PIN_SECONDARY )
612+ /* Secondary I2S pin configuration for dual codec setup */
613+ i2s_pin_config_t pins_secondary =
614+ {
615+ #ifdef I2S_MCLK_PIN_SECONDARY
616+ .mck_io_num = I2S_MCLK_PIN_SECONDARY ,
617+ #else
618+ .mck_io_num = I2S_PIN_NO_CHANGE ,
619+ #endif
620+ #ifdef I2S_BCLK_PIN_SECONDARY
621+ .bck_io_num = I2S_BCLK_PIN_SECONDARY ,
622+ #else
623+ .bck_io_num = I2S_PIN_NO_CHANGE ,
624+ #endif
625+ #ifdef I2S_WCLK_PIN_SECONDARY
626+ .ws_io_num = I2S_WCLK_PIN_SECONDARY ,
627+ #else
628+ .ws_io_num = I2S_PIN_NO_CHANGE ,
629+ #endif
630+ #ifdef I2S_DOUT_PIN_SECONDARY
631+ .data_out_num = I2S_DOUT_PIN_SECONDARY ,
632+ #else
633+ .data_out_num = I2S_PIN_NO_CHANGE ,
634+ #endif
635+ #ifdef I2S_DIN_PIN_SECONDARY
636+ .data_in_num = I2S_DIN_PIN_SECONDARY ,
637+ #else
638+ .data_in_num = I2S_PIN_NO_CHANGE ,
639+ #endif
640+ };
641+ #endif /* (defined I2S_BCLK_PIN_SECONDARY) && (defined I2S_WCLK_PIN_SECONDARY) && (defined I2S_DOUT_PIN_SECONDARY) */
642+ #endif /* DUAL_CODEC_ENABLED */
643+
538644#endif
539645
540646#if (defined I2S_BCLK_PIN ) && (defined I2S_WCLK_PIN ) && (defined I2S_DOUT_PIN )
@@ -569,7 +675,49 @@ void setup_i2s()
569675 Serial .printf (" MCLK: %d\n" , pins .mck_io_num );
570676#endif
571677 i2s_set_sample_rates (i2s_port_number , SAMPLE_RATE );
678+ #ifdef DUAL_CODEC_ENABLED
679+ #if (defined I2S_BCLK_PIN_SECONDARY ) || (defined I2S_WCLK_PIN_SECONDARY ) || (defined I2S_DOUT_PIN_SECONDARY ) || (defined I2S_DIN_PIN_SECONDARY )
680+ /* Setup secondary codec */
681+ i2s_driver_install (i2s_port_number_secondary , & i2s_configuration_secondary , 0 , NULL );
682+ Serial .printf ("Secondary i2s_configuration:\n" );
683+ Serial .printf ("\ttx_desc_auto_clear: %d\n" , i2s_configuration_secondary .tx_desc_auto_clear );
684+ Serial .printf ("\tfixed_mclk: %d\n" , i2s_configuration_secondary .fixed_mclk );
685+ Serial .printf ("\tmclk_multiple: %d\n" , i2s_configuration_secondary .mclk_multiple );
686+ Serial .printf ("\tbits_per_chan: %d\n" , i2s_configuration_secondary .bits_per_chan );
687+
688+ i2s_set_pin (i2s_port_number_secondary , & pins_secondary );
689+
690+ Serial .printf ("Secondary I2S_NUM_%d configured using following pins:\n" , i2s_port_number_secondary );
691+ Serial .printf (" BCLK,BCK: %d\n" , pins_secondary .bck_io_num );
692+ Serial .printf (" WCLK,LCK: %d\n" , pins_secondary .ws_io_num );
693+ Serial .printf (" DOUT: %d\n" , pins_secondary .data_out_num );
694+ Serial .printf (" DIN: %d\n" , pins_secondary .data_in_num );
695+ Serial .printf (" MCLK: %d\n" , pins_secondary .mck_io_num );
696+
697+ i2s_set_sample_rates (i2s_port_number_secondary , SAMPLE_RATE );
698+
699+ Serial .printf ("Secondary I2S configured using following pins:\n" );
700+ Serial .printf (" BCLK,BCK: %d\n" , pins_secondary .bck_io_num );
701+ Serial .printf (" WCLK,LCK: %d\n" , pins_secondary .ws_io_num );
702+ Serial .printf (" DOUT: %d\n" , pins_secondary .data_out_num );
703+ Serial .printf (" DIN: %d\n" , pins_secondary .data_in_num );
704+ Serial .printf (" MCLK: %d\n" , pins_secondary .mck_io_num );
705+
706+ #endif /* (defined I2S_BCLK_PIN_SECONDARY) && (defined I2S_WCLK_PIN_SECONDARY) && (defined I2S_DOUT_PIN_SECONDARY) */
707+ #include "esp_rom_gpio.h"
708+ #include "soc/i2s_periph.h"
709+ /* Connnect both BCLK signals */
710+ esp_rom_gpio_connect_out_signal (I2S_BCLK_PIN_SECONDARY , i2s_periph_signal [0 ].m_tx_bck_sig , 0 , 0 );
711+ esp_rom_gpio_connect_in_signal (I2S_BCLK_PIN_SECONDARY , i2s_periph_signal [1 ].s_rx_bck_sig , 0 );
712+ /* Connect both WS signals */
713+ esp_rom_gpio_connect_out_signal (I2S_WCLK_PIN_SECONDARY , i2s_periph_signal [0 ].m_tx_ws_sig , 0 , 0 );
714+ esp_rom_gpio_connect_in_signal (I2S_WCLK_PIN_SECONDARY , i2s_periph_signal [1 ].s_rx_ws_sig , 0 );
715+ i2s_start (i2s_port_number );
716+ i2s_start (i2s_port_number_secondary );
717+ #else
572718 i2s_start (i2s_port_number );
719+ #endif /* DUAL_CODEC_ENABLED */
720+
573721#ifdef ES8388_ENABLED
574722#ifdef PIN_CTRL
575723 REG_WRITE (PIN_CTRL , 0xFFFFFFF0 );
@@ -606,6 +754,116 @@ void setup_i2s()
606754}
607755#endif /* (defined I2S_BCLK_PIN) && (defined I2S_WCLK_PIN) && (defined I2S_DOUT_PIN) */
608756
757+ #ifdef DUAL_CODEC_ENABLED
758+ #ifdef SAMPLE_BUFFER_SIZE
759+ /* Dual codec write function - allows writing to specific codec */
760+ bool i2s_write_stereo_samples_buff_dual (const float * fl_sample , const float * fr_sample , const int buffLen , uint8_t codec_num )
761+ {
762+ static union sampleTUNT sampleDataU [SAMPLE_BUFFER_SIZE ];
763+ i2s_port_t target_port = (codec_num == 0 ) ? i2s_port_number : i2s_port_number_secondary ;
764+
765+ for (int n = 0 ; n < buffLen ; n ++ )
766+ {
767+ /* Using RIGHT_LEFT format for both codecs */
768+ sampleDataU [n ].ch [0 ] = (SAMPLE_DATA_TYPE )(fr_sample [n ] * MULTIPLIER_CONST );
769+ sampleDataU [n ].ch [1 ] = (SAMPLE_DATA_TYPE )(fl_sample [n ] * MULTIPLIER_CONST );
770+ }
771+
772+ static size_t bytes_written = 0 ;
773+
774+ #ifdef CYCLE_MODULE_ENABLED
775+ calcCycleCountPre ();
776+ #endif
777+ i2s_write (target_port , (const char * )& sampleDataU [0 ].sample , 2 * BYTES_PER_SAMPLE * buffLen , & bytes_written , portMAX_DELAY );
778+ #ifdef CYCLE_MODULE_ENABLED
779+ calcCycleCount ();
780+ #endif
781+
782+ if (bytes_written > 0 )
783+ {
784+ return true;
785+ }
786+ else
787+ {
788+ return false;
789+ }
790+ }
791+
792+ /* Dual codec write function for int16 - allows writing to specific codec */
793+ bool i2s_write_stereo_samples_i16_dual (const int16_t * fl_sample , const int16_t * fr_sample , const int buffLen , uint8_t codec_num )
794+ {
795+ static union sampleTUNT sampleDataU [SAMPLE_BUFFER_SIZE ];
796+ i2s_port_t target_port = (codec_num == 0 ) ? i2s_port_number : i2s_port_number_secondary ;
797+
798+ for (int n = 0 ; n < buffLen ; n ++ )
799+ {
800+ /* Using RIGHT_LEFT format for both codecs */
801+ sampleDataU [n ].ch [0 ] = fr_sample [n ];
802+ sampleDataU [n ].ch [1 ] = fl_sample [n ];
803+ }
804+
805+ static size_t bytes_written = 0 ;
806+
807+ #ifdef CYCLE_MODULE_ENABLED
808+ calcCycleCountPre ();
809+ #endif
810+ i2s_write (target_port , (const char * )& sampleDataU [0 ].sample , 2 * BYTES_PER_SAMPLE * buffLen , & bytes_written , portMAX_DELAY );
811+ #ifdef CYCLE_MODULE_ENABLED
812+ calcCycleCount ();
813+ #endif
814+
815+ if (bytes_written > 0 )
816+ {
817+ return true;
818+ }
819+ else
820+ {
821+ return false;
822+ }
823+ }
824+
825+ /* Dual codec read function - allows reading from specific codec */
826+ void i2s_read_stereo_samples_buff_dual (float * fl_sample , float * fr_sample , const int buffLen , uint8_t codec_num )
827+ {
828+ i2s_port_t target_port = (codec_num == 0 ) ? i2s_port_number : i2s_port_number_secondary ;
829+
830+ #ifdef I2S_DIN_PIN
831+ static size_t bytes_read = 0 ;
832+ static union sampleTUNT sampleData [SAMPLE_BUFFER_SIZE ];
833+
834+ i2s_read (target_port , (char * )& sampleData [0 ].sample , 2 * BYTES_PER_SAMPLE * buffLen , & bytes_read , 0 );
835+
836+ for (int n = 0 ; n < buffLen ; n ++ )
837+ {
838+ /* Using RIGHT_LEFT format */
839+ fr_sample [n ] = ((float )sampleData [n ].ch [0 ] * (1.0f / MULTIPLIER_CONST ));
840+ fl_sample [n ] = ((float )sampleData [n ].ch [1 ] * (1.0f / MULTIPLIER_CONST ));
841+ }
842+ #endif
843+ }
844+
845+ /* Dual codec read function for int16 - allows reading from specific codec */
846+ void i2s_read_stereo_samples_i16_dual (int16_t * fl_sample , int16_t * fr_sample , const int buffLen , uint8_t codec_num )
847+ {
848+ i2s_port_t target_port = (codec_num == 0 ) ? i2s_port_number : i2s_port_number_secondary ;
849+
850+ #ifdef I2S_DIN_PIN
851+ static size_t bytes_read = 0 ;
852+ static union sampleTUNT sampleData [SAMPLE_BUFFER_SIZE ];
853+
854+ i2s_read (target_port , (char * )& sampleData [0 ].sample , 2 * BYTES_PER_SAMPLE * buffLen , & bytes_read , 0 );
855+
856+ for (int n = 0 ; n < buffLen ; n ++ )
857+ {
858+ /* Using RIGHT_LEFT format */
859+ fr_sample [n ] = sampleData [n ].ch [0 ];
860+ fl_sample [n ] = sampleData [n ].ch [1 ];
861+ }
862+ #endif
863+ }
864+ #endif /* SAMPLE_BUFFER_SIZE */
865+ #endif /* DUAL_CODEC_ENABLED */
866+
609867#endif /* ESP32 */
610868
611869
0 commit comments