Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / mtb-pdl-cat1 / drivers / source / cy_profile.c
@Dustin Crossman Dustin Crossman on 4 Jun 2021 16 KB Fix file modes.
/***************************************************************************//**
* \file cy_profile.c
* \version 1.30
*
* Provides an API declaration of the energy profiler (EP) driver.
*
********************************************************************************
* \copyright
* Copyright 2016-2020 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#include "cy_device.h"

#if defined (CY_IP_MXPROFILE)

#include "cy_profile.h"
#include <string.h>

#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */

/* Number of elements in an array */
#define CY_N_ELMTS(a) (sizeof(a)/sizeof((a)[0]))

static cy_en_profile_status_t Cy_Profile_IsPtrValid(const cy_stc_profile_ctr_ptr_t ctrAddr);

/* Internal structure - Control and status information for each counter */
static cy_stc_profile_ctr_t cy_ep_ctrs[CY_EP_CNT_NR];


/* ========================================================================== */
/* =====================     LOCAL FUNCTION SECTION    ====================== */
/* ========================================================================== */
/*******************************************************************************
* Function Name: Cy_Profile_IsPtrValid
****************************************************************************//**
*
* Local utility function: reports (1) whether or not a given pointer points into
* the cy_ep_ctrs[] array, and (2) whether the counter has been assigned.
*
* \param ctrAddr The handle to (address of) the assigned counter
*
* \return CY_PROFILE_SUCCESS, or CY_PROFILE_BAD_PARAM for invalid ctrAddr or counter not
* in use.
*
*******************************************************************************/
static cy_en_profile_status_t Cy_Profile_IsPtrValid(const cy_stc_profile_ctr_ptr_t ctrAddr)
{
    cy_en_profile_status_t retStatus = CY_PROFILE_BAD_PARAM;

    /* check for valid ctrAddr */
    uint32_t p_epCtrs = (uint32_t)cy_ep_ctrs;
    if ((p_epCtrs <= (uint32_t)ctrAddr) && ((uint32_t)ctrAddr < (p_epCtrs + (uint32_t)sizeof(cy_ep_ctrs))))
    {
        if (ctrAddr->used != 0u) /* check for counter being used */
        {
            retStatus = CY_PROFILE_SUCCESS;
        }
    }
    return (retStatus);
}


/* ========================================================================== */
/* ====================    INTERRUPT FUNCTION SECTION    ==================== */
/* ========================================================================== */
/*******************************************************************************
* Function Name: Cy_Profile_ISR
****************************************************************************//**
*
* EP interrupt handler: Increments the overflow member of the counter structure,
* for each counter that is in use and has an overflow.
*
* This handler is not configured or used automatically. You must configure the
* interrupt handler for the EP, using Cy_SysInt_Init(). Typically you configure
* the system to use \ref Cy_Profile_ISR() as the overflow interrupt handler. You
* can provide a custom interrupt handler to perform additional operations if
* required. Your handler can call \ref Cy_Profile_ISR() to handle counter
* overflow.
*
*******************************************************************************/
void Cy_Profile_ISR(void)
{
    uint32_t ctr = 0UL;

    /* Grab a copy of the overflow register. Each bit in the register indicates
       whether or not the respective counter has overflowed. */
    uint32_t ovflowBits = _FLD2VAL(PROFILE_INTR_MASKED_CNT_OVFLW, PROFILE_INTR_MASKED);

    PROFILE_INTR = ovflowBits; /* clear the sources of the interrupts */

    /* scan through the overflow bits, i.e., for each counter */
    while((ctr < CY_EP_CNT_NR) && (ovflowBits != 0UL))
    {
        /* Increment the overflow bit only if the counter is being used.
           (which should always be the case.) */
        if (((ovflowBits & 1UL) != 0UL) && (cy_ep_ctrs[ctr].used != 0u))
        {
            cy_ep_ctrs[ctr].overflow++;
        }
        ovflowBits >>= 1; /* check the next bit, by shifting it into the LS position */
        ctr++;
    }
}


/* ========================================================================== */
/* ==================      GENERAL PROFILE FUNCTIONS     ==================== */
/* ========================================================================== */
/*******************************************************************************
* Function Name: Cy_Profile_StartProfiling
****************************************************************************//**
*
* Starts the profiling/measurement window.
*
* This operation allows the enabled profile counters to start counting.
*
* \note The profile interrupt should be enabled before calling this function
* for the firmware to be notified when a counter overflow occurs.
*
* \funcusage
* \snippet profile/snippet/main.c snippet_Cy_Profile_StartProfiling
*
*******************************************************************************/
void Cy_Profile_StartProfiling(void)
{
    uint32_t i = 0UL;

    /* clear all of the counter array overflow variables */
    while (i < CY_N_ELMTS(cy_ep_ctrs))
    {
        cy_ep_ctrs[i++].overflow = 0UL;
    }
    /* send the hardware command */
    PROFILE_CMD = CY_PROFILE_START_TR;
}


/* ========================================================================== */
/* ===================    COUNTER FUNCTIONS SECTION    ====================== */
/* ========================================================================== */
/*******************************************************************************
* Function Name: Cy_Profile_ClearConfiguration
****************************************************************************//**
*
* Clears all counter configurations and sets all counters and overflow counters
* to 0. Calls Cy_Profile_ClearCounters() to clear counter registers.
*
* \funcusage
* \snippet profile/snippet/main.c snippet_Cy_Profile_ClearConfiguration
*
*******************************************************************************/
void Cy_Profile_ClearConfiguration(void)
{
    (void)memset((void *)cy_ep_ctrs, 0, sizeof(cy_ep_ctrs));
    Cy_Profile_ClearCounters();
}


/*******************************************************************************
* Function Name: Cy_Profile_ConfigureCounter
****************************************************************************//**
*
* Configures and assigns a hardware profile counter to the list of used counters.
*
* This function assigns an available profile counter to a slot in the internal
* software data structure and returns the handle for that slot location. The data
* structure is used to keep track of the counter status and to implement a 64-bit
* profile counter. If no counter slots are available, the function returns a
* NULL pointer.
*
* \param monitor The monitor source number
*
* \param duration Events are monitored (0), or duration is monitored (1)
*
* \param refClk Counter reference clock
*
* \param weight Weighting factor for the counter value
*
* \return A pointer to the counter data structure. NULL if no counter is
* available.
*
* \funcusage
* \snippet profile/snippet/main.c snippet_Cy_Profile_ConfigureCounter
*
*******************************************************************************/
cy_stc_profile_ctr_ptr_t Cy_Profile_ConfigureCounter(en_ep_mon_sel_t monitor, cy_en_profile_duration_t duration,
                                                     cy_en_profile_ref_clk_t refClk,  uint32_t weight)
{
    CY_ASSERT_L1(CY_PROFILE_IS_MONITOR_VALID(monitor));
    CY_ASSERT_L3(CY_PROFILE_IS_DURATION_VALID(duration));
    CY_ASSERT_L3(CY_PROFILE_IS_REFCLK_VALID(refClk));

    cy_stc_profile_ctr_ptr_t retVal = NULL; /* error value if no counter is available */
    uint8_t i = 0u;

    /* Scan through the counters for an unused one */
    while (i < CY_EP_CNT_NR)
    {
        if(cy_ep_ctrs[i].used == 0u)
        {
            break;
        }
        i++;
    }
    if (i < CY_EP_CNT_NR)
    { /* found one, fill in its data structure */
        cy_ep_ctrs[i].ctrNum = i;
        cy_ep_ctrs[i].used = 1u;
        cy_ep_ctrs[i].cntAddr = (PROFILE_CNT_STRUCT_Type *)&(PROFILE_CNT_STRUCT[i]);
        cy_ep_ctrs[i].ctlRegVals.cntDuration = duration;
        cy_ep_ctrs[i].ctlRegVals.refClkSel = refClk;
        cy_ep_ctrs[i].ctlRegVals.monSel = monitor;
        cy_ep_ctrs[i].overflow = 0UL;
        cy_ep_ctrs[i].weight = weight;
        /* Pass back the handle to (address of) the counter data structure */
        retVal = &cy_ep_ctrs[i];

        /* Load the CTL register bitfields of the assigned counter. */
        retVal->cntAddr->CTL =
            _VAL2FLD(PROFILE_CNT_STRUCT_CTL_CNT_DURATION, retVal->ctlRegVals.cntDuration) |
            _VAL2FLD(PROFILE_CNT_STRUCT_CTL_REF_CLK_SEL,  retVal->ctlRegVals.refClkSel)   |
            _VAL2FLD(PROFILE_CNT_STRUCT_CTL_MON_SEL,      retVal->ctlRegVals.monSel);

    }
    return (retVal);
}


/*******************************************************************************
* Function Name: Cy_Profile_FreeCounter
****************************************************************************//**
*
* Frees up a counter from a previously-assigned monitor source.
*
* \ref Cy_Profile_ConfigureCounter() must have been called for this counter
* before calling this function.
*
* \param ctrAddr The handle to the assigned counter (returned by calling
* \ref Cy_Profile_ConfigureCounter()).
*
* \return
* Status of the operation.
*
* \note The counter is not disabled by this function.
*
* \funcusage
* \snippet profile/snippet/main.c snippet_Cy_Profile_FreeCounter
*
*******************************************************************************/
cy_en_profile_status_t Cy_Profile_FreeCounter(cy_stc_profile_ctr_ptr_t ctrAddr)
{
   cy_en_profile_status_t retStatus = CY_PROFILE_BAD_PARAM;

    retStatus = Cy_Profile_IsPtrValid(ctrAddr);
    if (retStatus == CY_PROFILE_SUCCESS)
    {
        ctrAddr->used = 0u;
    }
    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_Profile_EnableCounter
****************************************************************************//**
*
* Enables an assigned counter.
*
* \ref Cy_Profile_ConfigureCounter() must have been called for this counter
* before calling this function.
*
* \param ctrAddr The handle to the assigned counter, (returned by calling
* \ref Cy_Profile_ConfigureCounter()).
*
* \return
* Status of the operation.
*
* \funcusage
* \snippet profile/snippet/main.c snippet_Cy_Profile_EnableCounter
*
*******************************************************************************/
cy_en_profile_status_t Cy_Profile_EnableCounter(cy_stc_profile_ctr_ptr_t ctrAddr)
{
    cy_en_profile_status_t retStatus = Cy_Profile_IsPtrValid(ctrAddr);

    if (CY_PROFILE_SUCCESS == retStatus)
    {
        /* set the ENABLED bit */
        ctrAddr->cntAddr->CTL |= _VAL2FLD(PROFILE_CNT_STRUCT_CTL_ENABLED, 1UL);
        /* set the INTR_MASK bit for the counter being used */
        PROFILE_INTR_MASK |= (1UL << (ctrAddr->ctrNum));
    }

    return (retStatus);
}


/*******************************************************************************
* Function Name: Cy_Profile_DisableCounter
****************************************************************************//**
*
* Disables an assigned counter.
*
* \ref Cy_Profile_ConfigureCounter() must have been called for this counter
* before calling this function.
*
* \param ctrAddr The handle to the assigned counter, (returned by calling
* \ref Cy_Profile_ConfigureCounter()).
*
* \return
* Status of the operation.
*
* \funcusage
* \snippet profile/snippet/main.c snippet_Cy_Profile_DisableCounter
*
*******************************************************************************/
cy_en_profile_status_t Cy_Profile_DisableCounter(cy_stc_profile_ctr_ptr_t ctrAddr)
{
    cy_en_profile_status_t retStatus = Cy_Profile_IsPtrValid(ctrAddr);

    if (CY_PROFILE_SUCCESS == retStatus)
    {
        /* clear the ENABLED bit */
        ctrAddr->cntAddr->CTL &= ~(_VAL2FLD(PROFILE_CNT_STRUCT_CTL_ENABLED, 1UL));
        /* clear the INTR_MASK bit for the counter being used */
        PROFILE_INTR_MASK &= ~(1UL << (ctrAddr->ctrNum));
    }

    return (retStatus);
}


/* ========================================================================== */
/* ==================    CALCULATION FUNCTIONS SECTION    =================== */
/* ========================================================================== */
/*******************************************************************************
* Function Name: Cy_Profile_GetRawCount
****************************************************************************//**
*
* Reports the raw count value for a specified counter.
*
* \param ctrAddr The handle to the assigned counter, (returned by calling
* \ref Cy_Profile_ConfigureCounter()).
*
* \param result Output parameter used to write in the result.
*
* \return
* Status of the operation.
*
* \funcusage
* \snippet profile/snippet/main.c snippet_Cy_Profile_GetRawCount
*
*******************************************************************************/
cy_en_profile_status_t Cy_Profile_GetRawCount(cy_stc_profile_ctr_ptr_t ctrAddr, uint64_t *result)
{
    cy_en_profile_status_t retStatus = Cy_Profile_IsPtrValid(ctrAddr);

    if ((result != NULL) && (CY_PROFILE_SUCCESS == retStatus))
    {
        /* read the counter control register, and the counter current value */
        ctrAddr->ctlReg = ctrAddr->cntAddr->CTL;
        ctrAddr->cntReg = ctrAddr->cntAddr->CNT;

        /* report the count with overflow */
        *result = ((uint64_t)(ctrAddr->overflow) << 32) | (uint64_t)(ctrAddr->cntReg);
    }

    return (retStatus);
}

/*******************************************************************************
* Function Name: Cy_Profile_GetWeightedCount
****************************************************************************//**
*
* Reports the count value for a specified counter, multiplied by the weight
* factor for that counter.
*
* \param ctrAddr The handle to the assigned counter, (returned by calling
* \ref Cy_Profile_ConfigureCounter()).
*
* \param result Output parameter used to write in the result.
*
* \return
* Status of the operation.
*
* \funcusage
* \snippet profile/snippet/main.c snippet_Cy_Profile_GetWeightedCount
*
*******************************************************************************/
cy_en_profile_status_t Cy_Profile_GetWeightedCount(cy_stc_profile_ctr_ptr_t ctrAddr, uint64_t *result)
{
    uint64_t temp;
    cy_en_profile_status_t retStatus = Cy_Profile_GetRawCount(ctrAddr, &temp);

    if ((result != NULL) && (CY_PROFILE_SUCCESS == retStatus))
    {
        /* calculate weighted count */
        *result = temp * (uint64_t)(ctrAddr->weight);
    }

    return (retStatus);
}

/*******************************************************************************
* Function Name: Cy_Profile_GetSumWeightedCounts
****************************************************************************//**
*
* Reports the weighted sum result of the first n number of counter count values
* starting from the specified profile counter data structure base address.
*
* Each count value is multiplied by its weighing factor before the summing
* operation is performed.
*
* \param ptrsArray Base address of the profile counter data structure
*
* \param numCounters Number of measured counters in ptrsArray[]
*
* \return
* The weighted sum of the specified counters
*
* \funcusage
* \snippet profile/snippet/main.c snippet_Cy_Profile_GetSumWeightedCounts
*
*******************************************************************************/
uint64_t Cy_Profile_GetSumWeightedCounts(cy_stc_profile_ctr_ptr_t ptrsArray[],
                                    uint32_t numCounters)
{
    uint64_t daSum = (uint64_t)0UL;

    CY_ASSERT_L2(CY_PROFILE_IS_CNT_VALID(numCounters));

    if(ptrsArray != NULL)
    {
        uint64_t num;
        uint32_t i;

        for (i = 0UL; i < numCounters; i++)
        {
            /* ignore error reported by Ep_GetWeightedCount() */
            if (CY_PROFILE_SUCCESS == Cy_Profile_GetWeightedCount(ptrsArray[i], &num))
            {
                daSum += num;
            }
        }
    }

    return (daSum);
}

#if defined(__cplusplus)
}
#endif /* __cplusplus */

#endif /* CY_IP_MXPROFILE */

/* [] END OF FILE */