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.

CCS/CC1352P: ADCBuf SwiFxn issue

Part Number: CC1352P

Tool/software: Code Composer Studio

Hi,

I'm using multiple ADC channels. one of them is used by the Sensor controller.

Randomly when using ADC measurement from both sides (MCU and SC, note:  HW semaphore is used to determine which is the current controller and work great), I get HW reset.

after investigation of this issue, I'm noticed that the function 'ADCBufCC26X2_swiFxn' in 'ADCBufCC26X2_open' randomly set the 'object->activeSamplebuffer' from normal address to 0XFFFFFFF and then we got assertion.

  • Hi Moshe,

    What mode are you running the ADCBuf driver in? Have you made a convert prior to this or do you go straight from open -> exception?
  • Hi,

    This is my Implementation:


    // Set up an ADCBuf peripheral
    ADCBuf_Params_init(&gADCData.adcBufParams);
    gADCData.adcBufParams.callbackFxn = ADC_BufCallback;
    gADCData.adcBufParams.recurrenceMode = ADCBuf_RECURRENCE_MODE_ONE_SHOT;
    gADCData.adcBufParams.returnMode = ADCBuf_RETURN_MODE_CALLBACK;
    gADCData.adcBufParams.samplingFrequency = gADCData.A2DCfg.frequencyHz; // Hz
    gADCData.adcBufParams.custom = &gADCData.adcBufParamsExt;
    gADCData.adcBuf = ADCBuf_open(gADCData.A2DCfg.ADCBufId, &gADCData.adcBufParams);

    if (NULL == gADCData.adcBuf)
    {
    // AdcBuf did not open correctly.
    break;
    }

    // Control ADC Hardware semaphore to keep while converting //
    ADCBuf_control(gADCData.adcBuf, ADCBufCC26X2_CMD_KEEP_ADC_SEMAPHORE, NULL);
    ADCBuf_control(gADCData.adcBuf, ADCBufCC26X2_CMD_ACQUIRE_ADC_SEMAPHORE, NULL);

    // Configure the conversion structure
    gADCData.continuousConversion.arg = NULL;
    gADCData.continuousConversion.adcChannel = gADCData.A2DCfg.ADCBufChannel;
    gADCData.continuousConversion.sampleBuffer = gADCData.pBuffer;
    gADCData.continuousConversion.sampleBufferTwo = NULL;
    gADCData.continuousConversion.samplesRequestedCount = gADCData.A2DCfg.NumOfSamples;



    // Start converting.
    if (ADCBuf_STATUS_SUCCESS != ADCBuf_convert(gADCData.adcBuf, &gADCData.continuousConversion, 1))
    {
    // Convert failed
    break;
    }
  • Thanks for sharing Moshe,

    Could you also elaborate on when the exception happens more exactly? Based on the callstack you provided, I can see that you are inside the Swi, now the question is how you got there. Did you get there directly following the ADCBuf open, or following the convert?
  • Hi M-W,

    I get there directly following the 'ADCBuf open'.
  • Hi Moshe,

    Are you still applying the fix proposed to you in this thread (the post marked as resolved)?

    e2e.ti.com/.../759875
  • Hi Aviv,

    This sounds strange, in that case I would assume you are actually not having the exclusive access to the ADC that you assume you have.

    I can see that you don't check the return value of the "ADCBufCC26X2_CMD_ACQUIRE_ADC_SEMAPHORE" call, could you do this and make sure that you are actually successful in acquiring the ADC semaphore before proceeding?

  • Hi M-W,

    OK, Thanks.
    I will implement checking the return value of "ADCBufCC26X2_CMD_ACQUIRE_ADC_SEMAPHORE" call, and I will update.
  • Hi Moshe,

    Do you have any update on the issue?
  • Hi M-W,

    still in tests. I will update as soon as possible.
  • Hi M-W,

    I am Implemented reading of the return value of "ADCBufCC26X2_CMD_ACQUIRE_ADC_SEMAPHORE" call, and the HW Exception issue still occurred.

    ......
    // Control ADC Hardware semaphore to keep while converting //
    ADCBuf_control(gADCData.adcBuf, ADCBufCC26X2_CMD_KEEP_ADC_SEMAPHORE, NULL);
    status = ADCBuf_control(gADCData.adcBuf, ADCBufCC26X2_CMD_ACQUIRE_ADC_SEMAPHORE, NULL);

    if(status != 0)
    {
    // Convert failed
    status = 0;
    break;
    }

    ...

    the status always == 0. and the HW exception that I described still occurs.
  • Hi Moshe,

    If I remember correctly, you also use the "Peripheral Sharing" mechanism on the Sensor Controller Side right? Would it be possible for you to share the current ADCBuf driver you use so that I can look closer at it and try it out on my side to see if I can figure anything out.

     As for the Sensor Controller, are you in control of when it uses the ADC to the level where you know it is currently not trying to use it, or is it continuously trying to sample if it get the semaphore? 

  • A2D.c
    #define __LOG_MODULE_FACILITY__ LOG_FACILITY_GENERAL
    
    /***************************************************************************//**
     * @file A2D.c
     * @brief
     *  A/D driver
     *
     *
     *******************************************************************************
     * @section License
     * <b>Copyright (c) 2017 ESI - Essence Security Ltd.</b>
     *******************************************************************************
     *
     *  All Rights Reserved.
     *  Licensed Material-Property of Essence Security Ltd.
     *  This software is made available solely pursuant to the terms
     *  of ESI Ltd license agment which  governs its use.
     *  This code and the information contained in it are  proprietary
     *  and confidential to Essence Security Ltd.
     *  No person is allowed to copy, reprint, reproduce or publish
     *  any part of this code, nor disclose its contents to others,
     *  nor make any use of it, nor allow or assist others to make
     *  any use of it unless by prior written express authorization of
     *  ESI and then, only to the extent authorized.
     *
     ******************************************************************************/
    
    #include <assert.h>
    #include <termio.h>
    #include <string.h>
    #include <ctype.h>
    #include <stdlib.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/drivers/ADC.h>
    #include <ti/drivers/ADCBuf.h>
    #include <ti/drivers/adcbuf/ADCBufCC26X2.h>
    
    #include "A2D.h"
    #include "gpioHal.h"
    #include "sysOsEsi.h"
    #include "logger.h"
    
     // The main session information for this module
    typedef struct
    {
    
        bool                            initialized;            // a flag that tells us if we ware initialized or not
        ADCBuf_Handle                   adcBuf;
        ADCBuf_Params                   adcBufParams;
        ADCBuf_Conversion               continuousConversion;
        ADCBufCC26X2_ParamsExtension    adcBufParamsExt;
        S_osEsiEvent                    EventHandle;                    // OS Event Object
        uint16_t                        average;
        uint16_t                        *pBuffer;
        uint32_t                        *pmicoVolttBuffer;
        uint32_t                        micoVoltAvg;
        A2D_SampleRsltCb                SampleRsltCb;
        A2D_Config_s                    A2DCfg;
        uint8_t                         ADCBufChunnel;
        uint8_t                         ADCBufId;
        S_osEsiSemaphore                A2DSem;                                 // A2D  semaphore
    } ADC_DATA_T;
    
    // Holds all of the ADC module data
    ADC_DATA_T gADCData = { .initialized = false };
    
    // Internal events
    #define ADC_SAMPLE_READY_EVENT                (1<<0)
    
    
    
    /*!*****************************************************************************
     *  @brief
     * This function is called whenever a buffer is full.
     * The content of the buffer is then sent back to the caller via a callback
     *
     *
     ******************************************************************************/
    
    void ADC_BufCallback(ADCBuf_Handle handle, ADCBuf_Conversion *conversion,
        void *completedADCBuffer, uint32_t completedChannel)
    
    {
        int i;
        assert(gADCData.initialized); // Module must be initialized first
    
        // Adjust raw ADC values and convert them to microvolts
        ADCBuf_adjustRawValues(handle, completedADCBuffer, gADCData.A2DCfg.NumOfSamples, completedChannel);
        ADCBuf_convertAdjustedToMicroVolts(handle, completedChannel, completedADCBuffer, gADCData.pmicoVolttBuffer, gADCData.A2DCfg.NumOfSamples);
    
        // Get the average, accumulate and divide by the samples count
        gADCData.average = 0;
        for(i = 0; i< gADCData.A2DCfg.NumOfSamples;i++)
            gADCData.average += (uint16_t)gADCData.pBuffer[i];
        gADCData.average = (gADCData.average / gADCData.A2DCfg.NumOfSamples);
    
        // Get the average in micro-volt
        gADCData.micoVoltAvg = 0;
        for (i = 0; i< gADCData.A2DCfg.NumOfSamples;i++)
            gADCData.micoVoltAvg += gADCData.pmicoVolttBuffer[i];
        gADCData.micoVoltAvg = (gADCData.micoVoltAvg / gADCData.A2DCfg.NumOfSamples);
    
        // Inform the caller
        if (gADCData.SampleRsltCb)
            gADCData.SampleRsltCb(gADCData.pmicoVolttBuffer,gADCData.average,gADCData.micoVoltAvg);
    
        // Inject event to notify about result
    	sysOsEsi_SignalSet(&gADCData.EventHandle, ADC_SAMPLE_READY_EVENT);
    }
    
    /*!*****************************************************************************
     *  @brief
     *
     *
     *
     ******************************************************************************/
    
    void A2D_Init(void)
    {
    
        memset(&gADCData, 0, sizeof(gADCData));
    
        ADCBuf_init(); // Call driver init functions
    
        // Allocate buffer for the sampling, use max size
        gADCData.pBuffer = (uint16_t*)malloc(A2D_MAX_ASMPLES * sizeof(uint16_t));
        assert(gADCData.pBuffer);
    
        // Allocate buffer for the microvolts converted buffer, use max size
        gADCData.pmicoVolttBuffer = (uint32_t*)malloc(A2D_MAX_ASMPLES * sizeof(uint32_t));
        assert(gADCData.pmicoVolttBuffer);
        sysOsEsi_SemaphoreCreate(&gADCData.A2DSem, 1);
    
        // Create event used internally
        assert(sysOsEsi_SignalCreate(&gADCData.EventHandle) == StatusEsiSuccess);
    
        gADCData.initialized = true;
    }
    
    /*!*****************************************************************************
     *  @brief This function samples the A/D channel according to the
     *  config passed by pA2dConfig
     *  The result is the A/D digital count received by the caller
     *  task via the A2D_SampleRsltCb call-back
     *
     *
     ******************************************************************************/
    
    bool A2D_Sample(A2D_SampleRsltCb SampleRsltCb, A2D_Config_s *pA2dConfig)
    {
        uint32_t events;
        bool retVal = false;
        assert(gADCData.initialized); // Module must be initialized first
    
        sysOsEsi_SemaphoreWait(&gADCData.A2DSem, BIOS_WAIT_FOREVER);
    
        memcpy(&gADCData.A2DCfg, pA2dConfig, sizeof(A2D_Config_s));     // Store configuration
        gADCData.SampleRsltCb = SampleRsltCb;                           // Store the callers callback
    
        if (NULL != gADCData.A2DCfg.SpecialLoadCb)
        {
            // Turn on special load before measuring
            if (!gADCData.A2DCfg.SpecialLoadCb(true))
            {
                // Postpone battery level measurement
                sysOsEsi_SemaphorePost(&gADCData.A2DSem);
                return retVal;
            }
    
            /* wait for a special load to be applied
             * this is used when sampling battery
             * */
            sysOsEsi_Sleep(gADCData.A2DCfg.WaitLoad);
        }
    
        if(gADCData.A2DCfg.IsPowerLine)
        {
            // Turn the Battery measurement enable line
            GpioHal_setIO(gADCData.A2DCfg.PowerIO, gADCData.A2DCfg.IOPolarity);
            /* wait for measure enable
             * and sampling value to be stable
             * */
            sysOsEsi_Sleep(gADCData.A2DCfg.WaitPowerLine);
        }
    
        do
        {
            // Set up ADCBuf custom data
            gADCData.adcBufParamsExt.refSource = gADCData.A2DCfg.Vref;
            gADCData.adcBufParamsExt.inputScalingEnabled = gADCData.A2DCfg.IsScaling;
            gADCData.adcBufParamsExt.samplingDuration = gADCData.A2DCfg.SamplingDur;
    
            // Set up an ADCBuf peripheral
            ADCBuf_Params_init(&gADCData.adcBufParams);
            gADCData.adcBufParams.callbackFxn = ADC_BufCallback;
            gADCData.adcBufParams.recurrenceMode = ADCBuf_RECURRENCE_MODE_ONE_SHOT;
            gADCData.adcBufParams.returnMode = ADCBuf_RETURN_MODE_CALLBACK;
            gADCData.adcBufParams.samplingFrequency = gADCData.A2DCfg.frequencyHz; // Hz
            gADCData.adcBufParams.custom = &gADCData.adcBufParamsExt;
            gADCData.adcBuf = ADCBuf_open(gADCData.A2DCfg.ADCBufId, &gADCData.adcBufParams);
    
            if (NULL == gADCData.adcBuf)
            {
                // AdcBuf did not open correctly.
                break;
            }
    
            // Control ADC Hardware semaphore to keep while converting //
            ADCBuf_control(gADCData.adcBuf, ADCBufCC26X2_CMD_KEEP_ADC_SEMAPHORE, NULL);
            ADCBuf_control(gADCData.adcBuf, ADCBufCC26X2_CMD_ACQUIRE_ADC_SEMAPHORE, NULL);
    
            // Configure the conversion structure
            gADCData.continuousConversion.arg = NULL;
            gADCData.continuousConversion.adcChannel = gADCData.A2DCfg.ADCBufChannel;
            gADCData.continuousConversion.sampleBuffer = gADCData.pBuffer;
            gADCData.continuousConversion.sampleBufferTwo = NULL;
            gADCData.continuousConversion.samplesRequestedCount = gADCData.A2DCfg.NumOfSamples;
    
    
    
            // Start converting.
            if (ADCBuf_STATUS_SUCCESS != ADCBuf_convert(gADCData.adcBuf, &gADCData.continuousConversion, 1))
            {
                // Convert failed
                break;
            }
    
            // ADC conversion sequence begun successfully
            retVal = true;
    
        } while (0);
    
        if (retVal)
        {
            // ADC conversion is in progress & wait for conversion to complete
            if (StatusEsiSuccess == sysOsEsi_SignalWait(&gADCData.EventHandle, OSESI_ALL_EVENT_FLAGS, &events, 100))
            {
                if (events & ADC_SAMPLE_READY_EVENT)
                {
    #ifdef DEBUG
                    LOGT_I("%s: ADC driver has finished conversion sequence", sysOsEsi_GetTaskName());
    #endif
                }
            }
            else
            {
                retVal = false;
            }
        }
    
        // Measurement process finished - release semaphore, turn off load and measure enable line.
        if (gADCData.A2DCfg.IsPowerLine)
        {
            // Turn off the HW-Measurement line
            GpioHal_setIO(gADCData.A2DCfg.PowerIO, !gADCData.A2DCfg.IOPolarity);
        }
    
        if (NULL != gADCData.A2DCfg.SpecialLoadCb)
        {
            // Calling a callback for special load disable
            gADCData.A2DCfg.SpecialLoadCb(false);
        }
    
        // Measurement process finished - close ADC
        if (gADCData.adcBuf)
        {
            // Control ADC Hardware semaphore release  //
            ADCBuf_control(gADCData.adcBuf, ADCBufCC26X2_CMD_KEEP_ADC_SEMAPHORE_DISABLE, NULL);
            // Close the handle
            ADCBuf_close(gADCData.adcBuf);
    
            /* Release the ADC semaphore */
            AUXSMPHRelease(AUX_SMPH_2);
    
            gADCData.adcBuf = NULL;
        }
    
        // Release ADC driver
        sysOsEsi_SemaphorePost(&gADCData.A2DSem);
        return retVal;
    }
    
    
    

  • Hi M-W,

    A2D.c file and the Sensor Controller A2D implement picture are attached
  • Hi Moshe,

    I have tried to recreate the issue using the following example but without any luck:

    while(1) {
            // Do SCS reading
            scifResetTaskStructs(1 << SCIF_ADC_DATA_LOGGER_TASK_ID, 1 << SCIF_STRUCT_OUTPUT);
            uint32_t ret = scifExecuteTasksOnceNbl(1 << SCIF_ADC_DATA_LOGGER_TASK_ID);
            while(scifWaitOnNbl(0) != SCIF_SUCCESS);
    
            // Control ADC Hardware semaphore to keep while converting
            ADCBuf_Handle adcHandle = ADCBuf_open(CC1352R1_LAUNCHXL_ADCBUF0, &adcParams);
            ADCBuf_control(adcHandle, ADCBufCC26X2_CMD_KEEP_ADC_SEMAPHORE, NULL);
            ADCBuf_control(adcHandle, ADCBufCC26X2_CMD_ACQUIRE_ADC_SEMAPHORE, NULL);
    
            // Configure the conversion structure
            conv.arg = NULL;
            conv.adcChannel = CC1352R1_LAUNCHXL_ADCBUF0CHANNEL6;
            conv.sampleBuffer = buffer;
            conv.sampleBufferTwo = NULL;
            conv.samplesRequestedCount = 20;
    
            // Do the conversion
            uint32_t status = ADCBuf_convert(adcHandle, &conv, 1);
            if (status != ADCBuf_STATUS_SUCCESS) {
                while(1){};
            }
    
            // Control ADC Hardware semaphore release  //
            ADCBuf_control(adcHandle, ADCBufCC26X2_CMD_KEEP_ADC_SEMAPHORE_DISABLE, NULL);
            ADCBuf_close(adcHandle);
            /* Release the ADC semaphore */
            AUXSMPHRelease(AUX_SMPH_2);
            sleep(1);
        }

    Could you possibly share your version of the driver and/or a small example project which shows the issue that I can run?

  • Hi Moshe,

    This seems to be related to the fact that you do not own the semaphore prior to opening the ADCBuf driver. A workaround for this is to perform a small hack when opening the driver:

    // Acquire semaphore
    AUXSMPHAcquire(AUX_SMPH_2);
    ADCBuf_Handle adcHandle = ADCBuf_open(CC1352R1_LAUNCHXL_ADCBUF0, &adcParams);
    // Control ADC Hardware semaphore to keep while converting
    ADCBuf_control(adcHandle, ADCBufCC26X2_CMD_KEEP_ADC_SEMAPHORE, NULL);
    // Manually set the semaphore to be in possession of the driver
    ((ADCBufCC26X2_Object *) adcHandle->object)->adcSemaphoreInPossession = true;
    

  • Hi M-W,

    after some tests, it seems that this workaround solves this issue.
    Thanks.