1 /***************************************************************************//**
2 * \file cy_profile.h
3 * \version 1.30
4 *
5 * Provides an API declaration of the energy profiler 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 /**
26 * \addtogroup group_energy_profiler
27 * \{
28 *
29 * The energy profiler driver is an API for configuring and using the profile
30 * hardware block.
31 *
32 * The functions and other declarations used in this driver are in cy_profile.h.
33 * You can include cy_pdl.h to get access to all functions
34 * and declarations in the PDL.
35 *
36 * The profile block enables measurement of the signal activity
37 * of select peripherals and monitor sources during a measurement window. Using
38 * these measurements, you can construct a profile of the energy consumed
39 * in the device by scaling the individual peripheral activities with appropriate
40 * scaling (weight) factors. This gives the application the ability to monitor
41 * the energy consumed by the internal resources with minimal CPU overhead and
42 * without external monitoring hardware.
43 *
44 * \section group_profile_details Details
45 *
46 * \subsection group_profile_hardware Profile Hardware
47 *
48 * The profile hardware consists of a number of profile counters that accept specific
49 * triggers for incrementing the count value. This allows the events of the source
50 * (such as the number of SCB0 bus accesses or the duration of time the BLE RX radio
51 * is active) to be counted during the measurement window. The available monitor
52 * sources in the device can be found in the en_ep_mon_sel_t enum in the device
53 * configuration file (e.g. psoc62_config.h). These can be sourced to any of the
54 * profile counters as triggers. There are two methods of using the monitor sources
55 * in a profile counter.
56 *
57 * - Event: The count value is incremented when a pulse event signal is seen by the
58 *   counter. This type of monitoring is suitable when the monitoring source of
59 *   interest needs to count the discrete events (such as the number of flash read
60 *   accesses) happening in the measurement window.
61 *
62 * - Duration: The count value is incremented at every clock edge while the monitor
63 *   signal is high. This type of monitoring is suitable when a signal is active for
64 *   a finite amount of time (such as the time the BLE TX radio is active) and the
65 *   duration must be expressed as number of clock cycles in the measurement window.
66 *
67 * Many of the available monitor sources are suitable for event type monitoring.
68 * Using a duration type on these signals may not give valuable information. Review
69 * the device TRM for more information on the monitor sources and detail on how they
70 * should be used.
71 *
72 * \subsection group_profile_measurement_types Measurement Types
73 *
74 * Depending on the item of interest, energy measurement can be performed by using
75 * the following methods.
76 *
77 * - Continuous measurement: A profile counter can be assigned a monitor signal of
78 *   constant 1 (PROFILE_ONE), which sets the counter to increment at every (assigned)
79 *   clock cycle. This can be used to give a reference time for the measurement window
80 *   and also allows the construction of timestamps. For example, a software controlled
81 *   GPIO can be "timestamped" by reading the counter value (on the fly) before it is
82 *   toggled. When the measurement window ends, the energy contribution caused by the
83 *   GPIO toggle can be incorporated into the final calculation.
84 *
85 * - Event measurement: Monitored events happening in a measurement window can be
86 *   used to increment a profile counter. This gives the activity numbers, which can
87 *   then be multiplied by the instantaneous power numbers associated with the source
88 *   to give the average energy consumption (Energy = Power x time). For example, the
89 *   energy consumed by an Operating System (OS) task can be estimated by monitoring
90 *   the processor's active cycle count (E.g. CPUSS_MONITOR_CM4) and the flash read
91 *   accesses (CPUSS_MONITOR_FLASH). Note that these activity numbers can also be
92 *   timestamped using the continuous measurement method to differentiate between the
93 *   different task switches. The activity numbers are then multiplied by the associated
94 *   processor and flash access power numbers to give the average energy consumed by
95 *   that task.
96 *
97 * - Duration measurement: A peripheral event such as the SMIF select signal can be
98 *   used by a profile counter to measure the time spent on XIP communication through the
99 *   SPI interface. This activity number can then be multiplied by the power associated
100 *   with that activity to give the average energy consumed by that block during the
101 *   measurement window. This type of monitoring should be performed only for signals
102 *   that are difficult to track in software. For example, a combination of interrupts
103 *   and timestamps can be used to track the activity of many peripherals in a continuous
104 *   monitoring model. However tracking the activity of signals such the BLE radio
105 *   should be done using the duration measurement method.
106 *
107 * - Low power measurement: The profile counters do not support measurement during chip
108 *   Deep Sleep, Hibernate, and off states. I.e. the profile counters are meant for active
109 *   run-time measurements only. To measure the time spent in low power modes (LPM),
110 *   a real-time clock (RTC) should be used. Take a timestamp before LPM entry and a
111 *   timestamp upon LPM exit in a continuous measurement model. Then multiply the difference
112 *   by the appropriate LPM power numbers.
113 *
114 * \subsection group_profile_usage Driver Usage
115 *
116 * At the highest level, the energy profiler must perform the following steps to
117 * obtain a measurement:
118 *
119 *  1. Initialize the profile hardware block.
120 *  2. Initialize the profile interrupt (profile_interrupt_IRQn).
121 *  3. Configure, initialize, and enable the profile counters.
122 *  4. Enable the profile interrupt and start the profiling/measurement window.
123 *  5. Perform run-time reads of the counters (if needed).
124 *  6. Disable the profile interrupt and stop the profiling/measurement window.
125 *  7. Read the counters and gather the results.
126 *  8. Calculate the energy consumption.
127 *
128 * Refer to the SysInt driver on the details of configuring the profile hardware interrupt.
129 *
130 * The profile interrupt triggers when a counter overflow event is detected on any of the
131 * enabled profile counters. A sample interrupt service routine Cy_Profile_ISR() is provided,
132 * which can be used to update the internal counter states stored in RAM. Refer to the
133 * Configuration Considerations for more information.
134 *
135 * \section group_profile_configuration Configuration Considerations
136 *
137 * Each counter is a 32-bit register that counts either a number of clock cycles,
138 * or a number of events. Overflowing the 32-bit register is possible. To address
139 * this issue, the driver implements a 32-bit overflow counter. Combined with the 32-bit
140 * register, this gives a 64-bit counter for each monitored source.
141 *
142 * When an overflow occurs, the profile hardware generates an interrupt. The interrupt is
143 * configured using the SysInt driver, where the sample interrupt handler Cy_Profile_ISR()
144 * can be used as the ISR. The ISR increments the overflow counter for each profiling counter
145 * and clears the interrupt.
146 *
147 * \section group_profile_more_information More Information
148 *
149 * See the profiler chapter of the device technical reference manual (TRM).
150 *
151 * \section group_profile_changelog Changelog
152 * <table class="doxtable">
153 *   <tr><th>Version</th><th>Changes</th><th>Reason for Change</th></tr>
154 *   <tr>
155 *     <td>1.30</td>
156 *     <td>Fixed MISRA 2012 violations.</td>
157 *     <td>MISRA 2012 compliance.</td>
158 *   </tr>
159 *   <tr>
160 *     <td>1.20.1</td>
161 *     <td>Minor documentation updates.</td>
162 *     <td>Documentation enhancement.</td>
163 *   </tr>
164 *   <tr>
165 *     <td>1.20</td>
166 *     <td>Updated API function \ref Cy_Profile_GetSumWeightedCounts().</td>
167 *     <td>Minor defect fixing: now the function supports the correct number of counters.</td>
168 *   </tr>
169 *   <tr>
170 *     <td rowspan="3">1.10</td>
171 *     <td>Flattened the organization of the driver source code into the single source directory and the single include directory.</td>
172 *     <td>Driver library directory-structure simplification.</td>
173 *   </tr>
174 *   <tr>
175 *     <td>Added register access layer. Use register access macros instead
176 *         of direct register access using dereferenced pointers.</td>
177 *     <td>Makes register access device-independent, so that the PDL does
178 *         not need to be recompiled for each supported part number.</td>
179 *   </tr>
180 *   <tr>
181 *     <td>Added parameter check asserts.</td>
182 *     <td>Driver defect fix.</td>
183 *   </tr>
184 *   <tr>
185 *     <td>1.0</td>
186 *     <td>Initial version</td>
187 *     <td></td>
188 *   </tr>
189 * </table>
190 *
191 * \defgroup group_profile_macros Macros
192 * \defgroup group_profile_functions Functions
193 * \{
194 *   \defgroup group_profile_functions_interrupt    Interrupt Functions
195 *   \defgroup group_profile_functions_general      General Functions
196 *   \defgroup group_profile_functions_counter      Counter Functions
197 *   \defgroup group_profile_functions_calculation  Calculation Functions
198 * \}
199 * \defgroup group_profile_data_structures Data Structures
200 * \defgroup group_profile_enums Enumerated Types
201 */
202 
203 #if !defined(CY_PROFILE_H)
204 #define CY_PROFILE_H
205 
206 #include "cy_device.h"
207 
208 #if defined (CY_IP_MXPROFILE)
209 
210 #include "cy_syslib.h"
211 #include <stddef.h>
212 
213 #if defined(__cplusplus)
214 extern "C" {
215 #endif /* __cplusplus */
216 
217 /** \addtogroup group_profile_macros
218 * \{
219 */
220 
221 /** Driver major version */
222 #define CY_PROFILE_DRV_VERSION_MAJOR  1
223 
224 /** Driver minor version */
225 #define CY_PROFILE_DRV_VERSION_MINOR  30
226 
227 /** Profile driver identifier */
228 #define CY_PROFILE_ID   CY_PDL_DRV_ID(0x1EU)
229 
230 /** Start profiling command for the CMD register */
231 #define CY_PROFILE_START_TR    1UL
232 
233 /** Stop profiling command for the CMD register */
234 #define CY_PROFILE_STOP_TR     2UL
235 
236 /** Command to clear all counter registers to 0 */
237 #define CY_PROFILE_CLR_ALL_CNT 0x100UL
238 
239 /** \} group_profile_macros */
240 
241 /***************************************
242 *        Constants
243 ***************************************/
244 
245 /** \cond INTERNAL */
246 
247 /* Parameter check macros */
248 #define CY_PROFILE_IS_MONITOR_VALID(monitor)    (CY_EP_MONITOR_COUNT > ((uint32_t)(monitor)))
249 #define CY_PROFILE_IS_DURATION_VALID(duration)  (((duration) == CY_PROFILE_EVENT) || \
250                                                  ((duration) == CY_PROFILE_DURATION))
251 #define CY_PROFILE_IS_REFCLK_VALID(refClk)      (((refClk) == CY_PROFILE_CLK_TIMER) || \
252                                                  ((refClk) == CY_PROFILE_CLK_IMO) || \
253                                                  ((refClk) == CY_PROFILE_CLK_ECO) || \
254                                                  ((refClk) == CY_PROFILE_CLK_LF) || \
255                                                  ((refClk) == CY_PROFILE_CLK_HF) || \
256                                                  ((refClk) == CY_PROFILE_CLK_PERI))
257 #define CY_PROFILE_IS_CNT_VALID(numCounters)    (CY_EP_CNT_NR >= (numCounters))
258 
259 /** \endcond */
260 
261 /***************************************
262 *        Enumerations
263 ***************************************/
264 
265 /**
266 * \addtogroup group_profile_enums
267 * \{
268 */
269 
270 /**
271 * Profile counter reference clock source. Used when duration monitoring.
272 */
273 typedef enum
274 {
275     CY_PROFILE_CLK_TIMER  = 0, /**< Timer clock (TimerClk) */
276     CY_PROFILE_CLK_IMO    = 1, /**< Internal main oscillator (IMO) */
277     CY_PROFILE_CLK_ECO    = 2, /**< External crystal oscillator (ECO) */
278     CY_PROFILE_CLK_LF     = 3, /**< Low-frequency clock (LFCLK) */
279     CY_PROFILE_CLK_HF     = 4, /**< High-Frequency clock (HFCLK0) */
280     CY_PROFILE_CLK_PERI   = 5, /**< Peripheral clock (PeriClk) */
281 } cy_en_profile_ref_clk_t;
282 
283 /**
284 * Monitor method type.
285 */
286 typedef enum
287 {
288     CY_PROFILE_EVENT    = 0,  /**< Count (edge-detected) module events  */
289     CY_PROFILE_DURATION = 1,  /**< Count (level) duration in clock cycles */
290 } cy_en_profile_duration_t;
291 
292 /** Profiler status codes */
293 typedef enum
294 {
295     CY_PROFILE_SUCCESS = 0x00U,                                      /**< Operation completed successfully */
296     CY_PROFILE_BAD_PARAM = CY_PROFILE_ID | CY_PDL_STATUS_ERROR | 1UL /**< Invalid input parameters */
297 
298  } cy_en_profile_status_t;
299 
300  /** \} group_profile_enums */
301 
302 /***************************************
303 *       Configuration Structures
304 ***************************************/
305 
306 /**
307 * \addtogroup group_profile_data_structures
308 * \{
309 */
310 
311 /**
312 * Profile counter control register structure. For each counter, holds the CTL register fields.
313 */
314 typedef struct
315 {
316     cy_en_profile_duration_t  cntDuration; /**< 0 = event; 1 = duration */
317     cy_en_profile_ref_clk_t   refClkSel;   /**< The reference clock used by the counter */
318     en_ep_mon_sel_t           monSel;      /**< The monitor signal to be observed by the counter */
319 } cy_stc_profile_ctr_ctl_t;
320 
321 /**
322 * Software structure for holding a profile counter status and configuration information.
323 */
324 typedef struct
325 {
326     uint8_t                   ctrNum;      /**< Profile counter number */
327     uint8_t                   used;        /**< 0 = available; 1 = used */
328     cy_stc_profile_ctr_ctl_t  ctlRegVals;  /**< Initial counter CTL register settings */
329     PROFILE_CNT_STRUCT_Type * cntAddr;     /**< Base address of the counter instance registers */
330     uint32_t                  ctlReg;      /**< Current CTL register value */
331     uint32_t                  cntReg;      /**< Current CNT register value */
332     uint32_t                  overflow;    /**< Extension of cntReg to form a 64-bit counter value */
333     uint32_t                  weight;      /**< Weighting factor for the counter */
334 } cy_stc_profile_ctr_t;
335 
336 /**
337 * Pointer to a structure holding the status information for a profile counter.
338 */
339 typedef cy_stc_profile_ctr_t * cy_stc_profile_ctr_ptr_t;
340 /** \} group_profile_data_structures */
341 
342 /**
343 * \addtogroup group_profile_functions
344 * \{
345 */
346 
347 /**
348 * \addtogroup group_profile_functions_interrupt
349 * \{
350 */
351 /* ========================================================================== */
352 /* ====================    INTERRUPT FUNCTION SECTION    ==================== */
353 /* ========================================================================== */
354 void Cy_Profile_ISR(void);
355 /** \} group_profile_functions_interrupt */
356 
357 /**
358 * \addtogroup group_profile_functions_general
359 * \{
360 */
361 __STATIC_INLINE void Cy_Profile_Init(void);
362 __STATIC_INLINE void Cy_Profile_DeInit(void);
363                 void Cy_Profile_StartProfiling(void);
364 __STATIC_INLINE void Cy_Profile_StopProfiling(void);
365 __STATIC_INLINE uint32_t Cy_Profile_IsProfiling(void);
366 
367 
368 /* ========================================================================== */
369 /* ===============    GENERAL PROFILE FUNCTIONS SECTION     ================= */
370 /* ========================================================================== */
371 /*******************************************************************************
372 * Function Name: Cy_Profile_Init
373 ****************************************************************************//**
374 *
375 * Initializes and enables the profile hardware.
376 *
377 * This function must be called once when energy profiling is desired. The
378 * operation does not start a profiling session.
379 *
380 * \note The profile interrupt must also be configured. \ref Cy_Profile_ISR()
381 * can be used as its handler.
382 *
383 * \funcusage
384 * \snippet profile/snippet/main.c snippet_Cy_Profile_Init
385 *
386 *******************************************************************************/
Cy_Profile_Init(void)387 __STATIC_INLINE void Cy_Profile_Init(void)
388 {
389     PROFILE_CTL = _VAL2FLD(PROFILE_CTL_ENABLED,  1UL/*enabled */) |
390                   _VAL2FLD(PROFILE_CTL_WIN_MODE, 0UL/*start/stop mode*/);
391     PROFILE_INTR_MASK = 0UL; /* clear all counter interrupt mask bits */
392 }
393 
394 
395 /*******************************************************************************
396 * Function Name: Cy_Profile_DeInit
397 ****************************************************************************//**
398 *
399 * Clears the interrupt mask and disables the profile hardware.
400 *
401 * This function should be called when energy profiling is no longer desired.
402 *
403 * \note The profile interrupt is not disabled by this operation and must be
404 * disabled separately.
405 *
406 * \funcusage
407 * \snippet profile/snippet/main.c snippet_Cy_Profile_DeInit
408 *
409 *******************************************************************************/
Cy_Profile_DeInit(void)410 __STATIC_INLINE void Cy_Profile_DeInit(void)
411 {
412     PROFILE_CTL = _VAL2FLD(PROFILE_CTL_ENABLED, 0UL/*disabled */);
413     PROFILE_INTR_MASK = 0UL; /* clear all counter interrupt mask bits */
414 }
415 
416 
417 /*******************************************************************************
418 * Function Name: Cy_Profile_StopProfiling
419 ****************************************************************************//**
420 *
421 * Stops the profiling/measurement window.
422 *
423 * This operation prevents the enabled profile counters from counting.
424 *
425 * \note The profile interrupt should be disabled before calling this function.
426 *
427 * \funcusage
428 * \snippet profile/snippet/main.c snippet_Cy_Profile_StopProfiling
429 *
430 *******************************************************************************/
Cy_Profile_StopProfiling(void)431 __STATIC_INLINE void Cy_Profile_StopProfiling(void)
432 {
433     PROFILE_CMD = CY_PROFILE_STOP_TR;
434 }
435 
436 
437 /*******************************************************************************
438 * Function Name: Cy_Profile_IsProfiling
439 ****************************************************************************//**
440 *
441 * Reports the active status of the profiling window.
442 *
443 * \return 0 = profiling is not active; 1 = profiling is active
444 *
445 * \funcusage
446 * \snippet profile/snippet/main.c snippet_Cy_Profile_IsProfiling
447 *
448 *******************************************************************************/
Cy_Profile_IsProfiling(void)449 __STATIC_INLINE uint32_t Cy_Profile_IsProfiling(void)
450 {
451     return _FLD2VAL(PROFILE_STATUS_WIN_ACTIVE, PROFILE_STATUS);
452 }
453 /** \} group_profile_functions_general */
454 
455 /**
456 * \addtogroup group_profile_functions_counter
457 * \{
458 */
459 void Cy_Profile_ClearConfiguration(void);
460 __STATIC_INLINE void Cy_Profile_ClearCounters(void);
461 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);
462 cy_en_profile_status_t Cy_Profile_FreeCounter(cy_stc_profile_ctr_ptr_t ctrAddr);
463 cy_en_profile_status_t Cy_Profile_EnableCounter(cy_stc_profile_ctr_ptr_t ctrAddr);
464 cy_en_profile_status_t Cy_Profile_DisableCounter(cy_stc_profile_ctr_ptr_t ctrAddr);
465 
466 /* ========================================================================== */
467 /* ===================    COUNTER FUNCTIONS SECTION    ====================== */
468 /* ========================================================================== */
469 /*******************************************************************************
470 * Function Name: Cy_Profile_ClearCounters
471 ****************************************************************************//**
472 *
473 * Clears all hardware counters to 0.
474 *
475 * \funcusage
476 * \snippet profile/snippet/main.c snippet_Cy_Profile_ClearCounters
477 *
478 *******************************************************************************/
Cy_Profile_ClearCounters(void)479 __STATIC_INLINE void Cy_Profile_ClearCounters(void)
480 {
481     PROFILE_CMD = CY_PROFILE_CLR_ALL_CNT;
482 }
483 /** \} group_profile_functions_counter */
484 
485 /**
486 * \addtogroup group_profile_functions_calculation
487 * \{
488 */
489 /* ========================================================================== */
490 /* ==================    CALCULATION FUNCTIONS SECTION    =================== */
491 /* ========================================================================== */
492 cy_en_profile_status_t Cy_Profile_GetRawCount(cy_stc_profile_ctr_ptr_t ctrAddr, uint64_t *result);
493 cy_en_profile_status_t Cy_Profile_GetWeightedCount(cy_stc_profile_ctr_ptr_t ctrAddr, uint64_t *result);
494 uint64_t Cy_Profile_GetSumWeightedCounts(cy_stc_profile_ctr_ptr_t ptrsArray[], uint32_t numCounters);
495 /** \} group_profile_functions_calculation */
496 
497 /** \} group_profile_functions */
498 
499 #if defined(__cplusplus)
500 }
501 #endif /* __cplusplus */
502 
503 #endif /* CY_IP_MXPROFILE */
504 
505 #endif /* CY_PROFILE_H */
506 
507 /** \} group_profile */
508 
509 
510 /* [] END OF FILE */
511