xref: /btstack/port/renesas-ek-ra6m4a-da14531/e2-project/ra/fsp/src/bsp/mcu/all/bsp_delay.c (revision c30869498fb8e98c1408c9db0e7624f02f483b73)
1 /***********************************************************************************************************************
2  * Copyright [2020-2022] Renesas Electronics Corporation and/or its affiliates.  All Rights Reserved.
3  *
4  * This software and documentation are supplied by Renesas Electronics America Inc. and may only be used with products
5  * of Renesas Electronics Corp. and its affiliates ("Renesas").  No other uses are authorized.  Renesas products are
6  * sold pursuant to Renesas terms and conditions of sale.  Purchasers are solely responsible for the selection and use
7  * of Renesas products and Renesas assumes no liability.  No license, express or implied, to any intellectual property
8  * right is granted by Renesas. This software is protected under all applicable laws, including copyright laws. Renesas
9  * reserves the right to change or discontinue this software and/or this documentation. THE SOFTWARE AND DOCUMENTATION
10  * IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND TO THE FULLEST EXTENT
11  * PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY, INCLUDING WARRANTIES
12  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE SOFTWARE OR
13  * DOCUMENTATION.  RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH.  TO THE MAXIMUM
14  * EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR DOCUMENTATION
15  * (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER, INCLUDING,
16  * WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY LOST PROFITS,
17  * OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE POSSIBILITY
18  * 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 
33 /***********************************************************************************************************************
34  * Typedef definitions
35  **********************************************************************************************************************/
36 
37 /***********************************************************************************************************************
38  * Private function prototypes
39  **********************************************************************************************************************/
40 
41 /***********************************************************************************************************************
42  * Exported global variables (to be accessed by other files)
43  **********************************************************************************************************************/
44 
45 /***********************************************************************************************************************
46  * Private global variables and functions
47  **********************************************************************************************************************/
48 
49 /*******************************************************************************************************************//**
50  * @addtogroup BSP_MCU
51  * @{
52  **********************************************************************************************************************/
53 
54 /*******************************************************************************************************************//**
55  *              Delay for at least the specified duration in units and return.
56  * @param[in]   delay  The number of 'units' to delay.
57  * @param[in]   units  The 'base' (bsp_delay_units_t) for the units specified. Valid values are:
58  *              BSP_DELAY_UNITS_SECONDS, BSP_DELAY_UNITS_MILLISECONDS, BSP_DELAY_UNITS_MICROSECONDS.@n
59  *              For example:@n
60  *              At 1 MHz one cycle takes 1 microsecond (.000001 seconds).@n
61  *              At 12 MHz one cycle takes 1/12 microsecond or 83 nanoseconds.@n
62  *              Therefore one run through bsp_prv_software_delay_loop() takes:
63  *              ~ (83 * BSP_DELAY_LOOP_CYCLES) or 332 ns.
64  *              A delay of 2 us therefore requires 2000ns/332ns or 6 loops.
65  *
66  *              The 'theoretical' maximum delay that may be obtained is determined by a full 32 bit loop count and the system clock rate.
67  *              @120MHz:  ((0xFFFFFFFF loops * 4 cycles /loop) / 120000000) = 143 seconds.
68  *              @32MHz:  ((0xFFFFFFFF loops * 4 cycles /loop) / 32000000) = 536 seconds
69  *
70  *              Note that requests for very large delays will be affected by rounding in the calculations and the actual delay
71  *              achieved may be slightly longer. @32 MHz, for example, a request for 532 seconds will be closer to 536 seconds.
72  *
73  *              Note also that if the calculations result in a loop_cnt of zero, the bsp_prv_software_delay_loop() function is not called
74  *              at all. In this case the requested delay is too small (nanoseconds) to be carried out by the loop itself, and the
75  *              overhead associated with executing the code to just get to this point has certainly satisfied the requested delay.
76  *
77  * @note This function calls bsp_cpu_clock_get() which ultimately calls R_CGC_SystemClockFreqGet() and therefore requires
78  *       that the BSP has already initialized the CGC (which it does as part of the Sysinit).
79  *       Care should be taken to ensure this remains the case if in the future this function were to be called as part
80  *       of the BSP initialization.
81  *
82  * @note This function will delay for **at least** the specified duration. Due to overhead in calculating the correct number
83  *       of loops to delay, very small delay values (generally 1-5 microseconds) may be significantly longer than specified.
84  *       Approximate overhead for this function is as follows:
85  *           - CM4: 20-50 cycles
86  *           - CM33: 10-60 cycles
87  *           - CM23: 75-200 cycles
88  *
89  * @note If more accurate microsecond timing must be performed in software it is recommended to use
90  *       bsp_prv_software_delay_loop() directly. In this case, use BSP_DELAY_LOOP_CYCLES or BSP_DELAY_LOOPS_CALCULATE()
91  *       to convert a calculated delay cycle count to a number of software delay loops.
92  *
93  * @note Delays may be longer than expected when compiler optimization is turned off.
94  *
95  * @warning The delay will be longer than specified on CM23 devices when the core clock is greater than 32 MHz. Setting
96  *          BSP_DELAY_LOOP_CYCLES to 6 will improve accuracy at 48 MHz but will result in shorter than expected delays
97  *          at lower speeds.
98  **********************************************************************************************************************/
99 
R_BSP_SoftwareDelay(uint32_t delay,bsp_delay_units_t units)100 void R_BSP_SoftwareDelay (uint32_t delay, bsp_delay_units_t units)
101 {
102     uint32_t iclk_hz;
103     uint32_t cycles_requested;
104     uint32_t ns_per_cycle;
105     uint32_t loops_required = 0;
106     uint32_t total_us       = (delay * units);                        /** Convert the requested time to microseconds. */
107     uint64_t ns_64bits;
108 
109     iclk_hz = SystemCoreClock;                                        /** Get the system clock frequency in Hz. */
110 
111     /* Running on the Sub-clock (32768 Hz) there are 30517 ns/cycle. This means one cycle takes 31 us. One execution
112      * 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
113      * to the delay loop. Given this, at this frequency anything less then a delay request of 122 us will not even generate a single
114      * 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
115      * will generate a minimum delay of ~200 us.*/
116     ns_per_cycle = BSP_DELAY_NS_PER_SECOND / iclk_hz;                 /** Get the # of nanoseconds/cycle. */
117 
118     /* 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 */
119     /* division as that pulls in a division library. */
120     ns_64bits = (uint64_t) total_us * (uint64_t) BSP_DELAY_NS_PER_US; // Convert to ns.
121 
122     /* Have we overflowed 32 bits? */
123     if (ns_64bits <= UINT32_MAX)
124     {
125         /* No, we will not overflow. */
126         cycles_requested = ((uint32_t) ns_64bits / ns_per_cycle);
127         loops_required   = cycles_requested / BSP_DELAY_LOOP_CYCLES;
128     }
129     else
130     {
131         /* We did overflow. Try dividing down first. */
132         total_us  = (total_us / (ns_per_cycle * BSP_DELAY_LOOP_CYCLES));
133         ns_64bits = (uint64_t) total_us * (uint64_t) BSP_DELAY_NS_PER_US; // Convert to ns.
134 
135         /* Have we overflowed 32 bits? */
136         if (ns_64bits <= UINT32_MAX)
137         {
138             /* No, we will not overflow. */
139             loops_required = (uint32_t) ns_64bits;
140         }
141         else
142         {
143             /* We still overflowed, use the max count for cycles */
144             loops_required = UINT32_MAX;
145         }
146     }
147 
148     /** Only delay if the supplied parameters constitute a delay. */
149     if (loops_required > (uint32_t) 0)
150     {
151         bsp_prv_software_delay_loop(loops_required);
152     }
153 }
154 
155 /** @} (end addtogroup BSP_MCU) */
156 
157 /*******************************************************************************************************************//**
158  *        This assembly language routine takes roughly 4 cycles per loop. 2 additional cycles
159  *        occur when the loop exits. The 'naked' attribute  indicates that the specified function does not need
160  *        prologue/epilogue sequences generated by the compiler.
161  * @param[in]     loop_cnt  The number of loops to iterate.
162  **********************************************************************************************************************/
bsp_prv_software_delay_loop(uint32_t loop_cnt)163 BSP_ATTRIBUTE_STACKLESS void bsp_prv_software_delay_loop (__attribute__((unused)) uint32_t loop_cnt)
164 {
165     __asm volatile ("sw_delay_loop:         \n"
166 
167 #if defined(__ICCARM__) || defined(__ARMCC_VERSION)
168                     "   subs r0, #1         \n"   ///< 1 cycle
169 #elif defined(__GNUC__)
170                     "   sub r0, r0, #1      \n"   ///< 1 cycle
171 #endif
172 
173                     "   cmp r0, #0          \n"   ///< 1 cycle
174 
175 /* CM0 and CM23 have a different instruction set */
176 #if defined(__CORE_CM0PLUS_H_GENERIC) || defined(__CORE_CM23_H_GENERIC)
177                     "   bne sw_delay_loop   \n"   ///< 2 cycles
178 #else
179                     "   bne.n sw_delay_loop \n"   ///< 2 cycles
180 #endif
181                     "   bx lr               \n"); ///< 2 cycles
182 }
183