1 /* 2 * Copyright (c) 2016 - 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 #include <nrfx.h> 33 34 #if NRFX_CHECK(NRFX_CLOCK_ENABLED) 35 36 #include <nrfx_clock.h> 37 38 #define NRFX_LOG_MODULE CLOCK 39 #include <nrfx_log.h> 40 41 #if NRFX_CHECK(NRFX_POWER_ENABLED) 42 extern bool nrfx_power_irq_enabled; 43 #endif 44 45 #define EVT_TO_STR(event) \ 46 (event == NRF_CLOCK_EVENT_HFCLKSTARTED ? "NRF_CLOCK_EVENT_HFCLKSTARTED" : \ 47 (event == NRF_CLOCK_EVENT_LFCLKSTARTED ? "NRF_CLOCK_EVENT_LFCLKSTARTED" : \ 48 (event == NRF_CLOCK_EVENT_DONE ? "NRF_CLOCK_EVENT_DONE" : \ 49 (event == NRF_CLOCK_EVENT_CTTO ? "NRF_CLOCK_EVENT_CTTO" : \ 50 "UNKNOWN EVENT")))) 51 52 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 53 #if (NRF_CLOCK_HAS_CALIBRATION == 0) 54 #error "Calibration is not available in the SoC that is used." 55 #endif 56 #if (NRFX_CLOCK_CONFIG_LF_SRC != CLOCK_LFCLKSRC_SRC_RC) 57 #error "Calibration can be performed only for the RC Oscillator." 58 #endif 59 #endif 60 61 #if defined(NRF52810_XXAA) || \ 62 defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \ 63 defined(NRF52840_XXAA) 64 // Enable workaround for nRF52 anomaly 192 (LFRC oscillator frequency is wrong 65 // after calibration, exceeding 500 ppm). 66 #define USE_WORKAROUND_FOR_ANOMALY_192 67 68 // Enable workaround for nRF52 anomaly 201 (EVENTS_HFCLKSTARTED might be generated twice). 69 #define USE_WORKAROUND_FOR_ANOMALY_201 70 #endif 71 72 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 73 typedef enum 74 { 75 CAL_STATE_IDLE, 76 CAL_STATE_CAL 77 } nrfx_clock_cal_state_t; 78 #endif 79 80 /**@brief CLOCK control block. */ 81 typedef struct 82 { 83 nrfx_clock_event_handler_t event_handler; 84 bool module_initialized; /*< Indicate the state of module */ 85 #if defined(USE_WORKAROUND_FOR_ANOMALY_201) 86 bool hfclk_started; /*< Anomaly 201 workaround. */ 87 #endif 88 89 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 90 volatile nrfx_clock_cal_state_t cal_state; 91 #endif 92 } nrfx_clock_cb_t; 93 94 static nrfx_clock_cb_t m_clock_cb; 95 96 /** 97 * This variable is used to check whether common POWER_CLOCK common interrupt 98 * should be disabled or not if @ref nrfx_power tries to disable the interrupt. 99 */ 100 #if NRFX_CHECK(NRFX_POWER_ENABLED) 101 bool nrfx_clock_irq_enabled; 102 #endif 103 104 #if defined(NRF52832_XXAA) || defined(NRF52832_XXAB) 105 106 // ANOMALY 132 - LFCLK needs to avoid frame from 66us to 138us after LFCLK stop. This solution 107 // applies delay of 138us before starting LFCLK. 108 #define ANOMALY_132_REQ_DELAY_US 138UL 109 110 // nRF52832 is clocked with 64MHz. 111 #define ANOMALY_132_NRF52832_FREQ_MHZ 64UL 112 113 // Convert time to cycles. 114 #define ANOMALY_132_DELAY_CYCLES (ANOMALY_132_REQ_DELAY_US * ANOMALY_132_NRF52832_FREQ_MHZ) 115 116 /** 117 * @brief Function for applying delay of 138us before starting LFCLK. 118 */ 119 static void nrfx_clock_anomaly_132(void) 120 { 121 uint32_t cyccnt_inital; 122 uint32_t core_debug; 123 uint32_t dwt_ctrl; 124 125 // Preserve DEMCR register to do not influence into its configuration. Enable the trace and 126 // debug blocks. It is required to read and write data to DWT block. 127 core_debug = CoreDebug->DEMCR; 128 CoreDebug->DEMCR = core_debug | CoreDebug_DEMCR_TRCENA_Msk; 129 130 // Preserve CTRL register in DWT block to do not influence into its configuration. Make sure 131 // that cycle counter is enabled. 132 dwt_ctrl = DWT->CTRL; 133 DWT->CTRL = dwt_ctrl | DWT_CTRL_CYCCNTENA_Msk; 134 135 // Store start value of cycle counter. 136 cyccnt_inital = DWT->CYCCNT; 137 138 // Delay required time. 139 while ((DWT->CYCCNT - cyccnt_inital) < ANOMALY_132_DELAY_CYCLES) 140 {} 141 142 // Restore preserved registers. 143 DWT->CTRL = dwt_ctrl; 144 CoreDebug->DEMCR = core_debug; 145 } 146 147 #endif // defined(NRF52832_XXAA) || defined(NRF52832_XXAB) 148 149 nrfx_err_t nrfx_clock_init(nrfx_clock_event_handler_t event_handler) 150 { 151 NRFX_ASSERT(event_handler); 152 153 nrfx_err_t err_code = NRFX_SUCCESS; 154 if (m_clock_cb.module_initialized) 155 { 156 err_code = NRFX_ERROR_ALREADY_INITIALIZED; 157 } 158 else 159 { 160 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 161 m_clock_cb.cal_state = CAL_STATE_IDLE; 162 #endif 163 m_clock_cb.event_handler = event_handler; 164 m_clock_cb.module_initialized = true; 165 #if defined(USE_WORKAROUND_FOR_ANOMALY_201) 166 m_clock_cb.hfclk_started = false; 167 #endif 168 } 169 170 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 171 return err_code; 172 } 173 174 void nrfx_clock_enable(void) 175 { 176 NRFX_ASSERT(m_clock_cb.module_initialized); 177 nrfx_power_clock_irq_init(); 178 nrf_clock_lf_src_set((nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC); 179 180 #if NRFX_CHECK(NRFX_POWER_ENABLED) 181 nrfx_clock_irq_enabled = true; 182 #endif 183 184 NRFX_LOG_INFO("Module enabled."); 185 } 186 187 void nrfx_clock_disable(void) 188 { 189 NRFX_ASSERT(m_clock_cb.module_initialized); 190 #if NRFX_CHECK(NRFX_POWER_ENABLED) 191 NRFX_ASSERT(nrfx_clock_irq_enabled); 192 if (!nrfx_power_irq_enabled) 193 #endif 194 { 195 NRFX_IRQ_DISABLE(nrfx_get_irq_number(NRF_CLOCK)); 196 } 197 nrf_clock_int_disable(CLOCK_INTENSET_HFCLKSTARTED_Msk | 198 CLOCK_INTENSET_LFCLKSTARTED_Msk | 199 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 200 CLOCK_INTENSET_DONE_Msk | 201 CLOCK_INTENSET_CTTO_Msk | 202 #endif 203 0); 204 #if NRFX_CHECK(NRFX_POWER_ENABLED) 205 nrfx_clock_irq_enabled = false; 206 #endif 207 NRFX_LOG_INFO("Module disabled."); 208 } 209 210 void nrfx_clock_uninit(void) 211 { 212 NRFX_ASSERT(m_clock_cb.module_initialized); 213 nrfx_clock_lfclk_stop(); 214 nrfx_clock_hfclk_stop(); 215 m_clock_cb.module_initialized = false; 216 NRFX_LOG_INFO("Uninitialized."); 217 } 218 219 void nrfx_clock_lfclk_start(void) 220 { 221 NRFX_ASSERT(m_clock_cb.module_initialized); 222 nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED); 223 nrf_clock_int_enable(NRF_CLOCK_INT_LF_STARTED_MASK); 224 225 #if defined(NRF52832_XXAA) || defined(NRF52832_XXAB) 226 nrfx_clock_anomaly_132(); 227 #endif 228 229 nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART); 230 } 231 232 void nrfx_clock_lfclk_stop(void) 233 { 234 NRFX_ASSERT(m_clock_cb.module_initialized); 235 nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTOP); 236 while (nrf_clock_lf_is_running()) 237 {} 238 } 239 240 void nrfx_clock_hfclk_start(void) 241 { 242 NRFX_ASSERT(m_clock_cb.module_initialized); 243 nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED); 244 nrf_clock_int_enable(NRF_CLOCK_INT_HF_STARTED_MASK); 245 nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART); 246 } 247 248 void nrfx_clock_hfclk_stop(void) 249 { 250 NRFX_ASSERT(m_clock_cb.module_initialized); 251 nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTOP); 252 while (nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY)) 253 {} 254 #if defined(USE_WORKAROUND_FOR_ANOMALY_201) 255 m_clock_cb.hfclk_started = false; 256 #endif 257 } 258 259 nrfx_err_t nrfx_clock_calibration_start(void) 260 { 261 nrfx_err_t err_code = NRFX_SUCCESS; 262 263 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 264 if (nrfx_clock_hfclk_is_running() == false) 265 { 266 return NRFX_ERROR_INVALID_STATE; 267 } 268 269 if (nrfx_clock_lfclk_is_running() == false) 270 { 271 return NRFX_ERROR_INVALID_STATE; 272 } 273 274 if (m_clock_cb.cal_state == CAL_STATE_IDLE) 275 { 276 nrf_clock_event_clear(NRF_CLOCK_EVENT_DONE); 277 nrf_clock_int_enable(NRF_CLOCK_INT_DONE_MASK); 278 m_clock_cb.cal_state = CAL_STATE_CAL; 279 #if defined(USE_WORKAROUND_FOR_ANOMALY_192) 280 *(volatile uint32_t *)0x40000C34 = 0x00000002; 281 #endif 282 nrf_clock_task_trigger(NRF_CLOCK_TASK_CAL); 283 } 284 else 285 { 286 err_code = NRFX_ERROR_BUSY; 287 } 288 #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 289 290 NRFX_LOG_WARNING("Function: %s, error code: %s.", 291 __func__, 292 NRFX_LOG_ERROR_STRING_GET(err_code)); 293 return err_code; 294 } 295 296 nrfx_err_t nrfx_clock_is_calibrating(void) 297 { 298 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 299 if (m_clock_cb.cal_state == CAL_STATE_CAL) 300 { 301 return NRFX_ERROR_BUSY; 302 } 303 #endif 304 return NRFX_SUCCESS; 305 } 306 307 void nrfx_clock_calibration_timer_start(uint8_t interval) 308 { 309 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 310 nrf_clock_cal_timer_timeout_set(interval); 311 nrf_clock_event_clear(NRF_CLOCK_EVENT_CTTO); 312 nrf_clock_int_enable(NRF_CLOCK_INT_CTTO_MASK); 313 nrf_clock_task_trigger(NRF_CLOCK_TASK_CTSTART); 314 #endif 315 } 316 317 void nrfx_clock_calibration_timer_stop(void) 318 { 319 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 320 nrf_clock_int_disable(NRF_CLOCK_INT_CTTO_MASK); 321 nrf_clock_task_trigger(NRF_CLOCK_TASK_CTSTOP); 322 #endif 323 } 324 325 void nrfx_clock_irq_handler(void) 326 { 327 if (nrf_clock_event_check(NRF_CLOCK_EVENT_HFCLKSTARTED)) 328 { 329 nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED); 330 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_HFCLKSTARTED)); 331 nrf_clock_int_disable(NRF_CLOCK_INT_HF_STARTED_MASK); 332 333 #if defined(USE_WORKAROUND_FOR_ANOMALY_201) 334 if (!m_clock_cb.hfclk_started) 335 { 336 m_clock_cb.hfclk_started = true; 337 m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED); 338 } 339 #else 340 m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED); 341 #endif 342 } 343 if (nrf_clock_event_check(NRF_CLOCK_EVENT_LFCLKSTARTED)) 344 { 345 nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED); 346 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_LFCLKSTARTED)); 347 nrf_clock_int_disable(NRF_CLOCK_INT_LF_STARTED_MASK); 348 349 m_clock_cb.event_handler(NRFX_CLOCK_EVT_LFCLK_STARTED); 350 } 351 352 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 353 if (nrf_clock_event_check(NRF_CLOCK_EVENT_CTTO)) 354 { 355 nrf_clock_event_clear(NRF_CLOCK_EVENT_CTTO); 356 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_CTTO)); 357 nrf_clock_int_disable(NRF_CLOCK_INT_CTTO_MASK); 358 359 m_clock_cb.event_handler(NRFX_CLOCK_EVT_CTTO); 360 } 361 362 if (nrf_clock_event_check(NRF_CLOCK_EVENT_DONE)) 363 { 364 #if defined(USE_WORKAROUND_FOR_ANOMALY_192) 365 *(volatile uint32_t *)0x40000C34 = 0x00000000; 366 #endif 367 nrf_clock_event_clear(NRF_CLOCK_EVENT_DONE); 368 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_DONE)); 369 nrf_clock_int_disable(NRF_CLOCK_INT_DONE_MASK); 370 m_clock_cb.cal_state = CAL_STATE_IDLE; 371 m_clock_cb.event_handler(NRFX_CLOCK_EVT_CAL_DONE); 372 } 373 #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) 374 } 375 376 #endif // NRFX_CHECK(NRFX_CLOCK_ENABLED) 377