1 /*
2 * Copyright (c) 2018 - 2024, 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 #if NRFX_CHECK(ISA_RISCV)
39 #include <hal/nrf_vpr_csr.h>
40 #include <hal/nrf_vpr_csr_vtim.h>
41 #endif
42
43 /**
44 * @defgroup nrfx_coredep Core-dependent functionality
45 * @{
46 * @ingroup nrfx
47 * @brief Module containing functions with core-dependent implementation, like delay.
48 */
49
50 #if defined(__NRFX_DOXYGEN__)
51
52 /** @brief Core frequency (in MHz). */
53 #define NRFX_DELAY_CPU_FREQ_MHZ
54 /** @brief Availability of Data Watchpoint and Trace (DWT) unit in the given SoC. */
55 #define NRFX_DELAY_DWT_PRESENT
56 /**
57 * @brief Number of cycles consumed by one iteration of the internal loop
58 * in the function @ref nrfx_coredep_delay_us.
59 *
60 * This value can be specified externally (for example, when the SoC is emulated).
61 */
62 #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES
63
64 #elif defined(NRFX_DELAY_CPU_FREQ_MHZ) && defined(NRFX_DELAY_DWT_PRESENT)
65 /* Do nothing. */
66 #elif defined(NRF51)
67 #define NRFX_DELAY_CPU_FREQ_MHZ 16
68 #define NRFX_DELAY_DWT_PRESENT 0
69 #elif defined(NRF52805_XXAA) || defined(NRF52810_XXAA) || \
70 defined(NRF52811_XXAA) || defined(NRF52820_XXAA)
71 #define NRFX_DELAY_CPU_FREQ_MHZ 64
72 #define NRFX_DELAY_DWT_PRESENT 0
73 #elif defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
74 defined(NRF52833_XXAA) || defined(NRF52840_XXAA) || \
75 defined(NRF9120_XXAA) || defined(NRF9160_XXAA)
76 #define NRFX_DELAY_CPU_FREQ_MHZ 64
77 #define NRFX_DELAY_DWT_PRESENT 1
78 #elif defined(NRF5340_XXAA_APPLICATION)
79 #define NRFX_DELAY_CPU_FREQ_MHZ (SystemCoreClock / 1000000)
80 #define NRFX_DELAY_DWT_PRESENT 1
81 #elif defined(NRF5340_XXAA_NETWORK)
82 #define NRFX_DELAY_CPU_FREQ_MHZ 64
83 #define NRFX_DELAY_DWT_PRESENT 1
84 #elif defined(NRF54H20_XXAA) || defined(NRF54H20_ENGA_XXAA)
85 #define NRFX_DELAY_CPU_FREQ_MHZ (SystemCoreClock / 1000000)
86 #define NRFX_DELAY_DWT_PRESENT 0
87 #elif defined(NRF54L15_XXAA) || defined(NRF54L15_ENGA_XXAA)
88 #define NRFX_DELAY_CPU_FREQ_MHZ (SystemCoreClock / 1000000)
89 #define NRFX_DELAY_DWT_PRESENT 1
90 #else
91 #error "Unknown device"
92 #endif
93
94 /**
95 * @brief Function for delaying execution for a number of microseconds.
96 *
97 * The value of @p time_us is multiplied by the CPU frequency in MHz. Therefore, the delay
98 * is limited to the maximum value of the uint32_t type divided by the frequency.
99 * @sa NRFX_COREDEP_DELAY_US_LOOP_CYCLES
100 *
101 * @param time_us Number of microseconds to wait.
102 */
103 NRF_STATIC_INLINE void nrfx_coredep_delay_us(uint32_t time_us);
104
105 /** @} */
106
107 #ifndef NRF_DECLARE_ONLY
108
109 #if NRFX_CHECK(NRFX_DELAY_DWT_BASED)
110
111 #if !NRFX_DELAY_DWT_PRESENT
112 #error "DWT unit not present in the SoC that is used."
113 #endif
114
nrfx_coredep_delay_us(uint32_t time_us)115 NRF_STATIC_INLINE void nrfx_coredep_delay_us(uint32_t time_us)
116 {
117 if (time_us == 0)
118 {
119 return;
120 }
121 uint32_t time_cycles = time_us * NRFX_DELAY_CPU_FREQ_MHZ;
122
123 // Save the current state of the DEMCR register to be able to restore it before exiting
124 // this function. Enable the trace and debug blocks (including DWT).
125 uint32_t core_debug = CoreDebug->DEMCR;
126 CoreDebug->DEMCR = core_debug | CoreDebug_DEMCR_TRCENA_Msk;
127
128 // Save the current state of the CTRL register in the DWT block. Make sure
129 // that the cycle counter is enabled.
130 uint32_t dwt_ctrl = DWT->CTRL;
131 DWT->CTRL = dwt_ctrl | DWT_CTRL_CYCCNTENA_Msk;
132
133 // Store start value of the cycle counter.
134 uint32_t cyccnt_initial = DWT->CYCCNT;
135
136 // Delay required time.
137 while ((DWT->CYCCNT - cyccnt_initial) < time_cycles)
138 {}
139
140 // Restore preserved registers.
141 DWT->CTRL = dwt_ctrl;
142 CoreDebug->DEMCR = core_debug;
143 }
144
145 #else // NRFX_CHECK(NRFX_DELAY_DWT_BASED)
146
nrfx_coredep_delay_us(uint32_t time_us)147 NRF_STATIC_INLINE void nrfx_coredep_delay_us(uint32_t time_us)
148 {
149 if (time_us == 0)
150 {
151 return;
152 }
153
154 #if NRFX_CHECK(ISA_ARM)
155 // Allow overriding the number of cycles per loop iteration, in case it is
156 // needed to adjust this number externally (for example, when the SoC is
157 // emulated).
158 #ifndef NRFX_COREDEP_DELAY_US_LOOP_CYCLES
159 #if defined(NRF51)
160 // The loop takes 4 cycles: 1 for SUBS, 3 for BHI.
161 #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES 4
162 #elif defined(NRF52805_XXAA) || defined(NRF52810_XXAA) || \
163 defined(NRF52811_XXAA) || defined(NRF52820_XXAA)
164 // The loop takes 7 cycles: 1 for SUBS, 2 for BHI, 2 wait states
165 // for each instruction.
166 #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES 7
167 #else
168 // The loop takes 3 cycles: 1 for SUBS, 2 for BHI.
169 #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES 3
170 #endif
171 #endif // NRFX_COREDEP_DELAY_US_LOOP_CYCLES
172 // Align the machine code, so that it can be cached properly and no extra
173 // wait states appear.
174 __ALIGN(16)
175 static const uint16_t delay_machine_code[] = {
176 0x3800 + NRFX_COREDEP_DELAY_US_LOOP_CYCLES, // SUBS r0, #loop_cycles
177 0xd8fd, // BHI .-2
178 0x4770 // BX LR
179 };
180
181 typedef void (* delay_func_t)(uint32_t);
182 const delay_func_t delay_cycles =
183 // Set LSB to 1 to execute the code in the Thumb mode.
184 (delay_func_t)((((uint32_t)delay_machine_code) | 1));
185 uint32_t cycles = time_us * NRFX_DELAY_CPU_FREQ_MHZ;
186 delay_cycles(cycles);
187 #elif NRFX_CHECK(ISA_RISCV)
188 #if !NRFX_CHECK(NRFX_COREDEP_VPR_LEGACY)
189 nrf_vpr_csr_vtim_count_mode_set(1, NRF_VPR_CSR_VTIM_COUNT_TRIGGER_COMBINED);
190 nrf_vpr_csr_vtim_combined_counter_set(time_us * NRFX_DELAY_CPU_FREQ_MHZ);
191 nrf_vpr_csr_vtim_combined_wait_trigger();
192 #else
193 #if !defined(NRFX_DELAY_RISCV_SLOWDOWN)
194 #if defined(NRF54L15_XXAA) || defined(NRF54L15_ENGA_XXAA)
195 #define NRFX_DELAY_RISCV_SLOWDOWN 15
196 #else
197 #define NRFX_DELAY_RISCV_SLOWDOWN 50
198 #endif // defined(NRF54L15_XXAA) || defined(NRF54L15_ENGA_XXAA)
199 #endif // !defined(NRFX_DELAY_RISCV_SLOWDOWN)
200
201 for (volatile uint32_t i = 0;
202 i < ((NRFX_DELAY_CPU_FREQ_MHZ * time_us) / NRFX_DELAY_RISCV_SLOWDOWN);
203 i++)
204 {}
205
206 #endif // !NRFX_CHECK(NRFX_CONFIG_COREDEP_VPR_LEGACY)
207 #endif // NRFX_CHECK(ISA_ARM)
208 }
209
210 #endif // !NRFX_CHECK(NRFX_DELAY_DWT_BASED_DELAY)
211
212 #endif // NRF_DECLARE_ONLY
213
214 #endif // NRFX_COREDEP_H__
215