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 | |||