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
19 /***********************************************************************************************************************
20 * Typedef definitions
21 **********************************************************************************************************************/
22
23 /***********************************************************************************************************************
24 * Private function prototypes
25 **********************************************************************************************************************/
26
27 /***********************************************************************************************************************
28 * Exported global variables (to be accessed by other files)
29 **********************************************************************************************************************/
30
31 /***********************************************************************************************************************
32 * Private global variables and functions
33 **********************************************************************************************************************/
34
35 /*******************************************************************************************************************//**
36 * @addtogroup BSP_MCU
37 * @{
38 **********************************************************************************************************************/
39
40 /*******************************************************************************************************************//**
41 * Delay for at least the specified duration in units and return.
42 * @param[in] delay The number of 'units' to delay.
43 * @param[in] units The 'base' (bsp_delay_units_t) for the units specified. Valid values are:
44 * BSP_DELAY_UNITS_SECONDS, BSP_DELAY_UNITS_MILLISECONDS, BSP_DELAY_UNITS_MICROSECONDS.@n
45 * For example:@n
46 * At 1 MHz one cycle takes 1 microsecond (.000001 seconds).@n
47 * At 12 MHz one cycle takes 1/12 microsecond or 83 nanoseconds.@n
48 * Therefore one run through bsp_prv_software_delay_loop() takes:
49 * ~ (83 * BSP_DELAY_LOOP_CYCLES) or 332 ns.
50 * A delay of 2 us therefore requires 2000ns/332ns or 6 loops.
51 *
52 * The 'theoretical' maximum delay that may be obtained is determined by a full 32 bit loop count and the system clock rate.
53 * @120MHz: ((0xFFFFFFFF loops * 4 cycles /loop) / 120000000) = 143 seconds.
54 * @32MHz: ((0xFFFFFFFF loops * 4 cycles /loop) / 32000000) = 536 seconds
55 *
56 * Note that requests for very large delays will be affected by rounding in the calculations and the actual delay
57 * achieved may be slightly longer. @32 MHz, for example, a request for 532 seconds will be closer to 536 seconds.
58 *
59 * Note also that if the calculations result in a loop_cnt of zero, the bsp_prv_software_delay_loop() function is not called
60 * at all. In this case the requested delay is too small (nanoseconds) to be carried out by the loop itself, and the
61 * overhead associated with executing the code to just get to this point has certainly satisfied the requested delay.
62 *
63 * @note This function calls bsp_cpu_clock_get() which ultimately calls R_CGC_SystemClockFreqGet() and therefore requires
64 * that the BSP has already initialized the CGC (which it does as part of the Sysinit).
65 * Care should be taken to ensure this remains the case if in the future this function were to be called as part
66 * of the BSP initialization.
67 *
68 * @note This function will delay for **at least** the specified duration. Due to overhead in calculating the correct number
69 * of loops to delay, very small delay values (generally 1-5 microseconds) may be significantly longer than specified.
70 * Approximate overhead for this function is as follows:
71 * - CM4: 20-50 cycles
72 * - CM33: 10-60 cycles
73 * - CM23: 75-200 cycles
74 *
75 * @note If more accurate microsecond timing must be performed in software it is recommended to use
76 * bsp_prv_software_delay_loop() directly. In this case, use BSP_DELAY_LOOP_CYCLES or BSP_DELAY_LOOPS_CALCULATE()
77 * to convert a calculated delay cycle count to a number of software delay loops.
78 *
79 * @note Delays may be longer than expected when compiler optimization is turned off.
80 *
81 * @warning The delay will be longer than specified on CM23 devices when the core clock is greater than 32 MHz. Setting
82 * BSP_DELAY_LOOP_CYCLES to 6 will improve accuracy at 48 MHz but will result in shorter than expected delays
83 * at lower speeds.
84 **********************************************************************************************************************/
85
R_BSP_SoftwareDelay(uint32_t delay,bsp_delay_units_t units)86 BSP_SECTION_FLASH_GAP void R_BSP_SoftwareDelay (uint32_t delay, bsp_delay_units_t units)
87 {
88 uint32_t iclk_hz;
89 uint32_t cycles_requested;
90 uint32_t ns_per_cycle;
91 uint32_t loops_required = 0;
92 uint32_t total_us = (delay * units); /** Convert the requested time to microseconds. */
93 uint64_t ns_64bits;
94
95 iclk_hz = SystemCoreClock; /** Get the system clock frequency in Hz. */
96
97 /* Running on the Sub-clock (32768 Hz) there are 30517 ns/cycle. This means one cycle takes 31 us. One execution
98 * loop of the delay_loop takes 6 cycles which at 32768 Hz is 180 us. That does not include the overhead below prior to even getting
99 * to the delay loop. Given this, at this frequency anything less then a delay request of 122 us will not even generate a single
100 * pass through the delay loop. For this reason small delays (<=~200 us) at this slow clock rate will not be possible and such a request
101 * will generate a minimum delay of ~200 us.*/
102 ns_per_cycle = BSP_DELAY_NS_PER_SECOND / iclk_hz; /** Get the # of nanoseconds/cycle. */
103
104 /* 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 */
105 /* division as that pulls in a division library. */
106 ns_64bits = (uint64_t) total_us * (uint64_t) BSP_DELAY_NS_PER_US; // Convert to ns.
107
108 /* Have we overflowed 32 bits? */
109 if (ns_64bits <= UINT32_MAX)
110 {
111 /* No, we will not overflow. */
112 cycles_requested = ((uint32_t) ns_64bits / ns_per_cycle);
113 loops_required = cycles_requested / BSP_DELAY_LOOP_CYCLES;
114 }
115 else
116 {
117 /* We did overflow. Try dividing down first. */
118 total_us = (total_us / (ns_per_cycle * BSP_DELAY_LOOP_CYCLES));
119 ns_64bits = (uint64_t) total_us * (uint64_t) BSP_DELAY_NS_PER_US; // Convert to ns.
120
121 /* Have we overflowed 32 bits? */
122 if (ns_64bits <= UINT32_MAX)
123 {
124 /* No, we will not overflow. */
125 loops_required = (uint32_t) ns_64bits;
126 }
127 else
128 {
129 /* We still overflowed, use the max count for cycles */
130 loops_required = UINT32_MAX;
131 }
132 }
133
134 /** Only delay if the supplied parameters constitute a delay. */
135 if (loops_required > (uint32_t) 0)
136 {
137 bsp_prv_software_delay_loop(loops_required);
138 }
139 }
140
141 /** @} (end addtogroup BSP_MCU) */
142
143 /*******************************************************************************************************************//**
144 * This assembly language routine takes roughly 4 cycles per loop. 2 additional cycles
145 * occur when the loop exits. The 'naked' attribute indicates that the specified function does not need
146 * prologue/epilogue sequences generated by the compiler.
147 * @param[in] loop_cnt The number of loops to iterate.
148 **********************************************************************************************************************/
bsp_prv_software_delay_loop(uint32_t loop_cnt)149 BSP_SECTION_FLASH_GAP BSP_ATTRIBUTE_STACKLESS void bsp_prv_software_delay_loop (__attribute__(
150 (unused)) uint32_t loop_cnt)
151 {
152 __asm volatile (
153 #if defined(RENESAS_CORTEX_M85) && (defined(__ARMCC_VERSION) || defined(__GNUC__))
154
155 /* Align the branch target to a 64-bit boundary, a CM85 specific optimization. */
156 /* IAR does not support alignment control within inline assembly. */
157 ".balign 8\n"
158 #endif
159 "sw_delay_loop: \n"
160 #if defined(__ICCARM__) || defined(__ARMCC_VERSION) || (defined(__llvm__) && !defined(__CLANG_TIDY__))
161 " subs r0, #1 \n" ///< 1 cycle
162 #elif defined(__GNUC__)
163 " sub r0, r0, #1 \n" ///< 1 cycle
164 #endif
165
166 " cmp r0, #0 \n" ///< 1 cycle
167
168 /* CM0 and CM23 have a different instruction set */
169 #if defined(__CORE_CM0PLUS_H_GENERIC) || defined(__CORE_CM23_H_GENERIC)
170 " bne sw_delay_loop \n" ///< 2 cycles
171 #else
172 " bne.n sw_delay_loop \n" ///< 2 cycles
173 #endif
174 " bx lr \n"); ///< 2 cycles
175 }
176