Problem with TDM without Audio Library

Manuel Schalk

New member
Hi,
I am trying to program the MIMXRT1062 to use the SAI1 receiver as a TDM stream with 8 words @16 bit & 44.1 kHz. I know the library does this as well, but the future goal is to use the SAI at a different sample rate and bit depths & maybe to use all of the 4 available data lines.
The TDM input stream is generated by 8 PDM MEMS microphones that are converted to a TDM stream by the ADAU7118.
I was able to configure the right frame sync & bit clock at 44.1 kHz and 5,6448 MHz, respectively. I verified the correct TDM stream with a logic analyzer, so there should be valid data on the receive channel. However, when I print the received data to the serial monitor it only prints zeros. I would really appreciate any help!
This is my code:

Code:
/** @file main.cpp
*
* @brief Configures Teensy 4.1 to use SAI1 Receiver with 1 data line. TDM Mode with 8 words @ 16 bit & 44.1 kHz.
*
* @par
* @author Manuel Schalk
* @date 13.01.2023
*/

#include <Arduino.h>
#include "mimxrt1062.h"
#include "ADAU7118.h"

//#define NDEBUG

volatile static bool new_data_available;
volatile int32_t buf[8];
int32_t data[8];

/*
* @brief ISR reads the RX channel 0 data & stores it to buf.
*/
FASTRUN void SAI1_IRQ_Handler()
{
  cli();
  new_data_available = true; 

  for (int i=0; i<8; i++)
  {
    buf[i] = SAI1_RDR0;
  }
  sei();
}

void setup() {
  // put your setup code here, to run once:
# ifndef NDEBUG
    if(!Serial){
      Serial.begin(9600);
      while(!Serial); // Wait for serial monitor
    }
# endif /* NDEBUG */

  new_data_available = false;

  NVIC_DISABLE_IRQ(IRQ_SAI1);
  attachInterruptVector(IRQ_SAI1, &SAI1_IRQ_Handler);
  NVIC_ENABLE_IRQ(IRQ_SAI1);

  IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 0x3; // Assign SAI1_RX_DATA00 to GPIO_B1_00 (Teensy Pin 8)
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_11 = 0x3; // Assign SAI1_RX_BLCK to GPIO_AD_B1_11 (Teensy Pin 21)
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_10 = 0x3; // Assign SAI1_RX_SYNC to GPIO_AD_B1_10 (Teensy Pin 20)
  IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_09 = 0x3; // Assign SAI1_RX_MCLK to GPIO_AD_B1_09 (Teensy Pin 23)

  IOMUXC_GPR_GPR1 |= IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0); // use ccm.sai1_clk_root as SAI1_MCLK source
  IOMUXC_GPR_GPR1 |= IOMUXC_GPR_GPR1_SAI1_MCLK_DIR; // Sets sai1.MCLK as output signal

  /* Configure SAI1 MCLK frequency to be at 11,2896 MHz */
  CCM_ANALOG_PLL_AUDIO_CLR |= ((uint32_t) 1)<<16; // do not bypass Audio PLL
  CCM_ANALOG_PLL_AUDIO |= ((uint32_t) 30 & 0x7F); // set DIV_SELECT to 30
  CCM_ANALOG_PLL_AUDIO_NUM = (((uint32_t) 66) & 0x3FFFFFFF); // set NUM of fractional loop to 66
  CCM_ANALOG_PLL_AUDIO_DENOM = (((uint32_t) 625) & 0x3FFFFFFF); // set DENOM of fractional loop to 625
  CCM_ANALOG_PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2); // Switcher Clock - Divide PLL Fout by 1
  CCM_ANALOG_MISC2_CLR = (uint32_t) 1<<23; // Set MSB of AUDIO_DIV - divide by 1
  CCM_ANALOG_MISC2_CLR = (uint32_t) 1<<15; // Set LSB of AUDIO_DIV - divide by 1
  CCM_CS1CDR |= CCM_CS1CDR_SAI1_CLK_PRED(7); // Divide by 8
  CCM_CS1CDR |= CCM_CS1CDR_SAI1_CLK_PODF(7); // Divide by 8
  CCM_ANALOG_PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_ENABLE; // enable Audio PLL output
  
  CCM_CSCMR1 |= CCM_CSCMR1_SAI1_CLK_SEL(2); // Select Audio PLL as clock source
  // SAI1 clock has to be enabled before configuring SAI1
  CCM_CCGR5 |= CCM_CCGR5_SAI1(3); // enable SAI1 clock

  /*
    Configure SAI1
  */ 
# if 0
  // TODO: Why is SR bit not cleared even after writing 0?
  SAI1_RCSR |= SAI_RCSR_SR(1); // software reset on receiver
  delay(10);
  SAI1_RCSR = SAI_RCSR_SR(0); // clear software reset
# endif
  SAI1_RCSR |= SAI_RCSR_FRIE;  // enable FIFO Request Interrupt
  SAI1_RCR1 = 0x6; // set RX FIFO watermark to 7 words - Request flag set when words in FIFO greater than watermark
  SAI1_RCR2 |= SAI_RCR2_MSEL(1); // Select MCLK1 as master clock
  SAI1_RCR2 |= SAI_RCR2_BCD(1); // Set SAI1 RX to master mode
  SAI1_RCR2 |= SAI_RCR2_DIV(0); // Set Bit Clock division value to 2
  SAI1_RCR2 |= SAI_RCR2_BCP(1); // Sample inputs on rising edge
  SAI1_RCR3 |= SAI_RCR3_RCE(1); // enable SAI1 RX channel 0
  SAI1_RCR4 |= SAI_RCR4_FRSZ(7); // 8 words per frame
  SAI1_RCR4 |= SAI_RCR4_MF; // MSB is received first
  SAI1_RCR4 |= SAI_RCR4_FSD(1); // Frame sync generated internally in master mode
  SAI1_RCR4 |= SAI_RCR4_FCONT;
  SAI1_RCR5 |= SAI_RCR5_WNW(15); // 16 bits per word for each word except the first word in frame
  SAI1_RCR5 |= SAI_RCR5_W0W(15); // 16 bits in first word of frame
  SAI1_RCR5 |= SAI_RCR5_FBT(15); // bit 15 is the first bit transmitted

  SAI1_RCSR |= SAI_RCSR_RE; // Enable SAI1 receiver

  /*
    Initialize ADAU7118
  */
  ADAU7118_init(ADDR_CNFG1);
  delay(50);
}

void loop() {
  // put your main code here, to run repeatedly:
  cli();
  bool copy_new_data_available = new_data_available;
  sei();
  if (copy_new_data_available)
  {
    cli();
    memcpy(data, (int32_t*) buf, 32);
    sei();
    Serial.print(data[0]);
    Serial.print("\t");
    Serial.print(data[1]);
    Serial.print("\t");
    Serial.print(data[2]);
    Serial.print("\t");
    Serial.print(data[3]);
    Serial.print("\t");
    Serial.print(data[4]);
    Serial.print("\t");
    Serial.print(data[5]);
    Serial.print("\t");
    Serial.print(data[6]);
    Serial.print("\t");
    Serial.println(data[7]);
    cli();
    new_data_available = 0;
    sei();
  }
}

/*** end of file ***/
 
Back
Top