TDM with AK4619

john-mike

Well-known member
Update - realized I was mixed up about TDM in and out object pins. But still not getting the correct output.

I'm trying to get the AK4619 codec working via TDM with a 4.1 but with no luck so far. Right now I'm trying to determine if it's the hardware as it's hand soldered to a breakout board, the i2c setup, or something else.
I have the device hook up as descried in the TDM object(s!) on the tool.

I'm seeing the correct clocks on 23,21, and 20 and data on 7.

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioSynthWaveform waveform2;  //xy=371.46665954589844,254.46665954589844
AudioSynthWaveform waveform1;  //xy=409.46665954589844,214.46665954589844
AudioOutputTDM tdm2;           //xy=609.4667911529541,345.4666748046875
AudioConnection patchCord1(waveform2, 0, tdm2, 1);
AudioConnection patchCord2(waveform1, 0, tdm2, 0);
AudioConnection patchCord3(waveform2, 0, tdm2, 2);
AudioConnection patchCord4(waveform1, 0, tdm2, 3);
// GUItool: end automatically generated code

unsigned long current_time;
unsigned long prev_time[8];

byte br[40];

void setup() {
  AudioNoInterrupts();
  delay(500);
  AK2619_start();

  AudioMemory(100);
  waveform1.begin(1, 220, WAVEFORM_SINE);
  waveform2.begin(1, 440, WAVEFORM_SINE);
  AudioInterrupts();
}


void loop() {
  current_time = millis();

  if (current_time - prev_time[0] > 500 && 0) {
    prev_time[0] = current_time;
    Serial.print(AudioProcessorUsageMax());
    Serial.print(" ");
    Serial.print(AudioMemoryUsageMax());
    Serial.println();
    AudioProcessorUsageMaxReset();
    AudioMemoryUsageMaxReset();
  }
}

void AK2619_start() {
  Wire.begin();

  Wire.beginTransmission(0x11);

  Wire.write(0);
  Wire.write(B00110111);  //turn all on

  Wire.endTransmission();

  Wire.beginTransmission(0x11);

  Wire.write(1);
  Wire.write(B11111100);  //tdm

  Wire.endTransmission();

  Wire.beginTransmission(0x11);

  Wire.write(2);
  Wire.write(B00011100);  //tdm

  Wire.endTransmission();


  Wire.beginTransmission(0x11);
  Wire.write(0);
  Wire.endTransmission();

  Wire.beginTransmission(0x11);
  Wire.requestFrom(0x11, 4);

  br[0] = Wire.read();
  br[1] = Wire.read();
  br[2] = Wire.read();
  br[3] = Wire.read();

  Wire.endTransmission();
  for (byte j = 0; j < 4; j++) {
    Serial.println(br[j], BIN);
  }

}
 

Attachments

  • DS1Z_QuickPrint4.png
    DS1Z_QuickPrint4.png
    38.1 KB · Views: 27
Last edited:
More AudioMemory()? TDM objects need quite a lot, try at least 50…
Oh good point. I did that but no luck.

I did realize that there are separate connections for the TDM in and OUT in the tool.
I've removed the input object and changed the wire from 8 to 7 as that's the one sending the data.
My question about the little 44.1k pulse was answered by Paul's great video in the TDA output object as I was just looking at the input ooops.

Now with pin 7 going to the data in of the AK4619 but it's just making a quiet,15kHz sound.

Back to checking reg settings.
 
Last edited:
You don’t appear to be giving it a reset pulse on the PDN pin before initialising it. That’s proved important with other parts…
 
Another good point! Thanks again.
I've added it with no luck though.
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// GUItool: begin automatically generated code
AudioInputTDM tdm1;            //xy=183.46671676635742,349.4666748046875
AudioSynthWaveform waveform2;  //xy=371.46665954589844,254.46665954589844
AudioSynthWaveform waveform1;  //xy=409.46665954589844,214.46665954589844
AudioOutputTDM tdm2;           //xy=609.4667911529541,345.4666748046875
AudioConnection patchCord1(waveform2, 0, tdm2, 1);
AudioConnection patchCord2(waveform1, 0, tdm2, 0);
AudioConnection patchCord3(waveform2, 0, tdm2, 2);
AudioConnection patchCord4(waveform1, 0, tdm2, 3);
// GUItool: end automatically generated code
unsigned long current_time;
unsigned long prev_time[8];
byte br[40];
#define pdn_pin 32

void setup() {
  AudioNoInterrupts();
  pinMode(32, OUTPUT);
  digitalWrite(pdn_pin, 0);
  delay(100);
  digitalWrite(pdn_pin, 1);
  delay(100);
  AK2619_start();
  
  AudioMemory(100);
  waveform1.begin(1, 220, WAVEFORM_SINE);
  waveform2.begin(1, 440, WAVEFORM_SINE);
  AudioInterrupts();
}

void loop() {
  current_time = millis();
  if (current_time - prev_time[0] > 500 && 1) {
    prev_time[0] = current_time;
    Wire.beginTransmission(0x11);
    byte error = Wire.endTransmission();
    Serial.println(error);
    Serial.print(AudioProcessorUsageMax());
    Serial.print(" ");
    Serial.print(AudioMemoryUsageMax());
    Serial.println();
    AudioProcessorUsageMaxReset();
    AudioMemoryUsageMaxReset();
  }
}
void AK2619_start() {
  Wire.begin();
  Wire.beginTransmission(0x11);
  Wire.write(0);
  Wire.write(B00110111);  //turn all on
  Wire.endTransmission();
  Wire.beginTransmission(0x11);
  Wire.write(1);
  Wire.write(B11110000);  //tdm
  Wire.endTransmission();
  Wire.beginTransmission(0x11);
  Wire.write(2);
  Wire.write(B0001000);  //tdm
  Wire.endTransmission();

  Wire.beginTransmission(0x11);
  Wire.write(0);
  Wire.endTransmission();
  Wire.beginTransmission(0x11);
  Wire.requestFrom(0x11, 4);
  br[0] = Wire.read();
  br[1] = Wire.read();
  br[2] = Wire.read();
  br[3] = Wire.read();
  Wire.endTransmission();
  for (byte j = 0; j < 4; j++) {
    printBits(br[j]);
  }
}

void printBits(byte myByte){
  for(byte mask = 0x80; mask; mask >>= 1){
    if(mask  & myByte){
      Serial.print('1');
    }
    else{
      Serial.print('0');
    }
  }
      Serial.println("B ");
}
 
Rebuilt the circuit on perfboard with the same results. I think the breakout is properly soldered as it stops making noise if any wire is removed.
You can hear slight changes in the noise if you change the output frequency so I'm still thinking its an issue with the i2c setup?

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputTDM tdm1;            //xy=183.46671676635742,349.4666748046875
AudioSynthWaveform waveform2;  //xy=371.46665954589844,254.46665954589844
AudioSynthWaveform waveform1;  //xy=409.46665954589844,214.46665954589844
AudioOutputTDM tdm2;           //xy=609.4667911529541,345.4666748046875
AudioConnection patchCord1(waveform1, 0, tdm2, 1);
AudioConnection patchCord2(waveform1, 0, tdm2, 0);
// GUItool: end automatically generated code

unsigned long current_time;
unsigned long prev_time[8];

byte br[40];

#define pdn_pin 32


void setup() {
  AudioNoInterrupts();
  pinMode(32, OUTPUT);
  digitalWrite(pdn_pin, 0);
  delay(100);
  digitalWrite(pdn_pin, 1);
  delay(100);
  AK2619_start();


  AudioMemory(100);
  waveform1.begin(1, 220, WAVEFORM_SINE);
  waveform2.begin(1, 440, WAVEFORM_SINE);
  AudioInterrupts();
}


void loop() {
  current_time = millis();

  if (current_time - prev_time[0] > 1000 && 1) {
    prev_time[0] = current_time;
    Wire.beginTransmission(0x11);
    byte error = Wire.endTransmission();
    Serial.print(error);
    waveform1.frequency(random(10, 100) * 10.0);
    waveform2.frequency(random(10, 100) * 10.0);

    Serial.print(" ");
    Serial.print(AudioProcessorUsageMax());
    Serial.print(" ");
    Serial.print(AudioMemoryUsageMax());
    Serial.println();
    AudioProcessorUsageMaxReset();
    AudioMemoryUsageMaxReset();
  }
}

void AK2619_start() {
  Wire.begin();

  Wire.beginTransmission(0x11);

  Wire.write(0);
  Wire.write(B00110110);  //turn all on

  Wire.endTransmission();

  Wire.beginTransmission(0x11);

  Wire.write(1);
  Wire.write(B11111100);  //tdm

  Wire.endTransmission();

  Wire.beginTransmission(0x11);

  Wire.write(2);
  Wire.write(B00011100);  //tdm

  Wire.endTransmission();

  // Wire.beginTransmission(0x11);
  // Wire.write(12);
  // Wire.write(B0000000);  //dacxsel sdin 1 vs 2?
  // Wire.endTransmission();

  Wire.beginTransmission(0x11);

  Wire.write(0);
  Wire.write(B00110111);  //turn all on AGAIN

  Wire.endTransmission();


  Wire.beginTransmission(0x11);
  Wire.write(0);
  Wire.endTransmission();
  Wire.beginTransmission(0x11);
  Wire.requestFrom(0x11, 4);

  br[0] = Wire.read();
  br[1] = Wire.read();
  br[2] = Wire.read();
  br[3] = Wire.read();

  Wire.endTransmission();
  for (byte j = 0; j < 4; j++) {
    printBits(br[j]);
  }
}


void printBits(byte myByte) {
  for (byte mask = 0x80; mask; mask >>= 1) {
    if (mask & myByte) {
      Serial.print('1');
    } else {
      Serial.print('0');
    }
  }
  Serial.println("B ");
}
 
I got a new chip and soldered it using a stencil and paste this time but same results.
I believe I've tried pretty much every combination of TDM settings and they all give similar faint noise that changes when the oscillators change.
Any ideas @Paul ?

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputTDM tdm1;            //xy=183.46671676635742,349.4666748046875
AudioSynthWaveform waveform2;  //xy=371.46665954589844,254.46665954589844
AudioSynthWaveform waveform1;  //xy=409.46665954589844,214.46665954589844
AudioOutputTDM tdm2;           //xy=609.4667911529541,345.4666748046875
AudioConnection patchCord1(waveform1, 0, tdm2, 1);
AudioConnection patchCord2(waveform2, 0, tdm2, 0);
AudioConnection patchCord3(waveform1, 0, tdm2, 2);
AudioConnection patchCord4(waveform2, 0, tdm2, 3);
// GUItool: end automatically generated code

unsigned long current_time;
unsigned long prev_time[8];

byte br[40];

#define pdn_pin 32


void setup() {
  AudioNoInterrupts();
  pinMode(32, OUTPUT);
  digitalWrite(pdn_pin, 0);
  delay(100);
  digitalWrite(pdn_pin, 1);
  delay(100);
  AK2619_start();
  delay(100);


  AudioMemory(100);
  waveform1.begin(1, 220, WAVEFORM_SINE);
  waveform2.begin(1, 440, WAVEFORM_SINE);
  AudioInterrupts();
}


void loop() {
  current_time = millis();

  if (current_time - prev_time[0] > 1000 && 1) {
    prev_time[0] = current_time;

    waveform1.frequency(random(10, 100) * 10.0);
    waveform2.frequency(random(10, 100) * 10.0);

    byte error = 0;
    if (1) {
      Wire.beginTransmission(0x11);
      error = Wire.endTransmission();
      if (error > 0) {
        Serial.print("i2c error ");
        Serial.println(error);
      }
    }

    if (0) {
    Serial.print(AudioProcessorUsageMax());
    Serial.print(" ");
    Serial.print(AudioMemoryUsageMax());
    Serial.println();
    AudioProcessorUsageMaxReset();
    AudioMemoryUsageMaxReset();
  }
}
}

void AK2619_start() {
  Wire.begin();

  Wire.beginTransmission(0x11);
  Wire.write(0);
  Wire.write(B00110111);  //turn all on
  Wire.endTransmission();

  delay(10);

  Wire.beginTransmission(0x11);
  Wire.write(1);
  Wire.write(B11111100);  //tdm
  Wire.endTransmission();

  Wire.beginTransmission(0x11);
  Wire.write(2);
  Wire.write(B00011111);  //tdm
  Wire.endTransmission();

  Wire.beginTransmission(0x11);
  Wire.write(3);
  Wire.write(B00000000);  //clock
  Wire.endTransmission();

  if (1) {
    byte rn = 4;
    Wire.beginTransmission(0x11);
    Wire.write(0);
    Wire.endTransmission();
    Wire.beginTransmission(0x11);

    Wire.requestFrom(0x11, rn);
    for (byte j = 0; j < rn; j++) {
      br[j] = Wire.read();
    }
    Wire.endTransmission();
    for (byte j = 0; j < rn; j++) {
      Serial.print(j, HEX);
      Serial.print(" ");
      printBits(br[j]);
    }
    Serial.println();
  }
}

void printBits(byte myByte) {
  for (byte mask = 0x80; mask; mask >>= 1) {
    if (mask & myByte) {
      Serial.print('1');
    } else {
      Serial.print('0');
    }
  }
  Serial.println(" ");
}
 
What analog input mode are you using on the AK4619? The chip has three possible ways to connect your audio. The AK4619 datasheet has this information:

9.7. Analog input mode​

Three analog input modes are available: single-ended input, differential input, and pseudo-differential input. These modes are selected by ADxLSEL[1:0], ADxRSEL[1:0] bits(x = 1, 2), (Table 10).

IN single-ended mode, 2:1 multiplexer is used to select which pin to route to each ADC input.

Pseudo-differential signals may not be applied in differential input mode.

NB: the default is differential mode. Depending on which analog input pins you are using, you may need to select the correct mode by writing to the analog input setting register (register 0x0b). In my case, I am using single-ended mode 1, so my set-up code includes the following:

C:
  // ================== Values to send to the Analog Input mode register

  // Inputs to AIN1L, AIN1R, AIN4L and AIN4R
#define SINGLE_ENDED_MODE_1 0b01010101
  // Inputs to AIN2L, AIN2R, AIN5L and AIN5R
#define SINGLE_ENDED_MODE_2 0b10101010

  // Inputs to AIN3L/GND3L, AIN4L/GND4R. AIN6L/GND6L and AIN6R/GND6R
#define PSEUDO_MODE 0b11111111

  unsigned int AK4619_INPUT_MODE = SINGLE_ENDED_MODE_1;  // Set this variable to the required input mode register setting value


  Wire.beginTransmission(CodecAddress);  // Send START to AK4619 I2C Address = 0x10 (CAD pin = Low) or 0x11 (CAD pin = High)
  Wire.write(AK4619_ADC_ANALOG_INPUT);   // Send to the ADC Analog Input Setting register
  Wire.write(AK4619_INPUT_MODE);         // Send the data to set input mode
  returnCode = Wire.endTransmission();   // Send STOP
 
This is my set-up code for the AK4619 codec.

C:
void configure_AK4619_Codec(int CodecAddress) {

  uint8_t returnCode;

  // Do NOT call this function directly: use the setUpCodec() function above as this will ensure the correct configuration function for the fitted Codec is called

  /* Set audio inputs to Single-Ended1 mode See table 10, p43 in the AK4619 Datasheet
     Single-Ended1 mode uses the following analog inputs on the AK4619 chip

     Pin  Input
     16   AIN1L
     14   AIN1R
     12   AIN4L
     10   AIN4R

  */

  // ================== Values to send to the Analog Input mode register

  // Inputs to AIN1L, AIN1R, AIN4L and AIN4R
#define SINGLE_ENDED_MODE_1 0b01010101
  // Inputs to AIN2L, AIN2R, AIN5L and AIN5R
#define SINGLE_ENDED_MODE_2 0b10101010

  // Inputs to AIN3L/GND3L, AIN4L/GND4R. AIN6L/GND6L and AIN6R/GND6R
#define PSEUDO_MODE 0b11111111

  unsigned int AK4619_INPUT_MODE = SINGLE_ENDED_MODE_1;  // Set this variable to the required input mode register setting value


  Wire.beginTransmission(CodecAddress);  // Send START to AK4619 I2C Address = 0x10 (CAD pin = Low) or 0x11 (CAD pin = High)
  Wire.write(AK4619_ADC_ANALOG_INPUT);   // Send to the ADC Analog Input Setting register
  Wire.write(AK4619_INPUT_MODE);         // Send the data to set input mode
  returnCode = Wire.endTransmission();   // Send STOP

#ifdef DEBUG_CODEC_SETUP
  printf("Value sent to AK4619 Analog Input Setting Register = %.8b (0x%.2x)\n", AK4619_INPUT_MODE, AK4619_INPUT_MODE);
  printf("Wire (I2C) returned: %u <%s>\n", returnCode, WIRE_RETURN_CODE[returnCode]);
#endif

  //#define DO_LOOP_THROUGH_TEST

#ifdef DO_LOOP_THROUGH_TEST
  Wire.beginTransmission(CodecAddress);  // Send START to AK4619 I2C Address = 0x10 (CAD pin = Low) or 0x11 (CAD pin = High)
  Wire.write(AK4619_DAC_INPUT_SELECT);   //
  Wire.write(0b1110);                    // Send the ADC1 SDOUT1 -> DAC1 and ADC2 SDOUT2 -> DAC2 See page 49
  returnCode = Wire.endTransmission();   // Send STOP
#endif


  /*
     Power up the ADCs and DACs in the AK4619 by writing to the Power Management Register -  Datasheet page 60

    D7   D6    D5    D4    D3    D2    D1    D0
    0    0   PMAD2  PMAD1  0    PMDA2 PMDA1 RSTN
  */


  delay(100);  // See the AK4619 Datasheet page 42: "Start-up time on Analog input pin" - it recommends waiting 100ms for input caps to charge to avoid pop noise

  Wire.beginTransmission(CodecAddress);                                                 // Send START to AK4619 I2C Address = 0x10 (CAD pin = Low) or 0x11 (CAD pin = High)
  Wire.write(AK4619_PWR_MNGT);                                                          // Send to the Power Management register
  Wire.write(AK4619_PMAD2 | AK4619_PMAD1 | AK4619_PMDA2 | AK4619_PMDA1 | AK4619_RSTN);  // The data
  returnCode = Wire.endTransmission();                                                  // Send STOP

#ifdef DEBUG_CODEC_SETUP
  printf("Value sent to AK4619 Power Management Register = %.8b (0x%.2x)\n", AK4619_PMAD2 | AK4619_PMAD1 | AK4619_PMDA2 | AK4619_PMDA1 | AK4619_RSTN, AK4619_PMAD2 | AK4619_PMAD1 | AK4619_PMDA2 | AK4619_PMDA1 | AK4619_RSTN);
  printf("Wire (I2C) returned: %u <%s>\n", returnCode, WIRE_RETURN_CODE[returnCode]);
#endif

#ifdef SET_MIC_GAIN
  AK4619_SetMicGain(0);
#endif

  // #define DO_ADC_VOLUME_CHECK

#ifdef DO_ADC_VOLUME_CHECK
  for (int v = 0x30; v < 0xff; v++) {
    AK4619_SetADC1_Volume(v);  // -50dB
    delay(20);
  }
#endif
}

One thing I found when reading back the AK4619 registers to check the configration, I had to do a dummy write before reading the registers, otherwise the wrong registers are returned. There's a note in the datasheet Section 2-2, page 58 that states this:
2-2. Random Address Read

The random read operation allows the master to access any memory location at random. Prior to issuing a slave address with the R/W bit = “1”, the master must execute a “dummy” write operation first in order to identify the control register address. The master issues a start condition request, a slave address (R/W bit = “0”) and then the sub address (control register address) to read. After the register address is acknowledged, the master immediately reissues another start condition request as well as the slave address with the R/W bit = “1”. The AK4619 then generates an acknowledge, 1 byte of data, and increments the internal address counter by 1. If the master does not generate an acknowledge but generates a stop condition instead, the AK4619 ceases transmission.

C:
// This returns the values of the AK4619 control registers
// Useful for debugging CODEC set-up problems

void AK4619_readConfig(int CodecAddress) {
  // reads registers values
  uint8_t n = 0;
  uint8_t c = 0;
  uint8_t returnCode;

  // Do a 'dummy' write to the AK4619 to 'reset' the register location
  // See Page 58: '2-2. Random Address Read' in the AK4619 datasheet
  // The chip automatically increments its internal address counter on each access
  // If we don't do this dummy write we end up reading from the wrong register number(s)

  Wire.beginTransmission(CodecAddress);
  Wire.write(0);
  Wire.requestFrom(CodecAddress, 1);
  returnCode = Wire.endTransmission();

  // Now we can read all the registers correctly!

  uint8_t BytesReturned = Wire.requestFrom(CodecAddress, AK4619_numRegisters);

  printf("Wire.requestFrom(AK4619 registers) returned %u bytes\n", BytesReturned);
 
  while (Wire.available()) {
    c = Wire.read();
    printf("Register 0x%.2x = %.8b (0x%.2x)\n", n, c, c);
    n++;
  }

}
 
Well I tried just setting power on, single ended, and mux loop back and am still getting nothing on the output.
The registers have been reporting back the correct defaults so I'm sure I'm writing and reading to the correct ones.
I've tried a couple different teensys and they both work with sgtl5000s.

Here's how I have it connected:
T4.1 - codec
23 - 8 MCLK
21 - 7 BICK
20 - 6 LRCLK
7 - 1 SDIN1
PDN has a pull down resistor and is set high by the teensy after 100ms.
 
Last edited:
The clock pins are connected correctly, as far as I can tell. What clock frequncies are you seeing on each pin, or at least, are they compatible with the AK4619's requirements?

Your first post contained a screenshot from a scope but I don't see where you stated what that signal was. Which pin were you connected to and what are you expecting to see there?

I'm not very familiar with TDM/I2S pins on the Teensy so I may not have this correct! If you only have the Teensy I2S pin 7 (O1A, which I presume is the same as SDOUT1) connected to the codec SDIN1, shouldn't you actually have the codec SDOUT1 (codec pin 31) going to the Teensy SDIN pin? I'm not sure which pin that is, perhaps IN1 (pin 8)?

In my project, the signal from my audio preamp goes to the AK4619 (in single-ended1 mode). The resulting SDOUT1 goes to SDIN1 on my DSP chip, which does it's magic and sends the processed signal from its SDOUT1 to the AK4619 SDIN1. The AK4619's DAC then sends the analog audio signal to my output stage. The DSP generates the three clock signals for the AK4619 from crystal master oscillator.
 
I just realised that you are using the TDM audio format but the AK4619 defaults to I2S on power-up so you need to configure it to match the TDM data format that the Teensy is using. It will be one of modes 8, 9, 10, or 11, as listed in Table 2, page 32, of the AK4619 datasheet.

My project uses I2S so I never needed to set the audio format in my config routine. I can see you are setting a TDM mode but perhaps it isn't the same as the Teensy is using? Might be worth double-checking that and also the clock setting. Sorry, if that doesn't work, I'm kinda out of ideas!

What sample rate (fs) are you using? With your clock setting of B00000000 the MCLK needs to be 256fs.
 
The teensy is sending the correct clocks. 22.6Mhz to MCLK and 11.3 to BICLK
Teensy pin 7 is transmitting the data to SDIN on the codec. I don't have anything hooked up to the SDOUT of the codec as I'm just trying to get audio out of it first.

The code above has the TDM setup and I've tried it several different ways with the same results.

Thanks for your help, though!
 
The teensy is sending the correct clocks. 22.6Mhz to MCLK and 11.3 to BICLK
Teensy pin 7 is transmitting the data to SDIN on the codec. I don't have anything hooked up to the SDOUT of the codec as I'm just trying to get audio out of it first.

The code above has the TDM setup and I've tried it several different ways with the same results.

Thanks for your help, though!
I could be wrong (I often am!) but if your MCLK is 22.6MHz then since the datasheet states that MCLK = 256fs, dividing 22.6MHz by 256 gives fs = 882.8125kHz!!! When setting the AK4619 clock register to B00000000, as you are doing, then fs must be between 8kHz and 48kHz - see Table 1 in the AK4619 datasheet.

Screenshot 2024-06-01 173902.png
 
Yes I am confused about the whole clock thing hah.
In this table 512fs is listed but there is no way to switch the rest of the TDM to that in table 2.
When I set it to 011 I do get sound but its mangled. The top is channel 1, bottom is 2. 1 isn't clipping as it still has that shape if the amplitudes is much lower. 2 sounds like multiple oscillators getting digitally combines in some funky way.
AD_4nXd1YMF977TchTInfTXwc4GTSUv42Wf534-K_MM17d9pVFGBq6oWjuphvVPT7l-vQdRjpSIEVMdsbMTv__oN4UZRNGMw8erIgr_KWWNesGybQ94apF8vTJfzFKQ3OJkYRI9FjAFCBii_sjUCO1fSQGtfuNXK
.
I glanced at the datasheet for the CS42448 and it seems very similar but the teensy TDM objects works just fine with it.
There aren't any functions to change the Teensy TDM rates so again this might be something only Paul can help with.
I changed the value 256 in this section of output_TDM.cpp to 128 and 512. This halve or doubles the clock rates respectively but with no big change in the output. When I go back to 000 in table 1 I get no audio output no matter the value of "256".
 
Maybe the Teensy audio library cannot set the clock values that the AK4619 requires?

Remembering that I'm using a straightforward two channel (L/R) I2S with the DSP chip generating the clocks, my values are:

MCLK = 8.192MHz
BICLK = 2.048MHz
LRCLK = 32kHz

The sample rate (fs) used by my DSP is 32kHz. In other words, MCLK = 256fs and BICLK = 64fs.

Your channel 1 trace looks vaguely familiar - I may have seen something like that when I was first getting started with the AK4619. It looks like the top and bottom halves of your sine wave have been 'flipped' but don't ask me what the cause is! Perhaps you're getting half a cycle from channel 1, then the other half is from channel 2, because the LRCLK is the wrong frequency?

The fact that you are getting some sort of signal with a different clock register setting in the AK4619 makes me think that the solution is somewhere close! Perhaps @PaulStoffregen can tell you if the Teensy TDM library can support the AK4619 clock frequencies.
 
Hey there- I'm trying to do the exact same thing and running into different issues. Specifically, I get great signals out of the left channels of the first and second DAC of the AK4619, but nothing out of the right channels (as if I was sending zeros). The left channel of the first DAC seems to correspond to TDM output slot 0 and the left channel of the second DAC seems to correspond to TDM output slot 4. This is expected I think, since those TDM channels are 64 bits apart, with the right channels presumably corresponding to slots 2 and 6. I ran into a similar issue as @john-mike with that weird flipped sine wave, but I fixed it by setting the BCKP bit at address 0x01, bit D1. I'm currently running in TDM256 I2S-compatible mode and the clock signals coming out of the Teensy 4.1 look pretty close to what this diagram demonstrates. I've included some logic analyzer output from the Teensy, as well as the timing diagram for the mode I'm using and some evidence of the very nice waveforms coming out of pins 22 and 24 of the AK4619VN. (I'm running this at 20kHz for testing purposes because otherwise MCLK goes out of range for my logic analyzer, but I've tried this at 20kHz and 44.1kHz with the same behavior)_

I really don't know what to make of this weird half-working codec. Also, I've tried using the ADC but the signal is distorted and strange- I tried running a sine wave through it and like, every other fraction of the sine wave was cut off like it was being gated by a square wave at a multiple of the frequency of the sine. When I set up the codec to echo the ADC input to the DAC, that worked fine. However, the only the left channels of the codec seem to work for me- the right channels of the ADC and DAC spit out zeroes no matter what I do.

@Paul if you have a moment, do you have any insight? I feel like we're pretty close to figuring this one out, but I'm a bit stumped as to how to debug/move forward.

I have soldered up two of these and have observed the same behavior on both, so I'm fairly certain this is some kind of software issue and not a bad chip.

Oh, also, here's a dump of my register settings as listed on page 60 of the AK4619VN datasheet.

Code:
00:     0011 0111     37
01:     1101 1111     DF
02:     0001 1100     1C
03:     0000 0011     3
04:     0010 0010     22
05:     0010 0010     22
06:     0011 0000     30
07:     0011 0000     30
08:     0011 0000     30
09:     0011 0000     30
0A:     0000 0000     0
0B:     0101 0101     55
0C:     0000 0000     0
0D:     0000 0000     0
0E:     0001 1000     18
0F:     0001 1000     18
10:     0001 1000     18
11:     0001 1000     18
12:     0000 0100     4
13:     0000 0101     5
14:     0000 1010     A

1720476371072.png

1720476165618.png

1720476209550.png

1720476391102.png
1720476407893.png
1720476429798.png
 
Last edited:
I got it!! Well, at least all the outputs work. Here are the settings:

Code:
0:     0011 0111     37
1:     1111 1110     FE
2:     0001 1100     1C
3:     0000 0011     3
4:     0010 0010     22
5:     0010 0010     22
6:     0011 0000     30
7:     0011 0000     30
8:     0011 0000     30
9:     0011 0000     30
A:     0000 0000     0
B:     0101 0101     55
C:     0000 0000     0
D:     0000 0000     0
E:     0001 1000     18
F:     0001 1000     18
10:     0001 1000     18
11:     0001 1000     18
12:     0000 0100     4
13:     0000 0101     5
14:     0000 1010     A
 
Update: Something strange is still going on. Connecting my AudioInputTDM object to any other Teensy Audio component causes my output to look like this, even if nothing input-related is going to the AudioOutputTDM. I can even leave the actual digital output from the codec to the Teensy disconnected and it still does this, which indicates that using the AudioInputTDM is causing a change in the clock/dataframe signals.

I plan on doing some logic analyzer stuff tomorrow, but I'm wondering, are the input and output TDM objects not synchronized? Do they have different clocks and so they're fighting over the MCLK/BCLK/LRCLK pins?

Do AudioInputTDM and AudioOutputTDM not play nicely with each other? I assumed they were meant to be used in tandem since they share the same MCLK/BCLK/LRCLK pins but perhaps I misunderstood and they're fighting each other?

1720498914057.png
 
Last edited:
Ok, so what I'm actually seeing is no data coming from the TX pin of the Teensy like, half the time. This is only when I start actually using AudioInputTDM. It's weird, because I still have it declared so presumably it's being initialized either way, but it's only when I connect it to a Teensy audio object that my output starts cutting out half the time. As soon as I comment out the code that connects the AudioInputTDM, everything works great.

I don't know what's going on with that, but here it is. It would explain why my output is so choppy. I can only record 100k samples at a time at 50mHz so it was hard to get a good split, most of the time the TX pin (pin 3) was showing data or just nothing for a full frame. It really should show data nearly all of the time, since a sine wave is at 0 for a very short amount of time. Also there are different waveforms on each of the channels, so it's really just weird that I'm getting zero on all of them simultaneously at any point.

I'm going to simplify this code tomorrow, try again, see what happens. Either way once it's in a legible state I'll post it.

1720501081465.png
 
Last edited:
In your first post you mentioned you only had output from the left channels of both DACs. Is this note in the AK3619 datasheet P32, relevant to that, perhaps?

Screenshot 2024-07-09 130922.png
 
Last edited:
With your changed register settings, you are now operating in TDM Mode 9, not Mode 10 as in your first attempt.

What are the clock frequencies that the Teensy is outputting? For example is BICK equal to 128fs? What is the fs in your case? If it's 48kHz for example, BICK should be 5.12MHz.
Screenshot 2024-07-09 132208.png


Screenshot 2024-07-09 132247.png
 
With your changed register settings, you are now operating in TDM Mode 9, not Mode 10 as in your first attempt.

What are the clock frequencies that the Teensy is outputting? For example is BICK equal to 128fs? What is the fs in your case? If it's 48kHz for example, BICK should be 5.12MHz.
View attachment 34970

View attachment 34971
My FS[2:0] setting is 011, so I think I'm in this mode, which looks identical to TDM128 mode if you're just looking at the audio format registers.

1720539527690.png


I could be wrong, but I'm pretty sure if you look at the FS[2:0] bits in my latest register dump that they're set to MCLK 512fs mode.

1720539819905.png

With regards to getting only the left output channels, I'm getting all 4 in my current mode now. I'd need to review my previous settings to figure out why, but I was and still am definitely using SDIN1/SDOUT1. I am running at 20kHz currently for debugging purposes because my logic analyzer can't accurately measure the MCLK if I go any faster. As soon as I'm able to sit down at my workstation today I'm going to do some measurements, trim down the code to something reasonable, and report back.

Also, thank you so much for the help! I think this is really close to working and I'd love to get this documented and help add support for this codec. c:
 
Back
Top