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