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.

TMS320F280049C: ADC-to-DAC loopback check

Part Number: TMS320F280049C
Other Parts Discussed in Thread: C2000WARE

I am working on C2000Tm real-time MCU Safety Mechanisms where I came across ADC to DAC loopback test 

To implement this is there any example code that i can refer ??

because according to the TRM in ANALOG_SUBSYS_REGS Registers I can see ADCDACLOOPBACK

but the register is not visible in CCS Register section 

Is there any way i can tackle this problem??

  • Hi,

    We do not have any examples for this.

    I'm sorry that the register is not shown in CCS, but the TRM is correct. If you write to the location seen in the TRM, you will see the described behavior. You could verify that you have written correctly by checking the memory browser in CCS.

    Best Regards,

    Ben Collier

  • I'll try writing to the register and check if it works.

    But One More thing to add to this is the register is also Not mentioned in C2000Ware/driverlib of f28004x

  • Ok, please let me know if you have any trouble with the loopback. 

  • So, for TMSF280049C there are only Two 12-bit buffered DAC outputs

    and these are connected to ADC-A Input 0 and ADC-A Input 1 respectively, So there is no way I can test ADC-B and ADC-C 

    About ADC to DAC loopback what I observed is if ADC, DAC are initialized and DAC output is enabled 

    //
    // Enable the DAC output
    //
    DAC_enableOutput(DACA_BASE);
    DAC_enableOutput(DACB_BASE);

    By default the output of DACA and DACB is reflected in AdcaResultRegs for A0 and A1, Even when ADCDACLOOPBACK - ENLB2ADCC , ENLB2ADCB , ENLB2ADCA all are Disabled or set to 0

    HWREG(ANALOGSUBSYS_BASE + 0x88U) =
    (HWREG(ANALOGSUBSYS_BASE + 0x88U) | 0x1U) |
    (0xA5A5UL << 16U);

    HWREG(ANALOGSUBSYS_BASE + 0x88U) =
    (HWREG(ANALOGSUBSYS_BASE + 0x88U) | 0x2U) |
    (0xA5A5UL << 16U);

    HWREG(ANALOGSUBSYS_BASE + 0x88U) =
    (HWREG(ANALOGSUBSYS_BASE + 0x88U) | 0x4U) |
    (0xA5A5UL << 16U);

    DAC output value is set using :-

    DAC_setShadowValue(DACA_BASE, 2048);
    DAC_setShadowValue(DACB_BASE, 2048);

     But, ON Setting ENLB2ADCC to 1 (together with KEY = 0xA5A5), AdcaResultRegs for A0 and A1 gets disconnected from DAC and it Does Not read any external voltages if applied to these pins, (.. this might be because it will override the CHSEL.)

    What does this functionality mean?

    Is there any other way to check All the ADC channels as Self test code?

  • Hi,

    I do not think that there is any way to check all of the ADC channels. We do have open/shorts circuits that will allow you to test each ADC, but again this will not allow you to test all channels. 

    Could you explain why you want to test all of the ADC channels? 

    Best Regards,

    Ben Collier

  • Hi,

    Requirement is to check that all the ADC modules are working.

    And I think ADCDACLOOPBACK is the way to go forward but the issue what I am facing is 

    DAC output is enabled 

    void myDAC0_init(void){
        EALLOW;
        //
        // Set DAC reference voltage.
        //
        DAC_setReferenceVoltage(DACA_BASE, DAC_REF_ADC_VREFHI);
        DAC_setReferenceVoltage(DACB_BASE, DAC_REF_ADC_VREFHI);
        //
        // Set DAC load mode.
        //
        DAC_setLoadMode(DACA_BASE, DAC_LOAD_SYSCLK);
        DAC_setLoadMode(DACB_BASE, DAC_LOAD_SYSCLK);
        //
        // Enable the DAC output
        //
        DAC_enableOutput(DACA_BASE);
        DAC_enableOutput(DACB_BASE);
        //
        // Set the DAC shadow output
        //
        DAC_setShadowValue(DACA_BASE, 0U);
        DAC_setShadowValue(DACB_BASE, 0U);
    
        //
        // Delay for buffered DAC to power up.
        //
        DEVICE_DELAY_US(500);
    
        EDIS;
    }

    DAC_setShadowValue(DACA_BASE, dacVal);

    But As soon as I Enable the ENLB2ADCC bits 

        myDAC0_init();
        HWREG(ANALOGSUBSYS_BASE + 0x88U) =
                (HWREG(ANALOGSUBSYS_BASE + 0x88U) | 0x1U) |
                (0xA5A5UL << 16U);
    
        HWREG(ANALOGSUBSYS_BASE + 0x88U) =
                (HWREG(ANALOGSUBSYS_BASE + 0x88U) | 0x2U) |
                (0xA5A5UL << 16U);
    
        HWREG(ANALOGSUBSYS_BASE + 0x88U) =
                (HWREG(ANALOGSUBSYS_BASE + 0x88U) | 0x4U) |
                (0xA5A5UL << 16U);

    CHSEL is disabled and I am not able to read any values in this AdcResultRegs.

    Here is my example file of this project you can go through these.

    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    #include "board.h"
    
    //
    // Globals
    //
    uint16_t myADC0Result0;
    uint16_t myADC0Result1;
    uint16_t myADC1Result0;
    uint16_t myADC1Result1;
    uint16_t myADC2Result0;
    uint16_t myADC2Result1;
    
    
    uint16_t dacVal = 2048;
    
    void myDAC0_init(void);
    
    //
    // 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();
    
        //
        // Set up ADCs, initializing the SOCs to be triggered by software
        //
        Board_init();
    
        myDAC0_init();
        HWREG(ANALOGSUBSYS_BASE + 0x88U) =
                (HWREG(ANALOGSUBSYS_BASE + 0x88U) | 0x1U) |
                (0xA5A5UL << 16U);
    
        HWREG(ANALOGSUBSYS_BASE + 0x88U) =
                (HWREG(ANALOGSUBSYS_BASE + 0x88U) | 0x2U) |
                (0xA5A5UL << 16U);
    
        HWREG(ANALOGSUBSYS_BASE + 0x88U) =
                (HWREG(ANALOGSUBSYS_BASE + 0x88U) | 0x4U) |
                (0xA5A5UL << 16U);
    
        myADC2_init();
    
    //    HWREG(ANALOGSUBSYS_BASE + 0x88U) =
    //            (HWREG(ANALOGSUBSYS_BASE + 0x88U) & ~0x1U) |
    //            (0xA5A5UL << 16U);
    //
    //    HWREG(ANALOGSUBSYS_BASE + 0x88U) =
    //            (HWREG(ANALOGSUBSYS_BASE + 0x88U) & ~0x2U) |
    //            (0xA5A5UL << 16U);
    //
    //    HWREG(ANALOGSUBSYS_BASE + 0x88U) =
    //            (HWREG(ANALOGSUBSYS_BASE + 0x88U) & ~0x4U) |
    //            (0xA5A5UL << 16U);
    //    EDIS;
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        //
        // Loop indefinitely
        //
        while(1)
        {
            DAC_setShadowValue(DACA_BASE, dacVal);
            DAC_setShadowValue(DACB_BASE, dacVal);
            //
            // Convert, wait for completion, and store results
            //
            ADC_forceMultipleSOC(myADC0_BASE, (ADC_FORCE_SOC0 | ADC_FORCE_SOC1));
    
            //
            // Wait for ADCA to complete, then acknowledge flag
            //
            while(ADC_getInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1) == false)
            {
            }
            ADC_clearInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1);
    
            ADC_forceMultipleSOC(myADC1_BASE, (ADC_FORCE_SOC0 | ADC_FORCE_SOC1));
            //
            // Wait for ADCC to complete, then acknowledge flag
            //
            while(ADC_getInterruptStatus(myADC1_BASE, ADC_INT_NUMBER1) == false)
            {
            }
            ADC_clearInterruptStatus(myADC1_BASE, ADC_INT_NUMBER1);
    
            ADC_forceMultipleSOC(ADCB_BASE, (ADC_FORCE_SOC0 | ADC_FORCE_SOC1));
            //
            // Wait for ADCC to complete, then acknowledge flag
            //
            while(ADC_getInterruptStatus(ADCB_BASE, ADC_INT_NUMBER1) == false)
            {
            }
            ADC_clearInterruptStatus(ADCB_BASE, ADC_INT_NUMBER1);
    
            //
            // Store results
            //
            myADC0Result0 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
            myADC0Result1 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1);
            myADC1Result0 = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER0);
            myADC1Result1 = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER1);
            myADC2Result0 = ADC_readResult(ADCBRESULT_BASE, ADC_SOC_NUMBER0);
            myADC2Result1 = ADC_readResult(ADCBRESULT_BASE, ADC_SOC_NUMBER1);
    
    
        }
    }
    
    void myDAC0_init(void){
        EALLOW;
        //
        // Set DAC reference voltage.
        //
        DAC_setReferenceVoltage(DACA_BASE, DAC_REF_ADC_VREFHI);
        DAC_setReferenceVoltage(DACB_BASE, DAC_REF_ADC_VREFHI);
        //
        // Set DAC load mode.
        //
        DAC_setLoadMode(DACA_BASE, DAC_LOAD_SYSCLK);
        DAC_setLoadMode(DACB_BASE, DAC_LOAD_SYSCLK);
        //
        // Enable the DAC output
        //
        DAC_enableOutput(DACA_BASE);
        DAC_enableOutput(DACB_BASE);
        //
        // Set the DAC shadow output
        //
        DAC_setShadowValue(DACA_BASE, 0U);
        DAC_setShadowValue(DACB_BASE, 0U);
    
        //
        // Delay for buffered DAC to power up.
        //
        DEVICE_DELAY_US(500);
    
        EDIS;
    }
    
    void myADC2_init(){
        //
        // ADC Initialization: Write ADC configurations and power up the ADC
        //
        // Configures the ADC module's offset trim
        //
        ADC_setOffsetTrimAll(ADC_REFERENCE_INTERNAL,ADC_REFERENCE_3_3V);
        //
        // Configures the analog-to-digital converter module prescaler.
        //
        ADC_setPrescaler(ADCB_BASE, ADC_CLK_DIV_2_0);
        //
        // Sets the timing of the end-of-conversion pulse
        //
        ADC_setInterruptPulseMode(ADCB_BASE, ADC_PULSE_END_OF_CONV);
        //
        // Powers up the analog-to-digital converter core.
        //
        ADC_enableConverter(ADCB_BASE);
        //
        // Delay for 1ms to allow ADC time to power up
        //
        DEVICE_DELAY_US(5000);
        //
        // SOC Configuration: Setup ADC EPWM channel and trigger settings
        //
        // Disables SOC burst mode.
        //
        ADC_disableBurstMode(ADCB_BASE);
        //
        // Sets the priority mode of the SOCs.
        //
        ADC_setSOCPriority(ADCB_BASE, ADC_PRI_ALL_ROUND_ROBIN);
        //
        // Start of Conversion 0 Configuration
        //
        //
        // Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
        //      SOC number      : 0
        //      Trigger         : ADC_TRIGGER_SW_ONLY
        //      Channel         : ADC_CH_ADCIN2
        //      Sample Window   : 8 SYSCLK cycles
        //      Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
        //
        ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN15, 8U);
        ADC_setInterruptSOCTrigger(ADCB_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
        //
        // Start of Conversion 1 Configuration
        //
        //
        // Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
        //      SOC number      : 1
        //      Trigger         : ADC_TRIGGER_SW_ONLY
        //      Channel         : ADC_CH_ADCIN3
        //      Sample Window   : 8 SYSCLK cycles
        //      Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
        //
        ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN3, 8U);
        ADC_setInterruptSOCTrigger(ADCB_BASE, ADC_SOC_NUMBER1, ADC_INT_SOC_TRIGGER_NONE);
        //
        // ADC Interrupt 1 Configuration
        //      Source  : ADC_SOC_NUMBER1
        //      Interrupt Source: enabled
        //      Continuous Mode : disabled
        //
        //
        ADC_setInterruptSource(ADCB_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER1);
        ADC_clearInterruptStatus(ADCB_BASE, ADC_INT_NUMBER1);
        ADC_disableContinuousMode(ADCB_BASE, ADC_INT_NUMBER1);
        ADC_enableInterrupt(ADCB_BASE, ADC_INT_NUMBER1);
    }
    

    Also, ADCDACLOOPBACK  Register and the Corresponding functions are not Available in C2000Ware/driverlib of f28004x

  • Dikshith,

    Have you considered the open/short detection circuits? 

    Best Regards,

    Ben Collier