This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TLV320ADC6140: Signal Loss on Rapid PGA Gain Change

Part Number: TLV320ADC6140

Tool/software:

TLV320ADC6140 is configured to receive PGA gain change settings from a host over I2C based on user settings with a Microphone preamp. This is required when a very low output mic requires slightly more gain that the external pre-amp can't provide.

A differential pre-amp filter with 22uF capacitive coupling drives either IN1+/- or IN2+/- with up to two XLR inputs to the system.

Other settings: DRE/AGC disabled, I2S-slave/24-bit with single data output pin, input impedance = 2.5k, Vref quick charge = 3.5ms, In-cap quick charge = 2.5ms, Vref=2.75V

The routine for changing PGA gain is as follows: reset the ADC via PWR_CFG.ADC_PDZ = 0, change the appropriate PGA register CHx_CFG1 (limited to 0d42), then re-enable the ADC via PWR_CFG.ADC_PDZ = 1.

It takes some time of rapidly changing the gain at ~10ms up and down, but eventually the signal to the host is lost on one or both inputs (its random). Signal loss means the serializer no longer sends the expected PCM data (eg. can no longer step the signal level at the input into overdrive and observe the sign-bit moving up).

I can confirm that I2S and I2C is still functioning as expected (PGA values read back correctly), and signal is still present at IN1+/- or IN2+/- with a DC bias offset (~1.5V).

Is there a delay required with ADC_PDZ = 1 when setting PGA gain? Do i need to monitor CHx status as part of the PGA gain change process? Am I doing something else wrong?

  • Hi Marcus,

    When you see the loss is signal, can you also read the status registers and interrupt registers?

    Thanks and Regards,

    Lakshmi Narasimhan

  • Yes, I can still read and write registers

  • Hi Marcus.

    Sorry for the confusion, I meant can you share the readback values of the device status registers when this issue occurs:

    ASI_STS = Page0, register 0x15

    DEV_STS0/STS1 = Page0, registers 0x76 and 0x77

    Thanks and regards,

    Lakshmi Narasimhan

  • ASI_STS = 0x44

    DEV_STS0 = 0xc0

    DEV_STS1 = 0xe0

    These values are consistent before/ not in the bug state and after/ in the bug state with signal loss.

  • Adding a scope trace of one failure mode: CH1 = FSYNC input, CH2 = SDOUT.

    SDOUT is actually not changing at all, it appears to be stuck on a PCM word for both left and right and never changes. I've seen this on both words, and sometimes on only one word (where the other is still changing as expected).

  • Hi Marcus,

    Lakshmi is out of office today. He will follow up with you tomorrow.

    Thanks,
    Jeff McPherson

  • Hi Marcus,

    Can you share the complete configuration script used to configure the device at powerup?

    Based on the scope shot, the device is operating at 44.1kHz sampling rate, is that correct?

    Thanks and Regards,

    Lakshmi Narasimhan

  • Yes, the device is running at 44.1k. See attached script.

    //Load up the ADC's (RAM) register values:
    	((ADC6140_REG_P0_SLEEP_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_SLEEP_CFG])->bits.AREG_SELECT = 1;//use internal AREG
    	((ADC6140_REG_P0_SLEEP_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_SLEEP_CFG])->bits.VREF_QCHG = 0;//VREF quick-charge duration = 3.5ms
    	((ADC6140_REG_P0_ASI_CFG0_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_ASI_CFG0])->bits.FORMAT = 1;//I2S
    	((ADC6140_REG_P0_ASI_CFG0_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_ASI_CFG0])->bits.WLEN = 3;//32-bit
    	((ADC6140_REG_P0_SHDN_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_SHDN_CFG])->bits.INCAP_QCHG = 0;//INCAP quick-charge duration = 2.5ms
    
    	//Setting for XLR1 (CH1) + XLR2 (CH2):
    	//Place Channel-1 on I2S left slot-0 (but ASI_OUT_CH1_EN is disabled until selected):
    	((ADC6140_REG_P0_ASI_CH1_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_ASI_CH1])->bits.CH1_SLOT = 0;
    	//Place Channel-2 on I2S right slot-0 (but ASI_OUT_CH2_EN is disabled until selected):
    	((ADC6140_REG_P0_ASI_CH2_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_ASI_CH2])->bits.CH2_SLOT = 32;
    	//Place Channel-3 on I2S left slot-0 (but ASI_OUT_CH3_EN is disabled until selected):
    	((ADC6140_REG_P0_ASI_CH3_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_ASI_CH3])->bits.CH3_SLOT = 0;
    	//Place Channel-4 on I2S right slot-0 (but ASI_OUT_CH4_EN is disabled until selected):
    	((ADC6140_REG_P0_ASI_CH4_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_ASI_CH4])->bits.CH4_SLOT = 32;
    	//Disable ADC input channels 1-4 initially:
    	((ADC6140_REG_P0_IN_CH_EN_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_IN_CH_EN])->bits.IN_CH1_EN = 0;
    	((ADC6140_REG_P0_IN_CH_EN_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_IN_CH_EN])->bits.IN_CH2_EN = 0;
    	((ADC6140_REG_P0_IN_CH_EN_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_IN_CH_EN])->bits.IN_CH3_EN = 0;
    	((ADC6140_REG_P0_IN_CH_EN_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_IN_CH_EN])->bits.IN_CH4_EN = 0;
    
    	//Enable ADC, MICBIAS, and PLL:
    	((ADC6140_REG_P0_PWR_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG])->bits.MICBIAS_PDZ = 1;
    	((ADC6140_REG_P0_PWR_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG])->bits.ADC_PDZ = 1;
    	((ADC6140_REG_P0_PWR_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG])->bits.PLL_PDZ = 1;
    	
    	//Enable Dynamic channel power-up/down for CH1-4:
    	((ADC6140_REG_P0_PWR_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG])->bits.DYN_CH_PUPD_EN = 1;
    	((ADC6140_REG_P0_PWR_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG])->bits.DYN_MAXCH_SEL = 1;
    
    	//Configure CH1-4 as Line inputs:
    	((ADC6140_REG_P0_CH1_CFG0_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH1_CFG0])->bits.INTYP = 1;
    	((ADC6140_REG_P0_CH2_CFG0_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH2_CFG0])->bits.INTYP = 1;
    	((ADC6140_REG_P0_CH3_CFG0_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH3_CFG0])->bits.INTYP = 1;
    	((ADC6140_REG_P0_CH4_CFG0_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH4_CFG0])->bits.INTYP = 1;
    
    	//[Temp] Configure each channel's PGA register:
    	//XLR1:
    	((ADC6140_REG_P0_CH1_CFG1_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH1_CFG1])->bits.GAIN = 0;//XLR1 = +0dB
    	//XLR2:
    	((ADC6140_REG_P0_CH2_CFG1_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH2_CFG1])->bits.GAIN = 0;//XLR2 = +0dB
    	//TRS1 (CH3):
    	((ADC6140_REG_P0_CH3_CFG1_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH3_CFG1])->bits.GAIN = 0;//TRS1 = +0dB
    	//TRS2 (CH4):
    	((ADC6140_REG_P0_CH4_CFG1_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH4_CFG1])->bits.GAIN = 0;//TRS2 = +0dB
    
    	//Other misc:
    	((ADC6140_REG_P0_CH1_CFG0_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH1_CFG0])->bits.DRE_EN = 0;//DRE/AGC disabled for CH1
    	((ADC6140_REG_P0_CH2_CFG0_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH2_CFG0])->bits.DRE_EN = 0;//DRE/AGC disabled for CH2
    	((ADC6140_REG_P0_CH3_CFG0_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH3_CFG0])->bits.DRE_EN = 0;//DRE/AGC disabled for CH3
    	((ADC6140_REG_P0_CH4_CFG0_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH4_CFG0])->bits.DRE_EN = 0;//DRE/AGC disabled for CH4
    	
    	((ADC6140_REG_P0_DSP_CFG1_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_DSP_CFG1])->bits.DVOL_GANG = 0;//ganged volume disabled
    
    
    
    //Fetch initial input-select from the system and input-gain value from the host UI, then configure ASI and PGA:
    void drvAudioHW_Update(void)
    {
    	uint8_t new_pgas[NUM_ADC_CH];
    	uint8_t new_dvcs[2] = { 0 };
    	uint8_t new_input_enables;
    	uint8_t new_asi_enables;
    	new_input_enables = audiohw_codec.adc.reg_p0[ADC6140_REG_P0_IN_CH_EN];
    	new_asi_enables = audiohw_codec.adc.reg_p0[ADC6140_REG_P0_ASI_OUT_CH_EN];
    	bool power_down = false;
    	
    	for(int i = 0; i < NUM_ADC_CH; i++)
    	{
    		new_pgas[i] = audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH1_CFG1 +(5*i)];
    	}
    
    	switch (ParameterGetValue(PARAM_AUDIO_IN_SOURCE, 0))
    	{
    		case AUDIO_IN_SRC_NONE:
    		{
    			MUTE_T1_ASSERT();
    			MUTE_PH1_ASSERT();
    			MUTE_M1_ASSERT();
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH1_EN = 0;
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH3_EN = 0;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH1_EN = 0;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH3_EN = 0;
    			new_dvcs[0] = 201;
    		}
    		break;
    
    		case AUDIO_IN_SRC_COMBO:
    		{
    			MUTE_PH1_ASSERT();
    			MUTE_M1_ASSERT();
    
    			if (drvHWDetects_IsActive(HWD_XLR1_DET))
    			{
    				MUTE_T1_ASSERT();
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH1_EN = 1;
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH3_EN = 0;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH1_EN = 1;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH3_EN = 0;
    				new_pgas[ADC_CH1] = ((signal_chains[SIGNAL_CHAIN_XLR_L].pga & PGA_MSK) << PGA_OSF);
    				new_dvcs[0] = 201 + signal_chains[SIGNAL_CHAIN_XLR_L].dvc;
    				
    				// We're forcing the relays while phantom is engaging, so don't try to update them if that's happening
    				if(!phantom_engaging)
    				{
    					drvAudioHW_SetGainRelay(0, signal_chains[SIGNAL_CHAIN_XLR_L].pre_relay_en);
    					drvAudioHW_SetXLRpad(0, signal_chains[SIGNAL_CHAIN_XLR_L].pad_relay_en);
    				}
    			}
    			else if (drvHWDetects_IsActive(HWD_TRS1_DET))
    			{
    				MUTE_T1_DEASSERT();
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH1_EN = 0;
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH3_EN = 1;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH1_EN = 0;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH3_EN = 1;
    				new_pgas[ADC_CH3] = ((signal_chains[SIGNAL_CHAIN_TRS_L].pga & PGA_MSK) << PGA_OSF);
    				new_dvcs[0] = 201 + signal_chains[SIGNAL_CHAIN_TRS_L].dvc;
    			}
    			else
    			{
    				MUTE_T1_ASSERT();
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH1_EN = 0;
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH3_EN = 0;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH1_EN = 0;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH3_EN = 0;
    				new_dvcs[0] = 201;
    			}
    		}
    		break;
    
    		case AUDIO_IN_SRC_PHONO:
    		{
    			MUTE_T1_ASSERT();
    			MUTE_M1_ASSERT();
    			MUTE_PH1_DEASSERT();
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH1_EN = 0;
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH3_EN = 1;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH1_EN = 0;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH3_EN = 1;
    			new_pgas[ADC_CH3] = ((signal_chains[SIGNAL_CHAIN_PHO_L].pga & PGA_MSK) << PGA_OSF);
    			new_dvcs[0] = 201 + signal_chains[SIGNAL_CHAIN_PHO_L].dvc;
    		}
    		break;
    
    		case AUDIO_IN_SRC_INT_MIC:
    		{
    			MUTE_T1_ASSERT();
    			MUTE_PH1_ASSERT();
    			MUTE_M1_DEASSERT();
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH1_EN = 0;
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH3_EN = 1;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH1_EN = 0;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH3_EN = 1;
    			new_pgas[ADC_CH3] = ((signal_chains[SIGNAL_CHAIN_MIC_L].pga & PGA_MSK) << PGA_OSF);
    			new_dvcs[0] = 201 + signal_chains[SIGNAL_CHAIN_MIC_L].dvc;
    		}
    		break;
    	}
    
    	switch (ParameterGetValue(PARAM_AUDIO_IN_SOURCE, 1))
    	{
    		case AUDIO_IN_SRC_NONE:
    		{
    			MUTE_T2_ASSERT();
    			MUTE_PH2_ASSERT();
    			MUTE_M2_ASSERT();
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH2_EN = 0;
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH4_EN = 0;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH2_EN = 0;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH4_EN = 0;
    			new_dvcs[1] = 201;
    		}
    		break;
    
    		case AUDIO_IN_SRC_COMBO:
    		{
    			MUTE_PH2_ASSERT();
    			MUTE_M2_ASSERT();
    
    			if (drvHWDetects_IsActive(HWD_XLR2_DET))
    			{
    				MUTE_T2_ASSERT();
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH2_EN = 1;
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH4_EN = 0;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH2_EN = 1;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH4_EN = 0;
    				new_pgas[ADC_CH2] = ((signal_chains[SIGNAL_CHAIN_XLR_R].pga & PGA_MSK) << PGA_OSF);
    				new_dvcs[1] = 201 + signal_chains[SIGNAL_CHAIN_XLR_R].dvc;
    				
    				if(!phantom_engaging)
    				{
    					drvAudioHW_SetGainRelay(1, signal_chains[SIGNAL_CHAIN_XLR_R].pre_relay_en);
    					drvAudioHW_SetXLRpad(1, signal_chains[SIGNAL_CHAIN_XLR_R].pad_relay_en);
    				}
    			}
    			else if (drvHWDetects_IsActive(HWD_TRS2_DET))
    			{
    				MUTE_T2_DEASSERT();
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH2_EN = 0;
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH4_EN = 1;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH2_EN = 0;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH4_EN = 1;
    				new_pgas[ADC_CH4] = ((signal_chains[SIGNAL_CHAIN_TRS_R].pga & PGA_MSK) << PGA_OSF);
    				new_dvcs[1] = 201 + signal_chains[SIGNAL_CHAIN_TRS_R].dvc;
    			}
    			else
    			{
    				MUTE_T2_ASSERT();
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH2_EN = 0;
    				((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH4_EN = 0;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH2_EN = 0;
    				((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH4_EN = 0;
    				new_dvcs[1] = 201;
    			}
    		}
    		break;
    
    		case AUDIO_IN_SRC_PHONO:
    		{
    			MUTE_T2_ASSERT();
    			MUTE_M2_ASSERT();
    			MUTE_PH2_DEASSERT();
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH2_EN = 0;
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH4_EN = 1;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH2_EN = 0;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH4_EN = 1;
    			new_pgas[ADC_CH4] = ((signal_chains[SIGNAL_CHAIN_PHO_R].pga & PGA_MSK) << PGA_OSF);
    			new_dvcs[1] = 201 + signal_chains[SIGNAL_CHAIN_PHO_R].dvc;
    		}
    		break;
    
    		case AUDIO_IN_SRC_INT_MIC:
    		{
    			MUTE_T2_ASSERT();
    			MUTE_PH2_ASSERT();
    			MUTE_M2_DEASSERT();
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH2_EN = 0;
    			((ADC6140_REG_P0_IN_CH_EN_t *)&new_input_enables)->bits.IN_CH4_EN = 1;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH2_EN = 0;
    			((ADC6140_REG_P0_ASI_OUT_CH_EN_t *)&new_asi_enables)->bits.ASI_OUT_CH4_EN = 1;
    			new_pgas[ADC_CH4] = ((signal_chains[SIGNAL_CHAIN_MIC_R].pga & PGA_MSK) << PGA_OSF);
    			new_dvcs[1] = 201 + signal_chains[SIGNAL_CHAIN_MIC_R].dvc;
    		}
    		break;
    	}
    
    	// Update the Input and ASI channel enables:
    	if( (new_asi_enables != audiohw_codec.adc.reg_p0[ADC6140_REG_P0_ASI_OUT_CH_EN]) || (new_input_enables != audiohw_codec.adc.reg_p0[ADC6140_REG_P0_IN_CH_EN]) )
    	{
    		if(power_down == false){
    			((ADC6140_REG_P0_PWR_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG])->bits.ADC_PDZ = 0;
    			drvCodec_ADC6140_WriteRegister(&audiohw_codec.adc, ADC6140_PAGE_0, ADC6140_REG_P0_PWR_CFG, audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG]);
    			power_down = true;
    		}
    		drvCodec_ADC6140_WriteRegister(&audiohw_codec.adc, ADC6140_PAGE_0, ADC6140_REG_P0_IN_CH_EN, new_input_enables);
    		drvCodec_ADC6140_WriteRegister(&audiohw_codec.adc, ADC6140_PAGE_0, ADC6140_REG_P0_ASI_OUT_CH_EN, new_asi_enables);
    	}
    
    	// Update changed PGAs
    	if(	(new_pgas[ADC_CH1] != audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH1_CFG1]) ||
    		(new_pgas[ADC_CH2] != audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH2_CFG1]) ||
    		(new_pgas[ADC_CH3] != audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH3_CFG1]) ||
    		(new_pgas[ADC_CH4] != audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH4_CFG1]) )
    	{
    		if(pga_throttling == false){
    			//PRINTF("\n\r0x%02x, 0x%02x", drvCodec_ADC6140_ReadRegister(&audiohw_codec.adc, ADC6140_REG_P0_DEV_STS0), drvCodec_ADC6140_ReadRegister(&audiohw_codec.adc, ADC6140_REG_P0_DEV_STS1));
    			if(power_down == false){
    				((ADC6140_REG_P0_PWR_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG])->bits.ADC_PDZ = 0;
    				drvCodec_ADC6140_WriteRegister(&audiohw_codec.adc, ADC6140_PAGE_0, ADC6140_REG_P0_PWR_CFG, audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG]);
    				power_down = true;
    			}
    
    			for(int i = 0; i < NUM_ADC_CH; i++)
    			{
    				if(new_pgas[i] != audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH1_CFG1 + (5*i)])
    				{
    					audiohw_codec.adc.reg_p0[ADC6140_REG_P0_CH1_CFG1 + (5*i)] = new_pgas[i];
    					drvCodec_ADC6140_WriteRegister(&audiohw_codec.adc, ADC6140_PAGE_0, ADC6140_REG_P0_CH1_CFG1 + (5*i), new_pgas[i]);
    					//Init PGA throttle timeout:
    					pga_throttling = true;
    					pga_extend_update = false;
    					pga_throttle_timestamp = ticks();
    
    					if((i == 0) || (i == 2))
    						mixer_TempMuteInput(0, MUTE_FOR_PGA_CHANGE);
    
    					if((i == 1) || (i == 3))
    						mixer_TempMuteInput(1, MUTE_FOR_PGA_CHANGE);
    				}
    			}
    		}
    		else {
    			//Uh oh, we made it here before pga throttle timeout; schedule this update function to be called again later (eg. 1-10ms):
    			pga_extend_update = true;
    			//PRINTF("\n\rEXT");
    		}
    	}
    	if(power_down == true){
    		((ADC6140_REG_P0_PWR_CFG_t *)&audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG])->bits.ADC_PDZ = 1;
    		drvCodec_ADC6140_WriteRegister(&audiohw_codec.adc, ADC6140_PAGE_0, ADC6140_REG_P0_PWR_CFG, audiohw_codec.adc.reg_p0[ADC6140_REG_P0_PWR_CFG]);
    	}
    	/*
    	PRINTF("\n\r0x%02x, 0x%02x, 0x%02x", 
    		drvCodec_ADC6140_ReadRegister(&audiohw_codec.adc, ADC6140_REG_P0_ASI_STS), 
    		drvCodec_ADC6140_ReadRegister(&audiohw_codec.adc, ADC6140_REG_P0_DEV_STS0), 
    		drvCodec_ADC6140_ReadRegister(&audiohw_codec.adc, ADC6140_REG_P0_DEV_STS1));
    		*/
    }
    
    
    
    //<Do other non-ADC, RAM-based audio init...>
    
    
    //Now load all register values over I2C and run the ADC:
    bool drvCodec_ADC6140_Init(h_ADC6140_t codec)
    {
    	// Locals
    	bool error = false;
    
    	// Input validation
    	if(!codec) return true;
    
    	// Put the codec into reset:
    	if(codec->Callback_SetPDN) codec->Callback_SetPDN(codec, false);
    
    	//Allow at least minimum reset pulse width:
    	if(codec->Callback_DelayUS) codec->Callback_DelayUS(1000);//ADC6140 hardware shutdown = 1ms (min)
    	
    	//Take the codec out of (hardware) reset:
    	if(codec->Callback_SetPDN) codec->Callback_SetPDN(codec, true);
    	
    	//Allow at least minimum un-reset pulse width:
    	if(codec->Callback_DelayUS) codec->Callback_DelayUS(1000);//ADC6140-ready = 1ms
    	
    	//Take ADC out of sleep mode:
    	((ADC6140_REG_P0_SLEEP_CFG_t *)&codec->reg_p0[ADC6140_REG_P0_SLEEP_CFG])->bits.SLEEP_ENZ = 1;
    	drvCodec_ADC6140_WriteRegister(codec, ADC6140_PAGE_0, ADC6140_REG_P0_SLEEP_CFG, codec->reg_p0[ADC6140_REG_P0_SLEEP_CFG]);
    	if(codec->Callback_DelayUS) codec->Callback_DelayUS(2000);//See: DS 9.2.1.2
    	
    	// Load up the remaining registers with values supplied by caller:
    	
    	//Page-0 (start at 'ADC6140_REG_P0_SHDN_CFG' offset (=3) since 'ADC6140_REG_P0_SLEEP_CFG' is written above):
    	uint32_t p0_size = sizeof(p0_regs);
    	for(uint32_t i=ADC6140_REG_SHDN_CFG_OSF; i<p0_size; i++)
    	{
    		ADC6140_p0_register_t reg = p0_regs[i];
    		
    		//Send the value to the ADC, checking return value:
    		error |= drvCodec_ADC6140_WriteRegister(codec, ADC6140_PAGE_0, reg, codec->reg_p0[reg]);
    		
    		if(codec->Callback_DelayUS) codec->Callback_DelayUS(100);
    	}
    	
    	return error;
    }
    
    //Call drvAudioHW_Update() on any new input-gain change or input-selection

  • Note: this is a 4-input system, but only one 2-channel I2S output is provided back to the host. The user can only select two inputs at a time (dynamically), and the ASI framing is adjusted at the same time as the PGA gain setting.

    All testing for rapid gain changes has been with Channel 1 and 2 so far.