HiFi Audio CODEC Module - AK4558 evaluation board in a square inch PCB

Status
Not open for further replies.

MickMad

Well-known member
Hi guys,

long time no see. I've been participating in The Square Inch Project on Hackaday and I'm competing with the HiFi Audio CODEC module, a little board hosting an AK4558 chip, capable of 192 KHz/ 24 bit with >100 dB SNR @ 3.3V supply (datasheet here).

To make it work, I build a little API to integrate its functionality in the Teensy Audio Library; I actually forked the Audio Library (Github here). Right now the API only offers the enable() function, I'll add more functionalities for filters setting, volume setting, disable all, selective (ADC/DAC) disable, set input to mono (left or right only), and for every other configurable function that I'm currently missing. I also added the AK4558 to show up in the GUI editor, I'll edit that too as soon as I implement these functions.

I currently have no plans of building this in quantity, but if you enjoy it and if demand comes, I might. Of course, the project is OSHW so you can just grab files/parts and build your own. Gerbers as well as full KiCAD project are available here.
NOTE: I have to fix a couple of packages (the electrolytic caps on ins/outs should be 1 mm bigger in order to host the Nichicon Audio Series bipolar caps of that size (1uF on outs, 10uF on ins), currently the board can only host generic bipolar on the ins and generic electros on outs.

If you'd rather just brew your own, this chip is a really nice choice in a very convenient package, and you'd already have the software side ready to go!

Cheers,
Mick
 
Hey guys, I have made a version of this board in Eagle, with some changes (4 outputs and inputs). It was inspired by the
Teensy Audio Board.

I would like to get some feedback from you. The ground is stiched and analog VDD + analog GND are separated.
Bildschirmfoto 2016-02-15 um 22.36.45.jpg
Bildschirmfoto 2016-02-15 um 22.28.37.jpg


Bildschirmfoto 2016-02-15 um 22.54.24.jpg

Note: Decoupling Caps for DC left out intentionnally, in case DC output is needed.
 
Last edited:
You probably need to connect CAD0 high on the 2nd chip, so it'll have a unique I2C address.

Are you going to make & sell these boards, or share them somehow (eg, OSH Park)?
 
@Paul: CAD0 on the 2nd chip is connected to VDD :)
I might offer them on tindie or so, if the interest is there.
 
If youre going to selling them on tindie, i 'll buy an assembeld board there.. Otherwise it would be great if you could send me two chips ( + a single empty board)
 
@Frank: Sure! I'll first get 1-2 boards for myself, do some measurements and then go ahead with tindie eventually.
I'll still need to adapt the AK4558 control object to support setting the I2C control address, though. Or do you want to contribute to that?

Cheers
 
I'll still need to adapt the AK4558 control object to support setting the I2C control address

Please do it similarly to how the SGTL5000 object was modified for dual chip use, with a setAddress() function. Perhaps let it take a number from 0 to 3, but don't expose the actual I2C address in the API. The idea is to keep the API of these control objects similar, so sketches and examples written for SGTL5000, AK4558, CS4272, WM8731 and others can be easily used with any of the other chips, as long as they only access the basic features to enable the chip, set volume, select inputs, etc.

When it's tested with real hardware, please send a pull request on github.

Also let me know when (tested, confirmed working) boards are for sale or shared somewhere. I'd like to add a link in the quad I2S object documentation.
 
Hello,

I just received my boards for my design and soldered the QFN28 AK4558 - pretty sure there are no bridges and the connections are right.
I adjusted:
#ifndef AK4558_CAD1
#define AK4558_CAD1 0
#endif
// Chip Address 1 pin
// set to 'H' by default, configurable to 'L' via a jumper on bottom side of the board

#ifndef AK4558_CAD0
#define AK4558_CAD0 1
#endif

and

#ifndef PIN_PDN
#define PIN_PDN 0
#endif


Because I moved PDN to Pin 0 of the Teensy, because Pin 14 was used by SPI.

And initialize the dac with:
/*
Demo of the audio sweep function.
The user specifies the amplitude,
start and end frequencies (which can sweep up or down)
and the length of time of the sweep.

FMI:
The audio board uses the following pins.
6 - MEMCS
7 - MOSI
9 - BCLK
10 - SDCS
11 - MCLK
12 - MISO
13 - RX
14 - SCLK
15 - VOL
18 - SDA
19 - SCL
22 - TX
23 - LRCLK

*/

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce.h>

AudioSynthToneSweep myEffect;
AudioOutputI2SQuad audioOutput; // audio shield: headphones & line-out

// The tone sweep goes to left and right channels
AudioConnection c1(myEffect, 0, audioOutput, 0);
AudioConnection c2(myEffect, 0, audioOutput, 1);
AudioConnection c3(myEffect, 0, audioOutput, 2);
AudioConnection c4(myEffect, 0, audioOutput, 3);

AudioControlAK4558 wm8731m1;


float t_ampx = 0.8;
int t_lox = 10;
int t_hix = 22000;
// Length of time for the sweep in seconds
float t_timex = 100;
// <<<<<<<<<<<<<<>>>>>>>>>>>>>>>>
void setup(void)
{

Serial.begin(9600);
while (!Serial) ;

delay(3000);

AudioMemory(20);

wm8731m1.enable();
wm8731m1.enableOut();
wm8731m1.enableIn();
wm8731m1.volume(0.5);
wm8731m1.volumeLeft(0.5);
wm8731m1.volumeRight(0.5);

// wm8731m1.volume(0.5);
wm8731m1.volumeLeft(0.5);
wm8731m1.volumeRight(0.5);

Serial.println("setup done");

if (!myEffect.play(t_ampx, t_lox, t_hix, t_timex)) {
Serial.println("AudioSynthToneSweep - begin failed");
while (1);
}
// wait for the sweep to end
while (myEffect.isPlaying());

// and now reverse the sweep
if (!myEffect.play(t_ampx, t_hix, t_lox, t_timex)) {
Serial.println("AudioSynthToneSweep - begin failed");
while (1);
}
// wait for the sweep to end
while (myEffect.isPlaying());
Serial.println("Done");
}

void loop(void)
{
}


But the Audio Outputs of both DACs stay at 0.0V.

Edit: Scanning I2C also is without success - something must be wrong I think.
// --------------------------------------
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0...127 to 1...119,
// according to the i2c scanner by Nick Gammon
// http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>


void setup()
{
Wire.begin();

Serial.begin(9600);
Serial.println("\nI2C Scanner");
}


void loop()
{
byte error, address;
int nDevices;

Serial.println("Scanning...");

nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();

if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");

nDevices++;
}
else if (error==4)
{
Serial.print("Unknow error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");

delay(5000); // wait 5 seconds for next scan
}
 
Last edited:
I'd focus on getting the I2C scanning working first.

With the SGTL5000, there's no response on I2C without MCLK present. I don't know it that applied to AK4558.
 
I'd focus on getting the I2C scanning working first.

With the SGTL5000, there's no response on I2C without MCLK present. I don't know it that applied to AK4558.



I agree paul. I have been trying to run I2S and then scan for devices, but still without any success.

Measurements show that SCL + SDA on the Codec side have ~1MOhm Resistance to GND, which seems right.
SCL + SDA are pulled up by 2.2k - I have checked with a logic analyzer and that also looks all fine.

I have verified that there are no bridges on 2 boards I made and that Initialization is done as described in the Datasheet.

I have now found the following on the original authors article:
I could not understand why the codec would not output anything even if I double checked the registers' configuration parameters until I put a function that reads their values AFTER I performed my I2C write operations: everything would read as 0 (zero). That was the moment when I grabbed my logic anaylizer and attached it to the I2C bus and found out the truth: I performed an out-of-bounds write when trying to write the Power Management register, meaning that every other operation performed on the bus after that one would not go well. In particular, when I was trying to write that register I put the CODEC I2C address instead of the Power Management register in the function (which is out of bounds).

Maybe its related.
 
Last edited:
I get that you are unable to start basic I2C communication to the devices.

You should first of all modify my library; since the I2C address is hard coded in the lib, you could set the #DEFINEd address for IC#1 and use a dynamic boolean value to add 1 to the hard coded address. E.g.: #1 has address x+0, #2 has address x+1.

Then, you shall try to readInitConfig() from both ICs, and see if you get the default configuration from both (you can find the default settings for all registers in control_AK4558.h). If that's not the case, you shall check with a logic analyzer what happens on your I2C bus.

Anyway, I see that you defined CAD1 to 0 and CAD0 to 1, while you say that you have pulled up pins CAD1 and CAD0 with 2.2 K, so you might have your address wrongly set. Secondly, you could just #DEFINE CAD1 and CAD0 in your user code, not in the library itself (that's what #IFNDEFs are for).

You shall define TWO instances of AudioControlAK558, and you should setAddress() (as Paul suggested) on one to set it as the #2 in the quad output setup.

You have to carefully follow the AK4558 datasheet in order to enable the TDM mode; you shall set the following in order to work:

ACKS bit : 0 (Manual clock setting mode)
DFS1-0 : 00 - Normal speed mode (fs <54 KHz)
MCKS1-0 : 00 - Master clock input freq select (in normal speed mode, MCLK = 256 fs)
BCKO1-0 : 11 - BICK output frequency = 256fsn,256fsd,128fsq in TDM Mode (other settings of BCKO are not available for TDM mode)
TDM1-0 : 1X (x = don't care) for TDM256, 01 for TDM128
DIF2-0 : 011 (24 bit I2S compatible)

check table 26, page 57 of the datasheet to see what I'm talking about.

You also have to set SDS1-0 bits on both ICs in order to let them know that one is handling channels 1,2 (SDS1-0 = 00), and the other is handling channels 3,4 (SDS1-0 = 01).

You should configure both ICs together, that is you first set one register on IC#1, then the same register on IC#2; for most registers, except for the SDS bits, the configuration is the same on both ICs.

Note: please check what BCLK frequency the AudioOutputI2SQuad outputs on the BCLK pin to properly configure the ICs to expect the correct frequency.
 
Last edited:
Found the mistake - I2C SCL and SDA swapped in eagle. Also, PDN pin was hardcoded in MickMads Library to Pin 0, and on my board its Pin 1.

Still, there is no valid output on the DAC.
AK4558: Enable device
AK4558: PDN is HIGH (device reset)
Register 0 = 1
Register 1 = 100
Register 2 = 0
Register 3 = 111000
Register 4 = 10000
Register 5 = 101010
Register 6 = 101001
Register 7 = 111
Register 8 = 11111111
Register 9 = 11111111
AK4558: CTRL_1 set to 11000
AK4558: CTRL_2 set to 0
AK4558: MODE_CTRL set to 111000
AK4558: Enable device - Done
AK4558: Enable DAC
AK4558: MODE_CTRL set to 111001
AK4558: PWR_MNGT set to 111
AK4558: MODE_CTRL set to 111000
AK4558: Enable DAC - Done
AK4558: LOUT_VOL set to 0
AK4558: ROUT_VOL set to 0
AK4558: LOUT_VOL set to 0
AK4558: ROUT_VOL set to 0
 
Status
Not open for further replies.
Back
Top