3131#include " utility/imxrt_hw.h"
3232
3333DMAMEM __attribute__ ((aligned(32 )))
34- static uint32_t tdm_rx_buffer[AUDIO_BLOCK_SAMPLES*16];
35- audio_block_t * AudioInputTDM::block_incoming[16 ] = {
36- nullptr , nullptr , nullptr , nullptr , nullptr , nullptr , nullptr , nullptr ,
37- nullptr , nullptr , nullptr , nullptr , nullptr , nullptr , nullptr , nullptr
38- };
34+ static uint32_t tdm_rx_buffer[AUDIO_BLOCK_SAMPLES*TDM_IN_N_AUDIO_BLOCKS];
35+ audio_block_t * AudioInputTDM::block_incoming[TDM_IN_N_AUDIO_BLOCKS];
3936bool AudioInputTDM::update_responsibility = false ;
4037DMAChannel AudioInputTDM::dma (false );
4138
42-
4339void AudioInputTDM::begin (void )
4440{
41+ for (int i = 0 ; i < TDM_IN_N_AUDIO_BLOCKS; i++)
42+ block_incoming[i] = nullptr ;
4543 dma.begin (true ); // Allocate the DMA channel first
4644
4745 // TODO: should we set & clear the I2S_RCSR_SR bit here?
@@ -68,7 +66,22 @@ void AudioInputTDM::begin(void)
6866 dma.attachInterrupt (isr);
6967#elif defined(__IMXRT1062__)
7068 CORE_PIN8_CONFIG = 3 ; // RX_DATA0
71- IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2 ;
69+ IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2 ; // TEENSY P8, GPIO_B1_00_ALT3 as rx 0
70+ // When using combine mode, you *must* use the data pins in order.
71+ switch (AUDIO_N_SAI1_RX_DATAPINS) {
72+ case 4 :
73+ CORE_PIN32_CONFIG = 3 ; // RX_DATA3
74+ IOMUXC_SAI1_RX_DATA3_SELECT_INPUT = 1 ; // TEENSY P32, GPIO_B0_12_ALT3 as rx 1
75+ case 3 :
76+ CORE_PIN9_CONFIG = 3 ; // RX_DATA2
77+ IOMUXC_SAI1_RX_DATA2_SELECT_INPUT = 1 ; // TEENSY P9, GPIO_B0_11_ALT3 as rx 2
78+ case 2 :
79+ CORE_PIN6_CONFIG = 3 ; // RX_DATA1
80+ IOMUXC_SAI1_RX_DATA1_SELECT_INPUT = 1 ; // TEENSY P6, GPIO_B0_10_ALT3 as rx 1
81+ break ;
82+ default :
83+ break ;
84+ }
7285 dma.TCD ->SADDR = &I2S1_RDR0;
7386 dma.TCD ->SOFF = 0 ;
7487 dma.TCD ->ATTR = DMA_TCD_ATTR_SSIZE (2 ) | DMA_TCD_ATTR_DSIZE (2 );
@@ -89,33 +102,65 @@ void AudioInputTDM::begin(void)
89102#endif
90103}
91104
92- // TODO: needs optimization...
93- static void memcpy_tdm_rx (uint32_t *dest1, uint32_t *dest2, const uint32_t *src)
94- {
95- uint32_t i, in1, in2;
96-
97- for (i=0 ; i < AUDIO_BLOCK_SAMPLES/2 ; i++) {
98- in1 = *src;
99- in2 = *(src+8 );
100- src += 16 ;
101- *dest1++ = (in1 >> 16 ) | (in2 & 0xFFFF0000 );
102- *dest2++ = (in1 << 16 ) | (in2 & 0x0000FFFF );
103- }
105+ // Since we're grabbing data out of the fifo at 32-bits, but the words
106+ // are 16-bits and we're sharing fifos in a round-robbin manner, with
107+ //
108+ // 1 FIFO (pin) active, the word/channel order for the first frame is
109+ // C00 C02 C04 C06 C08 C10 C12 C14
110+ // C01 C03 C05 C07 C09 C11 C13 C15
111+ //
112+ // 2 FIFO (pin) active, the word/channel order for the first frame is
113+ // C00 C16 C02 C18 C04 C20 C06 C22 C08 C24 C10 C26 C12 C28 C14 C30
114+ // C01 C17 C03 C19 C05 C21 C07 C23 C09 C25 C11 C27 C13 C29 C15 C31
115+ //
116+ // 3 FIFO (pin) active, the word/channel order for the first frame is
117+ // C00 C16 C32 C02 C18 C34 C04 C20 C36 C06 C22 C38 C08 C24 C40 C10 C26 C42 C12 C28 C44 C14 C30 C46
118+ // C01 C17 C33 C03 C19 C35 C05 C21 C37 C07 C23 C39 C09 C25 C41 C11 C27 C43 C13 C29 C45 C15 C31 C47
119+ //
120+ // 4 FIFO (pin) active, the word/channel order for the first frame is
121+ // C00 C16 C32 C48|C02 C18 C34 C50|C04 C20 C36 C52|C06 C22 C38 C54|C08 C24 C40 C56|C10 C26 C42 C58|C12 C28 C44 C60|C14 C30 C46 C62
122+ // C01 C17 C33 C49|C03 C19 C35 C51|C05 C21 C37 C53|C07 C23 C39 C55|C09 C25 C41 C57|C11 C27 C43 C59|C13 C29 C45 C61|C15 C31 C47 C63
123+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <--- word index
124+ // where each column is a single 32-bit word popped from the fifo
125+ static void deinterleave (audio_block_t *block_incoming[TDM_IN_N_AUDIO_BLOCKS], const uint32_t *src) {
126+ int l = 0 ;
127+ for (int i=0 ; i < TDM_IN_N_AUDIO_BLOCKS/2 ; i++) {
128+ // ix = 0, 2, 4, 6, ... 1 pin
129+ // ix = 0, 16, 2, 18, 3, 20, ... 2 pins
130+ // ix = 0, 16, 32, 2, 18, 33 ... 3 pins
131+ // ix = 0, 16, 32, 48, 2, 18 ... 4 pins
132+
133+ // i = 0, 1, 2, 3, 4, 5,
134+ // ix = 0, 16, 32, 2, 18, 33 ... 3 pins
135+ // = (0*16 1*16 2*16)+i
136+ int ix = (l*16 ) + i/AUDIO_N_SAI1_RX_DATAPINS*2 ;
137+ l = (l + 1 ) % AUDIO_N_SAI1_RX_DATAPINS;
138+ uint32_t *dest1 = (uint32_t *)(block_incoming[ix]->data );
139+ uint32_t *dest2 = (uint32_t *)(block_incoming[ix+1 ]->data );
140+ const uint32_t *psrc = src;
141+ for (int j=0 ; j < AUDIO_BLOCK_SAMPLES/2 ; j++) {
142+ uint32_t in1 = *psrc;
143+ uint32_t in2 = *(psrc + TDM_IN_N_AUDIO_BLOCKS * AUDIO_N_SAI1_RX_DATAPINS / 2 );
144+ psrc += TDM_IN_N_AUDIO_BLOCKS;
145+ *dest1++ = ((in1 >> 16 ) & 0x0000FFFF ) | ((in2 << 0 ) & 0xFFFF0000 );
146+ *dest2++ = ((in1 >> 0 ) & 0x0000FFFF ) | ((in2 << 16 ) & 0xFFFF0000 );
147+ }
148+ src++;
149+ }
104150}
105151
106152void AudioInputTDM::isr (void )
107153{
108154 uint32_t daddr;
109155 const uint32_t *src;
110- unsigned int i;
111156
112157 daddr = (uint32_t )(dma.TCD ->DADDR );
113158 dma.clearInterrupt ();
114159
115160 if (daddr < (uint32_t )tdm_rx_buffer + sizeof (tdm_rx_buffer) / 2 ) {
116161 // DMA is receiving to the first half of the buffer
117162 // need to remove data from the second half
118- src = &tdm_rx_buffer[AUDIO_BLOCK_SAMPLES* 8 ];
163+ src = &tdm_rx_buffer[AUDIO_BLOCK_SAMPLES * TDM_IN_N_AUDIO_BLOCKS / 2 ];
119164 } else {
120165 // DMA is receiving to the second half of the buffer
121166 // need to remove data from the first half
@@ -125,25 +170,19 @@ void AudioInputTDM::isr(void)
125170 #if IMXRT_CACHE_ENABLED >=1
126171 arm_dcache_delete ((void *)src, sizeof (tdm_rx_buffer) / 2 );
127172 #endif
128- for (i=0 ; i < 16 ; i += 2 ) {
129- uint32_t *dest1 = (uint32_t *)(block_incoming[i]->data );
130- uint32_t *dest2 = (uint32_t *)(block_incoming[i+1 ]->data );
131- memcpy_tdm_rx (dest1, dest2, src);
132- src++;
133- }
173+ deinterleave (block_incoming, src);
134174 }
135175 if (update_responsibility) update_all ();
136176}
137177
138178
139179void AudioInputTDM::update (void )
140180{
141- unsigned int i, j;
142- audio_block_t *new_block[16 ];
143- audio_block_t *out_block[16 ];
144-
145- // allocate 16 new blocks. If any fails, allocate none
146- for (i=0 ; i < 16 ; i++) {
181+ unsigned int i, j;
182+ audio_block_t *new_block[TDM_IN_N_AUDIO_BLOCKS];
183+ audio_block_t *out_block[TDM_IN_N_AUDIO_BLOCKS];
184+ // allocate TDM_IN_N_AUDIO_BLOCKS new blocks. If any fails, allocate none
185+ for (i=0 ; i < TDM_IN_N_AUDIO_BLOCKS; i++) {
147186 new_block[i] = allocate ();
148187 if (new_block[i] == nullptr ) {
149188 for (j=0 ; j < i; j++) {
@@ -158,8 +197,8 @@ void AudioInputTDM::update(void)
158197 memcpy (block_incoming, new_block, sizeof (block_incoming));
159198 __enable_irq ();
160199 if (out_block[0 ] != nullptr ) {
161- // if we got 1 block, all 16 are filled
162- for (i=0 ; i < 16 ; i++) {
200+ // if we got 1 block, all TDM_IN_N_AUDIO_BLOCKS are filled
201+ for (i=0 ; i < TDM_IN_N_AUDIO_BLOCKS ; i++) {
163202 transmit (out_block[i], i);
164203 release (out_block[i]);
165204 }
0 commit comments