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_UNIT_CONV_S_TO_NS     (1000000000)
17 #define BSP_DELAY_UNIT_CONV_US_TO_NS    (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. This function shouldn't be used to
42  *              generate an accurate delay time. A running time of the function is depending on the region of memory
43  *              where the function is excuted on and a frequency of the CPU clock.
44  *
45  *              The funcion calls bsp_prv_software_delay_loop() which loops over the requested delay time.
46  *              One loop time through bsp_prv_software_delay_loop() takes roughly 500ns. This value is based on the
47  *              actual measured time in the condition that a frequency of the CPU clock is 200MHz and the code is
48  *              excuted on DDR3L-1333 DRAM(133MHz).
49  *              One loop running time of software_delay_loop() can be modified by redefining BSP_DELAY_LOOP_CYCLES.
50  *
51  * @param[in]   delay  The number of 'units' to delay.
52  * @param[in]   units  The 'base' (bsp_delay_units_t) for the units specified. Valid values are:
53  *              BSP_DELAY_UNITS_SECONDS, BSP_DELAY_UNITS_MILLISECONDS, BSP_DELAY_UNITS_MICROSECONDS.@n
54  *              For example:@n
55  *              One run through bsp_prv_software_delay_loop() takes roughly 500ns.
56  *              A delay of 100 us therefore requires 100000ns/500ns -> 200 loops.
57  *
58  *              The 'theoretical' maximum delay that may be obtained is determined by a full 32 bit loop count and the
59  *              system clock rate.
60  *              @200MHz:  ((0xFFFFFFFF loops * 500ns) = 2147 seconds.
61  *
62  *              Note that requests for very large delays will be affected by rounding in the calculations and the
63  *              actual delay achieved may be slightly off of a setting time.
64  *
65  *              Note also that if the calculations result in a loop_cnt of zero, the bsp_prv_software_delay_loop()
66  *              function is not called at all. In this case the requested delay is too small (nanoseconds) to be
67  *              carried out by the loop itself, and the overhead associated with executing the code to just get to this
68  *              point has certainly satisfied the requested delay.
69  *
70  * @note This function uses SystemCoreClock and therefore requires that the BSP has already initialized the variable
71  *       (which it does as part of the SystemInit).
72  *       Care should be taken to ensure this remains the case if in the future this function were to be called as part
73  *       of the BSP initialization.
74  **********************************************************************************************************************/
75 
R_BSP_SoftwareDelay(uint32_t delay,bsp_delay_units_t units)76 void R_BSP_SoftwareDelay (uint32_t delay, bsp_delay_units_t units)
77 {
78     uint32_t iclk_hz;
79     uint32_t cycles_requested;
80     uint32_t us_per_cycle;
81     uint32_t loops_required = 0;
82     uint32_t total_us       = (delay * units);
83     uint64_t ns_64bits;
84 
85     iclk_hz      = SystemCoreClock;
86     us_per_cycle = BSP_DELAY_UNIT_CONV_S_TO_NS / (iclk_hz / BSP_DELAY_UNIT_CONV_US_TO_NS);
87     ns_64bits    = (uint64_t) total_us * (uint64_t) BSP_DELAY_UNIT_CONV_US_TO_NS;
88 
89     /* Have we overflowed 32 bits? */
90     if (ns_64bits <= UINT32_MAX)
91     {
92         /* No, we will not overflow. */
93         cycles_requested = (((uint32_t) ns_64bits / us_per_cycle) * BSP_DELAY_UNIT_CONV_US_TO_NS);
94         loops_required   = cycles_requested / BSP_DELAY_LOOP_CYCLES;
95     }
96     else
97     {
98         /* We did overflow. Try dividing down first. */
99         total_us  = (total_us / ((us_per_cycle * BSP_DELAY_LOOP_CYCLES) / BSP_DELAY_UNIT_CONV_US_TO_NS));
100         ns_64bits = (uint64_t) total_us * (uint64_t) BSP_DELAY_UNIT_CONV_US_TO_NS; // Convert to ns.
101 
102         /* Have we overflowed 32 bits? */
103         if (ns_64bits <= UINT32_MAX)
104         {
105             /* No, we will not overflow. */
106             loops_required = (uint32_t) ns_64bits;
107         }
108         else
109         {
110             /* We still overflowed, use the max count for cycles */
111             loops_required = UINT32_MAX;
112         }
113     }
114 
115     /** Only delay if the supplied parameters constitute a delay. */
116     if (loops_required > (uint32_t) 0)
117     {
118         bsp_prv_software_delay_loop(loops_required);
119     }
120 }
121 
122 /** @} (end addtogroup BSP_MCU) */
123 
124 /*******************************************************************************************************************//**
125  *        This assembly language routine takes roughly 500ns per one loop.
126  *        The 'naked' attribute  indicates that the specified function does not need prologue/epilogue sequences
127  *        generated by the compiler.
128  * @param[in]     loop_cnt  The number of loops to iterate.
129  **********************************************************************************************************************/
bsp_prv_software_delay_loop(uint32_t loop_cnt)130 BSP_ATTRIBUTE_STACKLESS void bsp_prv_software_delay_loop (__attribute__((unused)) uint32_t loop_cnt)
131 {
132     __asm volatile ("sw_delay_loop:         \n"
133 
134 #if defined(__ICCARM__) || defined(__ARMCC_VERSION)
135                     "   subs r0, #1         \n"
136 #elif defined(__GNUC__)
137                     "   sub r0, r0, #1      \n"
138 #endif
139                     "   cmp r0, #0          \n"
140 
141                     "   bne.n sw_delay_loop \n"
142 
143                     "   bx lr               \n");
144 }
145