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.

TMS320F28075 ADC and DAC setup - a very strange connection

Other Parts Discussed in Thread: CONTROLSUITE

I have a strange error which looks like crosstalk between the ADC and DAC systems in the 28075.  The picture below shows my setup.  I am monitoring a photodiode amplifier with ADCA input A3 using a single SOC0.  I am also (on the ADC B system) monitoring four slowly changing signals at an entirely different time.  One of them is a thermistor on input B3.  The setup for ADCB uses four sequential SOC's (0,1,2 and 3) and the input channels are B2, B3, 14 and 15.

My setup code for the ADC's and DAC's is:-

(ADC)

void SetupADCSoftware(void)

{Uint16 acqps;

// ADC resolution is the same for both ADC's, so "acqps" value can be used for both.

if(ADC_RESOLUTION_12BIT == AdcaRegs.ADCCTL2.bit.RESOLUTION) acqps = 14; // 75ns
else acqps = 63; // 320ns

EALLOW; // ADC setup registers are protected

// ADC A, fast detector input - NB PINS A2 AND A3 STRAPPED FOR FAULT IDENTIFICATION

AdcaRegs.ADCSOC0CTL.bit.CHSEL = 3; // SOC0 will convert channel A3 (pin 22 PZP package)
AdcaRegs.ADCSOC0CTL.bit.ACQPS = acqps; // sample window is acqps + 1 SYSCLK cycles
AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // end of SOC0 will set INT1 flag
AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // enable INT1 flag
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // make sure INT1 flag is cleared

// ADC B, thermistor, laser diode x 2, CAN address resistive selection

AdcbRegs.ADCSOC0CTL.bit.CHSEL = 2; // SOC0 will convert pin B2 - CANADR
AdcbRegs.ADCSOC0CTL.bit.ACQPS = acqps;
AdcbRegs.ADCSOC1CTL.bit.CHSEL = 3; // SOC1 will convert pin B3 - THERMISTOR
AdcbRegs.ADCSOC1CTL.bit.ACQPS = acqps;
AdcbRegs.ADCSOC2CTL.bit.CHSEL = 14; // SOC2 will convert pin B14 - LAMON (A) LBMON (B)
AdcbRegs.ADCSOC2CTL.bit.ACQPS = acqps;
AdcbRegs.ADCSOC3CTL.bit.CHSEL = 15; // SOC3 will convert pin B15 - LBMON (B) LAMON (B)
AdcbRegs.ADCSOC3CTL.bit.ACQPS = acqps;
AdcbRegs.ADCINTSEL1N2.bit.INT1E = 1; // enable INT1 flag
AdcbRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // make sure INT1 flag is cleared

EDIS;
}

(DAC)

void Configure_DAC(Uint16 dacnum)                                           // param is DACA - DACC
{EALLOW;
DAC_PTR[dacnum]->DACCTL.bit.DACREFSEL = REFERENCE;           // internal VRef
DAC_PTR[dacnum]->DACOUTEN.bit.DACOUTEN = 1; // buffer ON
DAC_PTR[dacnum]->DACVALS.all = 0; // clear data register
DELAY_US(10);                                                                                            // Delay for buffered DAC to power up
EDIS;
}

And my driver code for the ADC's is as follows:-

void Aux_ADC(void)                                                    // Auxilliary ADC inputs to ADC B
{int CANAdr,THVal, LMON1, LMON2;

DINT;                                                                             // kill the World
EALLOW;
AdcbRegs.ADCINTSEL1N2.bit.INT1SEL = 3;                        // select SOC0 - 15, end of SOC3 will set INT1
EDIS;
AdcbRegs.ADCSOCFRC1.all = 0x0F;                                    // bit per SOC, Force Start of SOC0 - SOC3
while (!AdcbRegs.ADCINTFLG.bit.ADCINT1);                    // Wait for ADCINT1
AdcbRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;                       // Clear ADCINT1
CANAdr = AdcbResultRegs.ADCRESULT2;                        // save the raw data from chan B2
THVal = AdcbResultRegs.ADCRESULT3;                          // save the raw thermistor data chan B3
LMON1 = AdcbResultRegs.ADCRESULT14;                        // save the raw monitor data chan 14
LMON2 = AdcbResultRegs.ADCRESULT15;                          // save the raw monitor data chan 15
EINT;                                                                            // World back on
if (CANAdr > 3300) CANAdr = 3300;                                                 // limit to 3.3 volts
CANVal = CAN_ADR_Read(CANAdr);                                            // decode the CAN address
if (THVal > 3300) THVal = 3300;                                                       // limit to ambient at 25 deg
THVal = (3300 - THVal) / 550;                                                         // invert and scale for 3.3 volts at 60 deg
Put_DACOutB(THVal);                                                                         // send to the Peltier controller
if (LMON1 > 3300) LMON1 = 3300;                                           // limit to 3.3 volts - NOT USED YET
if (LMON2 > 3300) LMON2 = 3300;                                            // limit to 3.3 volts - NOT USED YET
}

// ********************* Data and AGC processing ************************************************************

// Getsample - reads in an FFTSIZE-sample to to work0[] (raw) and to buff[] (averaged)
// param ScaleItem is part of the AGC system, matches proccessed Doppler amplitude to the FFT process
// returns the average Doppler value for second (FFT-related) AGC process - smooth by 50 (a guess)

int GetSample(float ScaleItem)
{int p;                                                                                 // local buffer indexing
int readval;                                                                        // input value after coarse AGC has been applied
int ADCptr = 0;                                                                // local data transfer size
int val;
mean_value = 0;                                                            // placeholder for running average
accumulator = 0; p = -AvConstant;                                // start with a clean average
AvMult = (AvConstant - 1) / AvConstant;                           // moving average multiplier
DINT;                                                                                 // kill the World
EALLOW;
AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0;                            // select SOC0 - 15, end of SOC0 will set INT1 flag
EDIS;
for (ADCptr = p; ADCptr < FFTSIZE; ADCptr++)                         // read in <AvConstant> values to create the average
            {AdcaRegs.ADCSOCFRC1.all = 0x0001;                          // 1 bit per SOC, Force Start of Conversion bit 0
             while (!AdcaRegs.ADCINTFLG.bit.ADCINT1);                  // Wait for ADCINT1
               AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;                          // Clear ADCINT1
              if (ADCptr >= 0)                                                                      // now fetch the main body of data
                val = AdcaResultRegs.ADCRESULT3;                                   // chan 0 - 15, save the raw data from chan A3
            }
EINT;
return val;                                      // exit with last value
}

So here's the puzzle.  When I shine a light on the photodiode, the DACB output changes.  BUT when I monitor ADCRESULT3 for ADCA, I can't see the photodiode data changing.

I have checked for all of the likely errors (using b registers when I actually meant a).

Have I somehow mixed up my SOC's and channels?

Yours, in desperation,

Chris Moir

  • Hi Chris,

    Some quick points:

    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 3; // SOC0 will convert channel A3 (pin 22 PZP package)

    Will result in samples of pin A3 to ADCRESULT0, not ADCRESULT3. The result register corresponds to the SOC number, not the channel number.

    for (ADCptr = p; ADCptr < FFTSIZE; ADCptr++) // read in <AvConstant> values to create the average
    {AdcaRegs.ADCSOCFRC1.all = 0x0001; // 1 bit per SOC, Force Start of Conversion bit 0
    while (!AdcaRegs.ADCINTFLG.bit.ADCINT1); // Wait for ADCINT1
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // Clear ADCINT1
    if (ADCptr >= 0) // now fetch the main body of data
    val = AdcaResultRegs.ADCRESULT3; // chan 0 - 15, save the raw data from chan A3
    }

    I think currently this just returns one sample If you eventually want to use this for an FFT, this is probably not the best sampling method since you want equally spaced in time samples. Much better would be to keep the sample triggering process strictly in HW using a timer like the ePWM or CPU timer. See the adc_soc_epwm example in ControlSUITE.

    You can individually configure the S+H window duration (controlled by ACQPS register field) for each SOC. For your thermistor voltage divider you will probably want a longer S+H window, since the effective source impedance is roughly 4.7K || 10K = 3.2K. See the ADC input model in the datasheet, and the TRM section on "Choosing an Acquisition Window Duration".
  • Hi Devin,

    Many thanks for your prompt response. Setting the correct selector for the ADRESULT register to SOC instead of CHAN sorted it out.

    The example we were working from was too tidy - it used SOC0 to drive CHAN0 and put the result in ADRESULT0, SOC1 to drive CHAN1 and put the result in ADRESULT1, etc. It would have been clearer if it had been written using other than 0,1,2 etc in sequence - ie. SOC6 driving CHAN2 would have done it.

    As to why it appeared to be crosstalk between the two A/D's, that was genuinely finger trouble. As I moved my finger over the detector diode input to blank it off, it touched an adjacent but open A/D pin which was the thermistor input - but with no thermistor connected. As they said in the Big Bang Theory, "the MOVING finger writes ......" .

    Regards,

    Chris