Hello All,
I wanted to create a project with the Teensy4 and WM8904 audio codec. I'm currently trying to get a barebones test off the ground by just sending a signal (1khz 0.5Vpp sinewave) through the bypass signal path. I've created a custom eval board for the codec and have wired it up to the Teensy4 on a breadboard. Eval board schematic included.
The WM8904 includes a Write Control Sequencer that is supposed to set the registers to a known good startup configuration. I wasn't able to get it to work so I copied the startup sequence settings to a struct array and iterated through that in order to configure the codec. I then set the required LINEOUT Bypass bits in the Analogue OUT12 reg. After these steps I would expect to see an output on LINEOUT if I send an input signal on LINEIN, but I get nothing. I can't figure out if its an issue electrically or with the configuration of the codec registers.
Any ideas for debugging would be much appreciated![Smile :) :)](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
Test code:
Configuration struct:
I wanted to create a project with the Teensy4 and WM8904 audio codec. I'm currently trying to get a barebones test off the ground by just sending a signal (1khz 0.5Vpp sinewave) through the bypass signal path. I've created a custom eval board for the codec and have wired it up to the Teensy4 on a breadboard. Eval board schematic included.
The WM8904 includes a Write Control Sequencer that is supposed to set the registers to a known good startup configuration. I wasn't able to get it to work so I copied the startup sequence settings to a struct array and iterated through that in order to configure the codec. I then set the required LINEOUT Bypass bits in the Analogue OUT12 reg. After these steps I would expect to see an output on LINEOUT if I send an input signal on LINEIN, but I get nothing. I can't figure out if its an issue electrically or with the configuration of the codec registers.
Any ideas for debugging would be much appreciated
Test code:
C++:
#include <Arduino.h>
#include "Audio.h"
#include "Wire.h"
#include "wm8904_reg.h"
#define LED_PIN 13
#define BUTTON 12
#define WM8904_I2C_ADDRESS 0x1A
//------------------------------------------------------------------------------
int wm8904_i2c_write(uint8_t reg, uint16_t value);
int wm8904_i2c_read(uint8_t reg, uint16_t *value);
int wm8904_enable();
void wm8904_dump_reg();
AudioInputI2S i2s1; // I2S input (for future use)
AudioOutputI2S i2s2; // I2S output
void setup(){
Serial.begin(9600);
Wire.begin();
int debug = wm8904_enable();
switch(debug){
case 0:
Serial.println("Success!");
break;
case 1:
Serial.println("Data too long!");
break;
case 2:
Serial.println("Received NACK!");
break;
case 3:
Serial.println("Received other NACK!");
break;
case 4:
Serial.println("Something else fucked up!");
break;
case 5:
Serial.println("Timeout");
break;
default:
Serial.println("Default");
Serial.print("Debug: ");
Serial.println(debug);
break;
}
wm8904_dump_reg();
}
//------------------------------------------------------------------------------
// loop() is the main thread. Not used in this example.
void loop() {
}
int wm8904_enable(){
int len = sizeof(wm8904_startup_seq)/sizeof(reg_default_t);
Serial.printf("Num of default regs: %d\n", len);
//reset
wm8904_i2c_write(0x00, 0x0000);
for(int i = 0; i < len; i++){
//iterate through all reg values defined in wm8904_reg.h
if(wm8904_i2c_write(wm8904_startup_seq[i].addr, wm8904_startup_seq[i].val) != 0){
Serial.print("Failed reg write: ");
Serial.println(wm8904_startup_seq[i].addr);
return -1;
};
delay(10);
}
return 0;
}
void wm8904_dump_reg(){
uint16_t reg_data;
uint16_t reg_addr;
int len = sizeof(wm8904_reg_default)/sizeof(reg_default_t);
for(int i = 0; i < len; i++){
reg_addr = wm8904_reg_default[i].addr;
wm8904_i2c_read(reg_addr, ®_data);
Serial.print("REG: ");
Serial.print(reg_addr);
Serial.print("; DAT: ");
Serial.println(reg_data, 2);
}
int wm8904_i2c_write(uint8_t reg, uint16_t value) {
uint8_t data[3];
data[0] = reg; // Register address
data[1] = (value >> 8) & 0xFF; // Data MSB
data[2] = value & 0xFF; // Data LSB
Wire.beginTransmission(WM8904_I2C_ADDRESS);
Wire.write(data, (uint8_t)3);
return Wire.endTransmission();
}
int wm8904_i2c_read(uint8_t reg, uint16_t *value) {
uint8_t data[10];
Wire.beginTransmission(WM8904_I2C_ADDRESS);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(WM8904_I2C_ADDRESS, 2);
data[0] = Wire.read();
data[1] = Wire.read();
*value = (data[0] << 8) | data[1];
return 0;
}
}
Configuration struct:
C++:
struct reg_default_t{
uint8_t addr;
uint16_t val;
};
static const struct reg_default_t wm8904_startup_seq[] = {
{0x04, 0x001A}, /*R4 - ISEL=10b; BIAS_ENA=0*/
{0x05, 0x0047}, /*R5 - VMID_BUF_ENA=0; VMID_RES[1:0]=11b; VMID_ENA=1*/
{0x05, 0x0043}, /*VMID_RES[1:0]=01b*/
{0x04, 0x001B}, /*R4 - BIAS_ENA=1*/
{0x0E, 0x0003}, /*HPL_PGA_ENA=1; HPR_PGA_ENA=1*/
{0x0F, 0x0003}, /*LINEOUTL_PGA_ENA=1; LINEOUTR_PGA_ENA=1*/
{0x16, 0x0002}, /* CLK_DSP_ENA=1 */
{0x12, 0x000C}, /* DACL_ENA=1; DACR_ENA=1*/
{0xFF, 0x0000}, /* Dummy write */
{0x04, 0x000B}, /* delay write?*/
{0x62, 0x0001}, /* CP_ENA=1 */
{0xFF, 0x0000}, /* Dummy write */
{0x5A, 0x0011}, /* HPL_ENA = 1; HPR_ENA=1 */
{0x5E, 0x0011}, /* LINEOUTL_ENA = 1; LINEOUTR_ENA=1 */
{0x5A, 0x0033}, /* HPL_ENA_DLY=1; HPR_ENA_DLY=1*/
{0x5E, 0x0033}, /* LINEOUTL_ENA_DLY=1; LINEOUTR_ENA_DLY=1*/
{0x43, 0x000F}, /* R67 - DCS_ENA_CHANNEL_[3:0]=1 */
{0x44, 0x000F}, /* R68 - DCS_DAC_WR_[3:0]=1 */
{0xFF, 0x0000}, /* Dummy write */
{0x5A, 0x0077}, /* HPL_ENA_OUTP=1; HPR_ENA_OUTP=1*/
{0x5E, 0x0077}, /* LINEOUTL_ENA_OUTP=1; LINEOUTR_ENA_OUTP=1*/
{0x5A, 0x00FF}, /* HPL_RMV_SHORT=1; HPR_RMV_SHORT=1*/
{0x5E, 0x00FF}, /* LINEOUTL_RMV_SHORT=1; LINEOUTR_RMV_SHORT=1*/
{0x16, 0x0006}, /* CLK_SYS_ENA=1*/
{0x0C, 0x0003}, /* INL_ENA=1; INR_ENA=1*/
{0x3D, 0x0003}, /* LINEOUTL_BYP_ENA=1; LINEOUTR_BYP_ENA=1*/
{0x2C, 0x0005}, /* LINMUTE = 0*/
{0x2D, 0x0005}, /* LINMUTE = 0*/
{0x2E, 0x0040}, /* R46 - R_IP_SEL_P = 01 (IN1R)*/
{0x2F, 0x0040} /* R46 - L_IP_SEL_P = 01 (IN1L)*/
};