1 /***************************************************************************//**
2 * \file cy_profile.c
3 * \version 1.30
4 *
5 * Provides an API declaration of the energy profiler (EP) driver.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2016-2020 Cypress Semiconductor Corporation
10 * SPDX-License-Identifier: Apache-2.0
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *******************************************************************************/
24
25 #include "cy_device.h"
26
27 #if defined (CY_IP_MXPROFILE)
28
29 #include "cy_profile.h"
30 #include <string.h>
31
32 #if defined(__cplusplus)
33 extern "C" {
34 #endif /* __cplusplus */
35
36 /* Number of elements in an array */
37 #define CY_N_ELMTS(a) (sizeof(a)/sizeof((a)[0]))
38
39 static cy_en_profile_status_t Cy_Profile_IsPtrValid(const cy_stc_profile_ctr_ptr_t ctrAddr);
40
41 /* Internal structure - Control and status information for each counter */
42 static cy_stc_profile_ctr_t cy_ep_ctrs[CY_EP_CNT_NR];
43
44
45 /* ========================================================================== */
46 /* ===================== LOCAL FUNCTION SECTION ====================== */
47 /* ========================================================================== */
48 /*******************************************************************************
49 * Function Name: Cy_Profile_IsPtrValid
50 ****************************************************************************//**
51 *
52 * Local utility function: reports (1) whether or not a given pointer points into
53 * the cy_ep_ctrs[] array, and (2) whether the counter has been assigned.
54 *
55 * \param ctrAddr The handle to (address of) the assigned counter
56 *
57 * \return CY_PROFILE_SUCCESS, or CY_PROFILE_BAD_PARAM for invalid ctrAddr or counter not
58 * in use.
59 *
60 *******************************************************************************/
Cy_Profile_IsPtrValid(const cy_stc_profile_ctr_ptr_t ctrAddr)61 static cy_en_profile_status_t Cy_Profile_IsPtrValid(const cy_stc_profile_ctr_ptr_t ctrAddr)
62 {
63 cy_en_profile_status_t retStatus = CY_PROFILE_BAD_PARAM;
64
65 /* check for valid ctrAddr */
66 uint32_t p_epCtrs = (uint32_t)cy_ep_ctrs;
67 if ((p_epCtrs <= (uint32_t)ctrAddr) && ((uint32_t)ctrAddr < (p_epCtrs + (uint32_t)sizeof(cy_ep_ctrs))))
68 {
69 if (ctrAddr->used != 0u) /* check for counter being used */
70 {
71 retStatus = CY_PROFILE_SUCCESS;
72 }
73 }
74 return (retStatus);
75 }
76
77
78 /* ========================================================================== */
79 /* ==================== INTERRUPT FUNCTION SECTION ==================== */
80 /* ========================================================================== */
81 /*******************************************************************************
82 * Function Name: Cy_Profile_ISR
83 ****************************************************************************//**
84 *
85 * EP interrupt handler: Increments the overflow member of the counter structure,
86 * for each counter that is in use and has an overflow.
87 *
88 * This handler is not configured or used automatically. You must configure the
89 * interrupt handler for the EP, using Cy_SysInt_Init(). Typically you configure
90 * the system to use \ref Cy_Profile_ISR() as the overflow interrupt handler. You
91 * can provide a custom interrupt handler to perform additional operations if
92 * required. Your handler can call \ref Cy_Profile_ISR() to handle counter
93 * overflow.
94 *
95 *******************************************************************************/
Cy_Profile_ISR(void)96 void Cy_Profile_ISR(void)
97 {
98 uint32_t ctr = 0UL;
99
100 /* Grab a copy of the overflow register. Each bit in the register indicates
101 whether or not the respective counter has overflowed. */
102 uint32_t ovflowBits = _FLD2VAL(PROFILE_INTR_MASKED_CNT_OVFLW, PROFILE_INTR_MASKED);
103
104 PROFILE_INTR = ovflowBits; /* clear the sources of the interrupts */
105
106 /* scan through the overflow bits, i.e., for each counter */
107 while((ctr < CY_EP_CNT_NR) && (ovflowBits != 0UL))
108 {
109 /* Increment the overflow bit only if the counter is being used.
110 (which should always be the case.) */
111 if (((ovflowBits & 1UL) != 0UL) && (cy_ep_ctrs[ctr].used != 0u))
112 {
113 cy_ep_ctrs[ctr].overflow++;
114 }
115 ovflowBits >>= 1; /* check the next bit, by shifting it into the LS position */
116 ctr++;
117 }
118 }
119
120
121 /* ========================================================================== */
122 /* ================== GENERAL PROFILE FUNCTIONS ==================== */
123 /* ========================================================================== */
124 /*******************************************************************************
125 * Function Name: Cy_Profile_StartProfiling
126 ****************************************************************************//**
127 *
128 * Starts the profiling/measurement window.
129 *
130 * This operation allows the enabled profile counters to start counting.
131 *
132 * \note The profile interrupt should be enabled before calling this function
133 * for the firmware to be notified when a counter overflow occurs.
134 *
135 * \funcusage
136 * \snippet profile/snippet/main.c snippet_Cy_Profile_StartProfiling
137 *
138 *******************************************************************************/
Cy_Profile_StartProfiling(void)139 void Cy_Profile_StartProfiling(void)
140 {
141 uint32_t i = 0UL;
142
143 /* clear all of the counter array overflow variables */
144 while (i < CY_N_ELMTS(cy_ep_ctrs))
145 {
146 cy_ep_ctrs[i++].overflow = 0UL;
147 }
148 /* send the hardware command */
149 PROFILE_CMD = CY_PROFILE_START_TR;
150 }
151
152
153 /* ========================================================================== */
154 /* =================== COUNTER FUNCTIONS SECTION ====================== */
155 /* ========================================================================== */
156 /*******************************************************************************
157 * Function Name: Cy_Profile_ClearConfiguration
158 ****************************************************************************//**
159 *
160 * Clears all counter configurations and sets all counters and overflow counters
161 * to 0. Calls Cy_Profile_ClearCounters() to clear counter registers.
162 *
163 * \funcusage
164 * \snippet profile/snippet/main.c snippet_Cy_Profile_ClearConfiguration
165 *
166 *******************************************************************************/
Cy_Profile_ClearConfiguration(void)167 void Cy_Profile_ClearConfiguration(void)
168 {
169 (void)memset((void *)cy_ep_ctrs, 0, sizeof(cy_ep_ctrs));
170 Cy_Profile_ClearCounters();
171 }
172
173
174 /*******************************************************************************
175 * Function Name: Cy_Profile_ConfigureCounter
176 ****************************************************************************//**
177 *
178 * Configures and assigns a hardware profile counter to the list of used counters.
179 *
180 * This function assigns an available profile counter to a slot in the internal
181 * software data structure and returns the handle for that slot location. The data
182 * structure is used to keep track of the counter status and to implement a 64-bit
183 * profile counter. If no counter slots are available, the function returns a
184 * NULL pointer.
185 *
186 * \param monitor The monitor source number
187 *
188 * \param duration Events are monitored (0), or duration is monitored (1)
189 *
190 * \param refClk Counter reference clock
191 *
192 * \param weight Weighting factor for the counter value
193 *
194 * \return A pointer to the counter data structure. NULL if no counter is
195 * available.
196 *
197 * \funcusage
198 * \snippet profile/snippet/main.c snippet_Cy_Profile_ConfigureCounter
199 *
200 *******************************************************************************/
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)201 cy_stc_profile_ctr_ptr_t Cy_Profile_ConfigureCounter(en_ep_mon_sel_t monitor, cy_en_profile_duration_t duration,
202 cy_en_profile_ref_clk_t refClk, uint32_t weight)
203 {
204 CY_ASSERT_L1(CY_PROFILE_IS_MONITOR_VALID(monitor));
205 CY_ASSERT_L3(CY_PROFILE_IS_DURATION_VALID(duration));
206 CY_ASSERT_L3(CY_PROFILE_IS_REFCLK_VALID(refClk));
207
208 cy_stc_profile_ctr_ptr_t retVal = NULL; /* error value if no counter is available */
209 uint8_t i = 0u;
210
211 /* Scan through the counters for an unused one */
212 while (i < CY_EP_CNT_NR)
213 {
214 if(cy_ep_ctrs[i].used == 0u)
215 {
216 break;
217 }
218 i++;
219 }
220 if (i < CY_EP_CNT_NR)
221 { /* found one, fill in its data structure */
222 cy_ep_ctrs[i].ctrNum = i;
223 cy_ep_ctrs[i].used = 1u;
224 cy_ep_ctrs[i].cntAddr = (PROFILE_CNT_STRUCT_Type *)&(PROFILE_CNT_STRUCT[i]);
225 cy_ep_ctrs[i].ctlRegVals.cntDuration = duration;
226 cy_ep_ctrs[i].ctlRegVals.refClkSel = refClk;
227 cy_ep_ctrs[i].ctlRegVals.monSel = monitor;
228 cy_ep_ctrs[i].overflow = 0UL;
229 cy_ep_ctrs[i].weight = weight;
230 /* Pass back the handle to (address of) the counter data structure */
231 retVal = &cy_ep_ctrs[i];
232
233 /* Load the CTL register bitfields of the assigned counter. */
234 retVal->cntAddr->CTL =
235 _VAL2FLD(PROFILE_CNT_STRUCT_CTL_CNT_DURATION, retVal->ctlRegVals.cntDuration) |
236 _VAL2FLD(PROFILE_CNT_STRUCT_CTL_REF_CLK_SEL, retVal->ctlRegVals.refClkSel) |
237 _VAL2FLD(PROFILE_CNT_STRUCT_CTL_MON_SEL, retVal->ctlRegVals.monSel);
238
239 }
240 return (retVal);
241 }
242
243
244 /*******************************************************************************
245 * Function Name: Cy_Profile_FreeCounter
246 ****************************************************************************//**
247 *
248 * Frees up a counter from a previously-assigned monitor source.
249 *
250 * \ref Cy_Profile_ConfigureCounter() must have been called for this counter
251 * before calling this function.
252 *
253 * \param ctrAddr The handle to the assigned counter (returned by calling
254 * \ref Cy_Profile_ConfigureCounter()).
255 *
256 * \return
257 * Status of the operation.
258 *
259 * \note The counter is not disabled by this function.
260 *
261 * \funcusage
262 * \snippet profile/snippet/main.c snippet_Cy_Profile_FreeCounter
263 *
264 *******************************************************************************/
Cy_Profile_FreeCounter(cy_stc_profile_ctr_ptr_t ctrAddr)265 cy_en_profile_status_t Cy_Profile_FreeCounter(cy_stc_profile_ctr_ptr_t ctrAddr)
266 {
267 cy_en_profile_status_t retStatus = CY_PROFILE_BAD_PARAM;
268
269 retStatus = Cy_Profile_IsPtrValid(ctrAddr);
270 if (retStatus == CY_PROFILE_SUCCESS)
271 {
272 ctrAddr->used = 0u;
273 }
274 return (retStatus);
275 }
276
277
278 /*******************************************************************************
279 * Function Name: Cy_Profile_EnableCounter
280 ****************************************************************************//**
281 *
282 * Enables an assigned counter.
283 *
284 * \ref Cy_Profile_ConfigureCounter() must have been called for this counter
285 * before calling this function.
286 *
287 * \param ctrAddr The handle to the assigned counter, (returned by calling
288 * \ref Cy_Profile_ConfigureCounter()).
289 *
290 * \return
291 * Status of the operation.
292 *
293 * \funcusage
294 * \snippet profile/snippet/main.c snippet_Cy_Profile_EnableCounter
295 *
296 *******************************************************************************/
Cy_Profile_EnableCounter(cy_stc_profile_ctr_ptr_t ctrAddr)297 cy_en_profile_status_t Cy_Profile_EnableCounter(cy_stc_profile_ctr_ptr_t ctrAddr)
298 {
299 cy_en_profile_status_t retStatus = Cy_Profile_IsPtrValid(ctrAddr);
300
301 if (CY_PROFILE_SUCCESS == retStatus)
302 {
303 /* set the ENABLED bit */
304 ctrAddr->cntAddr->CTL |= _VAL2FLD(PROFILE_CNT_STRUCT_CTL_ENABLED, 1UL);
305 /* set the INTR_MASK bit for the counter being used */
306 PROFILE_INTR_MASK |= (1UL << (ctrAddr->ctrNum));
307 }
308
309 return (retStatus);
310 }
311
312
313 /*******************************************************************************
314 * Function Name: Cy_Profile_DisableCounter
315 ****************************************************************************//**
316 *
317 * Disables an assigned counter.
318 *
319 * \ref Cy_Profile_ConfigureCounter() must have been called for this counter
320 * before calling this function.
321 *
322 * \param ctrAddr The handle to the assigned counter, (returned by calling
323 * \ref Cy_Profile_ConfigureCounter()).
324 *
325 * \return
326 * Status of the operation.
327 *
328 * \funcusage
329 * \snippet profile/snippet/main.c snippet_Cy_Profile_DisableCounter
330 *
331 *******************************************************************************/
Cy_Profile_DisableCounter(cy_stc_profile_ctr_ptr_t ctrAddr)332 cy_en_profile_status_t Cy_Profile_DisableCounter(cy_stc_profile_ctr_ptr_t ctrAddr)
333 {
334 cy_en_profile_status_t retStatus = Cy_Profile_IsPtrValid(ctrAddr);
335
336 if (CY_PROFILE_SUCCESS == retStatus)
337 {
338 /* clear the ENABLED bit */
339 ctrAddr->cntAddr->CTL &= ~(_VAL2FLD(PROFILE_CNT_STRUCT_CTL_ENABLED, 1UL));
340 /* clear the INTR_MASK bit for the counter being used */
341 PROFILE_INTR_MASK &= ~(1UL << (ctrAddr->ctrNum));
342 }
343
344 return (retStatus);
345 }
346
347
348 /* ========================================================================== */
349 /* ================== CALCULATION FUNCTIONS SECTION =================== */
350 /* ========================================================================== */
351 /*******************************************************************************
352 * Function Name: Cy_Profile_GetRawCount
353 ****************************************************************************//**
354 *
355 * Reports the raw count value for a specified counter.
356 *
357 * \param ctrAddr The handle to the assigned counter, (returned by calling
358 * \ref Cy_Profile_ConfigureCounter()).
359 *
360 * \param result Output parameter used to write in the result.
361 *
362 * \return
363 * Status of the operation.
364 *
365 * \funcusage
366 * \snippet profile/snippet/main.c snippet_Cy_Profile_GetRawCount
367 *
368 *******************************************************************************/
Cy_Profile_GetRawCount(cy_stc_profile_ctr_ptr_t ctrAddr,uint64_t * result)369 cy_en_profile_status_t Cy_Profile_GetRawCount(cy_stc_profile_ctr_ptr_t ctrAddr, uint64_t *result)
370 {
371 cy_en_profile_status_t retStatus = Cy_Profile_IsPtrValid(ctrAddr);
372
373 if ((result != NULL) && (CY_PROFILE_SUCCESS == retStatus))
374 {
375 /* read the counter control register, and the counter current value */
376 ctrAddr->ctlReg = ctrAddr->cntAddr->CTL;
377 ctrAddr->cntReg = ctrAddr->cntAddr->CNT;
378
379 /* report the count with overflow */
380 *result = ((uint64_t)(ctrAddr->overflow) << 32) | (uint64_t)(ctrAddr->cntReg);
381 }
382
383 return (retStatus);
384 }
385
386 /*******************************************************************************
387 * Function Name: Cy_Profile_GetWeightedCount
388 ****************************************************************************//**
389 *
390 * Reports the count value for a specified counter, multiplied by the weight
391 * factor for that counter.
392 *
393 * \param ctrAddr The handle to the assigned counter, (returned by calling
394 * \ref Cy_Profile_ConfigureCounter()).
395 *
396 * \param result Output parameter used to write in the result.
397 *
398 * \return
399 * Status of the operation.
400 *
401 * \funcusage
402 * \snippet profile/snippet/main.c snippet_Cy_Profile_GetWeightedCount
403 *
404 *******************************************************************************/
Cy_Profile_GetWeightedCount(cy_stc_profile_ctr_ptr_t ctrAddr,uint64_t * result)405 cy_en_profile_status_t Cy_Profile_GetWeightedCount(cy_stc_profile_ctr_ptr_t ctrAddr, uint64_t *result)
406 {
407 uint64_t temp;
408 cy_en_profile_status_t retStatus = Cy_Profile_GetRawCount(ctrAddr, &temp);
409
410 if ((result != NULL) && (CY_PROFILE_SUCCESS == retStatus))
411 {
412 /* calculate weighted count */
413 *result = temp * (uint64_t)(ctrAddr->weight);
414 }
415
416 return (retStatus);
417 }
418
419 /*******************************************************************************
420 * Function Name: Cy_Profile_GetSumWeightedCounts
421 ****************************************************************************//**
422 *
423 * Reports the weighted sum result of the first n number of counter count values
424 * starting from the specified profile counter data structure base address.
425 *
426 * Each count value is multiplied by its weighing factor before the summing
427 * operation is performed.
428 *
429 * \param ptrsArray Base address of the profile counter data structure
430 *
431 * \param numCounters Number of measured counters in ptrsArray[]
432 *
433 * \return
434 * The weighted sum of the specified counters
435 *
436 * \funcusage
437 * \snippet profile/snippet/main.c snippet_Cy_Profile_GetSumWeightedCounts
438 *
439 *******************************************************************************/
Cy_Profile_GetSumWeightedCounts(cy_stc_profile_ctr_ptr_t ptrsArray[],uint32_t numCounters)440 uint64_t Cy_Profile_GetSumWeightedCounts(cy_stc_profile_ctr_ptr_t ptrsArray[],
441 uint32_t numCounters)
442 {
443 uint64_t daSum = (uint64_t)0UL;
444
445 CY_ASSERT_L2(CY_PROFILE_IS_CNT_VALID(numCounters));
446
447 if(ptrsArray != NULL)
448 {
449 uint64_t num;
450 uint32_t i;
451
452 for (i = 0UL; i < numCounters; i++)
453 {
454 /* ignore error reported by Ep_GetWeightedCount() */
455 if (CY_PROFILE_SUCCESS == Cy_Profile_GetWeightedCount(ptrsArray[i], &num))
456 {
457 daSum += num;
458 }
459 }
460 }
461
462 return (daSum);
463 }
464
465 #if defined(__cplusplus)
466 }
467 #endif /* __cplusplus */
468
469 #endif /* CY_IP_MXPROFILE */
470
471 /* [] END OF FILE */
472