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