Add AK4558 CODEC support / Merge branch 'master' of https://github.com/MickMad/Audiodds
@@ -66,6 +66,7 @@ | |||
#include "analyze_peak.h" | |||
#include "control_sgtl5000.h" | |||
#include "control_wm8731.h" | |||
#include "control_ak4558.h" | |||
#include "effect_bitcrusher.h" | |||
#include "effect_chorus.h" | |||
#include "effect_fade.h" |
@@ -0,0 +1,301 @@ | |||
/* | |||
* HiFi Audio Codec Module support library for Teensy 3.x | |||
* | |||
* Copyright 2015, Michele Perla | |||
* | |||
*/ | |||
#include "control_ak4558.h" | |||
#include "Wire.h" | |||
void AudioControlAK4558::initConfig(void) | |||
{ | |||
// puts all default registers values inside an array | |||
// this allows us to modify registers locally using annotation like follows: | |||
// | |||
// registers[AK4558_CTRL_1] &= ~AK4558_DIF2; | |||
// registers[AK4558_CTRL_1] |= AK4558_DIF1 | AK4558_DIF0; | |||
// | |||
// after manipulation, we can write the entire register value on the CODEC | |||
uint8_t n = 0; | |||
Wire.requestFrom(AK4558_I2C_ADDR,10); | |||
while(Wire.available()) { | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("Register "); | |||
Serial.print(n); | |||
Serial.print(" = "); | |||
#endif | |||
registers[n++] = Wire.read(); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println(registers[n-1], BIN); | |||
#endif | |||
} | |||
} | |||
void AudioControlAK4558::readConfig(void) | |||
{ | |||
// reads registers values | |||
uint8_t n = 0; | |||
uint8_t c = 0; | |||
Wire.requestFrom(AK4558_I2C_ADDR, 10); | |||
while(Wire.available()) { | |||
Serial.print("Register "); | |||
Serial.print(n++); | |||
Serial.print(" = "); | |||
c = Wire.read(); | |||
Serial.println(c, BIN); | |||
} | |||
} | |||
bool AudioControlAK4558::write(unsigned int reg, unsigned int val) | |||
{ | |||
Wire.beginTransmission(AK4558_I2C_ADDR); | |||
Wire.write(reg); | |||
Wire.write(val); | |||
return (Wire.endTransmission(true)==0); | |||
} | |||
bool AudioControlAK4558::enableIn(void) | |||
{ | |||
// ADC setup (datasheet page 74 | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println("AK4558: Enable ADC"); | |||
#endif | |||
// ignore this, leaving default values - ADC: Set up the de-emphasis filter (Addr = 07H). | |||
registers[AK4558_PWR_MNGT] |= AK4558_PMADR | AK4558_PMADL; | |||
write(AK4558_PWR_MNGT, registers[AK4558_PWR_MNGT]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: PWR_MNGT set to "); | |||
Serial.println(registers[AK4558_PWR_MNGT], BIN); | |||
#endif | |||
delay(300); | |||
// Power up the ADC: PMADL = PMADR bits = “0” → “1” | |||
// Initialization cycle of the ADC is 5200/fs @Normal mode. The SDTO pin outputs “L” during initialization. | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println("AK4558: Enable ADC - Done"); | |||
#endif | |||
return true; | |||
} | |||
bool AudioControlAK4558::enableOut(void) | |||
{ | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println("AK4558: Enable DAC"); | |||
#endif | |||
// DAC Output setup (datasheet page 75) | |||
registers[AK4558_MODE_CTRL] |= AK4558_LOPS; | |||
write(AK4558_MODE_CTRL, registers[AK4558_MODE_CTRL]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: MODE_CTRL set to "); | |||
Serial.println(registers[AK4558_MODE_CTRL], BIN); | |||
#endif | |||
// Set the DAC output to power-save mode: LOPS bit “0” → “1” | |||
// ignore this, leaving default values - DAC: Set up the digital filter mode. | |||
// ignore this, leaving default values - Set up the digital output volume (Address = 08H, 09H). | |||
registers[AK4558_PWR_MNGT] |= AK4558_PMDAR | AK4558_PMDAL; | |||
write(AK4558_PWR_MNGT, registers[AK4558_PWR_MNGT]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: PWR_MNGT set to "); | |||
Serial.println(registers[AK4558_PWR_MNGT], BIN); | |||
#endif | |||
delay(300); | |||
// Power up the DAC: PMDAL = PMDAR bits = “0” → “1” | |||
// Outputs of the LOUT and ROUT pins start rising. Rise time is 300ms (max.) when C = 1μF. | |||
registers[AK4558_MODE_CTRL] &= ~AK4558_LOPS; | |||
write(AK4558_MODE_CTRL, registers[AK4558_MODE_CTRL]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: MODE_CTRL set to "); | |||
Serial.println(registers[AK4558_MODE_CTRL], BIN); | |||
#endif | |||
// Release power-save mode of the DAC output: LOPS bit = “1” → “0” | |||
// Set LOPS bit to “0” after the LOUT and ROUT pins output “H”. Sound data will be output from the | |||
// LOUT and ROUT pins after this setting. | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println("AK4558: Enable DAC - Done"); | |||
#endif | |||
return true; | |||
} | |||
bool AudioControlAK4558::enable(void) | |||
{ | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println("AK4558: Enable device"); | |||
#endif | |||
// Power Up and Reset | |||
// Clock Setup (datasheet page 72) | |||
pinMode(PIN_PDN, OUTPUT); | |||
digitalWrite(0, LOW); | |||
delay(1); | |||
digitalWrite(0, HIGH); | |||
// After Power Up: PDN pin “L” → “H” | |||
// “L” time of 150ns or more is needed to reset the AK4558. | |||
delay(20); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println("AK4558: PDN is HIGH (device reset)"); | |||
#endif | |||
// Control register settings become available in 10ms (min.) when LDOE pin = “H” | |||
Wire.begin(); | |||
initConfig(); | |||
// access all registers to store locally their default values | |||
// DIF2-0, DFS1-0 and ACKS bits must be set before MCKI, LRCK and BICK are supplied | |||
// PMPLL = 0 (EXT Slave Mode; disables internal PLL and uses ext. clock) (by DEFAULT) | |||
// ACKS = 0 (Manual Setting Mode; disables automatic clock selection) (by DEFAULT) | |||
// DFS1-0 = 00 (Sampling Speed = Normal Speed Mode) (by DEFAULT) | |||
// TDM1-0 = 00 (Time Division Multiplexing mode OFF) (by DEFAULT) | |||
registers[AK4558_CTRL_1] &= ~AK4558_DIF2; | |||
registers[AK4558_CTRL_1] |= AK4558_DIF1 | AK4558_DIF0; | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: CTRL_1 set to "); | |||
Serial.println(registers[AK4558_CTRL_1], BIN); | |||
#endif | |||
// DIF2-1-0 = 011 ( 16 bit I2S compatible when BICK = 32fs) | |||
registers[AK4558_CTRL_2] &= ~AK4558_MCKS1; | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: CTRL_2 set to "); | |||
Serial.println(registers[AK4558_CTRL_2], BIN); | |||
#endif | |||
// MCKS1-0 = 00 (Master Clock Input Frequency Select, set 256fs for Normal Speed Mode -> 11.2896 MHz) | |||
registers[AK4558_MODE_CTRL] &= ~AK4558_BCKO0; | |||
// BCKO1-0 = 00 (BICK Output Frequency at Master Mode = 32fs = 1.4112 MHz) | |||
registers[AK4558_MODE_CTRL] |= AK4558_FS1; | |||
// Set up the sampling frequency (FS3-0 bits). The ADC must be powered-up in consideration of PLL | |||
// lock time. (in this case (ref. table 17): Set clock to mode 5 / 44.100 KHz) | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: MODE_CTRL set to "); | |||
Serial.println(registers[AK4558_MODE_CTRL], BIN); | |||
#endif | |||
// BCKO1-0 = 00 (BICK Output Frequency at Master Mode = 32fs = 1.4112 MHz) | |||
Wire.beginTransmission(AK4558_I2C_ADDR); | |||
Wire.write(AK4558_CTRL_1); | |||
Wire.write(registers[AK4558_CTRL_1]); | |||
Wire.write(registers[AK4558_CTRL_2]); | |||
Wire.write(registers[AK4558_MODE_CTRL]); | |||
Wire.endTransmission(); | |||
// Write configuration registers in a single write operation (datasheet page 81): | |||
// The AK4558 can perform more than one byte write operation per sequence. After receipt of the third byte | |||
// the AK4558 generates an acknowledge and awaits the next data. The master can transmit more than | |||
// one byte instead of terminating the write cycle after the first data byte is transferred. After receiving each | |||
// data packet the internal address counter is incremented by one, and the next data is automatically taken | |||
// into the next address. | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println("AK4558: Enable device - Done"); | |||
#endif | |||
return true; | |||
} | |||
bool AudioControlAK4558::disableIn(void) | |||
{ | |||
// ADC power-down (datasheet page 74 | |||
registers[AK4558_PWR_MNGT] &= ~AK4558_PMADR | ~AK4558_PMADL; | |||
write(AK4558_PWR_MNGT, registers[AK4558_PWR_MNGT]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: PWR_MNGT set to "); | |||
Serial.println(registers[AK4558_PWR_MNGT], BIN); | |||
#endif | |||
// Power down ADC: PMADL = PMADR bits = “1” → “0” | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println("AK4558: Enable ADC - Done"); | |||
#endif | |||
return true; | |||
} | |||
bool AudioControlAK4558::disableOut(void) | |||
{ | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println("AK4558: Disable DAC"); | |||
#endif | |||
// DAC Output power-down (datasheet page 75) | |||
registers[AK4558_MODE_CTRL] |= AK4558_LOPS; | |||
write(AK4558_MODE_CTRL, registers[AK4558_MODE_CTRL]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: MODE_CTRL set to "); | |||
Serial.println(registers[AK4558_MODE_CTRL], BIN); | |||
#endif | |||
// Set the DAC output to power-save mode: LOPS bit “0” → “1” | |||
registers[AK4558_PWR_MNGT] &= ~AK4558_PMDAR | ~AK4558_PMDAL; | |||
write(AK4558_PWR_MNGT, registers[AK4558_PWR_MNGT]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: PWR_MNGT set to "); | |||
Serial.println(registers[AK4558_PWR_MNGT], BIN); | |||
#endif | |||
delay(300); | |||
// Power down the DAC: PMDAL = PMDAR bits = “1” → “0” | |||
// Outputs of the LOUT and ROUT pins start falling. Rise time is 300ms (max.) when C = 1μF. | |||
registers[AK4558_MODE_CTRL] &= ~AK4558_LOPS; | |||
write(AK4558_MODE_CTRL, registers[AK4558_MODE_CTRL]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: MODE_CTRL set to "); | |||
Serial.println(registers[AK4558_MODE_CTRL], BIN); | |||
#endif | |||
// Release power-save mode of the DAC output: LOPS bit = “1” → “0” | |||
// Set LOPS bit to “0” after outputs of the LOUT and ROUT pins fall to “L”. | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.println("AK4558: Disable DAC - Done"); | |||
#endif | |||
return true; | |||
} | |||
uint8_t AudioControlAK4558::convertVolume(float vol) | |||
{ | |||
// Convert float (range 0.0-1.0) to unsigned char (range 0x00-0xFF) | |||
uint8_t temp = ((uint32_t)vol)>>22; | |||
return temp; | |||
} | |||
bool AudioControlAK4558::volume(float n) | |||
{ | |||
// Set DAC output volume | |||
uint8_t vol = convertVolume(n); | |||
registers[AK4558_LOUT_VOL] = vol; | |||
registers[AK4558_ROUT_VOL] = vol; | |||
Wire.beginTransmission(AK4558_I2C_ADDR); | |||
Wire.write(AK4558_LOUT_VOL); | |||
Wire.write(registers[AK4558_LOUT_VOL]); | |||
Wire.write(registers[AK4558_ROUT_VOL]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: LOUT_VOL set to "); | |||
Serial.println(registers[AK4558_LOUT_VOL], BIN); | |||
Serial.print("AK4558: ROUT_VOL set to "); | |||
Serial.println(registers[AK4558_ROUT_VOL], BIN); | |||
#endif | |||
return (Wire.endTransmission(true)==0); | |||
} | |||
bool AudioControlAK4558::volumeLeft(float n) | |||
{ | |||
// Set DAC left output volume | |||
uint8_t vol = convertVolume(n); | |||
registers[AK4558_LOUT_VOL] = vol; | |||
bool ret = write(AK4558_LOUT_VOL, registers[AK4558_LOUT_VOL]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: LOUT_VOL set to "); | |||
Serial.println(registers[AK4558_LOUT_VOL], BIN); | |||
#endif | |||
return ret; | |||
} | |||
bool AudioControlAK4558::volumeRight(float n) | |||
{ | |||
// Set DAC right output volume | |||
uint8_t vol = convertVolume(n); | |||
registers[AK4558_ROUT_VOL] = vol; | |||
bool ret = write(AK4558_ROUT_VOL, registers[AK4558_ROUT_VOL]); | |||
#if AK4558_SERIAL_DEBUG > 0 | |||
Serial.print("AK4558: ROUT_VOL set to "); | |||
Serial.println(registers[AK4558_ROUT_VOL], BIN); | |||
#endif | |||
return ret; | |||
} |
@@ -0,0 +1,255 @@ | |||
/* | |||
* HiFi Audio Codec Module support library for Teensy 3.x | |||
* | |||
* Copyright 2015, Michele Perla | |||
* | |||
*/ | |||
#ifndef control_ak4558_h_ | |||
#define control_ak4558_h_ | |||
#include "AudioControl.h" | |||
#define AK4558_SERIAL_DEBUG 1 | |||
//if 1, then Serial Monitor will show debug information about configuration of the AK4558 | |||
// for Teensy audio lib operation the following settings are needed | |||
// 1fs = 44.1 KHz | |||
// sample size = 16 bits | |||
// MCKI : 11.2896 MHz | |||
// BICK : 1.4112 MHz | |||
// LRCK : 44.100 KHz | |||
// to do so we need to set the following bits: | |||
// PMPLL = 0 (EXT Slave Mode; disables internal PLL and uses ext. clock) (by DEFAULT) | |||
// ACKS = 0 (Manual Setting Mode; disables automatic clock selection) (by DEFAULT) | |||
// DFS1-0 = 00 (Sampling Speed = Normal Speed Mode, default) | |||
// MCKS1-0 = 00 (Master Clock Input Frequency Select, set 256fs for Normal Speed Mode -> 11.2896 MHz) | |||
// BCKO1-0 = 00 (BICK Output Frequency at Master Mode = 32fs = 1.4112 MHz) | |||
// TDM1-0 = 00 (Time Division Multiplexing mode OFF) (by DEFAULT) | |||
// DIF2-1-0 = 011 ( 16 bit I2S compatible when BICK = 32fs) | |||
#ifndef PIN_PDN | |||
#define PIN_PDN 1 | |||
#endif | |||
// Power-Down & Reset Mode Pin | |||
// “L”: Power-down and Reset, “H”: Normal operation | |||
// The AK4558 should be reset once by bringing PDN pin = “L” | |||
#ifndef AK4558_CAD1 | |||
#define AK4558_CAD1 1 | |||
#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 | |||
// Chip Address 0 pin | |||
// set to 'H' by default, configurable to 'L' via a jumper on bottom side of the board | |||
#define AK4558_I2C_ADDR (0x10 + (AK4558_CAD1<<1) + AK4558_CAD0) | |||
// datasheet page 81: | |||
// This address is 7 bits long followed by the eighth bit that is a data direction bit (R/W). | |||
// The most significant five bits of the slave address are fixed as “00100”. The next bits are | |||
// CAD1 and CAD0 (device address bit). These bits identify the specific device on the bus. | |||
// The hard-wired input pins (CAD1 and CAD0) set these device address bits (Figure 69) | |||
// Power Management register | |||
#define AK4558_PWR_MNGT 0x00 | |||
// D4 D3 D2 D1 D0 | |||
// PMADR PMADL PMDAR PMDAL RSTN | |||
#define AK4558_PMADR (1u<<4) | |||
#define AK4558_PMADL (1u<<3) | |||
// PMADL/R: ADC L/Rch Power Management | |||
// 0: ADC L/Rch Power Down (default) | |||
// 1: Normal Operation | |||
#define AK4558_PMDAR (1u<<2) | |||
#define AK4558_PMDAL (1u<<1) | |||
// PMDAL/R: DAC L/Rch Power Management | |||
// 0: DAC L/Rch Power Down (default) | |||
// 1: Normal Operation | |||
#define AK4558_RSTN (1u) | |||
// RSTN: Internal Timing Reset | |||
// 0: Reset Register values are not reset. | |||
// 1: Normal Operation (default) | |||
// PLL Control register | |||
#define AK4558_PLL_CTRL 0X01 | |||
// D4 D3 D2 D1 D0 | |||
// PLL3 PLL2 PLL1 PLL0 PMPLL | |||
#define AK4558_PLL3 (1u<<4) | |||
#define AK4558_PLL2 (1u<<3) | |||
#define AK4558_PLL1 (1u<<2) | |||
#define AK4558_PLL0 (1u<<1) | |||
// PLL3-0: PLL Reference Clock Select (Table 16) | |||
// Default: “0010” (BICK pin=64fs) | |||
#define AK4558_PMPLL (1u) | |||
// PMPLL: PLL Power Management | |||
// 0: EXT Mode and Power down (default) | |||
// 1: PLL Mode and Power up | |||
// DAC TDM register | |||
#define AK4558_DAC_TDM 0X02 | |||
// D1 D0 | |||
// SDS1 SDS0 | |||
#define AK4558_SDS1 (1u<<1) | |||
#define AK4558_SDS0 (1u) | |||
// SDS1-0: DAC TDM Data Select (Table 24) | |||
// Default: “00” | |||
// Control 1 register | |||
#define AK4558_CTRL_1 0X03 | |||
// D7 D6 D5 D4 D3 D2 D1 D0 | |||
// TDM1 TDM0 DIF2 DIF1 DIF0 ATS1 ATS0 SMUTE | |||
#define AK4558_TDM1 (1u<<7) | |||
#define AK4558_TDM0 (1u<<6) | |||
// TDM1-0: TDM Format Select (Table 23, Table 25, Table 26) | |||
// Default: “00” (Stereo Mode) | |||
#define AK4558_DIF2 (1u<<5) | |||
#define AK4558_DIF1 (1u<<4) | |||
#define AK4558_DIF0 (1u<<3) | |||
// DIF2-0: Audio Interface Format Mode Select (Table 23) | |||
// Default: “111” (32bit I2S) | |||
#define AK4558_ATS1 (1u<<2) | |||
#define AK4558_ATS0 (1u<<1) | |||
// ATS1-0: Transition Time Setting of Digital Attenuator (Table 31) | |||
// Default: “00” | |||
#define AK4558_SMUTE (1u) | |||
// SMUTE: Soft Mute Enable | |||
// 0: Normal Operation (default) | |||
// 1: All DAC outputs are soft muted. | |||
// Control 2 register | |||
#define AK4558_CTRL_2 0X04 | |||
// D4 D3 D2 D1 D0 | |||
// MCKS1 MCKS0 DFS1 DFS0 ACKS | |||
#define AK4558_MCKS1 (1u<<4) | |||
#define AK4558_MCKS0 (1u<<3) | |||
// MCKS1-0: Master Clock Input Frequency Select (Table 9, follows): | |||
// MCKS1 MCKS0 NSM DSM QSM | |||
// 0 0 256fs 256fs 128fs | |||
// 0 1 384fs 256fs 128fs | |||
// 1 0 512fs 256fs 128fs (default) | |||
// 1 1 768fs 256fs 128fs | |||
#define AK4558_DFS1 (1u<<2) | |||
#define AK4558_DFS0 (1u<<1) | |||
// DFS1-0: Sampling Speed Control (Table 8) | |||
// The setting of DFS1-0 bits is ignored when ACKS bit =“1”. | |||
#define AK4558_ACKS (1u) | |||
// ACKS: Automatic Clock Recognition Mode | |||
// 0: Disable, Manual Setting Mode (default) | |||
// 1: Enable, Auto Setting Mode | |||
// When ACKS bit = “1”, master clock frequency is detected automatically. In this case, the setting of | |||
// DFS1-0 bits is ignored. When ACKS bit = “0”, DFS1-0 bits set the sampling speed mode. The MCKI | |||
// frequency of each mode is detected automatically. | |||
// Mode Control register | |||
#define AK4558_MODE_CTRL 0X05 | |||
// D6 D5 D4 D3 D2 D1 D0 | |||
// FS3 FS2 FS1 FS0 BCKO1 BCKO0 LOPS | |||
#define AK4558_FS3 (1u<<6) | |||
#define AK4558_FS2 (1u<<5) | |||
#define AK4558_FS1 (1u<<4) | |||
#define AK4558_FS0 (1u<<3) | |||
// FS3-0: Sampling Frequency (Table 17, Table 18) | |||
// Default: “0101” | |||
#define AK4558_BCKO1 (1u<<2) | |||
#define AK4558_BCKO0 (1u<<1) | |||
// BCKO1-0: BICK Output Frequency Setting in Master Mode (Table 21) | |||
// Default: “01” (64fs) | |||
#define AK4558_LOPS (1u<<0) | |||
// LOPS: Power-save Mode of LOUT/ROUT | |||
// 0: Normal Operation (default) | |||
// 1: Power-save Mode | |||
// Filter Setting register | |||
#define AK4558_FLTR_SET 0x06 | |||
// D7 D6 D5 D4 D3 D2 D1 D0 | |||
// FIRDA2 FIRDA1 FIRDA0 SLDA SDDA SSLOW DEM1 DEM0 | |||
#define AK4558_FIRDA2 (1u<<7) | |||
#define AK4558_FIRDA1 (1u<<6) | |||
#define AK4558_FIRDA0 (1u<<5) | |||
// FIRDA2-0: Out band noise eliminating Filters Setting (Table 32) | |||
// default: “001” (48kHz) | |||
#define AK4558_SLDA (1u<<4) | |||
// SLDA: DAC Slow Roll-off Filter Enable (Table 28) | |||
// 0: Sharp Roll-off filter (default) | |||
// 1: Slow Roll-off Filter | |||
#define AK4558_SDDA (1u<<3) | |||
// SDDA: DAC Short delay Filter Enable (Table 28) | |||
// 0: Normal filter | |||
// 1: Short delay Filter (default) | |||
#define AK4558_SSLOW (1u<<2) | |||
// SSLOW: Digital Filter Bypass Mode Enable | |||
// 0: Roll-off filter (default) | |||
// 1: Super Slow Roll-off Mode | |||
#define AK4558_DEM1 (1u<<1) | |||
#define AK4558_DEM0 (1u) | |||
// DEM1-0: De-emphasis response control for DAC (Table 22) | |||
// Default: “01”, OFF | |||
// HPF Enable, Filter Setting | |||
#define AK4558_HPF_EN_FLTR_SET 0x07 | |||
// D3 D2 D1 D0 | |||
// SLAD SDAD HPFER HPFEL | |||
#define AK4558_SLAD (1u<<3) | |||
// SLAD: ADC Slow Roll-off Filter Enable (Table 27) | |||
// 0: Sharp Roll-off filter (default) | |||
// 1: Slow Roll-off Filter | |||
#define AK4558_SDAD (1u<<2) | |||
// SDAD: ADC Short delay Filter Enable (Table 27) | |||
// 0: Normal filter | |||
// 1: Short delay Filter (default) | |||
#define AK4558_HPFER (1u<<1) | |||
#define AK4558_HPFEL (1u) | |||
// HPFEL/R: ADC HPF L/Rch Setting | |||
// 0: HPF L/Rch OFF | |||
// 1: HPF L/Rch ON (default) | |||
// LOUT Volume Control register | |||
#define AK4558_LOUT_VOL 0X08 | |||
// D7 D6 D5 D4 D3 D2 D1 D0 | |||
// ATL7 ATL6 ATL5 ATL4 ATL3 ATL2 ATL1 ATL0 | |||
// | |||
// ATL 7-0: Attenuation Level (Table 30) | |||
// Default:FF(0dB) | |||
// ROUT Volume Control register | |||
#define AK4558_ROUT_VOL 0X09 | |||
// D7 D6 D5 D4 D3 D2 D1 D0 | |||
// ATR7 ATR6 ATR5 ATR4 ATR3 ATR2 ATR1 ATR0 | |||
// | |||
// ATR 7-0: Attenuation Level (Table 30) | |||
// Default:FF(0dB) | |||
class AudioControlAK4558 : public AudioControl | |||
{ | |||
public: | |||
bool enable(void); //enables the CODEC, does not power up ADC nor DAC (use enableIn() and enableOut() for selective power up) | |||
bool enableIn(void); //powers up ADC | |||
bool enableOut(void); //powers up DAC | |||
bool disable(void) { return (disableIn()&&disableOut()); } //powers down ADC/DAC | |||
bool disableIn(void); //powers down ADC | |||
bool disableOut(void); //powers down DAC | |||
bool volume(float n); //sets LOUT/ROUT volume to n (range 0.0 - 1.0) | |||
bool volumeLeft(float n); //sets LOUT volume to n (range 0.0 - 1.0) | |||
bool volumeRight(float n); //sets ROUT volume to n (range 0.0 - 1.0) | |||
bool inputLevel(float n) { return false; } //not supported by AK4558 | |||
bool inputSelect(int n) { return false; } //sets inputs to mono left, mono right, stereo (default stereo), not yet implemented | |||
private: | |||
uint8_t registers[10]; | |||
void initConfig(void); | |||
void readConfig(void); | |||
bool write(unsigned int reg, unsigned int val); | |||
uint8_t convertVolume(float vol); | |||
}; | |||
#endif |
@@ -0,0 +1,32 @@ | |||
/* | |||
* AK4558 Passthrough Test | |||
* 2015 by Michele Perla | |||
* | |||
* A simple hardware test which receives audio from the HiFi Audio CODEC Module | |||
* LIN/RIN pins and send it to the LOUT/ROUT pins | |||
* | |||
*/ | |||
#include <Audio.h> | |||
#include <Wire.h> | |||
#include <SPI.h> | |||
#include <SD.h> | |||
#include <SerialFlash.h> | |||
AudioInputI2S i2s1; | |||
AudioOutputI2S i2s2; | |||
AudioConnection patchCord1(i2s1, 0, i2s2, 0); | |||
AudioConnection patchCord2(i2s1, 1, i2s2, 1); | |||
AudioControlAK4558 ak4558; | |||
void setup() { | |||
// put your setup code here, to run once: | |||
AudioMemory(12); | |||
while (!Serial); | |||
ak4558.enable(); | |||
ak4558.enableIn(); | |||
ak4558.enableOut(); | |||
} | |||
void loop() { | |||
} |
@@ -0,0 +1,47 @@ | |||
/* | |||
* AK4558 Sine Out Test | |||
* 2015 by Michele Perla | |||
* | |||
* A simple hardware test which sends two 440 Hz sinewaves to the | |||
* LOUT/ROUT pins of the HiFi Audio CODEC Module. One of the waves | |||
* is out-of-phase by 90° with the other. | |||
* | |||
*/ | |||
#include <Audio.h> | |||
#include <Wire.h> | |||
#include <SPI.h> | |||
#include <SD.h> | |||
#include <SerialFlash.h> | |||
AudioSynthWaveformSine sine2; | |||
AudioSynthWaveformSine sine1; | |||
AudioOutputI2S i2s1; | |||
AudioConnection patchCord1(sine2, 0, i2s1, 0); | |||
AudioConnection patchCord2(sine1, 0, i2s1, 1); | |||
AudioControlAK4558 ak4558; | |||
int phase = 0; | |||
void setup() { | |||
// put your setup code here, to run once: | |||
AudioMemory(12); | |||
while (!Serial); | |||
ak4558.enable(); | |||
ak4558.enableOut(); | |||
AudioNoInterrupts(); | |||
sine1.frequency(440); | |||
sine2.frequency(440); | |||
sine1.amplitude(1.0); | |||
sine2.amplitude(1.0); | |||
AudioInterrupts(); | |||
} | |||
void loop() { | |||
phase+=10; | |||
if (phase==360) phase=0; | |||
AudioNoInterrupts(); | |||
sine2.phase(phase); | |||
AudioInterrupts(); | |||
delay(250); | |||
} |
@@ -2792,5 +2792,64 @@ value frequency | |||
</div> | |||
</script> | |||
<script type="text/x-red" data-help-name="AudioControlAK4558"> | |||
<h3>Summary</h3> | |||
<p>Control the AK4558 chip on the <a href="https://hackaday.io/project/8567-hifi-audio-codec-module" target="_blank">HiFi Audio CODEC Module</a> | |||
in slave mode, where the Teensy controls all I2S timing.</p> | |||
<h3>Audio Connections</h3> | |||
<p>This object has no audio inputs or outputs. Separate I2S objects | |||
are used to send and receive audio data. | |||
</p> | |||
<h3>Functions</h3> | |||
<p class=func><span class=keyword>enable</span>();</p> | |||
<p class=desc>Enables the CODEC to work with 44.1 KHz - 16 bit data. This function does not enable the ADC/DAC modules. | |||
</p> | |||
<p class=func><span class=keyword>enableIn</span>();</p> | |||
<p class=desc>Enables the ADC module. | |||
</p> | |||
<p class=func><span class=keyword>enableOut</span>();</p> | |||
<p class=desc>Enables the DAC module. | |||
</p> | |||
<p class=func><span class=keyword>disable</span>();</p> | |||
<p class=desc>Disables the ADC and the DAC modules. | |||
</p> | |||
<p class=func><span class=keyword>disableIn</span>();</p> | |||
<p class=desc>Disable the ADC module. | |||
</p> | |||
<p class=func><span class=keyword>disableOut</span>();</p> | |||
<p class=desc>Disable the DAC module. | |||
</p> | |||
<p class=func><span class=keyword>volume</span>(level);</p> | |||
<p class=desc>Accepts a float in range 0.0-1.0 and sets the line output volume accordingly. | |||
</p> | |||
<p class=func><span class=keyword>volumeLeft</span>(level);</p> | |||
<p class=desc>Accepts a float in range 0.0-1.0 and sets the left line output volume accordingly. | |||
</p> | |||
<p class=func><span class=keyword>volumeRight</span>(level);</p> | |||
<p class=desc>Accepts a float in range 0.0-1.0 and sets the right line output volume accordingly. | |||
</p> | |||
<p class=func><span class=keyword>inputLevel</span>(level);</p> | |||
<p class=desc>NOT SUPPORTED BY THE AK4558 | |||
</p> | |||
<p class=func><span class=keyword>inputSelect</span>(input);</p> | |||
<p class=desc>not implemented yet | |||
</p> | |||
<h3>Examples</h3> | |||
<p class=exam>File > Examples > Audio > HardwareTesting > AK4558 > PassthroughTest | |||
</p> | |||
<p class=exam>File > Examples > Audio > HardwareTesting > AK4558 > SineOutTest | |||
</p> | |||
<h3>Notes</h3> | |||
<p>TODO: Implement inputSelect() function to enable mono left, mono right, stereo operation.</p> | |||
<p>TODO: Implement ADC and DAC filters control.</p> | |||
<p>TODO: Implement DAC level attenuator attack rate modifier.</p> | |||
</script> | |||
<script type="text/x-red" data-template-name="AudioControlWM8731master"> | |||
<div class="form-row"> | |||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label> | |||
<input type="text" id="node-input-name" placeholder="Name"> | |||
</div> | |||
</script> | |||
</body> | |||
</html> |
@@ -9,6 +9,7 @@ AudioOutputPWM KEYWORD2 | |||
AudioControlSGTL5000 KEYWORD2 | |||
AudioControlWM8731 KEYWORD2 | |||
AudioControlWM8731master KEYWORD2 | |||
AudioControlAK4558 KEYWORD2 | |||
AudioMemory KEYWORD2 | |||
AudioAnalyzeFFT256 KEYWORD2 | |||
@@ -74,8 +75,14 @@ trigger KEYWORD2 | |||
length KEYWORD2 | |||
threshold KEYWORD2 | |||
enable KEYWORD2 | |||
enableIn KEYWORD2 | |||
enableOut KEYWORD2 | |||
disable KEYWORD2 | |||
disableIn KEYWORD2 | |||
disableOut KEYWORD2 | |||
volume KEYWORD2 | |||
volumeLeft KEYWORD2 | |||
volumeRight KEYWORD2 | |||
attack KEYWORD2 | |||
hold KEYWORD2 | |||
decay KEYWORD2 |