i.MX RT1064 Custom Board – SGTL5000 Codec Not Responding Over I2C

Hi,



I have designed a custom PCB using the MIMXRT1064 processor and the SGTL5000 audio codec.



For the SGTL5000 circuit, I followed the standard/reference SGTL5000 schematic.



The connections between the RT1064 and SGTL5000 are as follows:



  • LPI2C1_SCL → GPIO_AD_B1_00
  • LPI2C1_SDA → GPIO_AD_B1_01
  • SAI1_MCLK → GPIO_AD_B1_09
  • SAI1_RXD → GPIO_AD_B1_12
  • SAI1_TXD → GPIO_AD_B1_13
  • SAI1_RX_BCLK → GPIO_AD_B1_11
  • SAI1_RX_LRCLK → GPIO_AD_B1_10


I have attached the relevant part of my schematic as well.









My main problem is that after flashing the firmware, I am not receiving any I2C ACK from the SGTL5000.



I measured the following voltages:



  • SCL = approximately 3.3 V
  • SDA = approximately 3.3 V
  • MCLK = approximately 1.6 V

    in output i am getting this

    === SGTL5000 bring-up test ===
    I2C scan ...
    Scan done: 0 device(s)
    Audio PLL = 786432000 Hz
    SAI1 mux=2 prediv=3 div=15 -> MCLK = 12288000 Hz (expect 12288000)
    LPI2C clock = 10000000 Hz (expect 10000000)
    -- try 1 --
    CHIP_ID @0x A: status=902 id=0x 0 0
    CHIP_ID @0x2A: status=902 id=0x 0 0
    -- try 2 --
    CHIP_ID @0x A: status=902 id=0x 0 0
    CHIP_ID @0x2A: status=902 id=0x 0 0
    -- try 3 --
    CHIP_ID @0x A: status=902 id=0x 0 0
    CHIP_ID @0x2A: status=902 id=0x 0 0
    SGTL5000 not answering. Stop.
 

Attachments

  • codec.png
    codec.png
    25.7 KB · Views: 35
Check MCLK output.

SGTL5000 remains in a low power reset state where it's unresponsive to I2C if no MCLK signal is seen.

If that doesn't solve your problem, perhaps get a Teensy 4.1 board and audio shield (known good hardware) to test your program.
 
On the MCLK pin I am getting 1.6 V.

Now, as output, I am getting this:

=== SGTL5000 bring-up test ===
Audio PLL = 786432000 Hz
SAI1 mux=2 prediv=3 div=15 -> MCLK = 12288000 Hz (expect 12288000)
LPI2C clock = 10000000 Hz (expect 10000000)
SLOW bit-bang (1 kHz): idle SCL=1 SDA=1 (expect 1 1)
bit-bang ACK at 0x A
bit-bang scan: 1 found, line errors = 0 (expect 0)
bit-bang CHIP_ID @0x0A: acks=1111 id=0xBFFF errors=0
I2C scan (Teensy style)...
Scan done: 0 device(s)
-- try 1 --
CHIP_ID @0x A: status=902 id=0x 0 0
CHIP_ID @0x2A: status=902 id=0x 0 0
-- try 2 --
CHIP_ID @0x A: status=902 id=0x 0 0
CHIP_ID @0x2A: status=902 id=0x 0 0
-- try 3 --
CHIP_ID @0x A: status=902 id=0x 0 0
CHIP_ID @0x2A: status=902 id=0x 0 0
SGTL5000 not answering. Stop.

Why is it working in the slow bit-bang test but not with LPI2C?
 
1790832611741.jpeg

Whereas from your code output (the code itself would be helpful…), you appear to have set the I2C to run at 10MHz, which isn’t viable for any parts I’m aware of.
 
Thanks for the reply. To clarify: 10 MHz is the LPI2C peripheral's functional clock inside the i.MX RT1064, not the SCL frequency. The bus is configured with baudRate_Hz = 100000, so SCL runs at 100 kHz, well below the 400 kHz limit.


Current status: with a slow bit-bang I2C (~1 kHz) the SGTL5000 ACKs at 0x0A, but CHIP_ID reads back as 0xBFFF instead of 0xA011. With LPI2C at 100 kHz every address NAKs. SCL/SDA have 2.2k pull-ups to 3.3 V, and MCLK is 12.288 MHz. The same codec board works with a Teensy 4. Any ideas?
 
You haven't shown any code at all, nor posted any confirmation of it working on a regular Teensy.
 
This is the code i am using in teensy with my custom board codec
and i am getting 0x0A correctlly
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>

// --- Audio objects ---
AudioInputI2S        i2s_in;       // I2S1 input from SGTL5000 ADC
AudioOutputI2S       i2s_out;      // I2S1 output to SGTL5000 DAC
AudioConnection      patchCord1(i2s_in, 0, i2s_out, 0); // Left in -> Left out
// For mono to both L/R, uncomment the line below
// AudioConnection      patchCord2(i2s_in, 0, i2s_out, 1);

AudioControlSGTL5000 sgtl5000_1;   // SGTL5000 control interface

void setup() {
  Serial.begin(115200);

  // 1️⃣ Start Audio library & MCLK
  AudioMemory(12);
  delay(5); // Let MCLK stabilize

  // 2️⃣ Scan for SGTL5000 on I2C
  Wire.begin();
  bool found = false;
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("I2C device found at 0x");
      Serial.println(addr, HEX);
      if (addr == 0x0A) found = true;
    }
  }

  if (!found) {
    Serial.println("SGTL5000 not found at 0x0A — check wiring/clock!");
    while (1) delay(1000);
  }

  // 3️⃣ Enable SGTL5000
  sgtl5000_1.enable();

  // 4️⃣ Use MIC input (shield MIC pin)
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  sgtl5000_1.micGain(10); // Adjust 20–36 for your mic

  // 5️⃣ Output level to LINE OUT
  sgtl5000_1.lineOutLevel(13); // ~1.2 Vrms; safe for your amp

  Serial.println("Loopback running: MIC -> LINE OUT");
}

void loop() {
  // Nothing needed — audio routing is automatic
}




And this is the code i am using in MCU expresso for RT1064 with sgtl both are in my custom pcb

Code:
/*
 * Minimal SGTL5000 bring-up for i.MX RT1064 (custom board)
 *
 * VERSION 2: LPI2C now uses the SAME clock + timing as Teensy 4 Wire library
 *            (24 MHz OSC source, glitch filters ON, longer data hold).
 *            Everything else is unchanged from your working code.
 *
 * Pin map (from your schematic):
 *   GPIO_AD_B1_00 (J11) LPI2C1_SCL
 *   GPIO_AD_B1_01 (K11) LPI2C1_SDA
 *   GPIO_AD_B1_09 (M13) SAI1_MCLK
 *   GPIO_AD_B1_12 (H12) SAI1_RX_DATA00  (codec DOUT)
 *   GPIO_AD_B1_13 (H11) SAI1_TX_DATA00  (codec DIN)
 *   GPIO_AD_B1_11 (J13) SAI1_RX_BCLK
 *   GPIO_AD_B1_10 (L13) SAI1_RX_SYNC    (LRCLK)
 */

#include "fsl_debug_console.h"
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "fsl_iomuxc.h"
#include "fsl_clock.h"
#include "fsl_lpi2c.h"
#include "fsl_sai.h"
#include "fsl_codec_common.h"
#include "fsl_sgtl5000.h"
#include "fsl_codec_adapter.h"
#include "fsl_gpio.h"

/* ------------------------------------------------------------------ */
/* Settings                                                            */
/* ------------------------------------------------------------------ */
#define MCLK_HZ       12288000U /* 786.432 MHz / 4 / 16 */
#define SAMPLE_RATE   16000U
#define SGTL_ADDR     0x0AU     /* 0x2A if CTRL_ADR0_CS is tied high */
#define LPI2C_CLK_HZ  24000000U /* CHANGED: 24 MHz OSC, same as Teensy */

#define CODEC_OUT_CH  (kCODEC_PlayChannelHeadphoneLeft | kCODEC_PlayChannelHeadphoneRight | \
                       kCODEC_PlayChannelLineOutLeft   | kCODEC_PlayChannelLineOutRight)

/* Audio PLL = 24 MHz * (32 + 768/1000) = 786.432 MHz */
static const clock_audio_pll_config_t s_audioPll = {
    .loopDivider = 32,
    .postDivider = 1,
    .numerator   = 768,
    .denominator = 1000,
};

static sgtl_config_t s_sgtlConfig = {
    .i2cConfig    = {.codecI2CInstance = 1U, .codecI2CSourceClock = LPI2C_CLK_HZ}, /* CHANGED */
    .route        = kSGTL_RoutePlayback,
    .slaveAddress = SGTL_ADDR,
    .bus          = kSGTL_BusI2S,
    .format       = {.mclk_HZ = MCLK_HZ, .sampleRate = SAMPLE_RATE, .bitWidth = 16U},
    .master_slave = false, /* codec is slave, RT1064 generates BCLK/LRCLK */
};

static codec_config_t s_codecConfig = {
    .codecDevType   = kCODEC_SGTL5000,
    .codecDevConfig = &s_sgtlConfig,
};

static codec_handle_t s_codec;

/* 1 kHz sine at 16 kHz = 16 samples per period, stereo interleaved */
static const int16_t s_sineMono[16] = {
    0, 3061, 5657, 7391, 8000, 7391, 5657, 3061,
    0, -3061, -5657, -7391, -8000, -7391, -5657, -3061,
};
static int16_t s_tone[32];

/* ------------------------------------------------------------------ */
/* Pins (UNCHANGED - your working values)                              */
/* ------------------------------------------------------------------ */
static void audio_pins_init(void)
{
    CLOCK_EnableClock(kCLOCK_Iomuxc);

    /* I2C: open-drain, SION on */
//    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 1U);
//    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 1U);
//    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0xF861U);
//    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0xF861U);

    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0U); // Changed from 1U to 0U
      IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0U); // Changed from 1U to 0U
      IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0x1F8B0U); // Changed from 0xF861U
      IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0x1F8B0U);

    /* SAI1 */
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_09_SAI1_MCLK, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_11_SAI1_RX_BCLK, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_10_SAI1_RX_SYNC, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_13_SAI1_TX_DATA00, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_12_SAI1_RX_DATA00, 1U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_09_SAI1_MCLK, 0x10B0U); /* keep: MCLK must be strong */
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_11_SAI1_RX_BCLK, 0x1008U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_10_SAI1_RX_SYNC, 0x1008U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_13_SAI1_TX_DATA00, 0x1008U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_12_SAI1_RX_DATA00, 0x1008U);
}

/* ------------------------------------------------------------------ */
/* NEW: LPI2C init with EXACT Teensy 4 Wire timing (100 kHz)           */
/*   source 24 MHz, prescale /2, glitch filter 5 cycles on SDA+SCL,    */
/*   data valid delay 25, setup/hold 40                                */
/* ------------------------------------------------------------------ */
static void lpi2c_init_teensy(void)
{
    lpi2c_master_config_t cfg;
    LPI2C_MasterGetDefaultConfig(&cfg);
    cfg.baudRate_Hz = 100000U;
    LPI2C_MasterInit(LPI2C1, &cfg, LPI2C_CLK_HZ);

    LPI2C1->MCR &= ~LPI2C_MCR_MEN_MASK; /* disable while changing */
    LPI2C1->MCCR0  = LPI2C_MCCR0_CLKHI(55) | LPI2C_MCCR0_CLKLO(59) |
                     LPI2C_MCCR0_DATAVD(25) | LPI2C_MCCR0_SETHOLD(40);
    LPI2C1->MCFGR1 = (LPI2C1->MCFGR1 & ~LPI2C_MCFGR1_PRESCALE_MASK) |
                     LPI2C_MCFGR1_PRESCALE(1);
    LPI2C1->MCFGR2 = LPI2C_MCFGR2_FILTSDA(5) | LPI2C_MCFGR2_FILTSCL(5) |
                     LPI2C_MCFGR2_BUSIDLE(3000);
    LPI2C1->MCR |= LPI2C_MCR_MEN_MASK;  /* enable again */
}

/* ------------------------------------------------------------------ */
/* Teensy-style I2C scan: address-only write                           */
/* ------------------------------------------------------------------ */
static void lpi2c_scan(void)
{
    lpi2c_init_teensy(); /* CHANGED */

    PRINTF("I2C scan (Teensy timing)...\r\n");
    int found = 0;
    for (uint8_t addr = 1; addr < 127; addr++)
    {
        uint8_t dummy = 0;
        lpi2c_master_transfer_t x = {0};
        x.slaveAddress = addr;
        x.direction    = kLPI2C_Write;
        x.data         = &dummy;
        x.dataSize     = 0U; /* address only */
        x.flags        = kLPI2C_TransferDefaultFlag;
        if (LPI2C_MasterTransferBlocking(LPI2C1, &x) == kStatus_Success)
        {
            PRINTF("  I2C device found at 0x%x\r\n", addr);
            found++;
        }
    }
    PRINTF("Scan done: %d device(s)\r\n", found);
    LPI2C_MasterDeinit(LPI2C1);
}

/* ------------------------------------------------------------------ */
/* SLOW bit-bang I2C (~1 kHz) on the same pins (UNCHANGED)             */
/* ------------------------------------------------------------------ */
#define BB_SCL 16U
#define BB_SDA 17U
static uint32_t s_bbErrors;

static void bb_wait(void) { SDK_DelayAtLeastUs(250U, SystemCoreClock); }
static void bb_low(uint32_t pin)     { GPIO1->DR &= ~(1UL << pin); GPIO1->GDIR |= (1UL << pin); }
static void bb_release(uint32_t pin) { GPIO1->GDIR &= ~(1UL << pin); }
static uint32_t bb_get(uint32_t pin) { return (GPIO1->PSR >> pin) & 1UL; }

static void bb_scl_high(void)
{
    bb_release(BB_SCL);
    for (int i = 0; (i < 1000) && (bb_get(BB_SCL) == 0U); i++)
    {
        SDK_DelayAtLeastUs(10U, SystemCoreClock);
    }
    if (bb_get(BB_SCL) == 0U) { s_bbErrors++; }
}

static void bb_start(void)
{
    bb_release(BB_SDA); bb_scl_high(); bb_wait();
    if (bb_get(BB_SDA) == 0U) { s_bbErrors++; }
    bb_low(BB_SDA); bb_wait();
    bb_low(BB_SCL); bb_wait();
}

static void bb_stop(void)
{
    bb_low(BB_SDA); bb_wait();
    bb_scl_high(); bb_wait();
    bb_release(BB_SDA); bb_wait();
}

static bool bb_write_byte(uint8_t b)
{
    for (int i = 7; i >= 0; i--)
    {
        if ((b >> i) & 1U) { bb_release(BB_SDA); } else { bb_low(BB_SDA); }
        bb_wait();
        bb_scl_high(); bb_wait();
        if ((((b >> i) & 1U) != 0U) && (bb_get(BB_SDA) == 0U)) { s_bbErrors++; }
        bb_low(BB_SCL); bb_wait();
    }
    bb_release(BB_SDA); bb_wait();
    bb_scl_high(); bb_wait();
    bool ack = (bb_get(BB_SDA) == 0U);
    bb_low(BB_SCL); bb_wait();
    return ack;
}

static uint8_t bb_read_byte(bool ack)
{
    uint8_t b = 0;
    bb_release(BB_SDA);
    for (int i = 0; i < 8; i++)
    {
        bb_wait(); bb_scl_high(); bb_wait();
        b = (uint8_t)((b << 1) | bb_get(BB_SDA));
        bb_low(BB_SCL);
    }
    if (ack) { bb_low(BB_SDA); } else { bb_release(BB_SDA); }
    bb_wait(); bb_scl_high(); bb_wait(); bb_low(BB_SCL); bb_wait();
    bb_release(BB_SDA);
    return b;
}

static void slow_bitbang_test(void)
{
    gpio_pin_config_t in = {kGPIO_DigitalInput, 0U, kGPIO_NoIntmode};

    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_GPIO1_IO16, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_GPIO1_IO17, 1U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_GPIO1_IO16, 0x1F8B0U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_GPIO1_IO17, 0x1F8B0U);
    GPIO_PinInit(GPIO1, BB_SCL, &in);
    GPIO_PinInit(GPIO1, BB_SDA, &in);
    SDK_DelayAtLeastUs(1000U, SystemCoreClock);

    PRINTF("\r\nSLOW bit-bang (1 kHz): idle SCL=%u SDA=%u (expect 1 1)\r\n",
           (unsigned)bb_get(BB_SCL), (unsigned)bb_get(BB_SDA));

    bb_release(BB_SDA);
    for (int i = 0; i < 9; i++) { bb_low(BB_SCL); bb_wait(); bb_scl_high(); bb_wait(); }
    bb_stop();

    s_bbErrors = 0;
    int found = 0;
    for (uint8_t a = 0x08; a <= 0x77; a++)
    {
        bb_start();
        bool ack = bb_write_byte((uint8_t)(a << 1));
        bb_stop();
        if (ack) { PRINTF("  bit-bang ACK at 0x%x\r\n", a); found++; }
    }
    PRINTF("bit-bang scan: %d found, line errors = %u (expect 0)\r\n", found, (unsigned)s_bbErrors);

    s_bbErrors = 0;
    bb_start();
    bool a1 = bb_write_byte(0x0A << 1);
    bool a2 = bb_write_byte(0x00);
    bool a3 = bb_write_byte(0x00);
    bb_start();
    bool a4 = bb_write_byte((0x0A << 1) | 1U);
    uint8_t hi = bb_read_byte(true);
    uint8_t lo = bb_read_byte(false);
    bb_stop();
    PRINTF("bit-bang CHIP_ID @0x0A: acks=%d%d%d%d id=0x%x errors=%u\r\n",
           a1, a2, a3, a4, (unsigned)((hi << 8) | lo), (unsigned)s_bbErrors);

//    /* back to LPI2C1 */
//    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 1U);
//    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 1U);
//    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0xF861U);
//    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0xF861U);

    /* back to LPI2C1 */
    // FIX 1: Change 1U to 0U to let the LPI2C peripheral control the lines properly
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0U);

    // FIX 2: Change 0xF861U to 0x1F8B0U to turn Open-Drain and proper pulling ON
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0x1F8B0U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0x1F8B0U);

}

/* ------------------------------------------------------------------ */
/* Clocks                                                              */
/* ------------------------------------------------------------------ */
static void audio_clocks_init(void)
{
    CLOCK_InitAudioPll(&s_audioPll);

    /* CHANGED: LPI2C root = OSC 24 MHz, no divide (same as Teensy) */
    CLOCK_SetMux(kCLOCK_Lpi2cMux, 1U);
    CLOCK_SetDiv(kCLOCK_Lpi2cDiv, 0U);

    /* SAI1 root: Audio PLL / 4 / 16 = 12.288 MHz */
    CLOCK_SetMux(kCLOCK_Sai1Mux, 2U);
    CLOCK_SetDiv(kCLOCK_Sai1PreDiv, 3U);
    CLOCK_SetDiv(kCLOCK_Sai1Div, 15U);
    CLOCK_EnableClock(kCLOCK_Sai1);

    /* MCLK pin = output, source = SAI1_CLK_ROOT */
    IOMUXC_GPR->GPR1 = (IOMUXC_GPR->GPR1 & ~IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK) |
                       IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK;

    PRINTF("Audio PLL = %u Hz\r\n", (unsigned)CLOCK_GetFreq(kCLOCK_AudioPllClk));
    PRINTF("SAI1 mux=%u prediv=%u div=%u -> MCLK = %u Hz (expect 12288000)\r\n",
           (unsigned)CLOCK_GetMux(kCLOCK_Sai1Mux),
           (unsigned)CLOCK_GetDiv(kCLOCK_Sai1PreDiv),
           (unsigned)CLOCK_GetDiv(kCLOCK_Sai1Div),
           (unsigned)(CLOCK_GetFreq(kCLOCK_AudioPllClk) /
                      (CLOCK_GetDiv(kCLOCK_Sai1PreDiv) + 1U) /
                      (CLOCK_GetDiv(kCLOCK_Sai1Div) + 1U)));
    PRINTF("LPI2C mux=%u div=%u (expect 1 0 = 24 MHz OSC)\r\n",
           (unsigned)CLOCK_GetMux(kCLOCK_Lpi2cMux), (unsigned)CLOCK_GetDiv(kCLOCK_Lpi2cDiv));
}

/* ------------------------------------------------------------------ */
/* SAI1 (UNCHANGED)                                                    */
/* ------------------------------------------------------------------ */
static void sai_init(void)
{
    sai_transceiver_t cfg;

    SAI_Init(SAI1);
    SAI_GetClassicI2SConfig(&cfg, kSAI_WordWidth16bits, kSAI_Stereo, 1U << 0);
    cfg.masterSlave = kSAI_Master;

    cfg.syncMode = kSAI_ModeAsync;
    SAI_RxSetConfig(SAI1, &cfg);

    cfg.syncMode = kSAI_ModeSync;
    SAI_TxSetConfig(SAI1, &cfg);

    SAI_RxSetBitClockRate(SAI1, MCLK_HZ, SAMPLE_RATE, kSAI_WordWidth16bits, 2U);
    SAI_TxSetBitClockRate(SAI1, MCLK_HZ, SAMPLE_RATE, kSAI_WordWidth16bits, 2U);

    SAI_TxEnable(SAI1, true);
}

/* ------------------------------------------------------------------ */
/* Direct CHIP_ID read                                                 */
/* ------------------------------------------------------------------ */
static bool sgtl_read_chip_id(void)
{
    lpi2c_init_teensy(); /* CHANGED */

    bool found = false;
    const uint8_t addrs[2] = {0x0A, 0x2A};

    for (int a = 0; a < 2; a++)
    {
        uint8_t id[2] = {0};
        lpi2c_master_transfer_t x = {0};
        x.slaveAddress   = addrs[a];
        x.direction      = kLPI2C_Read;
        x.subaddress     = 0x0000U; /* CHIP_ID */
        x.subaddressSize = 2U;
        x.data           = id;
        x.dataSize       = 2U;
        x.flags          = kLPI2C_TransferDefaultFlag;

        status_t s = LPI2C_MasterTransferBlocking(LPI2C1, &x);
        PRINTF("CHIP_ID @0x%x: status=%d id=0x%x\r\n",
               addrs[a], (int)s, (unsigned)((id[0] << 8) | id[1]));
//        if ((s == kStatus_Success) && (id[0] == 0xA0U))
//        {
//            found = true;
//        }

        // Shift the bytes into a single 16-bit word first
        uint16_t chip_id = (id[0] << 8) | id[1];

        // Mask out the revision bits (lower 8 bits) and verify the upper ID matches 0xA000
        if ((s == kStatus_Success) && ((chip_id & 0xFF00) == 0xA000))
        {
            found = true;
        }

    }

    LPI2C_MasterDeinit(LPI2C1);
    return found;
}

/* ------------------------------------------------------------------ */
int main(void)
{
    BOARD_ConfigMPU();
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitDebugConsole();

    PRINTF("\r\n=== SGTL5000 bring-up test (Teensy I2C timing) ===\r\n");

    audio_pins_init();
    audio_clocks_init();
    sai_init();

    SDK_DelayAtLeastUs(100000U, SystemCoreClock);

    slow_bitbang_test();
    lpi2c_scan();

    bool ok = false;
    for (int t = 1; (t <= 3) && !ok; t++)
    {
        PRINTF("-- try %d --\r\n", t);
        ok = sgtl_read_chip_id();
        if (!ok)
        {
            SDK_DelayAtLeastUs(1000000U, SystemCoreClock);
        }
    }
    if (!ok)
    {
        PRINTF("SGTL5000 not answering. Stop.\r\n");
        while (1)
        {
        }
    }

    PRINTF("CHIP_ID OK! Now trying CODEC_Init...\r\n");

    if (CODEC_Init(&s_codec, &s_codecConfig) != kStatus_Success)
    {
        PRINTF("CODEC_Init FAILED\r\n");
        while (1)
        {
        }
    }
    PRINTF("CODEC_Init OK\r\n");

    CODEC_SetMute(&s_codec, CODEC_OUT_CH, false);
    CODEC_SetVolume(&s_codec, CODEC_OUT_CH, 60U);

    for (int i = 0; i < 16; i++)
    {
        s_tone[2 * i]     = s_sineMono[i];
        s_tone[2 * i + 1] = s_sineMono[i];
    }

    PRINTF("Playing 1 kHz tone on headphone / line out...\r\n");

    while (1)
    {
        if ((SAI_TxGetStatusFlag(SAI1) & kSAI_FIFOErrorFlag) != 0U)
        {
            SAI_TxClearStatusFlags(SAI1, kSAI_FIFOErrorFlag);
            SAI_TxSoftwareReset(SAI1, kSAI_ResetTypeFIFO);
        }
        SAI_WriteBlocking(SAI1, 0U, 16U, (uint8_t *)s_tone, sizeof(s_tone));
    }
}


and getting this
=== SGTL5000 bring-up test (Teensy I2C timing) ===
Audio PLL = 786432000 Hz
SAI1 mux=2 prediv=3 div=15 -> MCLK = 12288000 Hz (expect 12288000)
LPI2C mux=1 div=0 (expect 1 0 = 24 MHz OSC)

SLOW bit-bang (1 kHz): idle SCL=1 SDA=1 (expect 1 1)
bit-bang ACK at 0xa
bit-bang scan: 1 found, line errors = 0 (expect 0)
bit-bang CHIP_ID @0x0A: acks=1111 id=0xbfff errors=0
I2C scan ...
 
Last edited:
this is my updated code
Code:
/*
 * Minimal SGTL5000 bring-up for i.MX RT1064 (custom board)
 *
 * Base project : SDK example "hello_world" for evkmimxrt1064
 * What it does : 1. sets up audio PLL -> SAI1 MCLK = 12.288 MHz
 *                2. muxes I2C + SAI pins exactly as on your schematic
 *                3. starts SAI1 so MCLK/BCLK/LRCLK are running
 *                4. reads SGTL5000 CHIP_ID over LPI2C1
 *                5. runs CODEC_Init and plays a 1 kHz sine on headphone/line-out
 *
 * Pin map (from your schematic):
 *   GPIO_AD_B1_00 (J11) LPI2C1_SCL
 *   GPIO_AD_B1_01 (K11) LPI2C1_SDA
 *   GPIO_AD_B1_09 (M13) SAI1_MCLK
 *   GPIO_AD_B1_12 (H12) SAI1_RX_DATA00  (codec DOUT)
 *   GPIO_AD_B1_13 (H11) SAI1_TX_DATA00  (codec DIN)
 *   GPIO_AD_B1_11 (J13) SAI1_RX_BCLK
 *   GPIO_AD_B1_10 (L13) SAI1_RX_SYNC    (LRCLK)
 */

#include "fsl_debug_console.h"
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "fsl_iomuxc.h"
#include "fsl_clock.h"
#include "fsl_lpi2c.h"
#include "fsl_sai.h"
#include "fsl_codec_common.h"
#include "fsl_sgtl5000.h"
#include "fsl_codec_adapter.h"
#include "fsl_gpio.h"

/* ------------------------------------------------------------------ */
/* Settings                                                            */
/* ------------------------------------------------------------------ */
#define MCLK_HZ       12288000U /* 786.432 MHz / 4 / 16 */
#define SAMPLE_RATE   16000U
#define SGTL_ADDR     0x0AU     /* 0x2A if CTRL_ADR0_CS is tied high */
#define LPI2C_CLK_HZ  ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8U) / (5U + 1U)) /* 10 MHz */

#define CODEC_OUT_CH  (kCODEC_PlayChannelHeadphoneLeft | kCODEC_PlayChannelHeadphoneRight | \
                       kCODEC_PlayChannelLineOutLeft   | kCODEC_PlayChannelLineOutRight)

/* Audio PLL = 24 MHz * (32 + 768/1000) = 786.432 MHz */
static const clock_audio_pll_config_t s_audioPll = {
    .loopDivider = 32,
    .postDivider = 1,
    .numerator   = 768,
    .denominator = 1000,
};

static sgtl_config_t s_sgtlConfig = {
    .i2cConfig    = {.codecI2CInstance = 1U, .codecI2CSourceClock = 10000000U},
    .route        = kSGTL_RoutePlayback,
    .slaveAddress = SGTL_ADDR,
    .bus          = kSGTL_BusI2S,
    .format       = {.mclk_HZ = MCLK_HZ, .sampleRate = SAMPLE_RATE, .bitWidth = 16U},
    .master_slave = false, /* codec is slave, RT1064 generates BCLK/LRCLK */
};

static codec_config_t s_codecConfig = {
    .codecDevType   = kCODEC_SGTL5000,
    .codecDevConfig = &s_sgtlConfig,
};

static codec_handle_t s_codec;

/* 1 kHz sine at 16 kHz = 16 samples per period, stereo interleaved */
static const int16_t s_sineMono[16] = {
    0, 3061, 5657, 7391, 8000, 7391, 5657, 3061,
    0, -3061, -5657, -7391, -8000, -7391, -5657, -3061,
};
static int16_t s_tone[32];

/* ------------------------------------------------------------------ */
/* Pins                                                                */
/* ------------------------------------------------------------------ */
static void audio_pins_init(void)
{
    CLOCK_EnableClock(kCLOCK_Iomuxc);

    /* I2C: open-drain, SION on */
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 1U);

    IOMUXC->SELECT_INPUT[kIOMUXC_LPI2C1_SCL_SELECT_INPUT] = 1U;
    IOMUXC->SELECT_INPUT[kIOMUXC_LPI2C1_SDA_SELECT_INPUT] = 1U;
    /* Same pad setting Teensy 4 Wire uses: 22k pull-up ENABLED (PUE=1),
     * open-drain, DSE=4, speed 1, fast slew. */
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0xF861U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0xF861U);

    /* SAI1 */
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_09_SAI1_MCLK, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_11_SAI1_RX_BCLK, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_10_SAI1_RX_SYNC, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_13_SAI1_TX_DATA00, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_12_SAI1_RX_DATA00, 1U);
    /* Weak drive (DSE=1), slow slew: reduces MCLK/BCLK ringing and
     * crosstalk into SDA/SCL on jumper wires. */
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_09_SAI1_MCLK, 0x10B0U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_11_SAI1_RX_BCLK, 0x1008U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_10_SAI1_RX_SYNC, 0x1008U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_13_SAI1_TX_DATA00, 0x1008U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_12_SAI1_RX_DATA00, 0x1008U);
}

/* ------------------------------------------------------------------ */
/* Teensy-style I2C scan: address-only write, same as                  */
/* Wire.beginTransmission(addr); Wire.endTransmission();               */
/* ------------------------------------------------------------------ */
static void lpi2c_scan(void)
{
    lpi2c_master_config_t cfg;
    LPI2C_MasterGetDefaultConfig(&cfg);
    cfg.baudRate_Hz = 100000U;
    LPI2C_MasterInit(LPI2C1, &cfg, LPI2C_CLK_HZ);

    PRINTF("I2C scan (Teensy style)...\r\n");
    int found = 0;
    for (uint8_t addr = 1; addr < 127; addr++)
    {
        uint8_t dummy = 0;
        lpi2c_master_transfer_t x = {0};
        x.slaveAddress = addr;
        x.direction    = kLPI2C_Write;
        x.data         = &dummy;
        x.dataSize     = 0U; /* address only */
        x.flags        = kLPI2C_TransferDefaultFlag;
        if (LPI2C_MasterTransferBlocking(LPI2C1, &x) == kStatus_Success)
        {
            PRINTF("  I2C device found at 0x%02X\r\n", addr);
            found++;
        }
    }
    PRINTF("Scan done: %d device(s)\r\n", found);
    LPI2C_MasterDeinit(LPI2C1);
}


/* ------------------------------------------------------------------ */
/* SLOW bit-bang I2C (~1 kHz) on the same pins, no LPI2C involved.     */
/* Also checks every bit: if a line we released does not go HIGH, or  */
/* reads wrong, something else is fighting the bus -> reported.        */
/* SCL = GPIO1_IO16 (AD_B1_00), SDA = GPIO1_IO17 (AD_B1_01)            */
/* ------------------------------------------------------------------ */
#define BB_SCL 16U
#define BB_SDA 17U
static uint32_t s_bbErrors;

static void bb_wait(void) { SDK_DelayAtLeastUs(250U, SystemCoreClock); }
static void bb_low(uint32_t pin)     { GPIO1->DR &= ~(1UL << pin); GPIO1->GDIR |= (1UL << pin); }
static void bb_release(uint32_t pin) { GPIO1->GDIR &= ~(1UL << pin); }
static uint32_t bb_get(uint32_t pin) { return (GPIO1->PSR >> pin) & 1UL; }

static void bb_scl_high(void)
{
    bb_release(BB_SCL);
    for (int i = 0; (i < 1000) && (bb_get(BB_SCL) == 0U); i++) /* allow clock stretching */
    {
        SDK_DelayAtLeastUs(10U, SystemCoreClock);
    }
    if (bb_get(BB_SCL) == 0U) { s_bbErrors++; }
}

static void bb_start(void)
{
    bb_release(BB_SDA); bb_scl_high(); bb_wait();
    if (bb_get(BB_SDA) == 0U) { s_bbErrors++; }   /* SDA should be high before START */
    bb_low(BB_SDA); bb_wait();
    bb_low(BB_SCL); bb_wait();
}

static void bb_stop(void)
{
    bb_low(BB_SDA); bb_wait();
    bb_scl_high(); bb_wait();
    bb_release(BB_SDA); bb_wait();
}

/* returns true if slave ACKed */
static bool bb_write_byte(uint8_t b)
{
    for (int i = 7; i >= 0; i--)
    {
        if ((b >> i) & 1U) { bb_release(BB_SDA); } else { bb_low(BB_SDA); }
        bb_wait();
        bb_scl_high(); bb_wait();
        if ((((b >> i) & 1U) != 0U) && (bb_get(BB_SDA) == 0U)) { s_bbErrors++; } /* released but low */
        bb_low(BB_SCL); bb_wait();
    }
    bb_release(BB_SDA); bb_wait();
    bb_scl_high(); bb_wait();
    bool ack = (bb_get(BB_SDA) == 0U);
    bb_low(BB_SCL); bb_wait();
    return ack;
}

static uint8_t bb_read_byte(bool ack)
{
    uint8_t b = 0;
    bb_release(BB_SDA);
    for (int i = 0; i < 8; i++)
    {
        bb_wait(); bb_scl_high(); bb_wait();
        b = (uint8_t)((b << 1) | bb_get(BB_SDA));
        bb_low(BB_SCL);
    }
    if (ack) { bb_low(BB_SDA); } else { bb_release(BB_SDA); }
    bb_wait(); bb_scl_high(); bb_wait(); bb_low(BB_SCL); bb_wait();
    bb_release(BB_SDA);
    return b;
}

static void slow_bitbang_test(void)
{
    gpio_pin_config_t in = {kGPIO_DigitalInput, 0U, kGPIO_NoIntmode};

    /* GPIO mode, open-drain, hysteresis ON, 22k pull-up */
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_GPIO1_IO16, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_GPIO1_IO17, 1U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_GPIO1_IO16, 0x1F8B0U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_GPIO1_IO17, 0x1F8B0U);
    GPIO_PinInit(GPIO1, BB_SCL, &in);
    GPIO_PinInit(GPIO1, BB_SDA, &in);
    SDK_DelayAtLeastUs(1000U, SystemCoreClock);

    PRINTF("\r\nSLOW bit-bang (1 kHz): idle SCL=%u SDA=%u (expect 1 1)\r\n",
           (unsigned)bb_get(BB_SCL), (unsigned)bb_get(BB_SDA));

    /* 9 clocks to free a stuck slave */
    bb_release(BB_SDA);
    for (int i = 0; i < 9; i++) { bb_low(BB_SCL); bb_wait(); bb_scl_high(); bb_wait(); }
    bb_stop();

    s_bbErrors = 0;
    int found = 0;
    for (uint8_t a = 0x08; a <= 0x77; a++)
    {
        bb_start();
        bool ack = bb_write_byte((uint8_t)(a << 1));
        bb_stop();
        if (ack) { PRINTF("  bit-bang ACK at 0x%02X\r\n", a); found++; }
    }
    PRINTF("bit-bang scan: %d found, line errors = %u (expect 0)\r\n", found, (unsigned)s_bbErrors);

    /* Direct CHIP_ID read at 0x0A */
    s_bbErrors = 0;
    bb_start();
    bool a1 = bb_write_byte(0x0A << 1);
    bool a2 = bb_write_byte(0x00);
    bool a3 = bb_write_byte(0x00);
    bb_start();                           /* repeated START */
    bool a4 = bb_write_byte((0x0A << 1) | 1U);
    uint8_t hi = bb_read_byte(true);
    uint8_t lo = bb_read_byte(false);
    bb_stop();
    PRINTF("bit-bang CHIP_ID @0x0A: acks=%d%d%d%d id=0x%02X%02X errors=%u\r\n",
           a1, a2, a3, a4, hi, lo, (unsigned)s_bbErrors);

    /* back to LPI2C1 */
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 1U);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 1U);

    IOMUXC->SELECT_INPUT[kIOMUXC_LPI2C1_SCL_SELECT_INPUT] = 1U;
    IOMUXC->SELECT_INPUT[kIOMUXC_LPI2C1_SDA_SELECT_INPUT] = 1U;

    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0xF861U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0xF861U);
}

/* ------------------------------------------------------------------ */
/* Clocks                                                              */
/* ------------------------------------------------------------------ */
static void audio_clocks_init(void)
{
    CLOCK_InitAudioPll(&s_audioPll);

    /* LPI2C root: PLL3/8 = 60 MHz, /6 = 10 MHz */
    CLOCK_SetMux(kCLOCK_Lpi2cMux, 0U);
    CLOCK_SetDiv(kCLOCK_Lpi2cDiv, 5U);

    /* SAI1 root: Audio PLL / 4 / 16 = 12.288 MHz */
    CLOCK_SetMux(kCLOCK_Sai1Mux, 2U);
    CLOCK_SetDiv(kCLOCK_Sai1PreDiv, 3U);
    CLOCK_SetDiv(kCLOCK_Sai1Div, 15U);
    CLOCK_EnableClock(kCLOCK_Sai1);

    /* MCLK pin = output, source = SAI1_CLK_ROOT */
    IOMUXC_GPR->GPR1 = (IOMUXC_GPR->GPR1 & ~IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK) |
                       IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK;

    PRINTF("Audio PLL = %u Hz\r\n", (unsigned)CLOCK_GetFreq(kCLOCK_AudioPllClk));
    PRINTF("SAI1 mux=%u prediv=%u div=%u -> MCLK = %u Hz (expect 12288000)\r\n",
           (unsigned)CLOCK_GetMux(kCLOCK_Sai1Mux),
           (unsigned)CLOCK_GetDiv(kCLOCK_Sai1PreDiv),
           (unsigned)CLOCK_GetDiv(kCLOCK_Sai1Div),
           (unsigned)(CLOCK_GetFreq(kCLOCK_AudioPllClk) /
                      (CLOCK_GetDiv(kCLOCK_Sai1PreDiv) + 1U) /
                      (CLOCK_GetDiv(kCLOCK_Sai1Div) + 1U)));
    PRINTF("LPI2C clock = %u Hz (expect 10000000)\r\n", (unsigned)LPI2C_CLK_HZ);
}

/* ------------------------------------------------------------------ */
/* SAI1: RX = clock master on RX_BCLK/RX_SYNC pins, TX synced to RX    */
/* ------------------------------------------------------------------ */
static void sai_init(void)
{
    sai_transceiver_t cfg;

    SAI_Init(SAI1);
    SAI_GetClassicI2SConfig(&cfg, kSAI_WordWidth16bits, kSAI_Stereo, 1U << 0);
    cfg.masterSlave = kSAI_Master;

    cfg.syncMode = kSAI_ModeAsync; /* RX drives BCLK + LRCLK */
    SAI_RxSetConfig(SAI1, &cfg);

    cfg.syncMode = kSAI_ModeSync;  /* TX uses RX clocks */
    SAI_TxSetConfig(SAI1, &cfg);

    SAI_RxSetBitClockRate(SAI1, MCLK_HZ, SAMPLE_RATE, kSAI_WordWidth16bits, 2U);
    SAI_TxSetBitClockRate(SAI1, MCLK_HZ, SAMPLE_RATE, kSAI_WordWidth16bits, 2U);

    /* In sync mode this also enables RX, so BCLK/LRCLK start running */
    SAI_TxEnable(SAI1, true);
}

/* ------------------------------------------------------------------ */
/* Direct CHIP_ID read, independent of the codec driver                */
/* ------------------------------------------------------------------ */
static bool sgtl_read_chip_id(void)
{
    lpi2c_master_config_t cfg;
    LPI2C_MasterGetDefaultConfig(&cfg);
    cfg.baudRate_Hz = 100000U;
    LPI2C_MasterInit(LPI2C1, &cfg, LPI2C_CLK_HZ);

    bool found = false;
    const uint8_t addrs[2] = {0x0A, 0x2A};

    for (int a = 0; a < 2; a++)
    {
        uint8_t id[2] = {0};
        lpi2c_master_transfer_t x = {0};
        x.slaveAddress   = addrs[a];
        x.direction      = kLPI2C_Read;
        x.subaddress     = 0x0000U; /* CHIP_ID */
        x.subaddressSize = 2U;
        x.data           = id;
        x.dataSize       = 2U;
        x.flags          = kLPI2C_TransferDefaultFlag;

        status_t s = LPI2C_MasterTransferBlocking(LPI2C1, &x);
        PRINTF("CHIP_ID @0x%02X: status=%d id=0x%02X%02X\r\n",
               addrs[a], (int)s, id[0], id[1]);
        if ((s == kStatus_Success) && (id[0] == 0xA0U))
        {
            found = true;
        }
    }

    LPI2C_MasterDeinit(LPI2C1);
    return found;
}

/* ------------------------------------------------------------------ */
int main(void)
{
    BOARD_ConfigMPU();
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitDebugConsole();

    PRINTF("\r\n=== SGTL5000 bring-up test ===\r\n");

    audio_pins_init();
    audio_clocks_init();
    sai_init();

    /* Give the codec time with MCLK running before first I2C access */
    SDK_DelayAtLeastUs(100000U, SystemCoreClock);

    slow_bitbang_test();
    lpi2c_scan();

    bool ok = false;
    for (int t = 1; (t <= 3) && !ok; t++)
    {
        PRINTF("-- try %d --\r\n", t);
        ok = sgtl_read_chip_id();
        if (!ok)
        {
            SDK_DelayAtLeastUs(1000000U, SystemCoreClock);
        }
    }
    if (!ok)
    {
        PRINTF("SGTL5000 not answering. Stop.\r\n");
        while (1)
        {
        }
    }

    if (CODEC_Init(&s_codec, &s_codecConfig) != kStatus_Success)
    {
        PRINTF("CODEC_Init FAILED\r\n");
        while (1)
        {
        }
    }
    PRINTF("CODEC_Init OK\r\n");

    CODEC_SetMute(&s_codec, CODEC_OUT_CH, false);
    CODEC_SetVolume(&s_codec, CODEC_OUT_CH, 60U);

    /* Build stereo tone buffer */
    for (int i = 0; i < 16; i++)
    {
        s_tone[2 * i]     = s_sineMono[i]; /* L */
        s_tone[2 * i + 1] = s_sineMono[i]; /* R */
    }

    PRINTF("Playing 1 kHz tone on headphone / line out...\r\n");

    while (1)
    {
        if ((SAI_TxGetStatusFlag(SAI1) & kSAI_FIFOErrorFlag) != 0U)
        {
            SAI_TxClearStatusFlags(SAI1, kSAI_FIFOErrorFlag);
            SAI_TxSoftwareReset(SAI1, kSAI_ResetTypeFIFO);
        }
        SAI_WriteBlocking(SAI1, 0U, 16U, (uint8_t *)s_tone, sizeof(s_tone));
    }
}

and here the initilaization


Code:
#define IOMUXC_GPIO_AD_B1_00_USB_OTG2_ID 0x401F80FCU, 0x0U, 0x401F83F8U, 0x1U, 0x401F82ECU
#define IOMUXC_GPIO_AD_B1_00_QTIMER3_TIMER0 0x401F80FCU, 0x1U, 0x401F857CU, 0x1U, 0x401F82ECU
#define IOMUXC_GPIO_AD_B1_00_LPUART2_CTS_B 0x401F80FCU, 0x2U, 0, 0, 0x401F82ECU
#define IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL 0x401F80FCU, 0x3U, 0x401F84CCU, 0x1U, 0x401F82ECU
#define IOMUXC_GPIO_AD_B1_00_WDOG1_B 0x401F80FCU, 0x4U, 0, 0, 0x401F82ECU
#define IOMUXC_GPIO_AD_B1_00_GPIO1_IO16 0x401F80FCU, 0x5U, 0, 0, 0x401F82ECU
#define IOMUXC_GPIO_AD_B1_00_USDHC1_WP 0x401F80FCU, 0x6U, 0x401F85D8U, 0x2U, 0x401F82ECU
#define IOMUXC_GPIO_AD_B1_00_KPP_ROW07 0x401F80FCU, 0x7U, 0, 0, 0x401F82ECU
#define IOMUXC_GPIO_AD_B1_00_ENET2_1588_EVENT0_OUT 0x401F80FCU, 0x8U, 0, 0, 0x401F82ECU
#define IOMUXC_GPIO_AD_B1_00_FLEXIO3_FLEXIO00 0x401F80FCU, 0x9U, 0, 0, 0x401F82ECU

#define IOMUXC_GPIO_AD_B1_01_USB_OTG1_PWR 0x401F8100U, 0x0U, 0, 0, 0x401F82F0U
#define IOMUXC_GPIO_AD_B1_01_QTIMER3_TIMER1 0x401F8100U, 0x1U, 0x401F8580U, 0x0U, 0x401F82F0U
#define IOMUXC_GPIO_AD_B1_01_LPUART2_RTS_B 0x401F8100U, 0x2U, 0, 0, 0x401F82F0U
#define IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA 0x401F8100U, 0x3U, 0x401F84D0U, 0x1U, 0x401F82F0U
#define IOMUXC_GPIO_AD_B1_01_CCM_PMIC_READY 0x401F8100U, 0x4U, 0x401F83FCU, 0x2U, 0x401F82F0U
#define IOMUXC_GPIO_AD_B1_01_GPIO1_IO17 0x401F8100U, 0x5U, 0, 0, 0x401F82F0U
#define IOMUXC_GPIO_AD_B1_01_USDHC1_VSELECT 0x401F8100U, 0x6U, 0, 0, 0x401F82F0U
#define IOMUXC_GPIO_AD_B1_01_KPP_COL07 0x401F8100U, 0x7U, 0, 0, 0x401F82F0U
#define IOMUXC_GPIO_AD_B1_01_ENET2_1588_EVENT0_IN 0x401F8100U, 0x8U, 0x401F8724U, 0x0U, 0x401F82F0U
#define IOMUXC_GPIO_AD_B1_01_FLEXIO3_FLEXIO01 0x401F8100U, 0x9U, 0, 0, 0x401F82F0U
output;-
=== SGTL5000 bring-up test ===
Audio PLL = 786432000 Hz
SAI1 mux=2 prediv=3 div=15 -> MCLK = 12288000 Hz (expect 12288000)
LPI2C clock = 10000000 Hz (expect 10000000)

SLOW bit-bang (1 kHz): idle SCL=1 SDA=1 (expect 1 1)
bit-bang ACK at 0x A
bit-bang scan: 1 found, line errors = 0 (expect 0)
bit-bang CHIP_ID @0x0A: acks=1111 id=0xA01F errors=0
I2C scan (Teensy style)...
Scan done: 0 device(s)
-- try 1 --
CHIP_ID @0x A: status=902 id=0x 0 0
CHIP_ID @0x2A: status=902 id=0x 0 0
-- try 2 --
CHIP_ID @0x A: status=902 id=0x 0 0
CHIP_ID @0x2A: status=902 id=0x 0 0
-- try 3 --
CHIP_ID @0x A: status=902 id=0x 0 0
CHIP_ID @0x2A: status=902 id=0x 0 0
SGTL5000 not answering. Stop.
 
Last edited:
Update: MCLK testing results


The RT1064 board and the codec board are two separate boards, connected with jumper wires. I tested the codec using MCLK from two different sources, with the same RT1064 I2C firmware.


Test 1: MCLK from the RT1064 (SAI1_MCLK, GPIO_AD_B1_09, 12.288 MHz)


  • A DC multimeter on the MCLK pin reads about 1.57 V (supply about 3.1 V).
  • Slow bit-bang I2C (~1 kHz): the codec ACKs, but CHIP_ID reads 0xBFFF / 0xA01F instead of 0xA011.
  • LPI2C at 5, 10, 20, 50 and 100 kHz: NAK at every speed (status 902).
  • With a weak MCLK pad setting (0x1008), the codec doesn't answer at all and the MCLK pin reads about 0 V.
  • Different MCLK pad drive settings made no difference.

Test 2: MCLK from a Teensy 4 (pin 23)


  • RT1064 MCLK jumper wire disconnected from the codec board.
  • Teensy MCLK connected to the codec board's MCLK pad , Teensy GND connected to the codec board's GND.
  • RT1064 still drives I2C (SCL/SDA) through jumper wires.
  • RT1064 LPI2C at 100 kHz: CHIP_ID = 0xA011 and CODEC_Init OK.
  • A DC multimeter on the Teensy MCLK reads about 1.7 V (3.3 V supply).

Conclusion so far
The codec board, its power supplies, the I2C wiring and the I2C firmware all work. The problem is only the MCLK coming from the RT1064 board. The DC level looks normal on a multimeter, but the codec behaves as if the 12.288 MHz clock arriving from the RT1064 is not usable.
 
connected with jumper wires
MCLK (~12 Mhz+ fast edges) via jumper wires is often unreliable. It should be kept as short as possible. If that doesn’t help, try adding a resistor (range 47–68 ohms) in series. Can you take a photo?
 
Last edited:
I already have a 100 Ω series resistor on the MCLK line. You can see it in the codec schematic that I posted in the previous chats.

When I tested my codec custom board with a Teensy, all the connections were made using jumper wires, and the codec worked correctly.

In another test, I connected only the I2C pins of the codec board to my RT1064 custom PCB, while the MCLK was supplied from the Teensy through a jumper wire. In this case also, the codec initialized and worked correctly.

However, when I soldered the codec custom PCB directly to the RT1064 custom PCB, the codec stopped working and I was unable to initialize it.

This makes me suspect that the problem may be related to the MCLK generated by the RT1064. The RT1064 may not be generating a proper clock signal for the codec. I am measuring approximately 1.57 V on the MCLK pin with a multimeter.

Currently, there is already a 100 Ω series resistor on the MCLK line.

Should I add another 47–68 Ω resistor in series with the existing 100 Ω resistor, or would that make the total series resistance too high?

Or is it more likely that there is a configuration issue in my RT1064 program, such as the MCLK clock source, PLL configuration, clock divider, pin mux, or SAI configuration?
 
Make sure there is indeed a solid connection between the MCU's pin and the 100R resistor.
1.57V measured with the multimeter is an averaged value, since it cannot measure such high frequencies.

Maybe the solder ball is flaky for that pin and the clock signal gets distorted, confusing the codec. The DC voltage measurement will not show it.

If you don't have a scope or one of those cheap logic analyzers, write a simple sketch setting the MCLk pin to OUTPUT_OPENDRAIN, add an external 10k pull up and toggle the pin each few hundred ms. Observe the multimeter and watch for any missed level changes.

If your multimeter has a duty cycle mode (%) you could also output a lower frequency PWM (ie 10kHz, depends on the multuimeter specs) on the MCLK pin, sweep the PWM duty in steps and look for any weird unstable readings. Blow some hot air on the MCU to see if the thermal expansion is causing any issues.

I guess you could also try to use a PWM audio output on the MCLK pin, add a sinewave generator, run the signal through a RC filter and record it on the PC into Audacity or any other audio editor. Any unregular distortion, glitches would indicate there is something wrong with the path between the MCLK pin and the outside world.
A scope would be ideal, but if there is none, there are other indirect test methods.
 
Back
Top