WM8731 Board Ideas

Bob Larkin

Well-known member
I was trying to evaluate a WM8731 codec and became aware that the Teensy audio library supported this. One thing led to another, and rather than running a board designed for a different system with proto wires, I ended up starting a Kicad board with the same layout as the current SGTL5000 adaptor. This would minimize lead lengths and make a module possible.

This is at the point of putting down traces for the PCB, and I thought I would post this for "design review" comments. It might save a board cycle and also make something more useful to others. The plan is to share this on OSH Park if it works out.

A couple of goals:
* Compatibility with the physical/electrical characteristics of the Adaptor.
* Able to be "Master" or "Slave " for the audio sampling.
* Support an external master clock, like a Si5351.
* Support experimentation in keeping the analog 3.3Volts quiet

The schematic: WM8731_Teensy_Sch.gif

The layout is at the part placement point and it looks like it will fit the board space on a 4-layer. There is no room for a headphone jack, so that would come from the J1 header. The headphone jack board would include the blocking capacitors and anti-pop resistors. The part layout:WM8731_Teensy_PCB.gif

Does anybody see problems/additions/subtractions, etc.? Thanks Bob W7PUA
 
I also did a WM8731 audio board for the Teensy. Mine is significantly larger because I added a lot more functionality including a preamp (to support instrument/mic level inputs), MIDI and connectors. Regarding noise, it all depends on how good a quality you want. My board was specifically with guitar in mind which is very sensitive to noise and sound quality. For lowest noise, you need the analog 3.3V to be supplied by a dedicated LDO. You also need to do a fair bit of careful PCB design to keep digital noise from coupling into the analog ground.

You can see the schematics for my board in the datasheet found here.
 
Looks like you have 2 jumpers meant to select MCLK (Teensy runs as I2S master) and the crystal (Teensy runs as I2S slave).

But I don't quite understand how the "ext" one works. Looks like it would just short the signal to ground. Is that really what you intended?
 
Looks like you have 2 jumpers meant to select MCLK (Teensy runs as I2S master) and the crystal (Teensy runs as I2S slave).

But I don't quite understand how the "ext" one works. Looks like it would just short the signal to ground. Is that really what you intended?

Hi Paul, I'm not quite sure exactly which "ext" in the schematic you're referring to? Here's a summary of a couple items for Bob's benefit, but let me know if I'm stilling missing the "ext" you were asking about.

Main board:
- *Master mode on the CODEC can be used by installing R4 resistor and removing R13. You would also populate X1 and C10,C13 for the crytsal.
- External power (instead of USB) which can be supplied to the mainboard at J2 if and only if you've modified your Teensy to use it's VIN pin as a power input and not the USB 5V. The four-pin J2 is not meant to be jumpered, it's meant for you to connect your own +5V source.
- the EXT signals (EXT0 to EXT7) are GPIO for connecting things like pots and switches to control your audio effects.

Expansion board: (provides some buttons, pots and LEDs)
- **The expansion board gets 3.3V from the Mainboard, but can also supply external power (+5V) at it's own J1, which connects to J2 on the mainboard. Here you can supply say, typical guitar 9V at the 2.1mm power plug, it's regulated down to +5 by U1. The PWR_SEL jumper J7 lets you either connect the 2-pin jumper between pins 3-2, which connects the onboard regulator to VIN, or the jumper connects 2-1 which leaves VIN unconnected (note J7-1 is a no-connect symbol, not a ground). This 2-pin jumper on a 3-pin header ensures you can't accidentally damage your Teensy by having it supply VIN from USB as well as the onboard regularor U1.
- EXT0/EXT1 are connected to big push-button switches (SW1/SW2) for turning effects on and off.

Notes:
* if you buy a mainboard board from me, it's always shipped with WM8731 as slave, you have to solder some parts for master mode.
**if you buy an expansion board from me, the power selection circuit is not populated to keep the cost down. You need to install the parts yourself.

The purpose of the Expansion board is to give you a working hardware circuit to develop your software controls with, then use the schematic as a guide on customizing your own circuit for the needs of your particular project. Most guitarists want to power their enclosure solely from a standard +9V 2.1mm plug rather than the USB. The schematic shows you a safe way to do that.
 
Thanks Blackaddr for sharing the schematic and other info. I checked my I2C and I2S against yours and I think they agree---this is very useful. And, of course, your goal with the boards is much broader than the one I am doing. It is interesting to see your implementation.

Paul, I think your "Ext" question was relative to my MCLK option. J5 is not a jumper but rather a 2-pin header to take an external clock signal replacing the internal crystal oscillator. This serves 2 (or more) purposes. It allows changing the sample rate without changing a crystal, and for radio applications, it allows a precision clock, as the sample rate affects the radio tuning. Notes 3 and 4 are cryptic descriptions of the 3 MCLK options: Slave Codec, Master Codec with the xtal and Master Codec with external clock.

I will revise the schematic to have a different symbol for jumpers than for headers! Sorry for the confusion. Right now the only clue is JPx for Jumpers and Jx for headers.
 
Here is a better schematic. There are no intentional changes to the content, but the jumper symbol has been improved. The scale is a bit easier to read, as well.

WM8731_Teensy_Sch2.gif
 
My interest is in radio and instrumentation related projects. For instance the SDR Control box that works with a variety of radio projects, like Frank DD4WH's:
http://www.janbob.com/electron/SDR_Ctrl1/SDR_Ctrl1.html
And the Vector Network Analyzer:
http://www.janbob.com/electron/AVNA1/AVNA1.htm

Currently, I am working with Farhan VU2ESE on a redo of an old SDR radio project, the DSP-10 using modern parts:
http://www.janbob.com/electron/dsp10/dsp10.htm

All of these tend to put emphasis on low noise and spurs.
 
X1 looks pretty far away from U1.
On J2 connector it would be nice to have separate ground pins for LOUT and ROUT (pins 6 & 10?)
 
QUOTE=bicycleguy;207247]X1 looks pretty far away from U1.
On J2 connector it would be nice to have separate ground pins for LOUT and ROUT (pins 6 & 10?)[/QUOTE]
On the X1 location, the scale is a bit deceiving. It is about 15mm or 0.6 inch away. At 12 MHz this I think is just a capacity issue that can be dealt with by changing C15, C16 if needed. It ended up over on the left because the audio stuff was given top priority for the right side by J2. The ground plane on layer 2 is split between analog and digital and X1 as well as the end of U1 by pins 25 and 26 are all over thedigital ground. The two grounds connect together at a single point in the middle of U1 on the bottom of the board.

On the connections to J2 you make an excellent point. It is as you see, because this is the way Paul set up the Audio Adaptor board. This board tries to mimic the Adaptor to allow experimentation without to much change. So, question: Does anybody see a reason to not connect the two unconnected pins on J2 (line in/out) to AGND??

Thanks for looking this over. Bob
 
I'm back with the WM8731 board in hardware. The schematic is as above and it is populated to be a master with R12 not installed, the crystal installed and nothing hooked to J5. Plugged into the T3.6 it looks like:
WM8731Codec_2157.jpg
There is a software problem. First though, note that the board seems to run as expected with the Teensy as master. Both input and output via I2S are fine This includes running the MCLK from the crystal oscillator. This sounds wrong at first, but the codec doesn't care where its MCLK timing comes from and the I2S and its DMA are independent activities (I think).

The INO that doesn't work is
Code:
// Simple sine wave to WM8731 Codec Board  RSL 15 July 2019

#include <Audio.h>
#include <Wire.h>

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;     //xy=254,297
AudioOutputI2Sslave      i2s1;      //xy=430,301
// AudioOutputI2S           i2s1;      //xy=430,301
AudioConnection          patchCord1(sine1, 0, i2s1, 0);
AudioControlWM8731master wm8731;       //xy=417,357
// AudioControlWM8731       wm8731;     //xy=417,357
// GUItool: end automatically generated code

void setup() {
  Serial.begin(9600);
  wm8731.enable();
  AudioMemory(15);
  while (!Serial) ;
  sine1.amplitude(0.5);
  sine1.frequency(600.0);
  Serial.println("Finished setup()");
}

void loop() {
    }
Apparently this hangs at the very beginning when creating an instance of AudioOutputI2Sslave. The setup doesn't seem to execute, no Serial.println() and no LED on the T3.6. Certainly no audio processing happens.

If you change the object AudioOutputI2Sslave to AudioOutputI2S it runs fine. It doesn't seem to make any difference whether the control object is AudioControlWM8731master or AudioControlWM8731 which is not surprising as I think the code is identical for both.

I do not believe this issue is related to the MCLK ringing of
https://forum.pjrc.com/threads/55334-I2C-problems-with-Teensy-3-6-and-WM8731-codec
as I2C programming of the 8731 seems to be fine when the T3.6 is master.

I think my board has the same logic wires as the MikroE WM8731 codec board. Can anyone confirm that the
https://github.com/PaulStoffregen/Audio/blob/master/examples/HardwareTesting/WM8731MikroSine/WM8731MikroSine.ino
INO works with the WM8731 as master? It does not for me with the same behavior.

Thanks for thinking about this! Bob
 
The master and slave code does have a difference during initialization.

Master:

write(WM8731_REG_INTERFACE, 0x42); // I2S, 16 bit, MCLK master

Slave:

write(WM8731_REG_INTERFACE, 0x02); // I2S, 16 bit, MCLK slave

I don't have one of those boards to test with, unfortunately.

If I'm understanding the problem correctly, perhaps an easy check would be to scope the master clock signal on the Teensy, to see if the Teensy is actually receiving it?
 
Last edited:
Thanks for the ideas. It really helps to have a fresh look at these things. Pursuing your directions, I did some measurements, they did not seem to show any issue. But first,
The master and slave code does have a difference during initialization.
Yes, you are right. The I2C command to the WM8731 must be there to direct the 8731 as to Master/Slave and that bit does it. My comment was wrong, but the problem is that never gets run. It does not get past "AudioOutputI2Sslave i2s1;"

And now some measurements,
If I'm understanding the problem correctly, perhaps an easy check would be to scope the master clock signal on the Teensy, to see if the Teensy is actually receiving it?
There is no path for MCLK when the Codec is the master. The only user of that signal is the Codec, I believe. The I2S signals are a different story AS you suggested, I hooked the scope to the I2S when the Teensy was master and observed, using the Teensy naming:
MCLK is coming from the Teensy and is at the 8731 at 12..288 MHz
BCLK about 3 MHz square wave
LRCLK about 40 kHz square wave
RX_I2S changing data
TX_I2S changing data
I think that is proper, and a 600 kHz is seen on the left DAC output of the 8731

With INO as shown above, all signals, except MCLK, are unchanging at 0. MCLK is seen at the 8731, including at CLKOUT, but no MCLK is coming from the Teensy. I suspect this is consistent with AudioControlWM8731Master never being created, do to the lock up at AudioOutputI2Sslave.

I am currently tracing the code for AudioOutputI2Sslave. Along those lines, I moved the object creation inside Setup() to allow Serial.print() to be used. It points to AudioOutputI2Sslave as well:
Code:
#include <Audio.h>
#include <Wire.h>

void setup() {
  Serial.begin(9600);
  while (!Serial) ;
  Serial.print (" 1 ");
  AudioSynthWaveformSine   sine1;
  Serial.print(" 2 ");
  AudioOutputI2Sslave      i2s1;
  Serial.print(" 3 ");
  AudioConnection          patchCord1(sine1, 0, i2s1, 0);
  AudioControlWM8731master wm8731;       //xy=417,357
  wm8731.enable();
  AudioMemory(15);
  sine1.amplitude(0.5);
  sine1.frequency(600.0);
  Serial.println("Finished setup()");
}

void loop() {
    }
This just prints " 1 2" and no "3".

More later. I hope this makes sense as to what I am seeing!

Bob
 
My mistake about MCLK, I kept thinking the Teensy needed it.

Here's an interesting experiment... my T3.6 locks up if I include an AudioOutputI2Sslave in my project. I'm using the audio shield, not the WM8731, but it does seem rather broken to me that the Teensy locks up. Perhaps there is either some kind of conflict that we're not aware of, or perhaps it's just a bug.

It might not be that big of a deal though, depending on your application. The WM8731 acting as the master is not really ideal according to some posts from Paul (due to the Teensy not being able to generate its own clock for USB audio and whatever else). For my application, I'd be perfectly happy with the Teensy as master and WM8731 as slave.
 
The reason that I am wanting to get the 8731 running as master is the jitter on the MCLK. For instrumentation and radio applications, the noise floor and spurs is a limiting factor.The SGTL5000 has problems in this area, running as a slave, and so with the 8731 I wanted to be able to measure and compare master/slave.

I'm really short of time right now as we are moving in a few weeks, but the open code for the AudioOutputI2Sslave object should show the reason for the not returning. Looking at output_i2s.h shows deliberate differences for slave/master that need to be looked at. BTW, thanks for trying to create the object; That should be possible without the hardware, I think.

Bob
 
Here's an interesting experiment... my T3.6 locks up if I include an AudioOutputI2Sslave in my project. I'm using the audio shield, not the WM8731, but it does seem rather broken to me that the Teensy locks up. Perhaps there is either some kind of conflict that we're not aware of, or perhaps it's just a bug.

It might be a bug. Or it may be a hardware issue, or a mistake or misunderstanding.

But nobody will ever investigate this if you don't give us the exact code to copy into Arduino to reproduce the problem. A photo or accurate diagram or description of the hardware connection used for the test is also important for me or anyone else to recreate the same result. If you're using the PJRC audio shield, which is designed to have Teensy run in I2S master mode, please be very clear about what hardware modifications you've made, especially what you're doing for MCLK.
 
Just to add more one piece of info here, while Teensy does not require MCLK, the SGTL5000 chip on the audio shield certainly does. In fact, the SGTL5000 stays in a low power shutdown/reset mode until it hears 8 pulses on its MCLK pin.

Maybe you already knew this (afterall, it is documented in the SGTL5000 datasheet) and you've accounted for this somehow, like a crystal oscillator or other way to create MCLK? But if not, this bug which appears to be Teensy locking up may be related to the SGTL5000 staying it's shutdown mode, and lack of code on the Teensy side to make this problem clear to you?
 
It might be a bug. Or it may be a hardware issue, or a mistake or misunderstanding.

But nobody will ever investigate this if you don't give us the exact code to copy into Arduino to reproduce the problem. A photo or accurate diagram or description of the hardware connection used for the test is also important for me or anyone else to recreate the same result. If you're using the PJRC audio shield, which is designed to have Teensy run in I2S master mode, please be very clear about what hardware modifications you've made, especially what you're doing for MCLK.

Paul, the details of this issue have gotten spread over several posts in this thread. That makes it confusing and hard to pick up at this point, so let me try to summarize the issue , noting the post #'s above in this thread:

1-The PJRC SGTL5000 has been run with T3.6 as master, and has always run as expected, and the SGTL5000 is not the issue (but it probably would be if the SGTL was operated as master). For this thread, the only problems have been with the WM8731 as master and the T3.6 as slave.

2-The WM8731 has been run with the T3.6 as master and no problems have been seen. Of course this involves software and MCLK hardware changes.

3-The hardware schematic for the WM8731 is in post #7 above, with Note 3 applying, saying that R12 is removed and the 12.288 MHz crystal oscillator is used. Scope measurements show that MCLK is as expected for the 8731 as master. More on scope measurements in post #14. My intention is that the schematic wired per Note 3, has digital connections equivalent to the MikroEWM8731 board, which is also the same as for the data sheet for the codec. The hardware is all short leads with a PJRC Audio Adapter size 4-layer board plugged into the T3.6. There are no signs of I2C failure, just I2S. No other hardware is involved but the T3.6 and the WM8731 codec.

4-There are three INO's that do not work, shown in post #12, #14 and also the MikroE (8731 as master)https://github.com/PaulStoffregen/Audio/blob/master/examples/HardwareTesting/WM8731MikroSine/WM8731MikroSine.ino. In every case, the problem appears to be that the program does not execute after an instance of the object AudioOutputI2Sslave is created. No further code will execute, the Serial monitor had been opened, but is totally blank, It is not shown in the ISOs, but the same problem occurs for an instance of AudioInputI2Sslave. The INO of post #14 strongly suggests that AudioOutputI2Sslave is the culprit

5-As noted in post #12, everything runs fine when the T3.6 is master, i.e., when AudioOutputI2S object is used. For this everything executes, Serial.print() prints and waveforms are outputted, etc.
 
It might be a bug. Or it may be a hardware issue, or a mistake or misunderstanding.

But nobody will ever investigate this if you don't give us the exact code to copy into Arduino to reproduce the problem. A photo or accurate diagram or description of the hardware connection used for the test is also important for me or anyone else to recreate the same result. If you're using the PJRC audio shield, which is designed to have Teensy run in I2S master mode, please be very clear about what hardware modifications you've made, especially what you're doing for MCLK.

I'm definitely not expecting anyone to investigate that Paul :) I know the rules here.
 
Frank B., great idea. I had Teensyduino 1.44 with Arduino 1.8.7 available (well before T4) and IT RUNS. No lockup, the waveform is generated, everything is normal.

I can actually proceed to evaluate the WM8731 board now, but what can I do to help track down the problem?? Bob
 
Back
Top