1 /***********************************************************************************************************************
2  * Copyright [2020-2024] Renesas Electronics Corporation and/or its affiliates.  All Rights Reserved.
3  *
4  * This software and documentation are supplied by Renesas Electronics Corporation and/or its affiliates and may only
5  * be used with products of Renesas Electronics Corp. and its affiliates ("Renesas").  No other uses are authorized.
6  * Renesas products are sold pursuant to Renesas terms and conditions of sale.  Purchasers are solely responsible for
7  * the selection and use of Renesas products and Renesas assumes no liability.  No license, express or implied, to any
8  * intellectual property right is granted by Renesas.  This software is protected under all applicable laws, including
9  * copyright laws. Renesas reserves the right to change or discontinue this software and/or this documentation.
10  * THE SOFTWARE AND DOCUMENTATION IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND
11  * TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY,
12  * INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE
13  * SOFTWARE OR DOCUMENTATION.  RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH.
14  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR
15  * DOCUMENTATION (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER,
16  * INCLUDING, WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY
17  * LOST PROFITS, OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE
18  * POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS.
19  **********************************************************************************************************************/
20 
21 /***********************************************************************************************************************
22  * Includes   <System Includes> , "Project Includes"
23  **********************************************************************************************************************/
24 #include "bsp_api.h"
25 #include "bsp_delay.h"
26 
27 /***********************************************************************************************************************
28  * Macro definitions
29  **********************************************************************************************************************/
30 #define BSP_DELAY_NS_PER_SECOND         (1000000000)
31 #define BSP_DELAY_NS_PER_US             (1000)
32 #define BSP_DELAY_SIGNIFICANT_DIGITS    (10000)
33 
34 /***********************************************************************************************************************
35  * Typedef definitions
36  **********************************************************************************************************************/
37 
38 /***********************************************************************************************************************
39  * Exported global variables (to be accessed by other files)
40  **********************************************************************************************************************/
41 
42 /***********************************************************************************************************************
43  * Private global variables and functions
44  **********************************************************************************************************************/
45 
46 /*******************************************************************************************************************//**
47  * @addtogroup BSP_MCU
48  * @{
49  **********************************************************************************************************************/
50 
51 /*******************************************************************************************************************//**
52  *              Delay for at least the specified duration in units and return.
53  * @param[in]   delay  The number of 'units' to delay.
54  * @param[in]   units  The 'base' (bsp_delay_units_t) for the units specified. Valid values are:
55  *              BSP_DELAY_UNITS_SECONDS, BSP_DELAY_UNITS_MILLISECONDS, BSP_DELAY_UNITS_MICROSECONDS.@n
56  *              For example:@n
57  *              At 200 MHz one cycle takes 1/200 microsecond or 5 nanoseconds.@n
58  *              At 800 MHz one cycle takes 1/800 microsecond or 1.25 nanoseconds.@n
59  *              Therefore one run through bsp_prv_software_delay_loop() takes:
60  *              ~ (1.25 * BSP_DELAY_LOOP_CYCLES) or 5 ns.
61  *              A delay of 2 us therefore requires 2000ns/5ns or 400 loops.
62  *
63  *              The 'theoretical' maximum delay that may be obtained is determined by a full 32 bit loop count and the system clock rate.
64  *              @200MHz:  ((0xFFFFFFFF loops * 4 cycles /loop) / 200000000) = 85 seconds.
65  *              @800MHz:  ((0xFFFFFFFF loops * 4 cycles /loop) / 800000000) = 21 seconds.
66  *
67  *              Note that requests for very large delays will be affected by rounding in the calculations and the actual delay
68  *              achieved may be slightly longer. @200 MHz, for example, a request for 85 seconds will be closer to 86 seconds.
69  *
70  *              Note also that if the calculations result in a loop_cnt of zero, the bsp_prv_software_delay_loop() function is not called
71  *              at all. In this case the requested delay is too small (nanoseconds) to be carried out by the loop itself, and the
72  *              overhead associated with executing the code to just get to this point has certainly satisfied the requested delay.
73  *
74  *
75  * @note R_BSP_SoftwareDelay() obtains the system clock value by reading the SystemCoreClock variable.
76  *       Therefore, R_BSP_SoftwareDelay() cannot be used until after the SystemCoreClock has been updated.
77  *       The SystemCoreClock is updated by executing SystemCoreClockUpdate() in startup;
78  *       users cannot call R_BSP_SoftwareDelay() inside R_BSP_WarmStart(BSP_WARM_START_RESET) and
79  *       R_BSP_WarmStart(BSP_WARM_START_POST_CLOCK) since they are invoked before SystemCoreClockUpdate() in startup.
80  *
81  * @note This function will delay for **at least** the specified duration. Due to overhead in calculating the correct number
82  *       of loops to delay, very small delay values (generally 1-5 microseconds) may be significantly longer than specified.
83  *       Approximate overhead for this function is as follows:
84  *           - CR52: 87-94 cycles
85  *
86  * @note If more accurate microsecond timing must be performed in software it is recommended to use
87  *       bsp_prv_software_delay_loop() directly. In this case, use BSP_DELAY_LOOP_CYCLES or BSP_DELAY_LOOPS_CALCULATE()
88  *       to convert a calculated delay cycle count to a number of software delay loops.
89  *
90  * @note Delays may be longer than expected when compiler optimization is turned off.
91  **********************************************************************************************************************/
92 
R_BSP_SoftwareDelay(uint32_t delay,bsp_delay_units_t units)93 void R_BSP_SoftwareDelay (uint32_t delay, bsp_delay_units_t units)
94 {
95     uint32_t cpu_hz;
96     uint32_t cycles_requested;
97     uint32_t ns_per_cycle;
98     uint32_t loops_required = 0;
99     uint32_t total_us       = (delay * units);                                        /** Convert the requested time to microseconds. */
100     uint64_t ns_64bits;
101 
102     cpu_hz = SystemCoreClock;                                                         /** Get the system clock frequency in Hz. */
103 
104     /* BSP_DELAY_SIGNIFICANT_DIGITS to keep the decimal point. */
105     ns_per_cycle = BSP_DELAY_NS_PER_SECOND / (cpu_hz / BSP_DELAY_SIGNIFICANT_DIGITS); /** Get the # of nanoseconds/cycle. */
106 
107     /* 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 */
108     /* division as that pulls in a division library. */
109     ns_64bits = (uint64_t) total_us * (uint64_t) BSP_DELAY_NS_PER_US;                 // Convert to ns.
110 
111     /* Have we overflowed 32 bits? */
112     if (ns_64bits <= UINT32_MAX)
113     {
114         ns_64bits = ns_64bits * (uint64_t) BSP_DELAY_SIGNIFICANT_DIGITS;
115 
116         /* No, we will not overflow.
117          * Multiply the calculation result by BSP_DELAY_SIGNIFICANT_DIGITS to disable the retention of the decimal point.*/
118         cycles_requested = (uint32_t) (ns_64bits / (uint64_t) ns_per_cycle);
119         loops_required   = cycles_requested / BSP_DELAY_LOOP_CYCLES;
120     }
121     else
122     {
123         /* We did overflow. Try dividing down first.
124          * Multiply the calculation result by BSP_DELAY_SIGNIFICANT_DIGITS to disable the retention of the decimal point.*/
125         total_us  = (total_us / (ns_per_cycle * BSP_DELAY_LOOP_CYCLES)) * BSP_DELAY_SIGNIFICANT_DIGITS;
126         ns_64bits = (uint64_t) total_us * (uint64_t) BSP_DELAY_NS_PER_US; // Convert to ns.
127 
128         /* Have we overflowed 32 bits? */
129         if (ns_64bits <= UINT32_MAX)
130         {
131             /* No, we will not overflow. */
132             loops_required = (uint32_t) ns_64bits;
133         }
134         else
135         {
136             /* We still overflowed, use the max count for cycles */
137             loops_required = UINT32_MAX;
138         }
139     }
140 
141     /** Only delay if the supplied parameters constitute a delay. */
142     if (loops_required > (uint32_t) 0)
143     {
144         bsp_prv_software_delay_loop(loops_required);
145     }
146 }
147 
148 /** @} (end addtogroup BSP_MCU) */
149 
150 /*******************************************************************************************************************//**
151  *        This assembly language routine takes roughly 4 cycles per loop. 2 additional cycles
152  *        occur when the loop exits. The 'naked' attribute  indicates that the specified function does not need
153  *        prologue/epilogue sequences generated by the compiler.
154  * @param[in]     loop_cnt  The number of loops to iterate.
155  **********************************************************************************************************************/
bsp_prv_software_delay_loop(uint32_t loop_cnt)156 void bsp_prv_software_delay_loop (uint32_t loop_cnt)
157 {
158     r_bsp_software_delay_loop(loop_cnt);
159 }
160