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 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 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