1 /*
2 * Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 
7 /***********************************************************************************************************************
8  * Includes   <System Includes> , "Project Includes"
9  **********************************************************************************************************************/
10 #include "bsp_api.h"
11 #include "bsp_delay.h"
12 
13 /***********************************************************************************************************************
14  * Macro definitions
15  **********************************************************************************************************************/
16 #define BSP_DELAY_NS_PER_SECOND         (1000000000)
17 #define BSP_DELAY_NS_PER_US             (1000)
18 #define BSP_DELAY_SIGNIFICANT_DIGITS    (10000)
19 
20 /***********************************************************************************************************************
21  * Typedef definitions
22  **********************************************************************************************************************/
23 
24 /***********************************************************************************************************************
25  * Exported global variables (to be accessed by other files)
26  **********************************************************************************************************************/
27 
28 /***********************************************************************************************************************
29  * Private global variables and functions
30  **********************************************************************************************************************/
31 
32 /*******************************************************************************************************************//**
33  * @addtogroup BSP_MCU
34  * @{
35  **********************************************************************************************************************/
36 
37 /*******************************************************************************************************************//**
38  *              Delay for at least the specified duration in units and return.
39  * @param[in]   delay  The number of 'units' to delay.
40  * @param[in]   units  The 'base' (bsp_delay_units_t) for the units specified. Valid values are:
41  *              BSP_DELAY_UNITS_SECONDS, BSP_DELAY_UNITS_MILLISECONDS, BSP_DELAY_UNITS_MICROSECONDS.@n
42  *              For example:@n
43  *              At 200 MHz one cycle takes 1/200 microsecond or 5 nanoseconds.@n
44  *              At 800 MHz one cycle takes 1/800 microsecond or 1.25 nanoseconds.@n
45  *              Therefore one run through bsp_prv_software_delay_loop() takes:
46  *              ~ (1.25 * BSP_DELAY_LOOP_CYCLES) or 5 ns.
47  *              A delay of 2 us therefore requires 2000ns/5ns or 400 loops.
48  *
49  *              The 'theoretical' maximum delay that may be obtained is determined by a full 32 bit loop count and the system clock rate.
50  *              @200MHz:  ((0xFFFFFFFF loops * 4 cycles /loop) / 200000000) = 85 seconds.
51  *              @800MHz:  ((0xFFFFFFFF loops * 4 cycles /loop) / 800000000) = 21 seconds.
52  *
53  *              Note that requests for very large delays will be affected by rounding in the calculations and the actual delay
54  *              achieved may be slightly longer. @200 MHz, for example, a request for 85 seconds will be closer to 86 seconds.
55  *
56  *              Note also that if the calculations result in a loop_cnt of zero, the bsp_prv_software_delay_loop() function is not called
57  *              at all. In this case the requested delay is too small (nanoseconds) to be carried out by the loop itself, and the
58  *              overhead associated with executing the code to just get to this point has certainly satisfied the requested delay.
59  *
60  *
61  * @note R_BSP_SoftwareDelay() obtains the system clock value by reading the SystemCoreClock variable.
62  *       Therefore, R_BSP_SoftwareDelay() cannot be used until after the SystemCoreClock has been updated.
63  *       The SystemCoreClock is updated by executing SystemCoreClockUpdate() in startup;
64  *       users cannot call R_BSP_SoftwareDelay() inside R_BSP_WarmStart(BSP_WARM_START_RESET) and
65  *       R_BSP_WarmStart(BSP_WARM_START_POST_CLOCK) since they are invoked before SystemCoreClockUpdate() in startup.
66  *
67  * @note This function will delay for **at least** the specified duration. Due to overhead in calculating the correct number
68  *       of loops to delay, very small delay values (generally 1-5 microseconds) may be significantly longer than specified.
69  *       Approximate overhead for this function is as follows:
70  *           - CR52: 87-94 cycles
71  *
72  * @note If more accurate microsecond timing must be performed in software it is recommended to use
73  *       bsp_prv_software_delay_loop() directly. In this case, use BSP_DELAY_LOOP_CYCLES or BSP_DELAY_LOOPS_CALCULATE()
74  *       to convert a calculated delay cycle count to a number of software delay loops.
75  *
76  * @note Delays may be longer than expected when compiler optimization is turned off.
77  **********************************************************************************************************************/
78 
R_BSP_SoftwareDelay(uint32_t delay,bsp_delay_units_t units)79 void R_BSP_SoftwareDelay (uint32_t delay, bsp_delay_units_t units)
80 {
81     uint32_t cpu_hz;
82     uint32_t cycles_requested;
83     uint32_t ns_per_cycle;
84     uint32_t loops_required = 0;
85     uint32_t total_us       = (delay * units);                                        /** Convert the requested time to microseconds. */
86     uint64_t ns_64bits;
87 
88     cpu_hz = SystemCoreClock;                                                         /** Get the system clock frequency in Hz. */
89 
90     /* BSP_DELAY_SIGNIFICANT_DIGITS to keep the decimal point. */
91     ns_per_cycle = BSP_DELAY_NS_PER_SECOND / (cpu_hz / BSP_DELAY_SIGNIFICANT_DIGITS); /** Get the # of nanoseconds/cycle. */
92 
93     /* We want to get the time in total nanoseconds but need to be conscious of overflowing 32 bits. We also do not want to do 64 bit */
94     /* division as that pulls in a division library. */
95     ns_64bits = (uint64_t) total_us * (uint64_t) BSP_DELAY_NS_PER_US;                 // Convert to ns.
96 
97     /* Have we overflowed 32 bits? */
98     if (ns_64bits <= UINT32_MAX)
99     {
100         ns_64bits = ns_64bits * (uint64_t) BSP_DELAY_SIGNIFICANT_DIGITS;
101 
102         /* No, we will not overflow.
103          * Multiply the calculation result by BSP_DELAY_SIGNIFICANT_DIGITS to disable the retention of the decimal point.*/
104         cycles_requested = (uint32_t) (ns_64bits / (uint64_t) ns_per_cycle);
105         loops_required   = cycles_requested / BSP_DELAY_LOOP_CYCLES;
106     }
107     else
108     {
109         /* We did overflow. Try dividing down first.
110          * Multiply the calculation result by BSP_DELAY_SIGNIFICANT_DIGITS to disable the retention of the decimal point.*/
111         total_us  = (total_us / (ns_per_cycle * BSP_DELAY_LOOP_CYCLES)) * BSP_DELAY_SIGNIFICANT_DIGITS;
112         ns_64bits = (uint64_t) total_us * (uint64_t) BSP_DELAY_NS_PER_US; // Convert to ns.
113 
114         /* Have we overflowed 32 bits? */
115         if (ns_64bits <= UINT32_MAX)
116         {
117             /* No, we will not overflow. */
118             loops_required = (uint32_t) ns_64bits;
119         }
120         else
121         {
122             /* We still overflowed, use the max count for cycles */
123             loops_required = UINT32_MAX;
124         }
125     }
126 
127     /** Only delay if the supplied parameters constitute a delay. */
128     if (loops_required > (uint32_t) 0)
129     {
130         bsp_prv_software_delay_loop(loops_required);
131     }
132 }
133 
134 /** @} (end addtogroup BSP_MCU) */
135 
136 /*******************************************************************************************************************//**
137  *        This assembly language routine takes roughly 4 cycles per loop. 2 additional cycles
138  *        occur when the loop exits. The 'naked' attribute  indicates that the specified function does not need
139  *        prologue/epilogue sequences generated by the compiler.
140  * @param[in]     loop_cnt  The number of loops to iterate.
141  **********************************************************************************************************************/
bsp_prv_software_delay_loop(uint32_t loop_cnt)142 void bsp_prv_software_delay_loop (uint32_t loop_cnt)
143 {
144     r_bsp_software_delay_loop(loop_cnt);
145 }
146