Teensy 4.0 and non DMA I2S transfer

Jean-Marc

Well-known member
I am looking for a way to transfer I2S using interrupt instead of DMA.

This library was supporting it on the Teensy 3.
https://github.com/hughpyle/teensy-i2s

It does not work on the Teensy4.
I want to use I2S1(mapped to SAI1)
I started for the Audio library DMA setup but I need to get an interrupt each time a word must be transferred.

If I do the following, it just hangs the sketch.
I don't do anything in the IRQ yet but is it normal?

I also find strange that some of the flags below I had to define myself.
#define I2S_TCSR_FRIE ((uint32_t)0x00000100) // FIFO Request Interrupt Enable
#define I2S_TCSR_FEF ((uint32_t)0x00040000) // FIFO transmit underrun
#define I2S_TCSR_FRF ((uint32_t)0x00010000) // FIFO transmit watermark reached
#define I2S_TCSR_SEF ((uint32_t)0x00020000) // FIFO transmit frame sync error



attachInterruptVector(IRQ_SAI1, i2s1_tx_isr);

NVIC_ENABLE_IRQ(IRQ_SAI1);
I2S1_TCSR |= I2S_TCSR_TE // Transmit Enable
| I2S_TCSR_BCE // Bit Clock Enable
| I2S_TCSR_FRIE // FIFO Request Interrupt Enable
| I2S_TCSR_FR // FIFO Reset
;

This just hangs on the T4.
Are non DMA I2S transfer (interrupt based) allowed on a T4.0?
 
Hi Paul,

It improves. If I start it using below code I get at least the interrupt but only once.

I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FRIE;

static int ind=0;

void i2s1_tx_isr(void)
{
if(!(I2S1_TCSR & I2S_TCSR_FRF)) return;
I2S1_TDR0 = (uint32_t)0;
if(I2S1_TCSR & I2S_TCSR_FEF) I2S1_TCSR |= I2S_TCSR_FEF; // clear if underrun
if(I2S1_TCSR & I2S_TCSR_SEF) I2S1_TCSR |= I2S_TCSR_SEF; // clear if frame sync error
ind = ind +1;
ind = ind & (AUDIO_BLOCK_SAMPLES-1);
if (ind==0) Serial.println( "I" );
}

when using the DMA in the audio lib, it writes to I2S1_TDR0+2.
I was wondering what is the frame size of the FIFO in transmit mode?
Is it always 16bits so a single sample?


But your sample seems to be the good starting point. Thanks I will have a look tomorrow. At least it generates the irq forever.
 
Last edited:
hi Paul,

Your sample did help, I could now add and I2S audio driver (interrupt based, for PCM5102) to the VGA output and now the disturbance on the video DMA transfers is gone.
I updated the VGA_t4 library code and I also add VGA (with sound) to most emulators of the MCUME project (all on the git)

There is still something I would like to improve which is reducing the amount of I2S interrupts.
Now there is 1 interrupt per 16bit sample sent one the bus.

I did copy the I2S setup from the output_i2s module of the audio lib. The DMA there is copying 16bits at a time to I2S1_TDR0 + 2.
I don't really understand this code as the I2S registers are set up for 32bits word ??? (32-1, see below code).

How should I change the registers setup to copy 32bits at a time to I2S1_TDR0. Is there a way to copy even more than 32bits in the ISR (e.g. 4 x L+R samples), it is a FIFO no?

I don't feel familiar with the SAI information of NXP documentation.

See below the current code I copied from the output_i2s:
int rsync = 0;
int tsync = 1;

I2S1_TMR = 0;
I2S1_TCR1 = I2S_TCR1_RFW(1);
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP // sync=0; tx is async;
| (I2S_TCR2_BCD | I2S_TCR2_DIV((1)) | I2S_TCR2_MSEL(1));
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ((2-1)) | I2S_TCR4_SYWD((32-1)) | I2S_TCR4_MF
| I2S_TCR4_FSD | I2S_TCR4_FSE | I2S_TCR4_FSP;
I2S1_TCR5 = I2S_TCR5_WNW((32-1)) | I2S_TCR5_W0W((32-1)) | I2S_TCR5_FBT((32-1));


I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(1);
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP // sync=0; rx is async;
| (I2S_RCR2_BCD | I2S_RCR2_DIV((1)) | I2S_RCR2_MSEL(1));
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ((2-1)) | I2S_RCR4_SYWD((32-1)) | I2S_RCR4_MF
| I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD;
I2S1_RCR5 = I2S_RCR5_WNW((32-1)) | I2S_RCR5_W0W((32-1)) | I2S_RCR5_FBT((32-1));

//CORE_PIN23_CONFIG = 3; // MCLK
CORE_PIN21_CONFIG = 3; // RX_BCLK
CORE_PIN20_CONFIG = 3; // RX_SYNC
CORE_PIN7_CONFIG = 3; // TX_DATA0
I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE;
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
 
@Jean-Marc can you point me to a working version of the non DMA i2s code?
I looked through some of you github repos but couldn't spot it
 
Back
Top