TDM as slave

Status
Not open for further replies.

Tengrii

Member
Hi.

I am currently working on a project where i make use of the 2 TDM channels.
My problem is they are not in sync, i have tried various solutions but none of them did solve my problem.

Did anyone else try to make 2 of TDM channels slave and run 1 of them as master so they will be in sync since they have the same master.
There 3 SAI in the chip, i know Teensy support 2 of them.

Thank you very much.
 
As far as I know, nobody has successfully used TDM in slave mode. Or if they have, I didn't hear about it (or maybe I just forgot). Of course it should be theoretically possible, but without any working code you'd probably be starting with quite a project just to implement TDM slave mode using the known-good I2S slave mode code as a guide.


But even if you get TDM slave mode working at all, I suspect your idea may be based on a misunderstanding of how the hardware actually works, specifically this:

Did anyone else try to make 2 of TDM channels slave and run 1 of them as master so they will be in sync since they have the same master. There 3 SAI in the chip, i know Teensy support 2 of them.

Just because you configure one SAI port in slave mode does not mean the other SAI port will be in sync. When a SAI port is configured as master mode, it runs from Teensy's clock, regardless of what the other SAI ports are doing! This is why we don't support more than one I2S port in slave mode, and when even 1 port is used in slave mode the other port can't be used at all, in any mode.

You can explore which features can work together by dragging I/O instances onto the canvas in the design tool. Known incompatible combinations will give little yellow error icons. Here is what you will see if you try to just use SAI1 in slave mode and SAI2 in master mode.

sc.png

The solution to digital audio ports running out of sync with each other is of course resampling the audio data. Earlier this year code was contributed to do this for the S/PDIF input port, which can only run in slave mode because the incoming data carries the transmitting system's clock. My long-term plan is to someday add I2S slave mode support with resampling, so people will be able to effortlessly connect I2S master-mode hardware to Teensy.

But resampling 16 audio streams of a TDM port, or 32 streams if using 2 of them probably isn't practical even with Teensy 4.x running at 600 MHz. Or at least not high quality resampling. Maybe a low quality scheme like sample skipping or duplication would be able to keep up with 32 simultaneous audio channels and leave enough CPU power unused to actually do something useful with so much audio data.


Having said all that, I do have doubt about one point. Earlier I said TDM slave most should be theoretically possible. But I'm not actually 100% confident of that. The issue to investigate is how fact can BCLK run with slave mode. The SAI ports are able to receive & sync to BCLK at 2.8 MHz used by I2S. But TDM requires BCLK at 11.3 MHz. Typically maximum clock speeds are slower when running as inputs, due to on-chip hardware which must sync the incoming clock. Whether SAI supports BCLK that high is a good question. I honestly do not know. I'm just pointing out a possible technical gotcha to check before you even start.

If you do go to so much trouble and manage to get even 1 SAI port running in TDM slave mode, I hope you'll share the code. Or at least confirm it does work, since right now the best I know is nobody has made it work and whether it's even possible is an open question.
 
I did use TDM in slave mode
or better, I used the MCLK as clock to a ADC that was set into master mode and received the data via TDM slave (yes one can do that)

The code for T3.6 is along the line
Code:
void acq_init(int fsamp)
    {
        SIM_SCGC6 |= SIM_SCGC6_I2S;

        I2S0_RCSR=0;

        // enable MCLK output
        I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1));
        while(I2S0_MCR & I2S_MCR_DUF);
        I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE;
        
        I2S0_RMR=0; // enable receiver mask
        I2S0_RCR1 = I2S_RCR1_RFW(3); 

        I2S0_RCR2 = I2S_RCR2_SYNC(0) 
                    | I2S_RCR2_BCP ;
                    
        I2S0_RCR3 = I2S_RCR3_RCE; // single rx channel

        I2S0_RCR4 = I2S_RCR4_FRSZ((NCHAN_I2S-1)) // NCHAN_I2S = 8 words (TDM - mode)
                    | I2S_RCR4_FSE  // frame sync early
                    | I2S_RCR4_MF;
        
        I2S0_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);

        // DMA 
        SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
        SIM_SCGC7 |= SIM_SCGC7_DMA;

        DMA_CR = DMA_CR_EMLM | DMA_CR_EDBG;
        DMA_CR |= DMA_CR_GRP1PRI;
        
        DMA_TCD0_SADDR = &I2S0_RDR0;
        DMA_TCD0_SOFF  = 0;
        DMA_TCD0_SLAST = 0;
        
        DMA_TCD0_ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
        DMA_TCD0_NBYTES_MLNO = 4;
            
        DMA_TCD0_DADDR = tdm_rx_buffer;
        DMA_TCD0_DOFF = 4;
        DMA_TCD0_DLASTSGA = -sizeof(tdm_rx_buffer); // Bytes
            
        DMA_TCD0_CITER_ELINKNO = DMA_TCD0_BITER_ELINKNO = sizeof(tdm_rx_buffer)/4;
            
        DMA_TCD0_CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
            
        DMAMUX0_CHCFG0 = DMAMUX_DISABLE;
        DMAMUX0_CHCFG0 = DMAMUX_SOURCE_I2S0_RX | DMAMUX_ENABLE;

        // start I2S
        I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE  | I2S_RCSR_FR | I2S_RCSR_FRDE;

        //start DMA
        _VectorsRam[IRQ_DMA_CH0 + 16] = acq_isr;
        NVIC_SET_PRIORITY(IRQ_DMA_CH0, I2S_DMA_PRIO);
        NVIC_ENABLE_IRQ(IRQ_DMA_CH0); 
        DMA_SERQ = 0;
    }

Obviously a lot of symbols are missing, but by comparing it to Audio library code, you may see the differences
 
Thank you very much for your replies.
I am sorry i didnt have time before today to answer.

As it can be seen on the picture, my frame clocks is out of sync with around 6.15 us.
I have tried various ways, i tried to reset the SAI blocks at the same time and start them again at the same time but it didnt help, the frame clock did move sometimes but they just got more out of sync.

out of sync.jpg

I dont think i have been clear enough what i meant by the chip 3 SAI blocks. According to the datasheet - IMXRT1060 manual.
There is 3 SAI blocks, i was thinking that if i did setup the 2 of the SAI´s blocks to run as slave and the last one as master, and wire them up they HAD to be in sync since they have same master if it makes sense?

I dont know if anyone else had this problem with the TDM frames been out of sync, i have been working on it for a long time and yet still i have no solution for it..

Thanks btw for your time.
 
I'm afraid page 1967 in the reference manual has some bad news.

sc.png

Before I write another lengthy message, maybe you could explain a bit more about what you're actually trying to accomplish? We can help you much better if we understand your goals, rather than just trying to respond to narrow tech questions lacking much context.
 
I'm afraid page 1967 in the reference manual has some bad news.

View attachment 22480

Before I write another lengthy message, maybe you could explain a bit more about what you're actually trying to accomplish? We can help you much better if we understand your goals, rather than just trying to respond to narrow tech questions lacking much context.

The project I am working on consists of 16 small speakers, where I try to play directional sound. I have managed to play sound from 16 small speakers. Of course, there are other components in the project as well, but I have control over them and they are integrated together.
My problem is that I now want to increase the number of speakers to a minimum of 24 preferably 32 and therefore I need 2 TDM channels with 16 channels each.
My challenge is that the TDM channels are staggered and not in sync with each other. As can also be seen in the picture I have posted earlier, there is 6.15 us between the frame clocks.
I do not know how to solve this problem, i need the TDM to have the same frame clock or at least being in sync with each other so the frame clocks come at the same time.

I have seen that on the datasheet it is not possible that they can be in sync, but with further search, i have found this document - https://www.nxp.com/docs/en/application-note/AN12090.pdf .
In the datasheet under the SAI section - i.MX RT1060 Processor Reference Manual, Rev. 2, 12/2019 p. 1973 - they indicate that it´s possible to run each SAI synchronized to each other.

My idea was to make 2 of the SAI channels as slave and connect them on the same master - with wires - if it makes sense since they will have the same master they would be in sync.
 
So you want a T4 to produce 2 TDM outputs that are precisely time synchronized with each other. I don't know much about it, but will give my thoughts anyway. 6.15 us is a long time for a T4. If you reset both SAIs, I'd expect them to be very close to each other - so close that it wouldn't matter in any audio application. And since they are both derived from the same clock source, they shouldn't accumulate drift wrt each other.
 
I do not understand why 6.15 us matters. The end use is driving speakers!

The speed of sound is approx 1.13 feet per millisecond. 6.15 us corresponds to only about 2mm difference in speaker position.
 
I do not understand why 6.15 us matters. The end use is driving speakers!

The speed of sound is approx 1.13 feet per millisecond. 6.15 us corresponds to only about 2mm difference in speaker position.

The keyword is directional sound (sound of all speakers must be phase aligned for a clean beam pattern)
I would agree that knowing the acoustic centre of a speaker within 2 mm is a challenge, and speakers are typically greater than 2 mm.
Now, if the system is for underwater speakers, than the numbers are changing.
 
So you want a T4 to produce 2 TDM outputs that are precisely time synchronized with each other. I don't know much about it, but will give my thoughts anyway. 6.15 us is a long time for a T4. If you reset both SAIs, I'd expect them to be very close to each other - so close that it wouldn't matter in any audio application. And since they are both derived from the same clock source, they shouldn't accumulate drift wrt each other.

I have tried to reset both SAI´s at the same time but without luck. :/ But thank you for the answer and input!


I do not understand why 6.15 us matters. The end use is driving speakers!

The speed of sound is approx 1.13 feet per millisecond. 6.15 us corresponds to only about 2mm difference in speaker position.

It may not sound as much but since I am trying to make directional sound it's important that both of the channels are in sync.

I have read further on the datasheet. There are 4 transmitters and 4 receivers that can be routed to 5 I / O 'cords' via an option register. It can then be set up as e.g. 2 x TX and 3 x RX.
Each TX string can then carry a frame of 16 16 bit words. That is a total of 32 x 16 bit audio with a bit clock of approx. 11.3MHz (MCLK 22.6MHz)
Similarly, there may be room for 32 x 16 bit channels RX on two of the remaining cords.

Document Number: IMXRT1060RM Rev. 2, 12/2019
page 1963
PastedGraphic-1 (2).png
 
Not sure if that goes into the right direction for your application (in my case it is input not output)
I use SAI1 with two dataports RXD0, RXD1
I control two ADCs with one bitclock and framesync. So, both ADC are sync within internal differences.
Each ADC sends 4 data in TDM format to Teensy.
As a result I get 8 synchronized data from 2 ADC
In my case the channel limit is with the ADC and not with Teensy

in my opinion you can use up to 4 data ports (call it channels) for SAI1 and drive up to 4 DAC's synchronously.
 
What would stop you from configuring TDM2's Frame Sync Direction to externally generated then running a wire from TDM's WS signal into TDM2's WS signal so that they share the same frame sync timing?
 
Not sure if that goes into the right direction for your application (in my case it is input not output)
I use SAI1 with two dataports RXD0, RXD1
I control two ADCs with one bitclock and framesync. So, both ADC are sync within internal differences.
Each ADC sends 4 data in TDM format to Teensy.
As a result I get 8 synchronized data from 2 ADC
In my case the channel limit is with the ADC and not with Teensy

in my opinion you can use up to 4 data ports (call it channels) for SAI1 and drive up to 4 DAC's synchronously.

That is also my intention right now. I will try to run 2 TX data lines through an SAI - that way they will have the same clocks. Thanks for your input!

What would stop you from configuring TDM2's Frame Sync Direction to externally generated then running a wire from TDM's WS signal into TDM2's WS signal so that they share the same frame sync timing?

It was also my intention until I discovered that the SAI-1 has 4 TX of 4 RX "cords" which can be set up as desired. That's what I want to try now. Thank for you input! :)
 
Status
Not open for further replies.
Back
Top