Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: Teensy 4.0 and non DMA I2S transfer

  1. #1
    Senior Member
    Join Date
    May 2018
    Posts
    196

    Teensy 4.0 and non DMA I2S transfer

    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?

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,447
    Maybe this can help?

    https://forum.pjrc.com/threads/62819...l=1#post253563

    Look for the comment "not using DMA" and "start generating TX FIFO interrupts" for the specific bits you need to configure for interrupts.

    You'll need to convert from that weird 20 bit format back to normal I2S, but that's mostly a matter of writing the correct vales into the 5 TCR & 5 RCR registers to configure the data format as I2S.

  3. #3
    Senior Member
    Join Date
    May 2018
    Posts
    196
    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 by Jean-Marc; 10-11-2020 at 10:45 PM.

  4. #4
    Senior Member
    Join Date
    May 2018
    Posts
    196
    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 */;

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •