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.

LAUNCHXL-F28P55X: ADC Open/Short Circuit Self-Test Example Code Missing in Latest C2000Ware

Part Number: LAUNCHXL-F28P55X
Other Parts Discussed in Thread: C2000WARE,

Tool/software:

Hello,

I’m working on implementing the ADC open-circuit and short-circuit self-test on a TMS320F28P55x

I can see the registers related to open/short-circuit self-test mentioned in the Analog-subsystem section of the device TRM, but I couldn’t find any corresponding example code in the latest C2000Ware release.

Could you please confirm:

  1. Whether example implementation code or driver support for this test is available in any C2000Ware version?

  2. If not, are there any recommended steps or register configurations to trigger and verify the open/short-circuit self-test manually?

Any reference to application notes or example projects related to this feature would also be appreciated.

  • Unfortunately we don't have an example in C2000Ware for this. I did recently create a routine for F29 devices that should be similar though, so I can share a snippet of that here and explain what I did.

    Start out by setting up the ADC/SOC for the channel you want to test. A few specifics:

    • Just using a software trigger probably makes the most sense here.
    • You can setup an ADC interrupt to signal when the conversion is complete.
    • You'll see a note in the TRM that because of the high drive impedance while using this mode, a longer S+H duration is needed. I just used 512 to start, but you may be able to do some calculations and arrive at a shorter duration.

    Then you cycle through the different OSDETECT modes. For each one, set the mode, wait a little to provide settling time (I used 2 microseconds, but you may need to adjust it), trigger the ADC conversion, wait for it to complete, and get the result. You don't necessarily need to do all the modes. The 4 shown in the snippet below should be enough.

        /*
         * Test full scale
         */
        ADC_configOSDetectMode(adcBase, ADC_OSDETECT_MODE_VDDA);
        SysCtl_delay(settlingTime);
        ADC_clearInterruptStatus(adcBase, ADC_INT_NUMBER1);
        ADC_forceSOC(adcBase, ADC_SOC_NUMBER0);
        while(!ADC_getInterruptStatus(adcBase, ADC_INT_NUMBER1))
        {
            ; /* Wait for conversion to complete */
        }
        testResults[FULL_SCALE] = ADC_readResult(adcResBase, ADC_SOC_NUMBER0);
    
        /*
         * Test 7/12 scale
         */
        ADC_configOSDetectMode(adcBase, ADC_OSDETECT_MODE_7BY12_VDDA);
        SysCtl_delay(settlingTime);
        ADC_clearInterruptStatus(adcBase, ADC_INT_NUMBER1);
        ADC_forceSOC(adcBase, ADC_SOC_NUMBER0);
        while(!ADC_getInterruptStatus(adcBase, ADC_INT_NUMBER1))
        {
            ; /* Wait for conversion to complete */
        }
        testResults[SEVENbyTWELVE_SCALE] = ADC_readResult(adcResBase, ADC_SOC_NUMBER0);
    
        /*
         * Test 5/12 scale
         */
        ADC_configOSDetectMode(adcBase, ADC_OSDETECT_MODE_5BY12_VDDA);
        SysCtl_delay(settlingTime);
        ADC_clearInterruptStatus(adcBase, ADC_INT_NUMBER1);
        ADC_forceSOC(adcBase, ADC_SOC_NUMBER0);
        while(!ADC_getInterruptStatus(adcBase, ADC_INT_NUMBER1))
        {
            ; /* Wait for conversion to complete */
        }
        testResults[FIVEbyTWELVE_SCALE] = ADC_readResult(adcResBase, ADC_SOC_NUMBER0);
    
        /*
         * Test zero scale
         */
        ADC_configOSDetectMode(adcBase, ADC_OSDETECT_MODE_VSSA);
        SysCtl_delay(settlingTime);
        ADC_clearInterruptStatus(adcBase, ADC_INT_NUMBER1);
        ADC_forceSOC(adcBase, ADC_SOC_NUMBER0);
        while(!ADC_getInterruptStatus(adcBase, ADC_INT_NUMBER1))
        {
            ; /* Wait for conversion to complete */
        }
        testResults[ZERO_SCALE] = ADC_readResult(adcResBase, ADC_SOC_NUMBER0);
    
        ADC_configOSDetectMode(adcBase, ADC_OSDETECT_MODE_DISABLED);

    Then you can check the results. If I run the test on my EVM, with nothing connected to the pin, my results for VDDA, 7BY12, 5BY12, and VSSA modes are around 4095, 2500, 1800, and 0 respectively with an allowed error of +/- 100. The expected results and acceptable amount of error for you however are going to depend on your system and what you have connected to the pin as described in the TRM.

    Whitney



  • This is code for configOSDetectMode in adc.h for f28p55x
    C2000Ware v6.00.00.00

    How will the ADC and AnalogSubsystem configuration change here ??
    Can you share me updated code for this.

  • Sorry, I didn't realize that F28P55x had a slightly different structure for the OSDETECT. 

    It looks like the difference is that the OSDETECT is part of AnalogSubsystem and shared between the ADC instances. So you use ADC_configOSDetectMode which looks pretty much the same except it takes the ANALOGSUBSYS_BASE base address. There's also a separate enable/disable bit so you'll need to use ADC_enableOSDetectMode and ADC_disableOSDetectMode.

    Finally there's a function called ASysCtl_setAnalogReferenceB which seems to select which instance the OSDETECT circuit gets connected to. According to the TRM, the ASYSCTL_TESTANA1_ENABLE option should be used for the modeVal parameter when using OSDETECT. You can then set it back to ASYSCTL_TESTANA0_TESTANA1_DISABLE when you're done.

    I'll find some time early next week to try it out myself and update you, but I wanted to share the info now in case you wanted to see if you could get it working before then.

    Whitney

  • Thanks for your patience. I'm attaching some example code that worked for me on F28P55x.

    //#############################################################################
    //
    // C2000Ware v6.00.00.00
    //
    // Copyright (C) 2024 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"
    #include "board.h"
    
    //
    // Defines
    //
    #define FULL_SCALE              0
    #define SEVENbyTWELVE_SCALE     1
    #define FIVEbyTWELVE_SCALE      2
    #define ZERO_SCALE              3
    #define NUMBER_OF_MEASUREMENTS  4
    
    // 5 microseconds
    #define OSDETECT_SETTLING (((((float64_t)5.0) / ((float64_t)1000000.0 / (float64_t)DEVICE_SYSCLK_FREQ)) - \
                                (float64_t)9.0) / (float64_t)5.0)
    
    /*
     * Initialize ADC instance
     */
    void initADC(uint32_t adcBase)
    {
        ADC_setVREF(adcBase, ADC_REFERENCE_VDDA, ADC_REFERENCE_2_5V);
        ADC_setPrescaler(adcBase, ADC_CLK_DIV_4_0);
        ADC_setInterruptPulseMode(adcBase, ADC_PULSE_END_OF_CONV);
        ADC_enableConverter(adcBase);
    
        /* ADC requires time to power on */
        DEVICE_DELAY_US(5000);
    
        ADC_enableInterrupt(adcBase, ADC_INT_NUMBER1);
        ADC_disableContinuousMode(adcBase, ADC_INT_NUMBER1);
        ADC_setInterruptSource(adcBase, ADC_INT_NUMBER1, ADC_INT_TRIGGER_EOC0);
        ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
    }
    
    /*
     * For the specified ADC channel, walk through ADC OSDETECT circuit settings and measure results.
     */
    bool testADCOpenShort(uint32_t adcBase, uint32_t adcResBase, ADC_Channel adcChannel,
                          uint16_t *expectedResults, uint16_t allowedError)
    {
        int32_t retVal = true;
        int16_t resError, testIndex;
        uint16_t testResults[NUMBER_OF_MEASUREMENTS] = {0, 0, 0, 0};
    
        ADC_setupSOC(adcBase, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, adcChannel, 512);
    
        /*
         * Test full scale
         */
        ADC_enableOSDetectMode(adcBase);
    
        ADC_configOSDetectMode(ANALOGSUBSYS_BASE, ADC_OSDETECT_MODE_VDDA);
        SysCtl_delay(OSDETECT_SETTLING);
        ADC_clearInterruptStatus(adcBase, ADC_INT_NUMBER1);
        ADC_forceSOC(adcBase, ADC_SOC_NUMBER0);
        while(!ADC_getInterruptStatus(adcBase, ADC_INT_NUMBER1))
        {
            ; /* Wait for conversion to complete */
        }
        testResults[FULL_SCALE] = ADC_readResult(adcResBase, ADC_SOC_NUMBER0);
    
        /*
         * Test 7/12 scale
         */
        ADC_configOSDetectMode(ANALOGSUBSYS_BASE, ADC_OSDETECT_MODE_7BY12_VDDA);
        SysCtl_delay(OSDETECT_SETTLING);
        ADC_clearInterruptStatus(adcBase, ADC_INT_NUMBER1);
        ADC_forceSOC(adcBase, ADC_SOC_NUMBER0);
        while(!ADC_getInterruptStatus(adcBase, ADC_INT_NUMBER1))
        {
            ; /* Wait for conversion to complete */
        }
        testResults[SEVENbyTWELVE_SCALE] = ADC_readResult(adcResBase, ADC_SOC_NUMBER0);
    
        /*
         * Test 5/12 scale
         */
        ADC_configOSDetectMode(ANALOGSUBSYS_BASE, ADC_OSDETECT_MODE_5BY12_VDDA);
        SysCtl_delay(OSDETECT_SETTLING);
        ADC_clearInterruptStatus(adcBase, ADC_INT_NUMBER1);
        ADC_forceSOC(adcBase, ADC_SOC_NUMBER0);
        while(!ADC_getInterruptStatus(adcBase, ADC_INT_NUMBER1))
        {
            ; /* Wait for conversion to complete */
        }
        testResults[FIVEbyTWELVE_SCALE] = ADC_readResult(adcResBase, ADC_SOC_NUMBER0);
    
        /*
         * Test zero scale
         */
        ADC_configOSDetectMode(ANALOGSUBSYS_BASE, ADC_OSDETECT_MODE_VSSA);
        SysCtl_delay(OSDETECT_SETTLING);
        ADC_clearInterruptStatus(adcBase, ADC_INT_NUMBER1);
        ADC_forceSOC(adcBase, ADC_SOC_NUMBER0);
        while(!ADC_getInterruptStatus(adcBase, ADC_INT_NUMBER1))
        {
            ; /* Wait for conversion to complete */
        }
        testResults[ZERO_SCALE] = ADC_readResult(adcResBase, ADC_SOC_NUMBER0);
    
        ADC_configOSDetectMode(ANALOGSUBSYS_BASE, ADC_OSDETECT_MODE_DISABLED);
        ADC_disableOSDetectMode(adcBase);
    
        /*
         * Check the results against the expected values
         */
        for(testIndex = 0U; testIndex < NUMBER_OF_MEASUREMENTS; testIndex++)
        {
            resError = expectedResults[testIndex] - testResults[testIndex];
            if(abs(resError) > allowedError)
            {
                retVal = false;
                break;
            }
        }
    
        return(retVal);
    }
    
    //
    // Main
    //
    void main(void)
    {
        uint16_t expectedResults[NUMBER_OF_MEASUREMENTS];
    
        //
        // 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();
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        /* Testing ADC A0 */
        initADC(ADCA_BASE);
    
        expectedResults[FULL_SCALE] = 4095;
        expectedResults[SEVENbyTWELVE_SCALE] = 2500;
        expectedResults[FIVEbyTWELVE_SCALE] = 1800;
        expectedResults[ZERO_SCALE] = 0;
    
        ASysCtl_setAnalogReferenceB(ASYSCTL_ADCA, ASYSCTL_TESTANA1_ENABLE);
        if(testADCOpenShort(ADCA_BASE, ADCARESULT_BASE, ADC_CH_ADCIN0, expectedResults, 150))
        {
            // PASS
            ESTOP0;
        }
        else
        {
            // FAIL
            ESTOP0;
        }
        ASysCtl_setAnalogReferenceB(ASYSCTL_ADCA, ASYSCTL_TESTANA0_TESTANA1_DISABLE);
    
        /* Testing ADC B2 */
        initADC(ADCB_BASE);
        ASysCtl_setAnalogReferenceB(ASYSCTL_ADCB, ASYSCTL_TESTANA1_ENABLE);
        if(testADCOpenShort(ADCB_BASE, ADCBRESULT_BASE, ADC_CH_ADCIN2, expectedResults, 150))
        {
            // PASS
            ESTOP0;
        }
        else
        {
            // FAIL
            ESTOP0;
        }
        ASysCtl_setAnalogReferenceB(ASYSCTL_ADCB, ASYSCTL_TESTANA0_TESTANA1_DISABLE);
    
        //
        // Loop indefinitely
        //
        while(1)
        {
            ESTOP0;
        }
    }
    

    Unfortunately in getting this to work, we did find a few driverlib bugs. I'll share the updated functions below:

    adc.h:

    //*****************************************************************************
    //
    //! Enables Open/Shorts Detection Circuit logic.
    //!
    //! \param base is the base address of the ASYSCTL.
    //!
    //! This function enables the open/short detection circuit logic. Use
    //! ADC_configOSDetectMode() to configure the mode of open/shorts detection
    //! circuit.
    //!
    //! \return None.
    //
    //*****************************************************************************
    static inline void
    ADC_enableOSDetectMode(uint32_t base)
    {
        //
        // Check the arguments.
        //
        ASSERT(ADC_isBaseValid(base));
    
        //
        // Enable open/shorts detection circuit.
        //
    
        EALLOW;
        HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ADCOSDETECT) |= ASYSCTL_ADCOSDETECT_OSDETECT_EN;
        HWREGH(base + ADC_O_CONFIG2) = 0x2U;
        EDIS;
    }
    
    //*****************************************************************************
    //
    //! Disables Open/Shorts Detection Circuit logic.
    //!
    //! \param base is the base address of the ASYSCTL.
    //!
    //! This function disables the open/short detection circuit logic.
    //!
    //! \return None.
    //
    //*****************************************************************************
    static inline void
    ADC_disableOSDetectMode(uint32_t base)
    {
        //
        // Check the arguments.
        //
        ASSERT(ADC_isBaseValid(base));
    
        //
        // Disable open/shorts detection circuit.
        //
    
        EALLOW;
        HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ADCOSDETECT) &= ~ASYSCTL_ADCOSDETECT_OSDETECT_EN;
        HWREGH(base + ADC_O_CONFIG2) = 0x0U;
        EDIS;
    }

    asysctl.h:

    //*****************************************************************************
    //
    //! Configure the analog reference B.
    //!
    //! \param adcInst is the instance of the ADC.
    //! \param modeVal is the desired ADC Test Mux mode.
    //!
    //! This function configures the analog reference B for ADC. The \e modeVal
    //! parameter selects which mode needs to be configured for the desired
    //! \e adcInst. Valid values for \e modeVal can be referred from the enum
    //! \e ASysCtl_ADCTestMuxMode.
    //!
    //! \return None.
    //
    //*****************************************************************************
    static inline void ASysCtl_setAnalogReferenceB(ASysCtl_AdcInst adcInst,
                                                    ASysCtl_ADCTestMuxMode modeVal)
    {
        uint32_t shiftVal;
    
        shiftVal = adcInst + ASYSCTL_REFCONFIGB_ADC_ATB_ENA_S;
    
        EALLOW;
        HWREG(ANALOGSUBSYS_BASE + ASYSCTL_O_REFCONFIGB) =
                        (HWREG(ANALOGSUBSYS_BASE + ASYSCTL_O_REFCONFIGB) &
                        ~((uint32_t)0x3 << shiftVal)) |
                        ((uint32_t)modeVal << shiftVal);
        EDIS;
    }
    
    

    We'll get these fixed in a future C2000Ware release.

    Whitney

  • I ran the example code you shared, along with the suggested changes in adc.h and asysctl.h. However, the test fails every time I try to run it.

    I’m using the LAUNCHXL-F28P55x LaunchPad for testing.
    Am I missing something specific required for this setup?

    Please help me understand if there are any additional steps or configurations needed to get this test working.

    Thanks,
    Dikshith

  • Could you check what silicon revision of the F28P55x you have on your LaunchPad? I should have mentioned that you'll need at least a rev A device for this to work--rev 0 doesn't have this feature enabled.

    Whitney

  • Hi Whitney,

    I checked the silicon versions.
    I initially had a Rev 0 device, which didn’t work as expected.
    I then tested the same code on a Rev A device, and it works fine.

    Thanks for pointing me in the right direction.

    Regards,
    Dikshith