parent
07d5e7e9dc
commit
eaa382cbfb
@ -0,0 +1,625 @@ |
||||
#include "control_ES8388_F32.h" |
||||
|
||||
|
||||
|
||||
#define ES8388_REG_CHIP_CTRL1 (0x00) // Default 0000 0110
|
||||
#define ES8388_REG_CHIP_CTRL1_DFLT (0x06) |
||||
#define ES8388_BIT_SCPRESET (1<<7) // 1=reset registers to default
|
||||
#define ES8388_BIT_LRCM (1<<6) |
||||
#define ES8388_BIT_DACMCLK (1<<5) |
||||
#define ES8388_BIT_SAMEFS (1<<4) |
||||
#define ES8388_BIT_SEQEN (1<<3) |
||||
#define ES8388_BIT_ENREF (1<<2) |
||||
#define ES8388_VMIDSEL_DIS (0x00) |
||||
#define ES8388_VMIDSEL_50K (0x01) |
||||
#define ES8388_VMIDSEL_500K (0x02) |
||||
#define ES8388_VMIDSEL_5K (0x03) |
||||
#define ES8388_REG_CHIP_CTRL2 (0x01) // Default 0101 1100
|
||||
#define ES8388_REG_CHIP_CTRL2_DFLT (0x5C) |
||||
#define ES8388_BIT_LPVCMMOD (1<<5) |
||||
#define ES8388_BIT_LPVREFBUF (1<<4) |
||||
#define ES8388_BIT_PDNANA (1<<3) |
||||
#define ES8388_BIT_PDBIBIASGEN (1<<2) |
||||
#define ES8388_BIT_VREFLO (1<<1) |
||||
#define ES8388_BIT_PDBVREFBUF (1<<0) |
||||
#define ES8388_REG_CHIP_PWR_MAN (0x02) // Default 1100 0011
|
||||
#define ES8388_REG_CHIP_PWR_MAN_DFLT (0xC3) |
||||
#define ES8388_BIT_ADC_DIGPDN (1<<7) |
||||
#define ES8388_BIT_DAC_DIGPDN (1<<6) |
||||
#define ES8388_BIT_ADCSTMRST (1<<5) |
||||
#define ES8388_BIT_DACSTMRST (1<<4) |
||||
#define ES8388_BIT_ADCDLL_PDN (1<<3) |
||||
#define ES8388_BIT_DACDLL_PDN (1<<2) |
||||
#define ES8388_BIT_ADCVREFPDN (1<<1) |
||||
#define ES8388_BIT_DACVREFPDN (1<<0) |
||||
#define ES8388_REG_ADC_PWR_MAN (0x03) // Default 1111 1100
|
||||
#define ES8388_REG_ADC_PWR_MAN_DFLT (0xFC) |
||||
#define ES8388_BIT_PDNAINL (1<<7) |
||||
#define ES8388_BIT_PDNAINR (1<<6) |
||||
#define ES8388_BIT_PDNADCL (1<<5) |
||||
#define ES8388_BIT_PDNADCR (1<<4) |
||||
#define ES8388_BIT_PDNMICB (1<<3) |
||||
#define ES8388_BIT_PDNADCBIASG (1<<2) |
||||
#define ES8388_BIT_FLASHLP (1<<1) |
||||
#define ES8388_BIT_INT1LP (1<<0) |
||||
#define ES8388_REG_DAC_PWR_MAN (0x04) // Default 1100 0000
|
||||
#define ES8388_REG_DAC_PWR_MAN_DFLT (0xC0) |
||||
#define ES8388_BIT_PDNDACL (1<<7) |
||||
#define ES8388_BIT_PDNDACR (1<<6) |
||||
#define ES8388_BIT_LOUT1_EN (1<<5) |
||||
#define ES8388_BIT_ROUT1_EN (1<<4) |
||||
#define ES8388_BIT_LOUT2_EN (1<<3) |
||||
#define ES8388_BIT_ROUT2_EN (1<<2) |
||||
#define ES8388_REG_CHIP_LOWPWR1 (0x05) // Default 0000 0000
|
||||
#define ES8388_REG_CHIP_LOWPWR1_DFLT (0x00) |
||||
#define ES8388_BIT_LPDACL (1<<7) |
||||
#define ES8388_BIT_LPDACR (1<<6) |
||||
#define ES8388_BIT_LPOUT1 (1<<5) |
||||
#define ES8388_BIT_LPOUT2 (1<<3) |
||||
#define ES8388_REG_CHIP_LOWPWR2 (0x06) // Default 0000 0000
|
||||
#define ES8388_REG_CHIP_LOWPWR2_DFLT (0x00) |
||||
#define ES8388_BIT_LPPGA (1<<7) |
||||
#define ES8388_BIT_LPMIX (1<<6) |
||||
#define ES8388_BIT_LPADCVRP (1<<1) |
||||
#define ES8388_BIT_LPDACVRP (1<<0) |
||||
#define ES8388_REG_ANALOG_VOLT_MAN (0x07) // Default 0111 1100
|
||||
#define ES8388_REG_ANALOG_VOLT_MAN_DFLT (0x7C) |
||||
#define ES8388_BIT_VSEL_MASK (0x7C) |
||||
#define ES8388_REG_MASTER_MODE_CTRL (0x08) // Default 1000 0000
|
||||
#define ES8388_REG_MASTER_MODE_CTRL_DFLT (0x80) |
||||
#define ES8388_BIT_MSC (1<<7) |
||||
#define ES8388_BIT_MCLKDIV2 (1<<6) |
||||
#define ES8388_BIT_BCLKINV (1<<5) |
||||
#define ES8388_BCLKDIVAUTO (0x00) |
||||
#define ES8388_BCLKDIV1 (0x01) |
||||
#define ES8388_BCLKDIV2 (0x02) |
||||
#define ES8388_BCLKDIV3 (0x03) |
||||
#define ES8388_BCLKDIV4 (0x04) |
||||
#define ES8388_BCLKDIV6 (0x05) |
||||
#define ES8388_BCLKDIV8 (0x06) |
||||
#define ES8388_BCLKDIV9 (0x07) |
||||
#define ES8388_BCLKDIV11 (0x08) |
||||
#define ES8388_BCLKDIV12 (0x09) |
||||
#define ES8388_BCLKDIV16 (0x0A) |
||||
#define ES8388_BCLKDIV18 (0x0B) |
||||
#define ES8388_BCLKDIV22 (0x0C) |
||||
#define ES8388_BCLKDIV24 (0x0D) |
||||
#define ES8388_BCLKDIV33 (0x0E) |
||||
#define ES8388_BCLKDIV36 (0x0F) |
||||
#define ES8388_BCLKDIV44 (0x10) |
||||
#define ES8388_BCLKDIV48 (0x11) |
||||
#define ES8388_BCLKDIV66 (0x12) |
||||
#define ES8388_BCLKDIV72 (0x13) |
||||
#define ES8388_BCLKDIV5 (0x14) |
||||
#define ES8388_BCLKDIV10 (0x15) |
||||
#define ES8388_BCLKDIV15 (0x16) |
||||
#define ES8388_BCLKDIV17 (0x17) |
||||
#define ES8388_BCLKDIV20 (0x18) |
||||
#define ES8388_BCLKDIV25 (0x19) |
||||
#define ES8388_BCLKDIV30 (0x1A) |
||||
#define ES8388_BCLKDIV32 (0x1B) |
||||
#define ES8388_BCLKDIV34 (0x1C) |
||||
#define ES8388_BCLKDIV(x) ((x)&0x1F) |
||||
#define ES8388_REG_ADC_CTRL1 (0x09) // Default 0000 0000
|
||||
#define ES8388_REG_ADC_CTRL1_DFLT (0x00) |
||||
#define ES8388_MICAMPL_MASK (0xF0) |
||||
#define ES8388_MICAMPL_SHIFT (0x04) |
||||
#define ES8388_MICAMPR_MASK (0x0F) |
||||
#define ES8388_MICAMPR_SHIFT (0x00) |
||||
#define ES8388_REG_ADC_CTRL2 (0x0A) // Default 0000 0000
|
||||
#define ES8388_REG_ADC_CTRL2_DFLT (0x00) |
||||
#define ES8388_LINSEL_MASK (0xC0) |
||||
#define ES8388_LINSEL_SHIFT (0x06) |
||||
#define ES8388_INPUT1 (0x00) |
||||
#define ES8388_INPUT2 (0x01) |
||||
#define ES8388_INPUTDIFF (0x03) |
||||
#define ES8388_LINSEL(x) (((x)<<ES8388_LINSEL_SHIFT)&ES8388_LINSEL_MASK) |
||||
#define ES8388_RINSEL_MASK (0x30) |
||||
#define ES8388_RINSEL_SHIFT (0x04) |
||||
#define ES8388_RINSEL(x) (((x)<<ES8388_RINSEL_SHIFT)&ES8388_RINSEL_MASK) |
||||
#define ES8388_BIT_DSSEL (1<<3) |
||||
#define ES8388_BIT_DSR (1<<2) |
||||
#define ES8388_REG_ADC_CTRL3 (0x0B) // Default 0000 0010
|
||||
#define ES8388_REG_ADC_CTRL3_DFLT (0x02) |
||||
#define ES8388_BIT_DS (1<<7) |
||||
#define ES8388_MONOMIX_MASK (0x18) |
||||
#define ES8388_MONOMIX_SHIFT (0x03) |
||||
#define ES8388_MONOMIX_STEREO (0x00) |
||||
#define ES8388_MONOMIX_ADCL (0x01) |
||||
#define ES8388_MONOMIX_ADCR (0x02) |
||||
#define ED8388_MONOMIX(x) (((x)<<ES8388_MONOMIX_SHIFT)&ES8388_MONOMIX_MASK) |
||||
#define ES8388_REG_ADC_CTRL4 (0x0C) // Default 0000 0000
|
||||
#define ES8388_REG_ADC_CTRL4_DFLT (0x00) |
||||
#define ES8388_DATSEL_MASK (0xC0) |
||||
#define ES8388_DATSEL_SHIFT (0x06) |
||||
#define ES8388_DATSEL_LL_RR (0x00) |
||||
#define ES8388_DATSEL_LL_LR (0x01) |
||||
#define ES8388_DATSEL_RL_RR (0x02) |
||||
#define ES8388_DATSEL_LR_RL (0x03) |
||||
#define ES8388_BIT_ADCLRP (1<<5) |
||||
#define ES8388_ADCWL_MASK (0x1C) |
||||
#define ES8388_ADCWL_SHIFT (0x1C) |
||||
#define ES8388_ADCWL_24BIT (0x00) |
||||
#define ES8388_ADCWL_20BIT (0x01) |
||||
#define ES8388_ADCWL_18BIT (0x02) |
||||
#define ES8388_ADCWL_16BIT (0x03) |
||||
#define ES8388_ADCWL_32BIT (0x04) |
||||
#define ES8388_ADCWL(x) (((x)<<ES8388_ADCWL_SHIFT)&ES8388_ADCWL_MASK) |
||||
#define ES8388_ADCFORMAT_MASK (0x03) |
||||
#define ES8388_ADCFORMAT_SHIFT (0x00) |
||||
#define ES8388_ADCFORMAT_I2S (0x00) |
||||
#define ES8388_ADCFORMAT_LJUST (0x01) |
||||
#define ES8388_ADCFORMAT_RJUST (0x02) |
||||
#define ES8388_ADCFORMAT_DSPPCM (0x03) |
||||
#define ES8388_ADCFORMAT(x) (((x)<<ES8388_ADCFORMAT_SHIFT)&ES8388_ADCFORMAT_MASK) |
||||
#define ES8388_REG_ADC_CTRL5 (0x0D) // Default 0000 0110
|
||||
#define ES8388_REG_ADC_CTRL5_DFLT (0x06) |
||||
#define ES8388_BIT_ADCFSMODE (1<<5) |
||||
#define ES8388_ADCFSRATIO_MASK (0x1F) |
||||
#define ES8388_ADCFSRATIO_SHIFT (0x00) |
||||
#define ES8388_FSRATIO_128 (0x00) |
||||
#define ES8388_FSRATIO_192 (0x01) |
||||
#define ES8388_FSRATIO_256 (0x02) |
||||
#define ES8388_FSRATIO_384 (0x03) |
||||
#define ES8388_FSRATIO_512 (0x04) |
||||
#define ES8388_FSRATIO_576 (0x05) |
||||
#define ES8388_FSRATIO_768 (0x06) // default
|
||||
#define ES8388_FSRATIO_1024 (0x07) |
||||
#define ES8388_FSRATIO_1152 (0x08) |
||||
#define ES8388_FSRATIO_1408 (0x09) |
||||
#define ES8388_FSRATIO_1536 (0x0A) |
||||
#define ES8388_FSRATIO_2112 (0x0B) |
||||
#define ES8388_FSRATIO_2304 (0x0C) |
||||
#define ES8388_FSRATIO_125 (0x10) |
||||
#define ES8388_FSRATIO_136 (0x11) |
||||
#define ES8388_FSRATIO_250 (0x12) |
||||
#define ES8388_FSRATIO_272 (0x13) |
||||
#define ES8388_FSRATIO_375 (0x14) |
||||
#define ES8388_FSRATIO_500 (0x15) |
||||
#define ES8388_FSRATIO_544 (0x16) |
||||
#define ES8388_FSRATIO_750 (0x17) |
||||
#define ES8388_FSRATIO_1000 (0x18) |
||||
#define ES8388_FSRATIO_1088 (0x19) |
||||
#define ES8388_FSRATIO_1496 (0x1A) |
||||
#define ES8388_FSRATIO_1500 (0x1B) |
||||
#define ES8388_ADCFSRATIO(x) (((x)<<ES8388_ADCFSRATIO_SHIFT)&ES8388_ADCFSRATIO_MASK) |
||||
#define ES8388_REG_ADC_CTRL6 (0x0E) // Default 0011 0000
|
||||
#define ES8388_REG_ADC_CTRL6_DFLT (0x30) |
||||
#define ES8388_BIT_ADCINVL (1<<7) |
||||
#define ES8388_BIT_ADCINVR (1<<6) |
||||
#define ES8388_BIT_ADCHPFL (1<<5) |
||||
#define ES8388_BIT_ADCHPFR (1<<4) |
||||
#define ES8388_REG_ADC_CTRL7 (0x0F) // Default 0010 0000
|
||||
#define ES8388_REG_ADC_CTRL7_DFLT (0x20) |
||||
#define ES8388_ADCRAMPRATE_MASK (0xC0) |
||||
#define ES8388_ADCRAMPRATE_SHIFT (0x06) |
||||
#define ES8388_ADCRAMPRATE_05DB_4LRCLK (0x00) |
||||
#define ES8388_ADCRAMPRATE_05DB_8LRCLK (0x01) |
||||
#define ES8388_ADCRAMPRATE_05DB_16LRCLK (0x02) |
||||
#define ES8388_ADCRAMPRATE_05DB_32LRCLK (0x03) |
||||
#define ES8388_ADCRAMPRATE(x) (((x)<<ES8388_ADCRAMPRATE_SHIFT)&ES8388_ADCRAMPRATE_MASK) |
||||
#define ES8388_BIT_ADCSOFTRAMP (1<<5) |
||||
#define ES8388_BIT_ADCLER (1<<3) |
||||
#define ES8388_BIT_ADCMUTE (1<<2) |
||||
#define ES8388_REG_ADC_CTRL8 (0x10) // Default 1100 0000
|
||||
#define ES8388_REG_ADC_CTRL8_DFLT (0xC0) |
||||
#define ESP8388_LADCVOL (ES8388_REG_ADC_CTRL8) |
||||
#define ES8388_REG_ADC_CTRL9 (0x11) // Default 1100 0000
|
||||
#define ES8388_REG_ADC_CTRL9_DFLT (0xC0) |
||||
#define ESP8388_RADCVOL (ES8388_REG_ADC_CTRL9) |
||||
#define ES8388_REG_ADC_CTRL10 (0x12) // Default 0011 1000
|
||||
#define ES8388_REG_ADC_CTRL10_DFLT (0x38) |
||||
#define ES8388_ALCSEL_MASK (0xC0) |
||||
#define ES8388_ALCSEL_SHIFT (0x06) |
||||
#define ES8388_ALCSEL_OFF (0x00) |
||||
#define ES8388_ALCSEL_R (0x01) |
||||
#define ES8388_ALCSEL_L (0x02) |
||||
#define ES8388_ALCSEL_LR (0x03) |
||||
#define ES8388_ALCSEL(x) (((x)<<ES8388_ALCSEL_SHIFT)&ES8388_ALCSEL_MASK) |
||||
#define ES8388_MAXGAIN_MASK (0x38) |
||||
#define ES8388_MAXGAIN_SHIFT (0x03) |
||||
#define ES8388_MAXGAIN_M6_5DB (0x00) |
||||
#define ES8388_MAXGAIN_M0_5DB (0x01) |
||||
#define ES8388_MAXGAIN_5_5DB (0x02) |
||||
#define ES8388_MAXGAIN_11_5DB (0x03) |
||||
#define ES8388_MAXGAIN_17_5DB (0x04) |
||||
#define ES8388_MAXGAIN_23_5DB (0x05) |
||||
#define ES8388_MAXGAIN_29_5DB (0x06) |
||||
#define ES8388_MAXGAIN_35_5DB (0x07) |
||||
#define ES8388_MAXGAIN(x) (((x)<<ES8388_MAXGAIN_SHIFT)&ES8388_MAXGAIN_MASK) |
||||
#define ES8388_MINGAIN_MASK (0x07) |
||||
#define ES8388_MINGAIN_SHIFT (0x00) |
||||
#define ES8388_MINGAIN_M12DB (0x00) |
||||
#define ES8388_MINGAIN_M6DB (0x01) |
||||
#define ES8388_MINGAIN_0DB (0x02) |
||||
#define ES8388_MINGAIN_6DB (0x03) |
||||
#define ES8388_MINGAIN_12DB (0x04) |
||||
#define ES8388_MINGAIN_18DB (0x05) |
||||
#define ES8388_MINGAIN_24DB (0x06) |
||||
#define ES8388_MINGAIN_30DB (0x07) |
||||
#define ES8388_MINGAIN(x) (((x)<<ES8388_MINGAIN_SHIFT)&ES8388_MINGAIN_MASK) |
||||
#define ES8388_REG_ADC_CTRL11 (0x13) // Default 1011 0000
|
||||
#define ES8388_REG_ADC_CTRL11_DFLT (0xB0) |
||||
#define ES8388_ALCLVL_MASK (0xF0) |
||||
#define ES8388_ALCLVL_SHIFT (0x04) |
||||
#define ES8388_ALCLVL(x) (((x)<<ES8388_ALCLVL_SHIFT)&ES8388_ALCLVL_MASK) |
||||
#define ES8388_ALCHLD_MASK (0x0F) |
||||
#define ES8388_ALCHLD_SHIFT (0x00) |
||||
#define ES8388_ALCHLD(x) (((x)<<ES8388_ALCHLD_SHIFT)&ES8388_ALCHLD_MASK) |
||||
#define ES8388_REG_ADC_CTRL12 (0x14) // Default 0011 0010
|
||||
#define ES8388_REG_ADC_CTRL12_DFLT (0x32) |
||||
#define ES8388_ALCDCY_MASK (0xF0) |
||||
#define ES8388_ALCDCY_SHIFT (0x04) |
||||
#define ES8388_ALCDCY(x) (((x)<<ES8388_ALCDCY_SHIFT)&ES8388_ALCDCY_MASK) |
||||
#define ES8388_ALCATK_MASK (0x0F) |
||||
#define ES8388_ALCATK_SHIFT (0x00) |
||||
#define ES8388_ALCATK(x) (((x)<<ES8388_ALCATK_SHIFT)&ES8388_ALCATK_MASK) |
||||
#define ES8388_REG_ADC_CTRL13 (0x15) // Default 0000 0110
|
||||
#define ES8388_REG_ADC_CTRL13_DFLT (0x06) |
||||
#define ES8388_BIT_ALCMODE (1<<7) |
||||
#define ES8388_BIT_ALCZC (1<<6) |
||||
#define ES8388_BIT_TIMEOUT (1<<5) |
||||
#define ES8388_WINSIZE_MASK (0x1F) |
||||
#define ES8388_WINSIZE_SHIFT (0x00) |
||||
#define ES8388_WINSIZE(x) (((x)<<ES8388_WINSIZE_SHIFT)&ES8388_WINSIZE_MASK) |
||||
#define ES8388_REG_ADC_CTRL14 (0x16) // Default 0000 0000
|
||||
#define ES8388_REG_ADC_CTRL14_DFLT (0x00) |
||||
#define ES8388_NGTH_MASK (0xF8) |
||||
#define ES8388_NGTH_SHIFT (0x03) |
||||
#define ES8388_NGTH(x) (((x)<<ES8388_NGTH_SHIFT)&ES8388_NGTH_MASK) |
||||
#define ES8388_NGG_MASK (0x06) |
||||
#define ES8388_NGG_SHIFT (0x01) |
||||
#define ES8388_NGG_PGA_CONST (0x00) |
||||
#define ES8388_NGG_ADCMUTE (0x01) |
||||
#define ES8388_NGG(x) (((x)<<ES8388_NGG_SHIFT)&ES8388_NGG_MASK) |
||||
#define ES8388_BIT_NGAT_EN (1<<0) |
||||
#define ES8388_REG_DAC_CTRL1 (0x17) // Default 0000 0000
|
||||
#define ES8388_REG_DAC_CTRL1_DFLT (0x00) |
||||
#define ES8388_BIT_DACLRSWAP (1<<7) |
||||
#define ES8388_BIT_DACLRP (1<<6) |
||||
#define ES8388_DACWL_MASK (0x38) |
||||
#define ES8388_DACWL_SHIFT (0x03) |
||||
#define ES8388_DACWL_24BIT (0x00) |
||||
#define ES8388_DACWL_20BIT (0x01) |
||||
#define ES8388_DACWL_18BIT (0x02) |
||||
#define ES8388_DACWL_16BIT (0x03) |
||||
#define ES8388_DACWL_32BIT (0x04) |
||||
#define ES8388_DACWL(x) (((x)<<ES8388_DACWL_SHIFT)&ES8388_DACWL_MASK) |
||||
#define ES8388_DACFORMAT_MASK (0x06) |
||||
#define ES8388_DACFORMAT_SHIFT (0x01) |
||||
#define ES8388_DACFORMAT_I2S (0x00) |
||||
#define ES8388_DACFORMAT_LJUST (0x01) |
||||
#define ES8388_DACFORMAT_RJUST (0x02) |
||||
#define ES8388_DACFORMAT_DSPPCM (0x03) |
||||
#define ES8388_DACFORMAT(x) (((x)<<ES8388_DACFORMAT_SHIFT)&ES8388_DACFORMAT_MASK) |
||||
#define ES8388_REG_DAC_CTRL2 (0x18) // Default 0000 0110
|
||||
#define ES8388_REG_DAC_CTRL2_DFLT (0x06) |
||||
#define ES8388_BIT_DACFSMODE (1<<5) |
||||
#define ES8388_DACFSRATIO_MASK (0x1F) |
||||
#define ES8388_DACFSRATIO_SHIFT (0x00) // values define in ADCFSRATIO
|
||||
#define ES8388_DACFSRATIO(x) (((x)<<ES8388_DACFSRATIO_SHIFT)&ES8388_DACFSRATIO_MASK) |
||||
#define ES8388_REG_DAC_CTRL3 (0x19) // Default 0010 0010
|
||||
#define ES8388_REG_DAC_CTRL3_DFLT (0x22) |
||||
#define ES8388_DACRAMPRATE_MASK (0xC0) |
||||
#define ES8388_DACRAMPRATE_SHIFT (0x06) |
||||
#define ES8388_DACRAMPRATE_05DB_4LRCLK (0x00) |
||||
#define ES8388_DACRAMPRATE_05DB_32LRCLK (0x01) |
||||
#define ES8388_DACRAMPRATE_05DB_64LRCLK (0x02) |
||||
#define ES8388_DACRAMPRATE_05DB_128LRCLK (0x03) |
||||
#define ES8388_DACRAMPRATE(x) (((x)<<ES8388_DACRAMPRATE_SHIFT)&ES8388_DACRAMPRATE_MASK) |
||||
#define ES8388_BIT_DACSOFTRAMP (1<<5) |
||||
#define ES8388_BIT_DACLER (1<<3) |
||||
#define ES8388_BIT_DACMUTE (1<<2) |
||||
#define ES8388_REG_DAC_CTRL4 (0x1A) // Default 1100 0000
|
||||
#define ES8388_REG_DAC_CTRL4_DFLT (0xC0) |
||||
#define ES8388_LDACVOL (ES8388_REG_DAC_CTRL4) |
||||
#define ES8388_REG_DAC_CTRL5 (0x1B) // Default 1100 0000
|
||||
#define ES8388_REG_DAC_CTRL5_DFLT (0xC0) |
||||
#define ES8388_RDACVOL (ES8388_REG_DAC_CTRL5) |
||||
#define ES8388_REG_DAC_CTRL6 (0x1C) // Default 0000 1000
|
||||
#define ES8388_REG_DAC_CTRL6_DFLT (0x08) |
||||
#define ES8388_DACDEEMP_MASK (0xC0) |
||||
#define ES8388_DACDEEMP_SHIFT (0x06) |
||||
#define ES8388_DACDEEMP_OFF (0x00) |
||||
#define ES8388_DACDEEMP_32KHZ (0x01) |
||||
#define ES8388_DACDEEMP_44_1KHZ (0x02) |
||||
#define ES8388_DACDEEMP_48KHZ (0x03) |
||||
#define ES8388_DACDEEMP(x) (((x)<<ES8388_DACDEEMP_SHIFT)&ES8388_DACDEEMP_MASK) |
||||
#define ES8388_BIT_DACINVL (1<<5) |
||||
#define ES8388_BIT_DACINVR (1<<4) |
||||
#define ES8388_BIT_CLICKFREE (1<<3) |
||||
#define ES8388_REG_DAC_CTRL7 (0x1D) // Default 0000 0000
|
||||
#define ES8388_BIT_DACZEROL (1<<7) |
||||
#define ES8388_BIT_DACZEROR (1<<6) |
||||
#define ES8388_BIT_DACMONO (1<<5) |
||||
#define ES8388_DACSE_MASK (0x1C) |
||||
#define ES8388_DACSE_SHIFT (0x02) |
||||
#define ES8388_DACSE(x) (((x)<<ES8388_DACSE_SHIFT)&ES8388_DACSE_MASK) |
||||
#define ES8388_VPP_MASK (0x03) |
||||
#define ES8388_VPP_SHIFT (0x00) |
||||
#define ES8388_VPP_3_5V (0x00) |
||||
#define ES8388_VPP_4V (0x01) |
||||
#define ES8388_VPP_3V (0x02) |
||||
#define ES8388_VPP_2_5V (0x03) |
||||
#define ES8388_VPP(x) (((x)<<ES8388_VPP_SHIFT)&ES8388_VPP_MASK) |
||||
#define ES8388_REG_DAC_CTRL8 (0x1E) // DAC shelving filter coeff a [29:24]
|
||||
#define ES8388_REG_DAC_CTRL9 (0x1F) // DAC shelving filter coeff a [23:16]
|
||||
#define ES8388_REG_DAC_CTRL10 (0x20) // DAC shelving filter coeff a [15:08]
|
||||
#define ES8388_REG_DAC_CTRL11 (0x21) // DAC shelving filter coeff a [07:00]
|
||||
#define ES8388_REG_DAC_CTRL12 (0x22) // DAC shelving filter coeff b [29:24]
|
||||
#define ES8388_REG_DAC_CTRL13 (0x23) // DAC shelving filter coeff b [23:16]
|
||||
#define ES8388_REG_DAC_CTRL14 (0x24) // DAC shelving filter coeff b [15:08]
|
||||
#define ES8388_REG_DAC_CTRL15 (0x25) // DAC shelving filter coeff b [07:00]
|
||||
#define ES8388_REG_DAC_CTRL16 (0x26) // Default 0000 0000
|
||||
#define ES8388_REG_DAC_CTRL16_DFLT (0x00) |
||||
#define ES8388_LMIXSEL_MASK (0x38) |
||||
#define ES8388_LMIXSEL_SHIFT (0x03) |
||||
#define ES8388_LMIXSEL_LIN1 (0x00) |
||||
#define ES8388_LMIXSEL_LIN2 (0x01) |
||||
#define ES8388_LMIXSEL_ADCL_P (0x03) |
||||
#define ES8388_LMIXSEL_ADCL_N (0x04) |
||||
#define ES8388_LMIXSEL(x) (((x)<<ES8388_LMIXSEL_SHIFT)&ES8388_LMIXSEL_MASK) |
||||
#define ES8388_RMIXSEL_MASK (0x03) |
||||
#define ES8388_RMIXSEL_SHIFT (0x00) |
||||
#define ES8388_RMIXSEL_RIN1 (0x00) |
||||
#define ES8388_RMIXSEL_RIN2 (0x01) |
||||
#define ES8388_RMIXSEL_ADCR_P (0x03) |
||||
#define ES8388_RMIXSEL_ADCR_N (0x04) |
||||
#define ES8388_RMIXSEL(x) (((x)<<ES8388_RMIXSEL_SHIFT)&ES8388_RMIXSEL_MASK) |
||||
#define ES8388_REG_DAC_CTRL17 (0x27) // Default 0011 1000
|
||||
#define ES8388_REG_DAC_CTRL17_DFLT (0x38) |
||||
#define ES8388_BIT_LD2LO (1<<7) |
||||
#define ES8388_BIT_LI2LO (1<<3) |
||||
#define ES8388_LI2LOVOL_MASK (0x38) |
||||
#define ES8388_LI2LOVOL_SHIFT (0x03) |
||||
#define ES8388_VOL_6DB (0x00) |
||||
#define ES8388_VOL_3DB (0x01) |
||||
#define ES8388_VOL_0DB (0x02) |
||||
#define ES8388_VOL_M3DB (0x03) |
||||
#define ES8388_VOL_M6DB (0x04) |
||||
#define ES8388_VOL_M9DB (0x05) |
||||
#define ES8388_VOL_M12DB (0x06) |
||||
#define ES8388_VOL_M15DB (0x07) |
||||
#define ES8388_LI2LOVOL(x) (((x)<<ES8388_LI2LOVOL_SHIFT)&ES8388_LI2LOVOL_MASK) |
||||
#define ES8388_REG_DAC_CTRL18 (0x28) // No data? Default 0010 1000
|
||||
#define ES8388_REG_DAC_CTRL19 (0x29) // No data? Default 0010 1000
|
||||
#define ES8388_REG_DAC_CTRL20 (0x2A) // Default 0011 1000
|
||||
#define ES8388_REG_DAC_CTRL20_DFLT (0x38) |
||||
#define ES8388_BIT_RD2RO (1<<7) // DACR to outmixer R
|
||||
#define ES8388_BIT_RI2RO (1<<6) // RIN to outmixer R
|
||||
#define ES8388_RI2ROVOL_MASK (0x38) |
||||
#define ES8388_RI2ROVOL_SHIFT (0x03) |
||||
#define ES8388_RI2ROVOL(x) (((x)<<ES8388_RI2ROVOL_SHIFT)&ES8388_RI2ROVOL_MASK) |
||||
#define ES8388_REG_DAC_CTRL21 (0x2B) // Default 0000 0000
|
||||
#define ES8388_REG_DAC_CTRL21_DFLT (0x00) |
||||
#define ES8388_BIT_SLRCK (1<<7) |
||||
#define ES8388_BIT_LRCK_SEL (1<<6) |
||||
#define ES8388_BIT_OFFSET_DIS (1<<5) |
||||
#define ES8388_BIT_MCLK_DIS (1<<4) |
||||
#define ES8388_BIT_ADC_DLL_PWD (1<<3) |
||||
#define ES8388_BIT_DAC_DLL_PWD (1<<2) |
||||
#define ES8388_REG_DAC_CTRL22 (0x2C) // Default 0000 0000
|
||||
#define ES8388_REG_DAC_OFFSET (ES8388_REG_DAC_CTRL21) |
||||
#define ES8388_REG_DAC_CTRL23 (0x2D) // Default 0000 0000
|
||||
#define ES8388_BIT_VROI (1<<4) |
||||
#define ES8388_REG_DAC_CTRL24 (0x2E) // Default 0000 0000
|
||||
#define ES8388_LOUT1VOL (ES8388_REG_DAC_CTRL24) |
||||
#define ES8388_REG_DAC_CTRL25 (0x2F) // Default 0000 0000
|
||||
#define ES8388_ROUT1VOL (ES8388_REG_DAC_CTRL25) |
||||
#define ES8388_REG_DAC_CTRL26 (0x30) // Default 0000 0000
|
||||
#define ES8388_LOUT2VOL (ES8388_REG_DAC_CTRL26) |
||||
#define ES8388_REG_DAC_CTRL27 (0x31) // Default 0000 0000
|
||||
#define ES8388_ROUT2VOL (ES8388_REG_DAC_CTRL27) |
||||
#define ES8388_REG_DAC_CTRL28 (0x32) // No data? Default 0000 1000
|
||||
|
||||
bool AudioControlES8388_F32::configured = false; |
||||
|
||||
bool AudioControlES8388_F32::enable(TwoWire *i2cBus, uint8_t addr, config_t cfg) |
||||
{ |
||||
configured = false; |
||||
ctrlBus = i2cBus; |
||||
i2cAddr = addr; |
||||
ctrlBus->begin(); |
||||
ctrlBus->setClock(100000); |
||||
bool reply = true; |
||||
|
||||
reply = writeReg(ES8388_REG_MASTER_MODE_CTRL, 0x00); // set to slave mode
|
||||
reply &= writeReg(ES8388_REG_CHIP_PWR_MAN, 0xF3); // power down
|
||||
reply &=writeReg(ES8388_REG_DAC_CTRL21, ES8388_BIT_SLRCK); // DACLRC = ADCLRC
|
||||
reply &=writeReg(ES8388_REG_CHIP_CTRL1, ES8388_VMIDSEL_5K | ES8388_BIT_ENREF); // 50k divider,
|
||||
reply &=writeReg(ES8388_REG_CHIP_CTRL2, 0x40); // low power modes off, bit6 not defined? based on default value
|
||||
reply &=writeReg(ES8388_REG_ADC_PWR_MAN, 0x00); // power up ADC, turn off the PDNMICB?
|
||||
reply &=writeReg(ES8388_REG_DAC_PWR_MAN, ES8388_BIT_LOUT1_EN | ES8388_BIT_ROUT1_EN); // enable LR1
|
||||
if (reply == false) |
||||
{ |
||||
DBG_SERIAL.println("Codec i2c error"); |
||||
return false; |
||||
} |
||||
switch (cfg) |
||||
{ |
||||
case ES8388_CFG_LINEIN_DIFF: |
||||
writeReg(ES8388_REG_ADC_CTRL2, ES8388_LINSEL(ES8388_INPUTDIFF) | // LIN=LIN1-RIN1 (ADCCTRL3[7] DS = 0)
|
||||
ES8388_RINSEL(ES8388_INPUTDIFF) | // RIN=LIN2-RIN2 (DSR = 1)
|
||||
ES8388_BIT_DSSEL | // use different DSR settings for L and R
|
||||
ES8388_BIT_DSR); // DS setting for channel R
|
||||
break; |
||||
case ES8388_CFG_LINEIN_SINGLE_ENDED: |
||||
writeReg(ES8388_REG_ADC_CTRL2, ES8388_LINSEL(ES8388_INPUT1) | // LIN=LIN1-RIN1 (ADCCTRL3[7] DS = 0)
|
||||
ES8388_RINSEL(ES8388_INPUT1)); // RIN=LIN2-RIN2 (DSR = 1)
|
||||
break; |
||||
default: |
||||
writeReg(ES8388_REG_ADC_CTRL2, ES8388_LINSEL(ES8388_INPUT1) | // LIN=LIN1-RIN1 (ADCCTRL3[7] DS = 0)
|
||||
ES8388_RINSEL(ES8388_INPUT1)); // RIN=LIN2-RIN2 (DSR = 1)
|
||||
break; |
||||
} |
||||
writeReg(ES8388_REG_ADC_CTRL6, 0x00); // disable HPF
|
||||
// 0dB
|
||||
writeReg(ES8388_REG_ADC_CTRL4, ES8388_ADCWL(ES8388_ADCWL_32BIT)); // 24bit
|
||||
writeReg(ES8388_REG_ADC_CTRL5, ES8388_ADCFSRATIO(ES8388_FSRATIO_256)); // 256*Fs, single speed
|
||||
// ADC digital volume
|
||||
writeReg(ESP8388_LADCVOL, 0x00); // 0dB
|
||||
writeReg(ESP8388_RADCVOL, 0x00); // 0dB
|
||||
// DAC setup
|
||||
writeReg(ES8388_REG_DAC_CTRL1, ES8388_DACWL(ES8388_DACWL_32BIT)); // 24bit
|
||||
writeReg(ES8388_REG_DAC_CTRL2, ES8388_DACFSRATIO(ES8388_FSRATIO_256)); // 256*Fs single speed
|
||||
// DAC digital volume
|
||||
writeReg(ES8388_REG_DAC_CTRL4, 0x00); // 0dB
|
||||
writeReg(ES8388_REG_DAC_CTRL5, 0x00); // 0dB
|
||||
// Mixer Setup
|
||||
writeReg(ES8388_REG_DAC_CTRL16, ES8388_LMIXSEL(ES8388_LMIXSEL_ADCL_P) | |
||||
ES8388_RMIXSEL(ES8388_RMIXSEL_ADCR_P)); |
||||
writeReg(ES8388_REG_DAC_CTRL17, ES8388_BIT_LD2LO); // LDAC to left mixer enable, gain 0dB
|
||||
writeReg(ES8388_REG_DAC_CTRL20, ES8388_BIT_RD2RO); // RDAC to right mixer enable, gain 0dB
|
||||
|
||||
// R L OUT volume
|
||||
dacGain = 0x1E; |
||||
writeReg(ES8388_LOUT1VOL, dacGain); // L1 0dB
|
||||
writeReg(ES8388_ROUT1VOL, dacGain); // R1 0dB
|
||||
// optimize A/D conversion for 1/4 Vrms range
|
||||
optimizeConversion(0); |
||||
writeReg(ES8388_REG_CHIP_PWR_MAN, 0x00); // Power up DEM and STM
|
||||
|
||||
// ALC config
|
||||
// writeReg(ES8388_REG_ADC_CTRL10, ES8388_ALCSEL(ES8388_ALCSEL_LR) | // ALC OFF
|
||||
// ES8388_MAXGAIN(ES8388_MAXGAIN_M0_5DB) | // max gain -0.5dB
|
||||
// ES8388_MINGAIN(ES8388_MINGAIN_M12DB)); // min gain -12dB
|
||||
// writeReg(ES8388_REG_ADC_CTRL11, ES8388_ALCLVL(0x0A)); // target gain -1.5dB, hold time=0
|
||||
// writeReg(ES8388_REG_ADC_CTRL12, ES8388_ALCATK(0x02) | // ALC limiter attack time 90.8us
|
||||
// ES8388_ALCDCY(0x01)); // ALC limiter decay time 182us
|
||||
// writeReg(ES8388_REG_ADC_CTRL13, ES8388_BIT_ALCMODE | ES8388_WINSIZE(0x06)); // Limiter mode, no ZC, 96*16 samples peak window
|
||||
// writeReg(ES8388_REG_ADC_CTRL14, 0x00); // disable noise gate
|
||||
//writeReg(ES8388_REG_ADC_CTRL14, ES8388_NGTH(0x1F) | ES8388_NGG(ES8388_NGG_ADCMUTE)| ES8388_BIT_NGAT_EN);
|
||||
// ADC PGA gain
|
||||
//writeReg(ES8388_REG_ADC_CTRL1, 0x00);
|
||||
|
||||
configured = true; |
||||
return true; |
||||
} |
||||
|
||||
void AudioControlES8388_F32::optimizeConversion(uint8_t range) |
||||
{ |
||||
uint8_t ingain[] = {0, 2, 4, 6, 8}; // 0db, 6dB, 12dB, 18dB, 24dB
|
||||
uint8_t outvol[] = {30, 26, 22, 18, 14}; // 0db, -6dB, -12dB, -18dB, -24dB
|
||||
if (range < 0) range = 0; |
||||
if (range > 4) range = 4; |
||||
volume(outvol[range]); |
||||
setInGain(ingain[range]); |
||||
} |
||||
|
||||
// get and set the output level (analog gain)
|
||||
// vol = 0-31
|
||||
void AudioControlES8388_F32::volume(uint8_t vol) |
||||
{ |
||||
if (vol > 30) |
||||
vol = 30; |
||||
writeReg(ES8388_REG_DAC_CTRL24, vol); // LOUT1VOL
|
||||
writeReg(ES8388_REG_DAC_CTRL25, vol); // ROUT1VOL
|
||||
} |
||||
bool AudioControlES8388_F32::volume(float n) |
||||
{ |
||||
n = constrain(n, 0.0f, 1.0f); |
||||
uint8_t vol = n * 30.99f; |
||||
if (vol > 30) |
||||
vol = 30; |
||||
writeReg(ES8388_REG_DAC_CTRL24, vol); // LOUT1VOL
|
||||
writeReg(ES8388_REG_DAC_CTRL25, vol); // ROUT1VOL
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
uint8_t AudioControlES8388_F32::getOutVol() |
||||
{ |
||||
uint8_t vol; |
||||
readReg(ES8388_REG_DAC_CTRL24, &vol); |
||||
return vol; |
||||
} |
||||
|
||||
bool AudioControlES8388_F32::setInGain(uint8_t gain) |
||||
{ |
||||
if (gain > 8) |
||||
gain = 8; |
||||
uint8_t temp; |
||||
temp = gain << 4; |
||||
temp = temp | gain; |
||||
|
||||
return writeReg(ES8388_REG_ADC_CTRL1, temp); |
||||
} |
||||
|
||||
uint8_t AudioControlES8388_F32::getInGain() |
||||
{ |
||||
uint8_t temp; |
||||
readReg(ES8388_REG_ADC_CTRL1, &temp); |
||||
temp = (temp & 0xF0) >> 4; |
||||
return temp; |
||||
} |
||||
void AudioControlES8388_F32::set_noiseGate(float thres) |
||||
{ |
||||
uint8_t thres_val = constrain(thres, 0.0f, 1.0f) * 31.99f; |
||||
DBG_SERIAL.printf("Gate: %d\r\n", thres_val); |
||||
writeReg(ES8388_REG_ADC_CTRL14, ES8388_NGTH(thres_val) | ES8388_NGG(ES8388_NGG_ADCMUTE)| ES8388_BIT_NGAT_EN);
|
||||
} |
||||
|
||||
// bypassed the analog input to the output, disconnect the digital i / o
|
||||
bool AudioControlES8388_F32::analogBypass(bool bypass) |
||||
{ |
||||
bool res = true; |
||||
if (bypass) |
||||
{ |
||||
res = writeReg(ES8388_REG_DAC_CTRL17, ES8388_BIT_LI2LO | ES8388_LI2LOVOL(ES8388_VOL_0DB)); |
||||
res &= writeReg(ES8388_REG_DAC_CTRL20, ES8388_BIT_RI2RO | ES8388_RI2ROVOL(ES8388_VOL_0DB)); |
||||
} |
||||
else |
||||
{ |
||||
res = writeReg(ES8388_REG_DAC_CTRL17, ES8388_BIT_LD2LO | ES8388_LI2LOVOL(ES8388_VOL_0DB)); |
||||
res &= writeReg(ES8388_REG_DAC_CTRL20, ES8388_BIT_RD2RO | ES8388_RI2ROVOL(ES8388_VOL_0DB)); |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
// bypassed the analog input to the output, disconnect the digital input, preserve the digital output connection
|
||||
bool AudioControlES8388_F32::analogSoftBypass(bool bypass) |
||||
{ |
||||
bool res = true; |
||||
if (bypass) |
||||
{ |
||||
res &= writeReg(ES8388_REG_DAC_CTRL17, ES8388_BIT_LI2LO | // Lin in on
|
||||
ES8388_BIT_LD2LO | // L Dac on
|
||||
ES8388_LI2LOVOL(ES8388_VOL_0DB)); // Lin gain 0dB
|
||||
res &= writeReg(ES8388_REG_DAC_CTRL20, ES8388_BIT_RI2RO | // Rin in on
|
||||
ES8388_BIT_RD2RO | // R Dac on
|
||||
ES8388_RI2ROVOL(ES8388_VOL_0DB)); // Rin gain 0dB
|
||||
} |
||||
else |
||||
{ |
||||
res = writeReg(ES8388_REG_DAC_CTRL17, ES8388_BIT_LD2LO | ES8388_LI2LOVOL(ES8388_VOL_0DB)); |
||||
res &= writeReg(ES8388_REG_DAC_CTRL20, ES8388_BIT_RD2RO | ES8388_RI2ROVOL(ES8388_VOL_0DB)); |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
bool AudioControlES8388_F32::writeReg(uint8_t addr, uint8_t val) |
||||
{ |
||||
ctrlBus->beginTransmission(i2cAddr); |
||||
ctrlBus->write(addr); |
||||
ctrlBus->write(val); |
||||
return ctrlBus->endTransmission() == 0; |
||||
} |
||||
bool AudioControlES8388_F32::readReg(uint8_t addr, uint8_t *valPtr) |
||||
{ |
||||
ctrlBus->beginTransmission(i2cAddr); |
||||
ctrlBus->write(addr); |
||||
if (ctrlBus->endTransmission(false) != 0) |
||||
return false;
|
||||
if (ctrlBus->requestFrom((int)i2cAddr, 1) < 1) return false; |
||||
*valPtr = ctrlBus->read(); |
||||
return true; |
||||
} |
||||
|
||||
uint8_t AudioControlES8388_F32::modifyReg(uint8_t reg, uint8_t val, uint8_t iMask) |
||||
{ |
||||
uint8_t val1; |
||||
val1 = (readReg(reg, &val1) & (~iMask)) | val; |
||||
if (!writeReg(reg, val1)) |
||||
return 0; |
||||
return val1; |
||||
} |
@ -0,0 +1,55 @@ |
||||
#ifndef _CONTROL_ES8388_F32_H_ |
||||
#define _CONTROL_ES8388_F32_H_ |
||||
|
||||
#include <Arduino.h> |
||||
#include <Wire.h> |
||||
#include "AudioControl.h" |
||||
|
||||
#define ES8388_I2C_ADDR_L (0x10) // CS/ADD pin low
|
||||
#define ES8388_I2C_ADDR_H (0x11) // CS/ADD pin high
|
||||
|
||||
class AudioControlES8388_F32 //: public AudioControl
|
||||
{ |
||||
public: |
||||
AudioControlES8388_F32(void){}; |
||||
~AudioControlES8388_F32(void){}; |
||||
typedef enum |
||||
{ |
||||
ES8388_CFG_LINEIN_SINGLE_ENDED = 0, |
||||
ES8388_CFG_LINEIN_DIFF, |
||||
}config_t;
|
||||
|
||||
|
||||
bool enable() |
||||
{ |
||||
return enable(&Wire, ES8388_I2C_ADDR_L, ES8388_CFG_LINEIN_SINGLE_ENDED); |
||||
} |
||||
bool enable(TwoWire *i2cBus, uint8_t addr, config_t cfg); |
||||
bool disable(void) { return false; } |
||||
bool volume(float n); |
||||
bool inputLevel(float n); // range: 0.0f to 1.0f
|
||||
|
||||
|
||||
void set_noiseGate(float thres); |
||||
|
||||
void volume(uint8_t vol); |
||||
uint8_t getOutVol(); |
||||
|
||||
bool setInGain(uint8_t gain); |
||||
uint8_t getInGain(); |
||||
|
||||
bool analogBypass(bool bypass); |
||||
bool analogSoftBypass(bool bypass); |
||||
private: |
||||
static bool configured; |
||||
TwoWire *ctrlBus; |
||||
uint8_t i2cAddr; |
||||
uint8_t dacGain; |
||||
|
||||
bool writeReg(uint8_t addr, uint8_t val); |
||||
bool readReg(uint8_t addr, uint8_t* valPtr); |
||||
uint8_t modifyReg(uint8_t reg, uint8_t val, uint8_t iMask); |
||||
void optimizeConversion(uint8_t range); |
||||
}; |
||||
|
||||
#endif // _CONTROL_ES8388_F32_H_
|
File diff suppressed because it is too large
Load Diff
@ -1,40 +1,123 @@ |
||||
#ifndef _CONTROL_SGTL5000_F32_H_ |
||||
#define _CONTROL_SGTL5000_F32_H_ |
||||
/* Audio Library for Teensy 3.X
|
||||
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com |
||||
* |
||||
* Development of this audio library was funded by PJRC.COM, LLC by sales of |
||||
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop |
||||
* open source software by purchasing Teensy or other PJRC products. |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
* of this software and associated documentation files (the "Software"), to deal |
||||
* in the Software without restriction, including without limitation the rights |
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
* copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice, development funding notice, and this permission |
||||
* notice shall be included in all copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
* THE SOFTWARE. |
||||
*/ |
||||
|
||||
/**
|
||||
* @file control_SGTL5000_ext.h |
||||
* @author Piotr Zapart
|
||||
* @brief enables the bit depth setting for the SGTL5000 codec chip |
||||
* @file control_SGTL5000_F32.h |
||||
* @author Piotr Zapart |
||||
* @brief enables the bit depth setting for the SGTL5000 codec chip + configurable Wire interface |
||||
* @version 0.1 |
||||
* @date 2024-03-20 |
||||
*
|
||||
* @copyright Copyright (c) 2024 www.hexefx.com |
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version. |
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. |
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>."
|
||||
*/ |
||||
|
||||
#include <Arduino.h> |
||||
#include <control_sgtl5000.h> |
||||
#include <Wire.h> |
||||
#include <AudioStream_F32.h> |
||||
#include "AudioControl.h" |
||||
|
||||
class AudioControlSGTL5000_F32 : public AudioControlSGTL5000 |
||||
|
||||
class AudioControlSGTL5000_F32 : public AudioControl |
||||
{ |
||||
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
|
||||
public: |
||||
AudioControlSGTL5000_F32(void) {}; |
||||
public: |
||||
AudioControlSGTL5000_F32(){}; |
||||
void setAddress(uint8_t gpioLevel); |
||||
bool enable(); |
||||
bool enable(TwoWire *i2cBus, uint8_t addr=0x0A, const uint32_t extMCLK=0, const uint32_t pllFreq = (4096.0l * AUDIO_SAMPLE_RATE_EXACT));
|
||||
bool disable(void) { return false; } |
||||
bool volume(float n) { return volumeInteger(n * 129 + 0.499f); } |
||||
bool inputLevel(float volume) {return false;} |
||||
bool muteHeadphone(void) { return write(0x0024, ana_ctrl | (1 << 4)); } |
||||
bool unmuteHeadphone(void) { return write(0x0024, ana_ctrl & ~(1 << 4)); } |
||||
bool muteLineout(void) { return write(0x0024, ana_ctrl | (1 << 8)); } |
||||
bool unmuteLineout(void) { return write(0x0024, ana_ctrl & ~(1 << 8)); } |
||||
bool inputSelect(int n); |
||||
bool headphoneSelect(int n); |
||||
|
||||
bool volume(float left, float right); |
||||
bool micGain(uint16_t dB); |
||||
bool lineInLevel(uint8_t n) { return lineInLevel(n, n); } |
||||
bool lineInLevel(uint8_t left, uint8_t right); |
||||
uint16_t lineOutLevel(uint8_t n); |
||||
uint16_t lineOutLevel(uint8_t left, uint8_t right); |
||||
uint16_t dacVolume(float n); |
||||
uint16_t dacVolume(float left, float right); |
||||
bool dacVolumeRamp(); |
||||
bool dacVolumeRampLinear(); |
||||
bool dacVolumeRampDisable(); |
||||
uint16_t adcHighPassFilterEnable(void); |
||||
uint16_t adcHighPassFilterFreeze(void); |
||||
uint16_t adcHighPassFilterDisable(void); |
||||
uint16_t audioPreProcessorEnable(void); |
||||
uint16_t audioPostProcessorEnable(void); |
||||
uint16_t audioProcessorDisable(void); |
||||
uint16_t eqFilterCount(uint8_t n); |
||||
uint16_t eqSelect(uint8_t n); |
||||
uint16_t eqBand(uint8_t bandNum, float n); |
||||
void eqBands(float bass, float mid_bass, float midrange, float mid_treble, float treble); |
||||
void eqBands(float bass, float treble); |
||||
void eqFilter(uint8_t filterNum, int *filterParameters); |
||||
uint16_t autoVolumeControl(uint8_t maxGain, uint8_t lbiResponse, uint8_t hardLimit, float threshold, float attack, float decay); |
||||
uint16_t autoVolumeEnable(void); |
||||
uint16_t autoVolumeDisable(void); |
||||
uint16_t enhanceBass(float lr_lev, float bass_lev); |
||||
uint16_t enhanceBass(float lr_lev, float bass_lev, uint8_t hpf_bypass, uint8_t cutoff); |
||||
uint16_t enhanceBassEnable(void); |
||||
uint16_t enhanceBassDisable(void); |
||||
uint16_t surroundSound(uint8_t width); |
||||
uint16_t surroundSound(uint8_t width, uint8_t select); |
||||
uint16_t surroundSoundEnable(void); |
||||
uint16_t surroundSoundDisable(void); |
||||
void killAutomation(void) { semi_automated = false; } |
||||
void setMasterMode(uint32_t freqMCLK_in); |
||||
typedef enum |
||||
{
|
||||
{ |
||||
I2S_BITS_32 = 0, |
||||
I2S_BITS_24, |
||||
I2S_BITS_20, |
||||
I2S_BITS_16 |
||||
}bit_depth_t; |
||||
|
||||
void set_bitDepth(bit_depth_t bits); |
||||
|
||||
protected: |
||||
bool muted; |
||||
bool volumeInteger(uint16_t n); // range: 0x00 to 0x80
|
||||
uint16_t ana_ctrl; |
||||
uint8_t i2c_addr; |
||||
unsigned char calcVol(float n, unsigned char range); |
||||
uint16_t read(uint16_t reg); |
||||
bool write(uint16_t reg, uint16_t val); |
||||
uint16_t modify(uint16_t reg, uint16_t val, uint16_t iMask); |
||||
uint16_t dap_audio_eq_band(uint8_t bandNum, float n); |
||||
|
||||
private: |
||||
bool semi_automated; |
||||
void automate(uint8_t dap, uint8_t eq); |
||||
void automate(uint8_t dap, uint8_t eq, uint8_t filterCount); |
||||
TwoWire *_wire; |
||||
}; |
||||
|
||||
#endif // _CONTROL_SGTL5000_EXT_H_
|
||||
#endif // _CONTROL_SGTL5000_F32_H_
|
||||
|
@ -0,0 +1,240 @@ |
||||
/*
|
||||
* input_i2s_f32.cpp |
||||
* |
||||
* Audio Library for Teensy 3.X |
||||
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com |
||||
* |
||||
* Development of this audio library was funded by PJRC.COM, LLC by sales of |
||||
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop |
||||
* open source software by purchasing Teensy or other PJRC products. |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
* of this software and associated documentation files (the "Software"), to deal |
||||
* in the Software without restriction, including without limitation the rights |
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
* copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice, development funding notice, and this permission |
||||
* notice shall be included in all copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
* THE SOFTWARE. |
||||
*/ |
||||
/*
|
||||
* Extended by Chip Audette, OpenAudio, May 2019 |
||||
* Converted to F32 and to variable audio block length |
||||
* The F32 conversion is under the MIT License. Use at your own risk. |
||||
*/ |
||||
// Updated OpenAudio F32 with this version from Chip Audette's Tympan Library Jan 2021 RSL
|
||||
// Removed unused pieces. RSL 30 May 2022
|
||||
|
||||
/*
|
||||
* Rewritten ny Piotr Zapart 04.2024: |
||||
* - made the 32bit mode default |
||||
* - new scale methods based on arm dsp library |
||||
* - For Teensy4.x only as Teensy3 is obsolete |
||||
*/ |
||||
|
||||
#include <Arduino.h> //do we really need this? (Chip: 2020-10-31) |
||||
#include "input_i2s_ext_F32.h" |
||||
#include "output_i2s_ext_F32.h" |
||||
#include "basic_DSPutils.h" |
||||
#include <arm_math.h> |
||||
|
||||
// DMAMEM __attribute__((aligned(32)))
|
||||
static uint64_t i2s_rx_buffer[AUDIO_BLOCK_SAMPLES]; // Two 32-bit transfers per sample.
|
||||
audio_block_f32_t *AudioInputI2S_ext_F32::block_left_f32 = NULL; |
||||
audio_block_f32_t *AudioInputI2S_ext_F32::block_right_f32 = NULL; |
||||
uint16_t AudioInputI2S_ext_F32::block_offset = 0; |
||||
bool AudioInputI2S_ext_F32::update_responsibility = false; |
||||
DMAChannel AudioInputI2S_ext_F32::dma(false); |
||||
|
||||
int AudioInputI2S_ext_F32::flag_out_of_memory = 0; |
||||
unsigned long AudioInputI2S_ext_F32::update_counter = 0; |
||||
|
||||
float AudioInputI2S_ext_F32::sample_rate_Hz = AUDIO_SAMPLE_RATE; |
||||
int AudioInputI2S_ext_F32::audio_block_samples = AUDIO_BLOCK_SAMPLES; |
||||
|
||||
#define I2S_BUFFER_TO_USE_BYTES (AudioOutputI2S_ext_F32::audio_block_samples * sizeof(i2s_rx_buffer[0])) |
||||
|
||||
|
||||
void AudioInputI2S_ext_F32::begin() |
||||
{ |
||||
dma.begin(true); // Allocate the DMA channel first
|
||||
|
||||
AudioOutputI2S_ext_F32::sample_rate_Hz = sample_rate_Hz; // these were given in the AudioSettings in the contructor
|
||||
AudioOutputI2S_ext_F32::audio_block_samples = audio_block_samples; // these were given in the AudioSettings in the contructor
|
||||
|
||||
// TODO: should we set & clear the I2S_RCSR_SR bit here?
|
||||
AudioOutputI2S_ext_F32::config_i2s(); |
||||
#if defined(__IMXRT1062__) |
||||
CORE_PIN8_CONFIG = 3; // 1:RX_DATA0
|
||||
IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2; |
||||
|
||||
dma.TCD->SADDR = (void *)((uint32_t)&I2S1_RDR0 + 0); |
||||
dma.TCD->SOFF = 0; |
||||
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); |
||||
dma.TCD->NBYTES_MLNO = 4; |
||||
dma.TCD->SLAST = 0; |
||||
dma.TCD->DADDR = i2s_rx_buffer; |
||||
dma.TCD->DOFF = 4; |
||||
dma.TCD->CITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4; |
||||
dma.TCD->DLASTSGA = -I2S_BUFFER_TO_USE_BYTES; |
||||
dma.TCD->BITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4; |
||||
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; |
||||
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_RX); |
||||
|
||||
I2S1_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR; |
||||
#endif |
||||
update_responsibility = update_setup(); |
||||
dma.enable(); |
||||
dma.attachInterrupt(isr); |
||||
|
||||
update_counter = 0; |
||||
} |
||||
|
||||
void AudioInputI2S_ext_F32::isr(void) |
||||
{ |
||||
uint32_t daddr, offset; |
||||
const int32_t *src, *end; |
||||
float32_t *dest_left_f32, *dest_right_f32; |
||||
audio_block_f32_t *left_f32, *right_f32; |
||||
|
||||
#if defined(__IMXRT1062__) |
||||
daddr = (uint32_t)(dma.TCD->DADDR); |
||||
#endif |
||||
dma.clearInterrupt(); |
||||
|
||||
if (daddr < (uint32_t)i2s_rx_buffer + I2S_BUFFER_TO_USE_BYTES / 2) |
||||
{ |
||||
// DMA is receiving to the first half of the buffer
|
||||
// need to remove data from the second half
|
||||
src = (int32_t *)&i2s_rx_buffer[audio_block_samples / 2]; |
||||
end = (int32_t *)&i2s_rx_buffer[audio_block_samples]; |
||||
update_counter++; // let's increment the counter here to ensure that we get every ISR resulting in audio
|
||||
if (AudioInputI2S_ext_F32::update_responsibility) |
||||
AudioStream_F32::update_all(); |
||||
} |
||||
else |
||||
{ |
||||
// DMA is receiving to the second half of the buffer
|
||||
// need to remove data from the first half
|
||||
src = (int32_t *)&i2s_rx_buffer[0]; |
||||
end = (int32_t *)&i2s_rx_buffer[audio_block_samples / 2]; |
||||
} |
||||
left_f32 = AudioInputI2S_ext_F32::block_left_f32; |
||||
right_f32 = AudioInputI2S_ext_F32::block_right_f32; |
||||
if (left_f32 != NULL && right_f32 != NULL) |
||||
{ |
||||
offset = AudioInputI2S_ext_F32::block_offset; |
||||
if (offset <= ((uint32_t)audio_block_samples / 2)) |
||||
{ |
||||
dest_left_f32 = &(left_f32->data[offset]); |
||||
dest_right_f32 = &(right_f32->data[offset]); |
||||
AudioInputI2S_ext_F32::block_offset = offset + audio_block_samples / 2; |
||||
do |
||||
{ |
||||
*dest_left_f32++ = (float32_t)*src++; |
||||
*dest_right_f32++ = (float32_t)*src++; |
||||
} while (src < end); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void AudioInputI2S_ext_F32::update_1chan(int chan, audio_block_f32_t *&out_f32) |
||||
{ |
||||
if (!out_f32) |
||||
return; |
||||
// scale the float values so that the maximum possible audio values span -1.0 to + 1.0
|
||||
arm_scale_f32(out_f32->data, I32_TO_F32_NORM_FACTOR, out_f32->data, audio_block_samples); |
||||
// prepare to transmit by setting the update_counter (which helps tell if data is skipped or out-of-order)
|
||||
out_f32->id = update_counter; |
||||
// transmit the f32 data!
|
||||
AudioStream_F32::transmit(out_f32, chan); |
||||
// release the memory blocks
|
||||
AudioStream_F32::release(out_f32); |
||||
} |
||||
|
||||
void AudioInputI2S_ext_F32::update(void) |
||||
{ |
||||
static bool flag_beenSuccessfullOnce = false; |
||||
audio_block_f32_t *new_left = NULL, *new_right = NULL, *out_left = NULL, *out_right = NULL; |
||||
|
||||
new_left = AudioStream_F32::allocate_f32(); |
||||
new_right = AudioStream_F32::allocate_f32(); |
||||
if ((!new_left) || (!new_right)) |
||||
{ |
||||
// ran out of memory. Clear and return!
|
||||
if (new_left) |
||||
AudioStream_F32::release(new_left); |
||||
if (new_right) |
||||
AudioStream_F32::release(new_right); |
||||
new_left = NULL; |
||||
new_right = NULL; |
||||
flag_out_of_memory = 1; |
||||
if (flag_beenSuccessfullOnce) |
||||
Serial.println("Input_I2S_F32: update(): WARNING!!! Out of Memory."); |
||||
} |
||||
else |
||||
{ |
||||
flag_beenSuccessfullOnce = true; |
||||
} |
||||
|
||||
__disable_irq(); |
||||
if (block_offset >= audio_block_samples) |
||||
{ |
||||
// the DMA filled 2 blocks, so grab them and get the
|
||||
// 2 new blocks to the DMA, as quickly as possible
|
||||
out_left = block_left_f32; |
||||
block_left_f32 = new_left; |
||||
out_right = block_right_f32; |
||||
block_right_f32 = new_right; |
||||
block_offset = 0; |
||||
__enable_irq(); |
||||
|
||||
// update_counter++; //I chose to update it in the ISR instead.
|
||||
update_1chan(0, out_left); // uses audio_block_samples and update_counter
|
||||
update_1chan(1, out_right); // uses audio_block_samples and update_counter
|
||||
} |
||||
else if (new_left != NULL) |
||||
{ |
||||
// the DMA didn't fill blocks, but we allocated blocks
|
||||
if (block_left_f32 == NULL) |
||||
{ |
||||
// the DMA doesn't have any blocks to fill, so
|
||||
// give it the ones we just allocated
|
||||
block_left_f32 = new_left; |
||||
block_right_f32 = new_right; |
||||
block_offset = 0; |
||||
__enable_irq(); |
||||
} |
||||
else |
||||
{ |
||||
// the DMA already has blocks, doesn't need these
|
||||
__enable_irq(); |
||||
AudioStream_F32::release(new_left); |
||||
AudioStream_F32::release(new_right); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
// The DMA didn't fill blocks, and we could not allocate
|
||||
// memory... the system is likely starving for memory!
|
||||
// Sadly, there's nothing we can do.
|
||||
__enable_irq(); |
||||
} |
||||
} |
||||
|
||||
/******************************************************************/ |
||||
|
||||
void AudioInputI2Sslave_ext_F32::begin(void) |
||||
{ |
||||
dma.begin(true); // Allocate the DMA channel first
|
||||
AudioOutputI2Sslave_ext_F32::config_i2s(); |
||||
} |
@ -0,0 +1,87 @@ |
||||
/*
|
||||
* ***** input_i2s_f32.h ****** |
||||
* |
||||
* Audio Library for Teensy 3.X |
||||
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com |
||||
* |
||||
* Development of this audio library was funded by PJRC.COM, LLC by sales of |
||||
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop |
||||
* open source software by purchasing Teensy or other PJRC products. |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
* of this software and associated documentation files (the "Software"), to deal |
||||
* in the Software without restriction, including without limitation the rights |
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
* copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice, development funding notice, and this permission |
||||
* notice shall be included in all copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
* THE SOFTWARE. |
||||
*/ |
||||
/*
|
||||
* Extended by Chip Audette, OpenAudio, May 2019 |
||||
* Converted to F32 and to variable audio block length |
||||
* The F32 conversion is under the MIT License. Use at your own risk. |
||||
*/ |
||||
// Updated OpenAudio F32 with this version from Chip Audette's Tympan Library Jan 2021 RSL
|
||||
// Removed unused pieces. RSL 30 May 2022
|
||||
|
||||
#ifndef _input_i2s_ext_f32_h_ |
||||
#define _input_i2s_ext_f32_h_ |
||||
|
||||
#include <Arduino.h> |
||||
#include <arm_math.h> |
||||
#include "AudioStream_F32.h" |
||||
#include "DMAChannel.h" |
||||
|
||||
class AudioInputI2S_ext_F32 : public AudioStream_F32 |
||||
{ |
||||
// GUI: inputs:0, outputs:2 //this line used for automatic generation of GUI nodes
|
||||
public: |
||||
AudioInputI2S_ext_F32(void) : AudioStream_F32(0, NULL) { begin(); } // uses default AUDIO_SAMPLE_RATE and BLOCK_SIZE_SAMPLES from AudioStream.h
|
||||
AudioInputI2S_ext_F32(const AudioSettings_F32 &settings) : AudioStream_F32(0, NULL) |
||||
{ |
||||
sample_rate_Hz = settings.sample_rate_Hz; |
||||
audio_block_samples = settings.audio_block_samples; |
||||
begin(); |
||||
} |
||||
|
||||
virtual void update(void); |
||||
void begin(void); |
||||
int get_isOutOfMemory(void) { return flag_out_of_memory; } |
||||
void clear_isOutOfMemory(void) { flag_out_of_memory = 0; } |
||||
|
||||
protected: |
||||
AudioInputI2S_ext_F32(int dummy) : AudioStream_F32(0, NULL) {} // to be used only inside AudioInputI2Sslave !!
|
||||
static bool update_responsibility; |
||||
static DMAChannel dma; |
||||
static void isr(void); |
||||
virtual void update_1chan(int, audio_block_f32_t *&); |
||||
|
||||
private: |
||||
static audio_block_f32_t *block_left_f32; |
||||
static audio_block_f32_t *block_right_f32; |
||||
static float sample_rate_Hz; |
||||
static int audio_block_samples; |
||||
static uint16_t block_offset; |
||||
static int flag_out_of_memory; |
||||
static unsigned long update_counter; |
||||
static bool msbFirstMode; // some codecs like the new AKM series (AK4558) use MSB exclusively
|
||||
}; |
||||
|
||||
class AudioInputI2Sslave_ext_F32 : public AudioInputI2S_ext_F32 |
||||
{ |
||||
public: |
||||
AudioInputI2Sslave_ext_F32(void) : AudioInputI2S_ext_F32(0) { begin(); } |
||||
void begin(void); |
||||
friend void dma_ch1_isr(void); |
||||
}; |
||||
#endif |
@ -0,0 +1,432 @@ |
||||
/*
|
||||
* ***** output_i2s_f32.cpp ***** |
||||
* |
||||
* Audio Library for Teensy 3.X |
||||
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com |
||||
* |
||||
* Development of this audio library was funded by PJRC.COM, LLC by sales of |
||||
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop |
||||
* open source software by purchasing Teensy or other PJRC products. |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
* of this software and associated documentation files (the "Software"), to deal |
||||
* in the Software without restriction, including without limitation the rights |
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
* copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice, development funding notice, and this permission |
||||
* notice shall be included in all copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
* THE SOFTWARE. |
||||
*/ |
||||
/*
|
||||
* Extended by Chip Audette, OpenAudio, May 2019 |
||||
* Converted to F32 and to variable audio block length |
||||
* The F32 conversion is under the MIT License. Use at your own risk. |
||||
*/ |
||||
// Updated OpenAudio F32 with this version from Chip Audette's Tympan Library Jan 2021 RSL
|
||||
// Removed old commented out code. RSL 30 May 2022
|
||||
|
||||
#include "output_i2s_ext_F32.h" |
||||
#include "basic_DSPutils.h" |
||||
#include <arm_math.h> |
||||
#include <Audio.h> //to get access to Audio/utlity/imxrt_hw.h...do we really need this??? WEA 2020-10-31 |
||||
|
||||
audio_block_f32_t *AudioOutputI2S_ext_F32::block_left_1st = NULL; |
||||
audio_block_f32_t *AudioOutputI2S_ext_F32::block_right_1st = NULL; |
||||
audio_block_f32_t *AudioOutputI2S_ext_F32::block_left_2nd = NULL; |
||||
audio_block_f32_t *AudioOutputI2S_ext_F32::block_right_2nd = NULL; |
||||
uint16_t AudioOutputI2S_ext_F32::block_left_offset = 0; |
||||
uint16_t AudioOutputI2S_ext_F32::block_right_offset = 0; |
||||
bool AudioOutputI2S_ext_F32::update_responsibility = false; |
||||
DMAChannel AudioOutputI2S_ext_F32::dma(false); |
||||
DMAMEM __attribute__((aligned(32))) static uint64_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES]; |
||||
|
||||
float AudioOutputI2S_ext_F32::sample_rate_Hz = AUDIO_SAMPLE_RATE; |
||||
int AudioOutputI2S_ext_F32::audio_block_samples = AUDIO_BLOCK_SAMPLES; |
||||
|
||||
#if defined(__IMXRT1062__) |
||||
#include <utility/imxrt_hw.h> //from Teensy Audio library. For set_audioClock() |
||||
#endif |
||||
|
||||
#define I2S_BUFFER_TO_USE_BYTES (AudioOutputI2S_ext_F32::audio_block_samples * sizeof(i2s_tx_buffer[0])) |
||||
|
||||
|
||||
void AudioOutputI2S_ext_F32::begin() |
||||
{ |
||||
|
||||
dma.begin(true); // Allocate the DMA channel first
|
||||
|
||||
block_left_1st = NULL; |
||||
block_right_1st = NULL; |
||||
|
||||
AudioOutputI2S_ext_F32::config_i2s(sample_rate_Hz); |
||||
|
||||
#if defined(__IMXRT1062__) |
||||
CORE_PIN7_CONFIG = 3; // 1:TX_DATA0
|
||||
dma.TCD->SADDR = i2s_tx_buffer; |
||||
dma.TCD->SOFF = 4; |
||||
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); |
||||
dma.TCD->NBYTES_MLNO = 4; |
||||
dma.TCD->SLAST = -I2S_BUFFER_TO_USE_BYTES; |
||||
dma.TCD->DOFF = 0; |
||||
dma.TCD->CITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4; |
||||
dma.TCD->DLASTSGA = 0; |
||||
dma.TCD->BITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4; |
||||
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; |
||||
dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR0 + 0); |
||||
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX); |
||||
dma.enable(); // newer location of this line in Teensy Audio library
|
||||
I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE; |
||||
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE; |
||||
#endif |
||||
update_responsibility = update_setup(); |
||||
dma.attachInterrupt(AudioOutputI2S_ext_F32::isr); |
||||
enabled = 1; |
||||
} |
||||
|
||||
void AudioOutputI2S_ext_F32::isr(void) |
||||
{ |
||||
#if defined(__IMXRT1062__) |
||||
int32_t *dest; |
||||
audio_block_f32_t *blockL, *blockR; |
||||
uint32_t saddr, offsetL, offsetR; |
||||
|
||||
saddr = (uint32_t)(dma.TCD->SADDR); |
||||
dma.clearInterrupt(); |
||||
if (saddr < (uint32_t)i2s_tx_buffer + I2S_BUFFER_TO_USE_BYTES / 2) |
||||
{ // are we transmitting the first half or second half of the buffer?
|
||||
// DMA is transmitting the first half of the buffer
|
||||
// so we must fill the second half
|
||||
dest = (int32_t *)&i2s_tx_buffer[audio_block_samples / 2]; |
||||
if (AudioOutputI2S_ext_F32::update_responsibility) |
||||
AudioStream_F32::update_all(); |
||||
} |
||||
else |
||||
{ |
||||
// DMA is transmitting the second half of the buffer
|
||||
// so we must fill the first half
|
||||
dest = (int32_t *)i2s_tx_buffer; |
||||
} |
||||
|
||||
blockL = AudioOutputI2S_ext_F32::block_left_1st; |
||||
blockR = AudioOutputI2S_ext_F32::block_right_1st; |
||||
offsetL = AudioOutputI2S_ext_F32::block_left_offset; |
||||
offsetR = AudioOutputI2S_ext_F32::block_right_offset; |
||||
|
||||
int32_t *d = dest; |
||||
if (blockL && blockR) |
||||
{ |
||||
float32_t *pL = blockL->data + offsetL; |
||||
float32_t *pR = blockR->data + offsetR; |
||||
for (int i = 0; i < audio_block_samples / 2; i++) |
||||
{ |
||||
*d++ = (int32_t)*pL++; |
||||
*d++ = (int32_t)*pR++; // interleave
|
||||
} |
||||
offsetL += audio_block_samples / 2; |
||||
offsetR += audio_block_samples / 2; |
||||
} |
||||
else if (blockL) |
||||
{ |
||||
float32_t *pL = blockL->data + offsetL; |
||||
for (int i = 0; i < audio_block_samples / 2 * 2; i += 2) |
||||
{ |
||||
*(d + i) = (int32_t)*pL++; |
||||
} // interleave
|
||||
offsetL += audio_block_samples / 2; |
||||
} |
||||
else if (blockR) |
||||
{ |
||||
float32_t *pR = blockR->data + offsetR; |
||||
for (int i = 0; i < audio_block_samples / 2 * 2; i += 2) |
||||
{ |
||||
*(d + i) = (int32_t)*pR++; |
||||
} // interleave
|
||||
offsetR += audio_block_samples / 2; |
||||
} |
||||
else |
||||
{ |
||||
memset(dest, 0, audio_block_samples * 4); |
||||
return; |
||||
} |
||||
|
||||
arm_dcache_flush_delete(dest, sizeof(i2s_tx_buffer) / 2); |
||||
|
||||
if (offsetL < (uint16_t)audio_block_samples) |
||||
{ |
||||
AudioOutputI2S_ext_F32::block_left_offset = offsetL; |
||||
} |
||||
else |
||||
{ |
||||
AudioOutputI2S_ext_F32::block_left_offset = 0; |
||||
AudioStream_F32::release(blockL); |
||||
AudioOutputI2S_ext_F32::block_left_1st = AudioOutputI2S_ext_F32::block_left_2nd; |
||||
AudioOutputI2S_ext_F32::block_left_2nd = NULL; |
||||
} |
||||
if (offsetR < (uint16_t)audio_block_samples) |
||||
{ |
||||
AudioOutputI2S_ext_F32::block_right_offset = offsetR; |
||||
} |
||||
else |
||||
{ |
||||
AudioOutputI2S_ext_F32::block_right_offset = 0; |
||||
AudioStream_F32::release(blockR); |
||||
AudioOutputI2S_ext_F32::block_right_1st = AudioOutputI2S_ext_F32::block_right_2nd; |
||||
AudioOutputI2S_ext_F32::block_right_2nd = NULL; |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
// update has to be carefully coded so that, if audio_blocks are not available, the code exits
|
||||
// gracefully and won't hang. That'll cause the whole system to hang, which would be very bad.
|
||||
// static int count = 0;
|
||||
void AudioOutputI2S_ext_F32::update(void) |
||||
{ |
||||
audio_block_f32_t *block_f32; |
||||
audio_block_f32_t *block_f32_scaled = AudioStream_F32::allocate_f32(); |
||||
audio_block_f32_t *block2_f32_scaled = AudioStream_F32::allocate_f32(); |
||||
if ((!block_f32_scaled) || (!block2_f32_scaled)) |
||||
{ |
||||
// couldn't get some working memory. Return.
|
||||
if (block_f32_scaled) |
||||
AudioStream_F32::release(block_f32_scaled); |
||||
if (block2_f32_scaled) |
||||
AudioStream_F32::release(block2_f32_scaled); |
||||
return; |
||||
} |
||||
// now that we have our working memory, proceed with getting the audio data and processing
|
||||
block_f32 = receiveReadOnly_f32(0); // input 0 = left channel
|
||||
if (block_f32) |
||||
{ |
||||
if (block_f32->length != audio_block_samples) |
||||
{ |
||||
Serial.print("AudioOutputI2S_ext_F32: *** WARNING ***: audio_block says len = "); |
||||
Serial.print(block_f32->length); |
||||
Serial.print(", but I2S settings want it to be = "); |
||||
Serial.println(audio_block_samples); |
||||
} |
||||
// Optional scaling for easy volume control. Leave outputScale==1.0f for default
|
||||
if (outputScale < 1.0f || outputScale > 1.0f) |
||||
arm_scale_f32(block_f32->data, outputScale, block_f32->data, block_f32->length); |
||||
|
||||
scale_float_to_int32range(block_f32->data, block_f32_scaled->data, audio_block_samples); |
||||
// now process the data blocks
|
||||
__disable_irq(); |
||||
if (block_left_1st == NULL) |
||||
{ |
||||
block_left_1st = block_f32_scaled; |
||||
block_left_offset = 0; |
||||
__enable_irq(); |
||||
} |
||||
else if (block_left_2nd == NULL) |
||||
{ |
||||
block_left_2nd = block_f32_scaled; |
||||
__enable_irq(); |
||||
} |
||||
else |
||||
{ |
||||
audio_block_f32_t *tmp = block_left_1st; |
||||
block_left_1st = block_left_2nd; |
||||
block_left_2nd = block_f32_scaled; |
||||
block_left_offset = 0; |
||||
__enable_irq(); |
||||
AudioStream_F32::release(tmp); |
||||
} |
||||
AudioStream_F32::transmit(block_f32, 0); |
||||
AudioStream_F32::release(block_f32); // echo the incoming audio out the outputs
|
||||
} |
||||
else |
||||
{ |
||||
// this branch should never get called, but if it does, let's release the buffer that was never used
|
||||
AudioStream_F32::release(block_f32_scaled); |
||||
} |
||||
|
||||
block_f32_scaled = block2_f32_scaled; // this is simply renaming the pre-allocated buffer
|
||||
|
||||
block_f32 = receiveReadOnly_f32(1); // input 1 = right channel
|
||||
if (block_f32) |
||||
{ |
||||
// Optional scaling for easy volume control. Leave outputScale==1.0f for default
|
||||
if (outputScale < 1.0f || outputScale > 1.0f) |
||||
arm_scale_f32(block_f32->data, outputScale, block_f32->data, block_f32->length); |
||||
// scale F32 to Int32
|
||||
scale_float_to_int32range(block_f32->data, block_f32_scaled->data, audio_block_samples); |
||||
__disable_irq(); |
||||
if (block_right_1st == NULL) |
||||
{ |
||||
block_right_1st = block_f32_scaled; |
||||
block_right_offset = 0; |
||||
__enable_irq(); |
||||
} |
||||
else if (block_right_2nd == NULL) |
||||
{ |
||||
block_right_2nd = block_f32_scaled; |
||||
__enable_irq(); |
||||
} |
||||
else |
||||
{ |
||||
audio_block_f32_t *tmp = block_right_1st; |
||||
block_right_1st = block_right_2nd; |
||||
block_right_2nd = block_f32_scaled; |
||||
block_right_offset = 0; |
||||
__enable_irq(); |
||||
AudioStream_F32::release(tmp); |
||||
} |
||||
AudioStream_F32::transmit(block_f32, 1); |
||||
AudioStream_F32::release(block_f32); // echo the incoming audio out the outputs
|
||||
} |
||||
else |
||||
{ |
||||
// this branch should never get called, but if it does, let's release the buffer that was never used
|
||||
AudioStream_F32::release(block_f32_scaled); |
||||
} |
||||
} |
||||
|
||||
void AudioOutputI2S_ext_F32::config_i2s(void) { config_i2s(AudioOutputI2S_ext_F32::sample_rate_Hz); } |
||||
void AudioOutputI2S_ext_F32::config_i2s(float fs_Hz) |
||||
{ |
||||
#if defined(__IMXRT1062__) |
||||
CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON); |
||||
|
||||
// if either transmitter or receiver is enabled, do nothing
|
||||
if (I2S1_TCSR & I2S_TCSR_TE) |
||||
return; |
||||
if (I2S1_RCSR & I2S_RCSR_RE) |
||||
return; |
||||
// PLL:
|
||||
int fs = fs_Hz; |
||||
|
||||
// PLL between 27*24 = 648MHz und 54*24=1296MHz
|
||||
int n1 = 4; // SAI prescaler 4 => (n1*n2) = multiple of 4
|
||||
int n2 = 1 + (24000000 * 27) / (fs * 256 * n1); |
||||
|
||||
double C = ((double)fs * 256 * n1 * n2) / 24000000; |
||||
int c0 = C; |
||||
int c2 = 10000; |
||||
int c1 = C * c2 - (c0 * c2); |
||||
set_audioClock(c0, c1, c2); |
||||
|
||||
// clear SAI1_CLK register locations
|
||||
CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK)) | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4
|
||||
CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK)) | CCM_CS1CDR_SAI1_CLK_PRED(n1 - 1) // &0x07
|
||||
| CCM_CS1CDR_SAI1_CLK_PODF(n2 - 1); // &0x3f
|
||||
|
||||
// Select MCLK
|
||||
IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK)) | (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0)); |
||||
|
||||
CORE_PIN23_CONFIG = 3; // 1:MCLK
|
||||
CORE_PIN21_CONFIG = 3; // 1:RX_BCLK
|
||||
CORE_PIN20_CONFIG = 3; // 1:RX_SYNC
|
||||
|
||||
int rsync = 0; |
||||
int tsync = 1; |
||||
|
||||
I2S1_TMR = 0; |
||||
|
||||
I2S1_TCR1 = I2S_TCR1_RFW(1); |
||||
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP // sync=0; tx is async;
|
||||
| (I2S_TCR2_BCD | I2S_TCR2_DIV((1)) | I2S_TCR2_MSEL(1)); |
||||
I2S1_TCR3 = I2S_TCR3_TCE; |
||||
|
||||
I2S1_TCR4 = I2S_TCR4_FRSZ((2 - 1)) | I2S_TCR4_SYWD((32 - 1)) | I2S_TCR4_MF | I2S_TCR4_FSD | I2S_TCR4_FSE | I2S_TCR4_FSP; |
||||
I2S1_TCR5 = I2S_TCR5_WNW((32 - 1)) | I2S_TCR5_W0W((32 - 1)) | I2S_TCR5_FBT((32 - 1)); |
||||
|
||||
I2S1_RMR = 0; |
||||
|
||||
I2S1_RCR1 = I2S_RCR1_RFW(1); |
||||
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP // sync=0; rx is async;
|
||||
| (I2S_RCR2_BCD | I2S_RCR2_DIV((1)) | I2S_RCR2_MSEL(1)); |
||||
I2S1_RCR3 = I2S_RCR3_RCE; |
||||
I2S1_RCR4 = I2S_RCR4_FRSZ((2 - 1)) | I2S_RCR4_SYWD((32 - 1)) | I2S_RCR4_MF | I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD; |
||||
I2S1_RCR5 = I2S_RCR5_WNW((32 - 1)) | I2S_RCR5_W0W((32 - 1)) | I2S_RCR5_FBT((32 - 1)); |
||||
|
||||
#endif |
||||
} |
||||
|
||||
/******************************************************************/ |
||||
|
||||
// From Chip: The I2SSlave functionality has NOT been extended to
|
||||
// allow for different block sizes or sample rates (2020-10-31)
|
||||
|
||||
void AudioOutputI2Sslave_ext_F32::begin(void) |
||||
{ |
||||
dma.begin(true); // Allocate the DMA channel first
|
||||
|
||||
// pinMode(2, OUTPUT);
|
||||
block_left_1st = NULL; |
||||
block_right_1st = NULL; |
||||
|
||||
AudioOutputI2Sslave_ext_F32::config_i2s(); |
||||
#if defined(__IMXRT1062__) |
||||
CORE_PIN7_CONFIG = 3; // 1:TX_DATA0
|
||||
dma.TCD->SADDR = i2s_tx_buffer; |
||||
dma.TCD->SOFF = 2; |
||||
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); |
||||
dma.TCD->NBYTES_MLNO = 2; |
||||
dma.TCD->SLAST = -sizeof(i2s_tx_buffer); |
||||
// dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR1 + 2);
|
||||
dma.TCD->DOFF = 0; |
||||
dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; |
||||
dma.TCD->DLASTSGA = 0; |
||||
dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; |
||||
// dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI2_TX);
|
||||
dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR0 + 2); |
||||
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; |
||||
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX); |
||||
dma.enable(); |
||||
|
||||
I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE; |
||||
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE; |
||||
|
||||
#endif |
||||
|
||||
update_responsibility = update_setup(); |
||||
// dma.enable();
|
||||
dma.attachInterrupt(AudioOutputI2S_ext_F32::isr); |
||||
} |
||||
|
||||
void AudioOutputI2Sslave_ext_F32::config_i2s(void) |
||||
{ |
||||
#if defined(__IMXRT1062__) |
||||
|
||||
CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON); |
||||
|
||||
// if either transmitter or receiver is enabled, do nothing
|
||||
if (I2S1_TCSR & I2S_TCSR_TE) |
||||
return; |
||||
if (I2S1_RCSR & I2S_RCSR_RE) |
||||
return; |
||||
|
||||
// not using MCLK in slave mode - hope that's ok?
|
||||
// CORE_PIN23_CONFIG = 3; // AD_B1_09 ALT3=SAI1_MCLK
|
||||
CORE_PIN21_CONFIG = 3; // AD_B1_11 ALT3=SAI1_RX_BCLK
|
||||
CORE_PIN20_CONFIG = 3; // AD_B1_10 ALT3=SAI1_RX_SYNC
|
||||
IOMUXC_SAI1_RX_BCLK_SELECT_INPUT = 1; // 1=GPIO_AD_B1_11_ALT3, page 868
|
||||
IOMUXC_SAI1_RX_SYNC_SELECT_INPUT = 1; // 1=GPIO_AD_B1_10_ALT3, page 872
|
||||
|
||||
// configure transmitter
|
||||
I2S1_TMR = 0; |
||||
I2S1_TCR1 = I2S_TCR1_RFW(1); // watermark at half fifo size
|
||||
I2S1_TCR2 = I2S_TCR2_SYNC(1) | I2S_TCR2_BCP; |
||||
I2S1_TCR3 = I2S_TCR3_TCE; |
||||
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(31) | I2S_TCR4_MF | I2S_TCR4_FSE | I2S_TCR4_FSP | I2S_RCR4_FSD; |
||||
I2S1_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31); |
||||
|
||||
// configure receiver
|
||||
I2S1_RMR = 0; |
||||
I2S1_RCR1 = I2S_RCR1_RFW(1); |
||||
I2S1_RCR2 = I2S_RCR2_SYNC(0) | I2S_TCR2_BCP; |
||||
I2S1_RCR3 = I2S_RCR3_RCE; |
||||
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(31) | I2S_RCR4_MF | I2S_RCR4_FSE | I2S_RCR4_FSP; |
||||
I2S1_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31); |
||||
|
||||
#endif |
||||
} |
@ -0,0 +1,99 @@ |
||||
/*
|
||||
* ***** output_i2s_f32.h ***** |
||||
* |
||||
* Audio Library for Teensy 3.X |
||||
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com |
||||
* |
||||
* Development of this audio library was funded by PJRC.COM, LLC by sales of |
||||
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop |
||||
* open source software by purchasing Teensy or other PJRC products. |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
* of this software and associated documentation files (the "Software"), to deal |
||||
* in the Software without restriction, including without limitation the rights |
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
* copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice, development funding notice, and this permission |
||||
* notice shall be included in all copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
* THE SOFTWARE. |
||||
*/ |
||||
/*
|
||||
* Extended by Chip Audette, OpenAudio, May 2019 |
||||
* Converted to F32 and to variable audio block length |
||||
* The F32 conversion is under the MIT License. Use at your own risk. |
||||
*/ |
||||
// Updated OpenAudio F32 with this version from Chip Audette's Tympan Library Jan 2021 RSL
|
||||
// Removed old commented out code. RSL 30 May 2022
|
||||
|
||||
#ifndef output_i2s_ext_f32_h_ |
||||
#define output_i2s_ext_f32_h_ |
||||
|
||||
#include <Arduino.h> |
||||
#include <arm_math.h> |
||||
#include "AudioStream_F32.h" |
||||
#include "DMAChannel.h" |
||||
|
||||
class AudioOutputI2S_ext_F32 : public AudioStream_F32 |
||||
{ |
||||
//GUI: inputs:2, outputs:0 //this line used for automatic generation of GUI node
|
||||
public: |
||||
//uses default AUDIO_SAMPLE_RATE and BLOCK_SIZE_SAMPLES from AudioStream.h:
|
||||
AudioOutputI2S_ext_F32(void) : AudioStream_F32(2, inputQueueArray) { begin();} |
||||
// Allow variable sample rate and block size:
|
||||
AudioOutputI2S_ext_F32(const AudioSettings_F32 &settings) : AudioStream_F32(2, inputQueueArray) |
||||
{ |
||||
sample_rate_Hz = settings.sample_rate_Hz; |
||||
audio_block_samples = settings.audio_block_samples; |
||||
begin(); |
||||
} |
||||
// outputScale is a gain control for both left and right. If set exactly
|
||||
// to 1.0f it is left as a pass-through.
|
||||
void setGain(float _oscale) {outputScale = _oscale; } |
||||
virtual void update(void); |
||||
void begin(void); |
||||
friend class AudioInputI2S_ext_F32; |
||||
#if defined(__IMXRT1062__) |
||||
friend class AudioOutputI2SQuad_F32; |
||||
friend class AudioInputI2SQuad_F32; |
||||
#endif |
||||
protected: |
||||
AudioOutputI2S_ext_F32(int dummy): AudioStream_F32(2, inputQueueArray) {} // to be used only inside AudioOutputI2Sslave !!
|
||||
static void config_i2s(void); |
||||
static void config_i2s(float); |
||||
static audio_block_f32_t *block_left_1st; |
||||
static audio_block_f32_t *block_right_1st; |
||||
static bool update_responsibility; |
||||
static DMAChannel dma; |
||||
static void isr(void); |
||||
private: |
||||
static audio_block_f32_t *block_left_2nd; |
||||
static audio_block_f32_t *block_right_2nd; |
||||
static uint16_t block_left_offset; |
||||
static uint16_t block_right_offset; |
||||
audio_block_f32_t *inputQueueArray[2]; |
||||
static float sample_rate_Hz; |
||||
static int audio_block_samples; |
||||
volatile uint8_t enabled = 1; |
||||
float outputScale = 1.0f; // Quick volume control
|
||||
}; |
||||
|
||||
class AudioOutputI2Sslave_ext_F32 : public AudioOutputI2S_ext_F32 |
||||
{ |
||||
public: |
||||
AudioOutputI2Sslave_ext_F32(void) : AudioOutputI2S_ext_F32(0) { begin(); } ; |
||||
void begin(void); |
||||
friend class AudioInputI2Sslave_ext_F32; |
||||
friend void dma_ch0_isr(void); |
||||
protected: |
||||
static void config_i2s(void); |
||||
}; |
||||
#endif |
Loading…
Reference in new issue