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