1 /***********************************************************************************************************************
2 * Copyright [2015-2017] Renesas Electronics Corporation and/or its licensors. All Rights Reserved.
3 *
4 * This file is part of Renesas SynergyTM Software Package (SSP)
5 *
6 * The contents of this file (the "contents") are proprietary and confidential to Renesas Electronics Corporation
7 * and/or its licensors ("Renesas") and subject to statutory and contractual protections.
8 *
9 * This file is subject to a Renesas SSP license agreement. Unless otherwise agreed in an SSP license agreement with
10 * Renesas: 1) you may not use, copy, modify, distribute, display, or perform the contents; 2) you may not use any name
11 * or mark of Renesas for advertising or publicity purposes or in connection with your use of the contents; 3) RENESAS
12 * MAKES NO WARRANTY OR REPRESENTATIONS ABOUT THE SUITABILITY OF THE CONTENTS FOR ANY PURPOSE; THE CONTENTS ARE PROVIDED
13 * "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14 * PARTICULAR PURPOSE, AND NON-INFRINGEMENT; AND 4) RENESAS SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, OR
15 * CONSEQUENTIAL DAMAGES, INCLUDING DAMAGES RESULTING FROM LOSS OF USE, DATA, OR PROJECTS, WHETHER IN AN ACTION OF
16 * CONTRACT OR TORT, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE CONTENTS. Third-party contents
17 * included in this file may be subject to different terms.
18 **********************************************************************************************************************/
19 /***********************************************************************************************************************
20 * File Name : bsp_delay.c
21 * Description : Implements a software delay function, common to all BSPs.
22 ***********************************************************************************************************************/
23
24 /***********************************************************************************************************************
25 Includes <System Includes> , "Project Includes"
26 ***********************************************************************************************************************/
27 #include "bsp_api.h"
28 #include "bsp_delay.h"
29 /***********************************************************************************************************************
30 Macro definitions
31 ***********************************************************************************************************************/
32 #define DELAY_LOOP_CYCLES 4 ///< 4 cycles per loop.
33
34 #if defined(__ICCARM__)
35 #define BSP_ATTRIBUTE_STACKLESS __stackless
36 #elif defined(__GNUC__)
37 /*LDRA_INSPECTED 293 S */
38 #define BSP_ATTRIBUTE_STACKLESS __attribute__((naked))
39 #endif
40
41 /***********************************************************************************************************************
42 Typedef definitions
43 ***********************************************************************************************************************/
44
45 /***********************************************************************************************************************
46 Private function prototypes
47 ***********************************************************************************************************************/
48
49 /***********************************************************************************************************************
50 Exported global variables (to be accessed by other files)
51 ***********************************************************************************************************************/
52
53 /***********************************************************************************************************************
54 Private global variables and functions
55 ***********************************************************************************************************************/
56
57 static void software_delay_loop (uint32_t loop_cnt);
58
59 /*******************************************************************************************************************//**
60 * @addtogroup BSP_MCU_DELAY
61 * @{
62 ***********************************************************************************************************************/
63
64 /*******************************************************************************************************************//**
65 * @brief Delay the specified duration in units and return.
66 * @param[in] delay The number of 'units' to delay.
67 * @param[in] units The 'base' (bsp_delay_units_t) for the units specified. Valid values are:
68 * BSP_DELAY_UNITS_SECONDS, BSP_DELAY_UNITS_MILLISECONDS, BSP_DELAY_UNITS_MICROSECONDS.@n
69 * For example:@n
70 * At 1 MHz one cycle takes 1 microsecond (.000001 seconds).@n
71 * At 12 MHz one cycle takes 1/12 microsecond or 83 nanoseconds.@n
72 * Therefore one run through software_delay_loop() takes:
73 * ~ (83 * DELAY_LOOP_CYCLES) or 332 ns.
74 * A delay of 2 us therefore requires 2000ns/332ns or 6 loops.
75 *
76 * The 'theoretical' maximum delay that may be obtained is determined by a full 32 bit loop count and the system clock rate.
77 * @240MHz: ((0xFFFFFFFF loops * 4 cycles /loop) / 240000000) = 71 seconds.
78 * @32MHz: ((0xFFFFFFFF loops * 4 cycles /loop) / 32000000) = 536 seconds
79 *
80 * Note that requests for very large delays will be affected by rounding in the calculations and the actual delay
81 * achieved may be slightly less. @32 MHz, for example, a request for 532 seconds will be closer to 536 seconds.
82 *
83 * Note also that if the calculations result in a loop_cnt of zero, the software_delay_loop() function is not called
84 * at all. In this case the requested delay is too small (nanoseconds) to be carried out by the loop itself, and the
85 * overhead associated with executing the code to just get to this point has certainly satisfied the requested delay.
86 *
87 *
88 * @note This function calls bsp_cpu_clock_get() which ultimately calls R_CGC_SystemClockFreqGet() and therefore requires
89 * that the BSP has already initialized the CGC (which it does as part of the Sysinit).
90 * Care should be taken to ensure this remains the case if in the future this function were to be called as part
91 * of the BSP initialization.
92 * @retval None.
93 ***********************************************************************************************************************/
94
R_BSP_SoftwareDelay(uint32_t delay,bsp_delay_units_t units)95 void R_BSP_SoftwareDelay(uint32_t delay, bsp_delay_units_t units)
96 {
97 uint32_t iclk_hz;
98 uint32_t cycles_requested;
99 uint32_t ns_per_cycle;
100 uint32_t loops_required = 0;
101 uint32_t total_us = (delay * units); /** Convert the requested time to microseconds. */
102 uint64_t ns_64bits;
103
104 iclk_hz = bsp_cpu_clock_get(); /** Get the system clock frequency in Hz. */
105
106 /* Running on the Sub-clock (32768 Hz) there are 30517 ns/cycle. This means one cycle takes 31 us. One execution
107 * 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
108 * to the delay loop. Given this, at this frequency anything less then a delay request of 122 us will not even generate a single
109 * 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
110 * will generate a minimum delay of ~200 us.*/
111
112 ns_per_cycle = (1000000000)/iclk_hz; /** Get the # of nanoseconds/cycle. */
113
114 /* 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 */
115 /* division as that pulls in a division library. */
116 ns_64bits = (uint64_t)total_us * (uint64_t)1000; // Convert to ns.
117
118 /* Have we overflowed 32 bits? */
119 if (ns_64bits <= 0xFFFFFFFFUL)
120 {
121 /* No, we will not overflow. */
122 cycles_requested = ((uint32_t)ns_64bits / ns_per_cycle);
123 loops_required = cycles_requested / DELAY_LOOP_CYCLES;
124 }
125 else
126 {
127 /* We did overflow. Try dividing down first. */
128 total_us = (total_us / (ns_per_cycle * DELAY_LOOP_CYCLES));
129 ns_64bits = (uint64_t)total_us * (uint64_t)1000; // Convert to ns.
130
131 /* Have we overflowed 32 bits? */
132 if (ns_64bits <= 0xFFFFFFFFUL)
133 {
134 /* No, we will not overflow. */
135 loops_required = (uint32_t)ns_64bits;
136 }
137 else
138 {
139 /* We still overflowed, use the max count for cycles */
140 loops_required = 0xFFFFFFFFUL;
141 }
142 }
143
144 /** Only delay if the supplied parameters constitute a delay. */
145 if (loops_required > (uint32_t)0)
146 {
147 software_delay_loop(loops_required);
148 }
149 }
150
151
152
153 /*******************************************************************************************************************//**
154 * @brief This assembly language routine takes roughly 4 cycles per loop. 2 additional cycles
155 * occur when the loop exits. The 'naked' attribute indicates that the specified function does not need
156 * prologue/epilogue sequences generated by the compiler.
157 * @param[in] loop_cnt The number of loops to iterate.
158 * @retval None.
159 ***********************************************************************************************************************/
software_delay_loop(uint32_t loop_cnt)160 BSP_ATTRIBUTE_STACKLESS static void software_delay_loop (uint32_t loop_cnt)
161 {
162 __asm volatile ("sw_delay_loop: \n"
163
164 #if defined(__ICCARM__)
165 " subs r0, #1 \n" ///< 1 cycle
166 #elif defined(__GNUC__)
167 " sub r0, r0, #1 \n" ///< 1 cycle
168 #endif
169
170 " cmp r0, #0 \n" ///< 1 cycle
171 /* CM0 and ARMv8MBL (CM23) have a different instruction set */
172 #if defined(__CORE_CM0PLUS_H_GENERIC) || defined(__CORE_ARMV8MBL_H_GENERIC)
173 " bne sw_delay_loop \n" ///< 2 cycles
174 #else
175 " bne.n sw_delay_loop \n" ///< 2 cycles
176 #endif
177 " bx lr \n"); ///< 2 cycles
178
179 /** loop_cnt is used but since it is used in assembly an unused parameter warning can be generated. */
180 SSP_PARAMETER_NOT_USED(loop_cnt);
181 }
182
183 /** @} (end addtogroup BSP_MCU_COMMON) */
184