xref: /nrf52832-nimble/nordic/nrfx/soc/nrfx_coredep.h (revision 150812a83cab50279bd772ef6db1bfaf255f2c5b)
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