1 /*
2 * Copyright (c) 2018 - 2023, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #ifndef NRFX_COREDEP_H__
35 #define NRFX_COREDEP_H__
36
37 #include <nrfx.h>
38
39 /**
40 * @defgroup nrfx_coredep Core-dependent functionality
41 * @{
42 * @ingroup nrfx
43 * @brief Module containing functions with core-dependent implementation, like delay.
44 */
45
46 #if defined(__NRFX_DOXYGEN__)
47
48 /** @brief Core frequency (in MHz). */
49 #define NRFX_DELAY_CPU_FREQ_MHZ
50 /** @brief Availability of Data Watchpoint and Trace (DWT) unit in the given SoC. */
51 #define NRFX_DELAY_DWT_PRESENT
52 /**
53 * @brief Number of cycles consumed by one iteration of the internal loop
54 * in the function @ref nrfx_coredep_delay_us.
55 *
56 * This value can be specified externally (for example, when the SoC is emulated).
57 */
58 #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES
59
60 #elif defined(NRF51)
61 #define NRFX_DELAY_CPU_FREQ_MHZ 16
62 #define NRFX_DELAY_DWT_PRESENT 0
63 #elif defined(NRF52805_XXAA) || defined(NRF52810_XXAA) || \
64 defined(NRF52811_XXAA) || defined(NRF52820_XXAA)
65 #define NRFX_DELAY_CPU_FREQ_MHZ 64
66 #define NRFX_DELAY_DWT_PRESENT 0
67 #elif defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
68 defined(NRF52833_XXAA) || defined(NRF52840_XXAA) || \
69 defined(NRF9120_XXAA) || defined(NRF9160_XXAA)
70 #define NRFX_DELAY_CPU_FREQ_MHZ 64
71 #define NRFX_DELAY_DWT_PRESENT 1
72 #elif defined(NRF5340_XXAA_APPLICATION)
73 #define NRFX_DELAY_CPU_FREQ_MHZ (SystemCoreClock / 1000000)
74 #define NRFX_DELAY_DWT_PRESENT 1
75 #elif defined(NRF5340_XXAA_NETWORK)
76 #define NRFX_DELAY_CPU_FREQ_MHZ 64
77 #define NRFX_DELAY_DWT_PRESENT 1
78 #elif !defined(NRFX_DELAY_CPU_FREQ_MHZ) || !defined(NRFX_DELAY_DWT_PRESENT)
79 #error "Unknown device"
80 #endif
81
82 #if ISA_RISCV
83 /** @brief Slowdown for RISCV cores. */
84 #define NRFX_DELAY_RISCV_SLOWDOWN 110
85 #endif
86
87 /**
88 * @brief Function for delaying execution for a number of microseconds.
89 *
90 * The value of @p time_us is multiplied by the CPU frequency in MHz. Therefore, the delay
91 * is limited to the maximum value of the uint32_t type divided by the frequency.
92 * @sa NRFX_COREDEP_DELAY_US_LOOP_CYCLES
93 *
94 * @param time_us Number of microseconds to wait.
95 */
96 NRF_STATIC_INLINE void nrfx_coredep_delay_us(uint32_t time_us);
97
98 /** @} */
99
100 #ifndef NRF_DECLARE_ONLY
101
102 #if NRFX_CHECK(NRFX_DELAY_DWT_BASED)
103
104 #if !NRFX_DELAY_DWT_PRESENT
105 #error "DWT unit not present in the SoC that is used."
106 #endif
107
nrfx_coredep_delay_us(uint32_t time_us)108 NRF_STATIC_INLINE void nrfx_coredep_delay_us(uint32_t time_us)
109 {
110 if (time_us == 0)
111 {
112 return;
113 }
114 uint32_t time_cycles = time_us * NRFX_DELAY_CPU_FREQ_MHZ;
115
116 // Save the current state of the DEMCR register to be able to restore it before exiting
117 // this function. Enable the trace and debug blocks (including DWT).
118 uint32_t core_debug = CoreDebug->DEMCR;
119 CoreDebug->DEMCR = core_debug | CoreDebug_DEMCR_TRCENA_Msk;
120
121 // Save the current state of the CTRL register in the DWT block. Make sure
122 // that the cycle counter is enabled.
123 uint32_t dwt_ctrl = DWT->CTRL;
124 DWT->CTRL = dwt_ctrl | DWT_CTRL_CYCCNTENA_Msk;
125
126 // Store start value of the cycle counter.
127 uint32_t cyccnt_initial = DWT->CYCCNT;
128
129 // Delay required time.
130 while ((DWT->CYCCNT - cyccnt_initial) < time_cycles)
131 {}
132
133 // Restore preserved registers.
134 DWT->CTRL = dwt_ctrl;
135 CoreDebug->DEMCR = core_debug;
136 }
137
138 #else // NRFX_CHECK(NRFX_DELAY_DWT_BASED)
139
nrfx_coredep_delay_us(uint32_t time_us)140 NRF_STATIC_INLINE void nrfx_coredep_delay_us(uint32_t time_us)
141 {
142 if (time_us == 0)
143 {
144 return;
145 }
146
147 #if ISA_ARM
148 // Allow overriding the number of cycles per loop iteration, in case it is
149 // needed to adjust this number externally (for example, when the SoC is
150 // emulated).
151 #ifndef NRFX_COREDEP_DELAY_US_LOOP_CYCLES
152 #if defined(NRF51)
153 // The loop takes 4 cycles: 1 for SUBS, 3 for BHI.
154 #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES 4
155 #elif defined(NRF52805_XXAA) || defined(NRF52810_XXAA) || \
156 defined(NRF52811_XXAA) || defined(NRF52820_XXAA)
157 // The loop takes 7 cycles: 1 for SUBS, 2 for BHI, 2 wait states
158 // for each instruction.
159 #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES 7
160 #else
161 // The loop takes 3 cycles: 1 for SUBS, 2 for BHI.
162 #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES 3
163 #endif
164 #endif // NRFX_COREDEP_DELAY_US_LOOP_CYCLES
165 // Align the machine code, so that it can be cached properly and no extra
166 // wait states appear.
167 __ALIGN(16)
168 static const uint16_t delay_machine_code[] = {
169 0x3800 + NRFX_COREDEP_DELAY_US_LOOP_CYCLES, // SUBS r0, #loop_cycles
170 0xd8fd, // BHI .-2
171 0x4770 // BX LR
172 };
173
174 typedef void (* delay_func_t)(uint32_t);
175 const delay_func_t delay_cycles =
176 // Set LSB to 1 to execute the code in the Thumb mode.
177 (delay_func_t)((((uint32_t)delay_machine_code) | 1));
178 uint32_t cycles = time_us * NRFX_DELAY_CPU_FREQ_MHZ;
179 delay_cycles(cycles);
180 #elif ISA_RISCV
181 for (volatile uint32_t i = 0;
182 i < ((NRFX_DELAY_CPU_FREQ_MHZ * time_us) / NRFX_DELAY_RISCV_SLOWDOWN);
183 i++)
184 {}
185 #endif
186 }
187
188 #endif // !NRFX_CHECK(NRFX_DELAY_DWT_BASED_DELAY)
189
190 #endif // NRF_DECLARE_ONLY
191
192 #endif // NRFX_COREDEP_H__
193