Add AK4558 CODEC support / Merge branch 'master' of https://github.com/MickMad/Audiodds
#include "analyze_peak.h" | #include "analyze_peak.h" | ||||
#include "control_sgtl5000.h" | #include "control_sgtl5000.h" | ||||
#include "control_wm8731.h" | #include "control_wm8731.h" | ||||
#include "control_ak4558.h" | |||||
#include "effect_bitcrusher.h" | #include "effect_bitcrusher.h" | ||||
#include "effect_chorus.h" | #include "effect_chorus.h" | ||||
#include "effect_fade.h" | #include "effect_fade.h" |
/* | |||||
* 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; | |||||
} |
/* | |||||
* 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 |
/* | |||||
* 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() { | |||||
} |
/* | |||||
* 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); | |||||
} |
</div> | </div> | ||||
</script> | </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> | </body> | ||||
</html> | </html> |
AudioControlSGTL5000 KEYWORD2 | AudioControlSGTL5000 KEYWORD2 | ||||
AudioControlWM8731 KEYWORD2 | AudioControlWM8731 KEYWORD2 | ||||
AudioControlWM8731master KEYWORD2 | AudioControlWM8731master KEYWORD2 | ||||
AudioControlAK4558 KEYWORD2 | |||||
AudioMemory KEYWORD2 | AudioMemory KEYWORD2 | ||||
AudioAnalyzeFFT256 KEYWORD2 | AudioAnalyzeFFT256 KEYWORD2 | ||||
length KEYWORD2 | length KEYWORD2 | ||||
threshold KEYWORD2 | threshold KEYWORD2 | ||||
enable KEYWORD2 | enable KEYWORD2 | ||||
enableIn KEYWORD2 | |||||
enableOut KEYWORD2 | |||||
disable KEYWORD2 | disable KEYWORD2 | ||||
disableIn KEYWORD2 | |||||
disableOut KEYWORD2 | |||||
volume KEYWORD2 | volume KEYWORD2 | ||||
volumeLeft KEYWORD2 | |||||
volumeRight KEYWORD2 | |||||
attack KEYWORD2 | attack KEYWORD2 | ||||
hold KEYWORD2 | hold KEYWORD2 | ||||
decay KEYWORD2 | decay KEYWORD2 |