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 |