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.

TMS320F28379D: AC signla ADC using adc_ex2_soc_epwm example

Part Number: TMS320F28379D

I want to do ADC for Vpp AC signal.

But it does not go down to 0.

I put 1Vpp so it should +1 and -1.

I think this is because the vreflo is GND.

How can I solve this problem?

Best regards

  • Mingi Oh,

    For proper operation, the ADC input must be maintained within the supported conversion range:

    At -1V, the input exceeds the Absolute Maximum Rating of -0.3V MIN, and the device may have suffered permanent damage:

    It is the responsibility of the user to ensure that the ADC input signal is properly conditioned to meet the supported operating conditions. If you are using a signal generator, the easiest method of doing so would be to introduce a DC offset. Otherwise, you would need to introduce some signal conditioning circuitry of your own.

    For high precision ADC sampling, these appnotes should be reviewed:

    -Tommy

  • Thank you so much.

    I have two more questions.

    1. Waveform in CCS

    When I did ADC,  I put the AC input 1Vpp.

    But the waveform in the CCS is clear.

    I was thinking this is because of the high frequency of the input signal.

    But it isn't... this is because lower frequency also werid.

    What did I missed?

      1kHz

     100Hz

     60Hz

    2. I wanted to transfer the ADC value to real value.

    So I made ADCreal 

    But it does not work. The ADCreal is initialized and it does not save the ADC value

    Can you check the code?

    // FILE: adc_ex2_soc_epwm.c
    
    //
    
    // TITLE: ADC ePWM Triggering
    
    //
    
    //! \addtogroup driver_example_list
    
    //! <h1>ADC ePWM Triggering</h1>
    
    //!
    
    //! This example sets up ePWM1 to periodically trigger a conversion on ADCA.
    
    //!
    
    //! \b External \b Connections \n
    
    //! - A0 should be connected to a signal to convert
    
    //!
    
    //! \b Watch \b Variables \n
    
    //! - \b adcAResults - A sequence of analog-to-digital conversion samples from
    
    //! pin A0. The time between samples is determined based on the period
    
    //! of the ePWM timer.
    
    //!
    
    //
    
    //#############################################################################
    
    // $TI Release: F2837xD Support Library v3.12.00.00 $
    
    // $Release Date: Fri Feb 12 19:03:23 IST 2021 $
    
    // $Copyright:
    
    // Copyright (C) 2013-2021 Texas Instruments Incorporated - http://www.ti.com/
    
    //
    
    // 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.
    
    // $
    
    //#############################################################################
    
    //
    
    ​
    
    //
    
    // Included Files
    
    //
    
    #include "driverlib.h"
    
    #include "device.h"
    
    ​
    
    //
    
    // Defines
    
    //
    
    #define RESULTS_BUFFER_SIZE 256
    
    #define EX_ADC_RESOLUTION 12 //분해능 능력, single ended 모드, VREFLO 가 low이다.
    
    // 12 for 12-bit conversion resolution, which supports (ADC_MODE_SINGLE_ENDED)
    
    // Sample on single pin (VREFLO is the low reference)
    
    // Or 16 for 16-bit conversion resolution, which supports (ADC_MODE_DIFFERENTIAL)
    
    // Sample on pair of pins (difference between pins is converted, subject to
    
    // common mode voltage requirements; see the device data manual)
    
    ​
    
    //
    
    // Globals
    
    //
    
    uint16_t adcAResults[RESULTS_BUFFER_SIZE]; // Buffer for results
    
    uint16_t adcReal[RESULTS_BUFFER_SIZE];
    
    uint16_t index; // Index into result buffer
    
    volatile uint16_t bufferFull; // Flag to indicate buffer is full
    
    long a;
    
    //
    
    // Function Prototypes
    
    //
    
    void initADC(void);
    
    void initEPWM(void);
    
    void initADCSOC(void);
    
    __interrupt void adcA1ISR(void);
    
    ​
    
    int BackTicker = 0;
    
    int IrsTicker = 0;
    
    //
    
    // Main
    
    //
    
    void main(void)
    
    {
    
    //
    
    // Initialize device clock and peripherals
    
    //
    
    Device_init();
    
    ​
    
    //
    
    // Disable pin locks and enable internal pullups.
    
    //
    
    Device_initGPIO();
    
    ​
    
    //
    
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    
    //
    
    Interrupt_initModule();
    
    ​
    
    //
    
    // Initialize the PIE vector table with pointers to the shell Interrupt
    
    // Service Routines (ISR).
    
    //
    
    Interrupt_initVectorTable();
    
    ​
    
    //
    
    // Interrupts that are used in this example are re-mapped to ISR functions
    
    // found within this file.
    
    //
    
    Interrupt_register(INT_ADCA1, &adcA1ISR);
    
    ​
    
    //
    
    // Set up the ADC and the ePWM and initialize the SOC
    
    //
    
    initADC();
    
    initEPWM();
    
    initADCSOC();
    
    ​
    
    //
    
    // Initialize results buffer
    
    //
    
    for(index = 0; index < RESULTS_BUFFER_SIZE; index++)
    
    {
    
    adcAResults[index] = 0;
    
    adcReal[index] = 0;
    
    }
    
    ​
    
    index = 0;
    
    bufferFull = 0;
    
    ​
    
    //
    
    // Enable ADC interrupt
    
    //
    
    Interrupt_enable(INT_ADCA1);
    
    ​
    
    //
    
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    
    //
    
    EINT;
    
    ERTM;
    
    ​
    
    //
    
    // Loop indefinitely
    
    //
    
    while(1)
    
    {
    
    BackTicker++;//무한 루프 발생 횟수 측정
    
    //
    
    // Start ePWM1, enabling SOCA and putting the counter in up-count mode
    
    // 변환하는 모드랑, 어떤 모드 쓸지..이건 좀 더 공부 필요
    
    EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
    
    EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
    
    ​
    
    //
    
    // Wait while ePWM1 causes ADC conversions which then cause interrupts.
    
    // When the results buffer is filled, the bufferFull flag will be set.
    
    //
    
    while(bufferFull == 0)
    
    {
    
    }
    
    bufferFull = 0; // Clear the buffer full flag
    
    ​
    
    //
    
    // Stop ePWM1, disabling SOCA and freezing the counter
    
    //
    
    EPWM_disableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
    
    EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_STOP_FREEZE);
    
    ​
    
    //
    
    // Software breakpoint. At this point, conversion results are stored in
    
    // adcAResults.
    
    //
    
    // Hit run again to get updated conversions.
    
    //
    
    // ESTOP0;
    
    }
    
    }
    
    ​
    
    //
    
    // Function to configure and power up ADCA.
    
    //
    
    void initADC(void)
    
    {
    
    ​
    
    //
    
    // Set ADCDLK divider to /4
    
    // 4분주 사용, 200Mhz(system clock)/2(based 분주)/4(ADC 분주) = 25Mhz
    
    ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
    
    ​
    
    //
    
    // Set resolution and signal mode (see #defines above) and load
    
    // corresponding trims.
    
    //
    
    #if(EX_ADC_RESOLUTION == 12) // 12분주로 위에 이미 선택함
    
    ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
    
    #elif(EX_ADC_RESOLUTION == 16)
    
    ADC_setMode(ADCA_BASE, ADC_RESOLUTION_16BIT, ADC_MODE_DIFFERENTIAL);
    
    #endif
    
    ​
    
    //
    
    // Set pulse positions to late
    
    // 변환후 인터럽트 발생
    
    ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_CONV);
    
    ​
    
    //
    
    // Power up the ADC and then delay for 1 ms
    
    // 아래 두갠 무조건 들어가야 하는 것임, 그냥 전력 넣어주고 딜레이 걸어 준다고 생각하렴
    
    ADC_enableConverter(ADCA_BASE);
    
    DEVICE_DELAY_US(1000);
    
    }
    
    ​
    
    //
    
    // Function to configure ePWM1 to generate the SOC.
    
    //
    
    void initEPWM(void)
    
    {
    
    //
    
    // Disable SOCA
    
    //
    
    EPWM_disableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
    
    ​
    
    //
    
    // Configure the SOC to occur on the first up-count event
    
    //
    
    EPWM_setADCTriggerSource(EPWM1_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_U_CMPA);
    
    EPWM_setADCTriggerEventPrescale(EPWM1_BASE, EPWM_SOC_A, 1);
    
    ​
    
    //
    
    // Set the compare A value to 1000 and the period to 1999
    
    // Assuming ePWM clock is 100MHz, this would give 50kHz sampling
    
    // 50MHz ePWM clock would give 25kHz sampling, etc. 
    
    // The sample rate can also be modulated by changing the ePWM period
    
    // directly (ensure that the compare A value is less than the period). 
    
    //
    
    EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 1000);
    
    EPWM_setTimeBasePeriod(EPWM1_BASE, 1999);
    
    ​
    
    //
    
    // Set the local ePWM module clock divider to /1
    
    //
    
    EPWM_setClockPrescaler(EPWM1_BASE,
    
    EPWM_CLOCK_DIVIDER_1,
    
    EPWM_HSCLOCK_DIVIDER_1);
    
    ​
    
    //
    
    // Freeze the counter
    
    //
    
    EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_STOP_FREEZE);
    
    }
    
    ​
    
    //
    
    // Function to configure ADCA's SOC0 to be triggered by ePWM1.
    
    //
    
    void initADCSOC(void)
    
    {
    
    //
    
    // Configure SOC0 of ADCA to convert pin A0. The EPWM1SOCA signal will be
    
    // the trigger.
    
    // - For 12-bit resolution, a sampling window of 15 (75 ns at a 200MHz
    
    // SYSCLK rate) will be used. For 16-bit resolution, a sampling window
    
    // of 64 (320 ns at a 200MHz SYSCLK rate) will be used.
    
    // - NOTE: A longer sampling window will be required if the ADC driving
    
    // source is less than ideal (an ideal source would be a high bandwidth
    
    // op-amp with a small series resistance). See TI application report
    
    // SPRACT6 for guidance on ADC driver design.
    
    //
    
    ​
    
    #if(EX_ADC_RESOLUTION == 12)
    
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA,
    
    ADC_CH_ADCIN0, 15);
    
    #elif(EX_ADC_RESOLUTION == 16)
    
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA,
    
    ADC_CH_ADCIN0, 64);
    
    #endif
    
    ​
    
    //
    
    // Set SOC0 to set the interrupt 1 flag. Enable the interrupt and make
    
    // sure its flag is cleared.
    
    //
    
    ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
    
    ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
    
    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
    
    }
    
    ​
    
    //
    
    // ADC A Interrupt 1 ISR
    
    //
    
    __interrupt void adcA1ISR(void)
    
    {
    
    IrsTicker++;
    
    //
    
    // Add the latest result to the buffer
    
    //
    
    adcAResults[index] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
    
    adcReal[index] = adcAResults[index]/4096*3;
    
    index++;
    
    //
    
    // Set the bufferFull flag if the buffer is full
    
    //
    
    if(RESULTS_BUFFER_SIZE <= index)
    
    {
    
    index = 0;
    
    bufferFull = 1;
    
    }
    
    ​
    
    //
    
    // Clear the interrupt flag
    
    //
    
    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
    
    ​
    
    //
    
    // Check if overflow has occurred
    
    //
    
    if(true == ADC_getInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1))
    
    {
    
    ADC_clearInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1);
    
    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
    
    }
    
    ​
    
    //
    
    // Acknowledge the interrupt
    
    //
    
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
    
    }

  • Mingi Oh,

    These questions are generally the responsibility of the developer to resolve.

    For debugging the reconstructed waveform, I recommend toggling a GPIO in the ADC ISR and profiling this activity against the input signal so that you can have a better idea of what conversions to expect. When observing the conversions, it would be more reliable to set a breakpoint in the code when the buffer is full and reading the results back directly from the array. The background refresh activity for the CCS graph is not synchronized with the software execution so you may be seeing mixed conversions from different sweeps.

    As far as your adcReal array goes, you have defined it as an array of unsigned integers, which does not support real numbers. Please use a floating point format instead.

    -Tommy