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.

TMS320F28069: ADC Drop Out

Part Number: TMS320F28069
Other Parts Discussed in Thread: MOTORWARE

Hi C2000 Team,

We received feedback from the customer that they are seeing ADC corruption on the TMS320F28069. See below for additional details:

  • ADC corruption of the 3 phase current feedback will cause motor control to be unreliable
  • It has been observed phase C is most susceptible on motor dyne
  • TI has indicated ADC issues with this processor see SPRZ342N http://www.ti.com/lit/er/sprz342n/sprz342n.pdf

Normal ADC function, all feedback currents read.
Sum (Ia, Ib, Ic) ~= 0

Eventually Ic ADC feedback will stop reading – but oscilloscope shows really high current on the phase C
Sum (Ia, Ib, Ic) = 33

Do we have a suggested way to implement a fix?

Thanks,
Barend

  • Hi Barend,

    It's hard to say what is going on based on the information provided. We'll need some further details to narrow down the issue and get to a possible fix.

    Could you please answer or comment on the questions below for us:

    1. Could you compare the actual ADC results (ADCRESULTx register) in a good vs. bad case and provide them? This would be instead of looking at the current measurements recorded, which is calculated based on the read ADC values

    2. Could you provide the ADC initialization code being used?

    3. As mentioned, there are several ADC advisories in the device errata. Have these been understood and have the suggested workarounds been properly implemented?

    4. Could you provide more details on when this issue seems to happen? Is there something in the application that is systematically triggering the ADC results to be bad? Does it appear to happen after a certain length of operation, i.e. what is meant by eventually? Any details you can provide around these occurrences would be helpful in diagnosing the issue.

    Best,
    Kevin
  • /* --COPYRIGHT--,BSD
     * Copyright (c) 2015, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * --/COPYRIGHT--*/
    //! \file   drivers/adc/src/32b/f28x/f2806x/adc.c
    //! \brief  Contains the various functions related to the
    //!         analog-to-digital converter (ADC) object
    //!
    //! (C) Copyright 2015, Texas Instruments, Inc.
    
    
    // **************************************************************************
    // the includes
    #include "adc.h"
    #include "hal.h"
    #include "scheduler.h"
    #include "GM_MCP/mcpphio.h"
    #include "hwiofcpu.h"
    #include "MicroDiagnostic.h"
    
    
    // assembly file
    extern void usDelay(uint32_t Count);
    
    
    // **************************************************************************
    // the defines
    
    
    // **************************************************************************
    // the globals
    uint32_t AdcISRcount = 0;
    extern HAL_Obj     hal;
    
    
    // **************************************************************************
    // the functions
    
    void ADC_disable(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      adc->ADCCTL1 &= (~ADC_ADCCTL1_ADCENABLE_BITS);
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_disable() function
    
    
    void ADC_disableBandGap(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCCTL1 &= (~ADC_ADCCTL1_ADCBGPWD_BITS);
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_disableBandGap() function
    
    
    void ADC_disableInt(ADC_Handle adcHandle,const ADC_IntNumber_e intNumber)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
      uint_least8_t regNumber = intNumber >> 1;
      uint16_t clearValue = ADC_INTSELxNy_INTE_BITS << 
        (ADC_INTSELxNy_NUMBITS_PER_REG - (((intNumber+1) & 0x1) << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG));
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->INTSELxNy[regNumber] &= (~clearValue);
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_disableInt() function
    
    
    void ADC_disableRefBuffers(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCCTL1 &= (~ADC_ADCCTL1_ADCREFPWD_BITS);
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_disableRefBuffers() function
    
    
    void ADC_enable(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the bits
      adc->ADCCTL1 |= ADC_ADCCTL1_ADCENABLE_BITS;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_enable() function
    
    
    void ADC_enableBandGap(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the bits
      adc->ADCCTL1 |= ADC_ADCCTL1_ADCBGPWD_BITS;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_enableBandGap() function
    
    
    void ADC_enableInt(ADC_Handle adcHandle,const ADC_IntNumber_e intNumber)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
      uint_least8_t regNumber = intNumber >> 1;
      uint_least8_t lShift = ADC_INTSELxNy_NUMBITS_PER_REG - (((intNumber+1) & 0x1) << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG);
      uint16_t setValue = ADC_INTSELxNy_INTE_BITS << lShift;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the value
      adc->INTSELxNy[regNumber] |= setValue;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_enableInt() function
    
    
    void ADC_enableRefBuffers(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the bits
      adc->ADCCTL1 |= ADC_ADCCTL1_ADCREFPWD_BITS;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_enableRefBuffers() function
    
    
    // current sampled last
    ADC_Handle ADC_init(void *pMemory,const size_t numBytes)
    {
      ADC_Handle adcHandle;
    
    
      if(numBytes < sizeof(ADC_Obj))
        return((ADC_Handle)NULL);
    
    
      // assign the handle
      adcHandle = (ADC_Handle)pMemory;
    
      return(adcHandle);
    } // end of ADC_init() function
    
    
    void ADC_powerDown(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCCTL1 &= (~ADC_ADCCTL1_ADCPWDN_BITS);
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_powerDown() function
    
    
    void ADC_powerUp(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the bits
      adc->ADCCTL1 |= ADC_ADCCTL1_ADCPWDN_BITS;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_powerUp() function
    
    
    void ADC_reset(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the bits
      adc->ADCCTL1 |= (uint16_t)ADC_ADCCTL1_RESET_BITS;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_reset() function
    
    
    void ADC_setSampleOverlapMode(ADC_Handle adcHandle, ADC_ADCCTL2_ADCNONOVERLAP_e OverLap)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the bits
      if(OverLap == ADC_ADCCTL2_Overlap)
        adc->ADCCTL2 &= ~((uint16_t)(ADC_ADCCTL2_ADCNONOVERLAP_BITS));
      else
        adc->ADCCTL2 |= (uint16_t)ADC_ADCCTL2_ADCNONOVERLAP_BITS;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setSampleOverlapMode() function
    
    
    void ADC_setIntMode(ADC_Handle adcHandle,const ADC_IntNumber_e intNumber,const ADC_IntMode_e intMode)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
      uint_least8_t regNumber = intNumber >> 1;
      uint_least8_t lShift = (ADC_INTSELxNy_NUMBITS_PER_REG - (((intNumber+1) & 0x1) << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG));
      uint16_t clearValue = ADC_INTSELxNy_INTCONT_BITS << lShift;
      uint16_t setValue = intMode << lShift;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->INTSELxNy[regNumber] &= ~(clearValue);
    
    
      // set the bits
      adc->INTSELxNy[regNumber] |= setValue;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setIntMode() function
    
    
    void ADC_setIntPulseGenMode(ADC_Handle adcHandle,const ADC_IntPulseGenMode_e pulseMode)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCCTL1 &= (~ADC_ADCCTL1_INTPULSEPOS_BITS);
    
    
      // set the bits
      adc->ADCCTL1 |= pulseMode;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setIntPulseGenMode() function
    
    
    void ADC_setIntSrc(ADC_Handle adcHandle,const ADC_IntNumber_e intNumber,const ADC_IntSrc_e intSrc)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
      uint_least8_t regNumber = intNumber >> 1;
      uint_least8_t lShift = (ADC_INTSELxNy_NUMBITS_PER_REG - (((intNumber+1) & 0x1) << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG));
      uint16_t clearValue = ADC_INTSELxNy_INTSEL_BITS << lShift;
      uint16_t setValue = intSrc << lShift;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
    
      // clear the bits
      adc->INTSELxNy[regNumber] &= ~(clearValue);
    
    
      // set the bits
      adc->INTSELxNy[regNumber] |= setValue;
    
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setIntSrc() function
    
    
    void ADC_setSampleMode(ADC_Handle adcHandle,const ADC_SampleMode_e sampleMode)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      if(sampleMode & ADC_ADCSAMPLEMODE_SEPARATE_FLAG) // separate
        {
          adc->ADCSAMPLEMODE &= (~(sampleMode - ADC_ADCSAMPLEMODE_SEPARATE_FLAG));
        }
      else
        {
          adc->ADCSAMPLEMODE |= sampleMode;
        }
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setSampleMode() function
    
    
    void ADC_setSocChanNumber(ADC_Handle adcHandle,const ADC_SocNumber_e socNumber,const ADC_SocChanNumber_e chanNumber)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCSOCxCTL[socNumber] &= (~ADC_ADCSOCxCTL_CHSEL_BITS);
    
    
      // set the bits
      adc->ADCSOCxCTL[socNumber] |= chanNumber;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setSocChanNumber() function
    
    
    void ADC_setSocSampleDelay(ADC_Handle adcHandle,const ADC_SocNumber_e socNumber,const ADC_SocSampleDelay_e sampleDelay)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCSOCxCTL[socNumber] &= (~ADC_ADCSOCxCTL_ACQPS_BITS);
    
    
      // set the bits
      adc->ADCSOCxCTL[socNumber] |= sampleDelay;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setSocSampleDelay() function
    
    
    void ADC_setSocTrigSrc(ADC_Handle adcHandle,const ADC_SocNumber_e socNumber,const ADC_SocTrigSrc_e trigSrc)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCSOCxCTL[socNumber] &= (~ADC_ADCSOCxCTL_TRIGSEL_BITS);
    
    
      // set the bits
      adc->ADCSOCxCTL[socNumber] |= trigSrc;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setSocTrigSrc() function
    
    
    void ADC_setSocFrc(ADC_Handle adcHandle,const ADC_SocFrc_e socFrc)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the bits
      adc->ADCSOCFRC1 = 1 << socFrc;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setSocFrc() function
    
    
    void ADC_setSocFrcWord(ADC_Handle adcHandle,const uint16_t socFrc)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // write the entire word
      adc->ADCSOCFRC1 = socFrc;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setSocFrcWord() function
    
    
    void ADC_setTempSensorSrc(ADC_Handle adcHandle,const ADC_TempSensorSrc_e sensorSrc)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCCTL1 &= (~ADC_ADCCTL1_TEMPCONV_BITS);
    
    
      // set the bits
      adc->ADCCTL1 |= sensorSrc;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setTempSensorSrc() function
    
    
    void ADC_setVoltRefSrc(ADC_Handle adcHandle,const ADC_VoltageRefSrc_e voltSrc)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCCTL1 &= (~ADC_ADCCTL1_ADCREFSEL_BITS);
    
    
      // set the bits
      adc->ADCCTL1 |= voltSrc;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setVoltRefSrc() function
    
    
    extern ADC_DivideSelect_e ADC_getDivideSelect(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
      // get the bits
      ADC_DivideSelect_e divSelect = (ADC_DivideSelect_e)((adc->ADCCTL2) & (ADC_ADCCTL2_CLKDIV2EN_BITS | ADC_ADCCTL2_CLKDIV4EN_BITS));
    
      if(divSelect == 4)
        divSelect = ADC_DivideSelect_ClkIn_by_1;
    
      return (divSelect);
    } // end of ADC_getDivideSelect() function
    
    
    void ADC_setDivideSelect(ADC_Handle adcHandle,const ADC_DivideSelect_e divSelect)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCCTL2 &= (~(ADC_ADCCTL2_CLKDIV2EN_BITS|ADC_ADCCTL2_CLKDIV4EN_BITS));
    
    
      // set the bits
      adc->ADCCTL2 |= divSelect;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setDivideSelect() function
    
    
    void ADC_enableNoOverlapMode(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the bits
      adc->ADCCTL2 |= ADC_ADCCTL2_ADCNONOVERLAP_BITS;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_enableNoOverlapMode() function
    
    
    void ADC_disableNoOverlapMode(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // clear the bits
      adc->ADCCTL2 &= (~(ADC_ADCCTL2_ADCNONOVERLAP_BITS));
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_enableNoOverlapMode() function
    
    
    void ADC_setupSocTrigSrc(ADC_Handle adcHandle, const ADC_SocNumber_e socNumber, const ADC_IntTriggerSOC_e intTrigSrc)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
      uint16_t clearValue;
      uint16_t setValue;
      uint16_t lShift_socsel1 = socNumber << 1;
      uint16_t lShift_socsel2 = (socNumber - ADC_SocNumber_8) << 1;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      if(socNumber < ADC_SocNumber_8)
        {
          clearValue = ADC_ADCINTSOCSELx_SOCx_BITS << lShift_socsel1;
          setValue = intTrigSrc << lShift_socsel1;
    
          // clear the bits
          adc->ADCINTSOCSEL1 &= (~(clearValue));
    
          // set the bits
          adc->ADCINTSOCSEL1 |= setValue;
        }
      else
        {
          clearValue = ADC_ADCINTSOCSELx_SOCx_BITS << lShift_socsel2;
          setValue = intTrigSrc << lShift_socsel2;
    
          // clear the bits
          adc->ADCINTSOCSEL2 &= (~(clearValue));
    
          // set the bits
          adc->ADCINTSOCSEL2 |= setValue;
        }
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setupSocTrigSrc() function
    
    void ADC_setOffTrim(ADC_Handle adcHandle, const uint16_t offtrim)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the offtrim bits
      adc->ADCOFFTRIM = offtrim;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_setOffTrim() function
    
    void ADC_enableVoltRefLoConv(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the bits
      adc->ADCCTL1 |= ADC_ADCCTL1_VREFLOCONV_BITS;
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_enableVoltRefLoConv() function
    
    void ADC_disableVoltRefLoConv(ADC_Handle adcHandle)
    {
      ADC_Obj *adc = (ADC_Obj *)adcHandle;
    
    
      ENABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      // set the bits
      adc->ADCCTL1 &= (~ADC_ADCCTL1_VREFLOCONV_BITS);
    
      DISABLE_PROTECTED_REGISTER_WRITE_MODE;
    
      return;
    } // end of ADC_disableVoltRefLoConv() function
    
    
    /* ADC ISR used for motor control analog parameters*/
    interrupt void adc_isr(void)
    {
        uint32_t ulStartTime;
        uint32_t ulEndTime;
        uint32_t ulDeltaTime;
    
    	/* Read task start time */
        ulStartTime= hal.timer1Handle->TIM;
    
        /* Stack overflow and underflow check */
        Stack_Pointer_Check();
    
    	/* keep count of ISRs to schedule motor control internal tasks */
        AdcISRcount++;
    
        // acknowledge the ADC interrupt
        HAL_acqAdcInt(&hal, ADC_IntNumber_6); // Clear ADC IRQ flag to acknowledge IRQ
    
        /* Motor control 20kHZ task */
        MngMCP_MtrCntrl_Task0();
    
        ulEndTime = hal.timer1Handle->TIM;
    
    	/* Calculate task execution time */
    	if(ulStartTime >= ulEndTime)
        {
    	    ulDeltaTime = ulStartTime - ulEndTime;
        }
    	else
    	{
    	    ulDeltaTime = ((uint32_t)(USER_SYSTEM_FREQ_MHz * TIMER1_INTERVAL) - ulEndTime) + ulStartTime;
    	}
    
    	stTaskExecTime.ulTask0ExecTime = ulDeltaTime / USER_SYSTEM_FREQ_MHz;
    
    	stTaskExecTime.ulCumlTaskTime += stTaskExecTime.ulTask0ExecTime;
    
    	stTaskExecTime.ulSubsTask0ExecTime += stTaskExecTime.ulTask0ExecTime;
    
    	/* Calculate maximum task execution time */
    	if(stTaskExecTime.ulTask0ExecTime > stTaskExecTime.ulTask0MaxExecTime)
        {
           stTaskExecTime.ulTask0MaxExecTime = stTaskExecTime.ulTask0ExecTime;
        }
    }
    
    
    // end of file
    
    adc.hHi Kevin,

    Please see below for answers to the questions you need to know more about.

    1. Could you compare the actual ADC results (ADCRESULTx register) in a good vs. bad case and provide them? This would be instead of looking at the current measurements recorded, which is calculated based on the read ADC values.

    The customer is working on finding a way to collect raw ADC through CCS, is this possible? If so, how?

    Also additional data was collected last night using scope to show measured ADC voltage reading @ ADC micro pin matching measured AC current, but reported reading by micro was incorrect (stopped updating).  

    Phase C where is most susceptible is connected to ADCINA6 thought might indicate something to be last in the ADC queue.

    2. Could you provide the ADC initialization code being used?

    Attached is source code for the ADC functions (including initialization). These were created by TI to their understanding and the customer did not modify them (they are from 2015), so not sure if they contain the errata fixes.

    3. As mentioned, there are several ADC advisories in the device errata. Have these been understood and have the suggested workarounds been properly implemented?

    Currently, they are working through the ADC advisories, and have completed:

    • Initial conversion,
    • ADC result conversion when sampling ends on 14th cycle,
    • ADC revision register limitation
    • ADC can become non-responsive when ADCNONOVERLAP or RESET is called

    They are still working on the others, and would be happy to review them with us to make sure we implemented them correctly.

    4. Could you provide more details on when this issue seems to happen? Is there something in the application that is systematically triggering the ADC results to be bad? Does it appear to happen after a certain length of operation, i.e. what is meant by eventually? Any details you can provide around these occurrences would be helpful in diagnosing the issue.

    The issue seems to happen after a low power sleep mode is induced and then the controller is woken back up.  It is very repeatable on the motor dyne, issue happens after 30 sleep cycles.  On the actual project it seems more random.

    Thanks,
    Barend

  • Hi Barend,

    You can check the ADCRESULT registers in CCS using the Register window while debugging, like below. Checking the defined struct _ADC_Obj_ handler in the expressions window should work as well:

    We're specifically wanting to look at the ADC samples used to calculate the Phase C current.

    Was this project built off of one of the kits/projects in Motorware? If so which ones?

    The software provided includes the ADC function definitions/prototypes and defines. It would be more useful to see the ADC initialization code used within main() and the values configured in the ADC register. Could you provide a snapshot of the ADC registers after initialization? This can be collected using the registers window in CCS.

    Best,

    Kevin

  • Currently taking this off forum, will come back with our findings if there is something of note for the community.

    Best,
    Matthew
  • Bumping post to keep from closing.

    Best,
    Kevin
  • The issue was on the customer's software side - the 3 phase ePWM modules can lose synchronization during the CAN sleep process. The issue is fixed after resynchronizing time base clock for three ePWM modules using TBCLKSYNC.

    Thanks,
    Barend