diff --git a/hal/targets.json b/hal/targets.json index 4beaec92bc..477f0bc083 100644 --- a/hal/targets.json +++ b/hal/targets.json @@ -1100,7 +1100,7 @@ "inherits": ["Target"], "core": "Cortex-M0", "OVERRIDE_BOOTLOADER_FILENAME": "nrf51822_bootloader.hex", - "macros": ["NRF51", "TARGET_NRF51822"], + "macros": ["NRF51", "TARGET_NRF51822", "SOFTDEVICE_PRESENT"], "MERGE_BOOTLOADER": false, "extra_labels": ["NORDIC", "MCU_NRF51", "MCU_NRF51822", "NRF5"], "OUTPUT_EXT": "hex", @@ -1738,11 +1738,11 @@ "MCU_NRF52": { "inherits": ["Target"], "core": "Cortex-M4F", - "macros": ["NRF52", "TARGET_NRF52832"], + "macros": ["NRF52", "TARGET_NRF52832", "SOFTDEVICE_PRESENT"], "extra_labels": ["NORDIC", "MCU_NRF52", "MCU_NRF52832", "NRF5"], "OUTPUT_EXT": "hex", "is_disk_virtual": true, - "supported_toolchains": ["ARM", "GCC_ARM"], + "supported_toolchains": ["GCC_ARM"], "public": false, "detect_code": ["1101"], "program_cycle_s": 6, diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/clock/nrf_drv_clock.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/clock/nrf_drv_clock.c new file mode 100644 index 0000000000..2d18431ad0 --- /dev/null +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/clock/nrf_drv_clock.c @@ -0,0 +1,479 @@ +/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ + +#include "nrf_drv_clock.h" +#include "nrf_error.h" +#include "nordic_common.h" + +#ifdef SOFTDEVICE_PRESENT +#include "nrf_sdm.h" +#include "nrf_soc.h" +#include "app_util_platform.h" +#else +#include "app_util_platform.h" +#endif // SOFTDEVICE_PRESENT + +/*lint -save -e652 */ +#define NRF_CLOCK_LFCLK_RC CLOCK_LFCLKSRC_SRC_RC +#define NRF_CLOCK_LFCLK_Xtal CLOCK_LFCLKSRC_SRC_Xtal +#define NRF_CLOCK_LFCLK_Synth CLOCK_LFCLKSRC_SRC_Synth +/*lint -restore */ + +#define INT_MAX 0xFFFFFFFF + +#if (CLOCK_CONFIG_LF_SRC == NRF_CLOCK_LFCLK_RC) && !defined(SOFTDEVICE_PRESENT) +#define CALIBRATION_SUPPORT 1 +#else +#define CALIBRATION_SUPPORT 0 +#endif +typedef enum +{ + CAL_STATE_IDLE, + CAL_STATE_CT, + CAL_STATE_HFCLK_REQ, + CAL_STATE_CAL, + CAL_STATE_ABORT, +} nrf_drv_clock_cal_state_t; + +/**@brief CLOCK control block. */ +typedef struct +{ + volatile uint32_t hfclk_requests; /*< High-frequency clock request counter. */ + volatile nrf_drv_clock_handler_item_t * p_hf_head; + bool module_initialized; /*< Indicate the state of module */ + volatile bool hfclk_on; /*< High-frequency clock state. */ +#ifndef SOFTDEVICE_PRESENT + volatile bool lfclk_on; /*< Low-frequency clock state. */ + uint32_t lfclk_requests; /*< Low-frequency clock request counter. */ + volatile nrf_drv_clock_handler_item_t * p_lf_head; +#if CALIBRATION_SUPPORT + nrf_drv_clock_handler_item_t cal_hfclk_started_handler_item; + nrf_drv_clock_event_handler_t cal_done_handler; + volatile nrf_drv_clock_cal_state_t cal_state; +#endif //CALIBRATION_SUPPORT +#endif //SOFTDEVICE_PRESENT +}nrf_drv_clock_cb_t; + +static nrf_drv_clock_cb_t m_clock_cb; + +#ifndef SOFTDEVICE_PRESENT +/**@brief Function for starting LFCLK. This function will return immediately without waiting for start. + */ +static void lfclk_start(void) +{ + nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED); + nrf_clock_int_enable(NRF_CLOCK_INT_LF_STARTED_MASK); + nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART); +} + +/**@brief Function for stopping LFCLK and calibration (if it was set up). + */ +static void lfclk_stop(void) +{ +#if CALIBRATION_SUPPORT + (void)nrf_drv_clock_calibration_abort(); +#endif //CALIBRATION_SUPPORT + + nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTOP); + while (nrf_clock_lf_is_running()) + {} +} +#endif +static void hfclk_start(void) +{ +#ifndef SOFTDEVICE_PRESENT + nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED); + nrf_clock_int_enable(NRF_CLOCK_INT_HF_STARTED_MASK); + nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART); +#else + UNUSED_VARIABLE(sd_clock_hfclk_request()); +#endif +} + +static void hfclk_stop(void) +{ +#ifndef SOFTDEVICE_PRESENT + nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTOP); + while (nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY)) + {} +#else + UNUSED_VARIABLE(sd_clock_hfclk_release()); +#endif +} + +ret_code_t nrf_drv_clock_init(void) +{ + uint32_t result = NRF_SUCCESS; + + if (m_clock_cb.module_initialized) + { + return MODULE_ALREADY_INITIALIZED; + } + + m_clock_cb.p_hf_head = NULL; + m_clock_cb.hfclk_requests = 0; +#ifndef SOFTDEVICE_PRESENT + m_clock_cb.p_lf_head = NULL; + m_clock_cb.lfclk_requests = 0; + nrf_clock_xtalfreq_set(CLOCK_CONFIG_XTAL_FREQ); + nrf_clock_lf_src_set((nrf_clock_lfclk_t)CLOCK_CONFIG_LF_SRC); + nrf_drv_common_irq_enable(POWER_CLOCK_IRQn, CLOCK_CONFIG_IRQ_PRIORITY); +#if CALIBRATION_SUPPORT + m_clock_cb.cal_state = CAL_STATE_IDLE; +#endif // CALIBRATION_SUPPORT +#else // SOFTDEVICE_PRESENT + uint8_t is_enabled; + result = sd_softdevice_is_enabled(&is_enabled); + if((result == NRF_SUCCESS) && !is_enabled) + { + result = NRF_ERROR_SOFTDEVICE_NOT_ENABLED; + } +#endif // SOFTDEVICE_PRESENT + m_clock_cb.module_initialized = true; + return result; +} + +void nrf_drv_clock_uninit(void) +{ + ASSERT(m_clock_cb.module_initialized); +#ifndef SOFTDEVICE_PRESENT + nrf_drv_common_irq_disable(POWER_CLOCK_IRQn); + nrf_clock_int_disable(0xFFFFFFFF); + lfclk_stop(); +#endif + hfclk_stop(); + m_clock_cb.module_initialized = false; +} + +static void item_enqueue(nrf_drv_clock_handler_item_t ** p_head, + nrf_drv_clock_handler_item_t * p_item) +{ + if (*p_head) + { + p_item->p_next = *p_head; + *p_head = p_item; + } + else + { + p_item->p_next = NULL; + *p_head = p_item; + } +} + +static nrf_drv_clock_handler_item_t * item_dequeue(nrf_drv_clock_handler_item_t ** p_head) +{ + nrf_drv_clock_handler_item_t * p_item = *p_head; + if (p_item) + { + *p_head = p_item->p_next; + } + + return p_item; +} + +void nrf_drv_clock_lfclk_request(nrf_drv_clock_handler_item_t * p_handler_item) +{ + ASSERT(m_clock_cb.module_initialized); +#ifndef SOFTDEVICE_PRESENT + ASSERT(m_clock_cb.lfclk_requests != INT_MAX); + CRITICAL_REGION_ENTER(); + if (m_clock_cb.lfclk_on) + { + if (p_handler_item) + { + p_handler_item->event_handler(NRF_DRV_CLOCK_EVT_LFCLK_STARTED); + } + } + else + { + + if (p_handler_item) + { + item_enqueue((nrf_drv_clock_handler_item_t **)&m_clock_cb.p_lf_head, p_handler_item); + } + if (m_clock_cb.lfclk_requests == 0) + { + lfclk_start(); + } + } + m_clock_cb.lfclk_requests++; + CRITICAL_REGION_EXIT(); +#else + if (p_handler_item) + { + p_handler_item->event_handler(NRF_DRV_CLOCK_EVT_LFCLK_STARTED); + } +#endif // SOFTDEVICE_PRESENT +} + + +void nrf_drv_clock_lfclk_release(void) +{ + ASSERT(m_clock_cb.module_initialized); +#ifndef SOFTDEVICE_PRESENT + ASSERT(m_clock_cb.lfclk_requests > 0); + + CRITICAL_REGION_ENTER(); + m_clock_cb.lfclk_requests--; + if (m_clock_cb.lfclk_requests == 0) + { + lfclk_stop(); + m_clock_cb.lfclk_on = false; + m_clock_cb.p_lf_head = NULL; + } + CRITICAL_REGION_EXIT(); +#endif // SOFTDEVICE_PRESENT +} + + +bool nrf_drv_clock_lfclk_is_running(void) +{ + ASSERT(m_clock_cb.module_initialized); + bool result; +#ifndef SOFTDEVICE_PRESENT + result = nrf_clock_lf_is_running(); +#else + result = true; +#endif + return result; +} + +void nrf_drv_clock_hfclk_request(nrf_drv_clock_handler_item_t * p_handler_item) +{ + ASSERT(m_clock_cb.module_initialized); + ASSERT(m_clock_cb.hfclk_requests != INT_MAX); + + CRITICAL_REGION_ENTER(); + if (m_clock_cb.hfclk_on) + { + if (p_handler_item) + { + p_handler_item->event_handler(NRF_DRV_CLOCK_EVT_HFCLK_STARTED); + } + } + else + { + if (p_handler_item) + { + item_enqueue((nrf_drv_clock_handler_item_t **)&m_clock_cb.p_hf_head, p_handler_item); + } + if (m_clock_cb.hfclk_requests == 0) + { + hfclk_start(); + } + } + m_clock_cb.hfclk_requests++; + CRITICAL_REGION_EXIT(); +} + +void nrf_drv_clock_hfclk_release(void) +{ + ASSERT(m_clock_cb.module_initialized); + ASSERT(m_clock_cb.hfclk_requests > 0); + + //disable interrupts CLOCK or SoftDevice events + CRITICAL_REGION_ENTER(); + m_clock_cb.hfclk_requests--; + if (m_clock_cb.hfclk_requests == 0) + { + hfclk_stop(); + m_clock_cb.hfclk_on = false; + m_clock_cb.p_hf_head = NULL; + } + CRITICAL_REGION_EXIT(); + //enable interrupts CLOCK or SoftDevice events +} + +bool nrf_drv_clock_hfclk_is_running(void) +{ + bool result; + ASSERT(m_clock_cb.module_initialized); +#ifndef SOFTDEVICE_PRESENT + result = nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY); +#else + uint32_t is_running; + UNUSED_VARIABLE(sd_clock_hfclk_is_running(&is_running)); + result = is_running ? true : false; +#endif + return result; +} + +#if CALIBRATION_SUPPORT +static void clock_calibration_hf_started(nrf_drv_clock_evt_type_t event) +{ + if (m_clock_cb.cal_state == CAL_STATE_ABORT) + { + nrf_drv_clock_hfclk_release(); + m_clock_cb.cal_state = CAL_STATE_IDLE; + if (m_clock_cb.cal_done_handler) + { + m_clock_cb.cal_done_handler(NRF_DRV_CLOCK_EVT_CAL_ABORTED); + } + } + else + { + nrf_clock_int_enable(NRF_CLOCK_INT_DONE_MASK); + m_clock_cb.cal_state = CAL_STATE_CAL; + nrf_clock_task_trigger(NRF_CLOCK_TASK_CAL); + } +} +#endif + +ret_code_t nrf_drv_clock_calibration_start(uint8_t interval, nrf_drv_clock_event_handler_t handler) +{ +#if CALIBRATION_SUPPORT + ASSERT(m_clock_cb.cal_state == CAL_STATE_IDLE); + ret_code_t ret = NRF_SUCCESS; + if (m_clock_cb.lfclk_on == false) + { + ret = NRF_ERROR_INVALID_STATE; + } + else if (m_clock_cb.cal_state == CAL_STATE_IDLE) + { + m_clock_cb.cal_done_handler = handler; + m_clock_cb.cal_hfclk_started_handler_item.event_handler = clock_calibration_hf_started; + if (interval == 0) + { + m_clock_cb.cal_state = CAL_STATE_HFCLK_REQ; + nrf_drv_clock_hfclk_request(&m_clock_cb.cal_hfclk_started_handler_item); + } + else + { + m_clock_cb.cal_state = CAL_STATE_CT; + nrf_clock_cal_timer_timeout_set(interval); + nrf_clock_int_enable(NRF_CLOCK_INT_CTTO_MASK); + nrf_clock_task_trigger(NRF_CLOCK_TASK_CTSTART); + } + } + else + { + ret = NRF_ERROR_BUSY; + } + return ret; +#else //CALIBRATION_SUPPORT + return NRF_ERROR_FORBIDDEN; +#endif +} + + +ret_code_t nrf_drv_clock_calibration_abort(void) +{ +#if CALIBRATION_SUPPORT + CRITICAL_REGION_ENTER(); + switch(m_clock_cb.cal_state) + { + case CAL_STATE_CT: + nrf_clock_int_disable(NRF_CLOCK_INT_CTTO_MASK); + nrf_clock_task_trigger(NRF_CLOCK_TASK_CTSTOP); + m_clock_cb.cal_state = CAL_STATE_IDLE; + if (m_clock_cb.cal_done_handler) + { + m_clock_cb.cal_done_handler(NRF_DRV_CLOCK_EVT_CAL_ABORTED); + } + break; + case CAL_STATE_HFCLK_REQ: + /* fall through. */ + case CAL_STATE_CAL: + m_clock_cb.cal_state = CAL_STATE_ABORT; + break; + default: + break; + } + CRITICAL_REGION_EXIT(); + return NRF_SUCCESS; +#else //CALIBRATION_SUPPORT + return NRF_ERROR_FORBIDDEN; +#endif +} + +ret_code_t nrf_drv_clock_is_calibrating(bool * p_is_calibrating) +{ +#if CALIBRATION_SUPPORT + ASSERT(m_clock_cb.module_initialized); + *p_is_calibrating = (m_clock_cb.cal_state != CAL_STATE_IDLE); + return NRF_SUCCESS; +#else //CALIBRATION_SUPPORT + return NRF_ERROR_FORBIDDEN; +#endif +} + +static __INLINE void clock_clk_started_notify(nrf_drv_clock_handler_item_t **p_head, + nrf_drv_clock_evt_type_t evt_type) +{ + while(1) + { + nrf_drv_clock_handler_item_t * p_item = item_dequeue(p_head); + if (p_item) + { + p_item->event_handler(evt_type); + } + else + { + break; + } + } +} + +#ifndef SOFTDEVICE_PRESENT +void POWER_CLOCK_IRQHandler(void) +{ + if (nrf_clock_event_check(NRF_CLOCK_EVENT_HFCLKSTARTED)) + { + nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED); + nrf_clock_int_disable(NRF_CLOCK_INT_HF_STARTED_MASK); + m_clock_cb.hfclk_on = true; + clock_clk_started_notify((nrf_drv_clock_handler_item_t **)&m_clock_cb.p_hf_head, NRF_DRV_CLOCK_EVT_HFCLK_STARTED); + } + if (nrf_clock_event_check(NRF_CLOCK_EVENT_LFCLKSTARTED)) + { + nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED); + nrf_clock_int_disable(NRF_CLOCK_INT_LF_STARTED_MASK); + m_clock_cb.lfclk_on = true; + clock_clk_started_notify((nrf_drv_clock_handler_item_t **)&m_clock_cb.p_lf_head, NRF_DRV_CLOCK_EVT_LFCLK_STARTED); + } +#if CALIBRATION_SUPPORT + if (nrf_clock_event_check(NRF_CLOCK_EVENT_CTTO)) + { + nrf_clock_event_clear(NRF_CLOCK_EVENT_CTTO); + nrf_clock_int_disable(NRF_CLOCK_INT_CTTO_MASK); + nrf_drv_clock_hfclk_request(&m_clock_cb.cal_hfclk_started_handler_item); + } + + if (nrf_clock_event_check(NRF_CLOCK_EVENT_DONE)) + { + nrf_clock_event_clear(NRF_CLOCK_EVENT_DONE); + nrf_clock_int_disable(NRF_CLOCK_INT_DONE_MASK); + + nrf_drv_clock_hfclk_release(); + nrf_drv_clock_evt_type_t evt_type = (m_clock_cb.cal_state == CAL_STATE_ABORT) ? + NRF_DRV_CLOCK_EVT_CAL_ABORTED : NRF_DRV_CLOCK_EVT_CAL_DONE; + m_clock_cb.cal_state = CAL_STATE_IDLE; + if (m_clock_cb.cal_done_handler) + { + m_clock_cb.cal_done_handler(evt_type); + } + } +#endif //CALIBRATION_SUPPORT +} +#else +void nrf_drv_clock_on_soc_event(uint32_t evt_id) +{ + if (evt_id == NRF_EVT_HFCLKSTARTED) + { + clock_clk_started_notify((nrf_drv_clock_handler_item_t **)&m_clock_cb.p_hf_head, NRF_DRV_CLOCK_EVT_HFCLK_STARTED); + } +} +#endif // SOFTDEVICE_PRESENT + +#undef NRF_CLOCK_LFCLK_RC +#undef NRF_CLOCK_LFCLK_Xtal +#undef NRF_CLOCK_LFCLK_Synth diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/clock/nrf_drv_clock.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/clock/nrf_drv_clock.h new file mode 100644 index 0000000000..d0a650cf09 --- /dev/null +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/clock/nrf_drv_clock.h @@ -0,0 +1,246 @@ +/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ + +#ifndef NRF_DRV_CLOCK_H__ +#define NRF_DRV_CLOCK_H__ + +#include +#include +#include "sdk_errors.h" +#include "nrf_assert.h" +#include "nrf_clock.h" +#include "nrf_drv_config.h" +#include "nrf_drv_common.h" + +/** + * + * @addtogroup nrf_clock Clock HAL and driver + * @ingroup nrf_drivers + * @brief Clock APIs. + * @details The clock HAL provides basic APIs for accessing the registers of the clock. + * The clock driver provides APIs on a higher level. + * + * @defgroup nrf_clock_drv Clock driver + * @{ + * @ingroup nrf_clock + * @brief Driver for managing the low-frequency clock (LFCLK) and the high-frequency clock (HFCLK). + */ + +/** + * @brief Clock events. + */ +typedef enum +{ + NRF_DRV_CLOCK_EVT_HFCLK_STARTED, ///< HFCLK has been started. + NRF_DRV_CLOCK_EVT_LFCLK_STARTED, ///< LFCLK has been started. + NRF_DRV_CLOCK_EVT_CAL_DONE, ///< Calibration is done. + NRF_DRV_CLOCK_EVT_CAL_ABORTED, ///< Calibration has been aborted. +} nrf_drv_clock_evt_type_t; + +/** + * @brief Clock event handler. + * + * @param[in] event Event. + */ +typedef void (*nrf_drv_clock_event_handler_t)(nrf_drv_clock_evt_type_t event); + +// Forward declaration of the nrf_drv_clock_handler_item_t type. +typedef struct nrf_drv_clock_handler_item_s nrf_drv_clock_handler_item_t; + +struct nrf_drv_clock_handler_item_s +{ + nrf_drv_clock_handler_item_t * p_next; ///< A pointer to the next handler that should be called when the clock is started. + nrf_drv_clock_event_handler_t event_handler; ///< Function to be called when the clock is started. +}; + +/** + * @brief Function for initializing the nrf_drv_clock module. + * + * After initialization, the module is in power off state (clocks are not requested). + * + * @retval NRF_SUCCESS If the procedure was successful. + * @retval MODULE_ALREADY_INITIALIZED If the driver was already initialized. + * @retval NRF_ERROR_SOFTDEVICE_NOT_ENABLED If the SoftDevice was not enabled. + */ +ret_code_t nrf_drv_clock_init(void); + +/** + * @brief Function for uninitializing the clock module. + * + */ +void nrf_drv_clock_uninit(void); + +/** + * @brief Function for requesting the LFCLK. + * + * The low-frequency clock can be requested by different modules + * or contexts. The driver ensures that the clock will be started only when it is requested + * the first time. If the clock is not ready but it was already started, the handler item that is + * provided as an input parameter is added to the list of handlers that will be notified + * when the clock is started. If the clock is already enabled, user callback is called from the + * current context. + * + * The first request will start the selected LFCLK source. If an event handler is + * provided, it will be called once the LFCLK is started. If the LFCLK was already started at this + * time, the event handler will be called from the context of this function. Additionally, + * the @ref nrf_drv_clock_lfclk_is_running function can be polled to check if the clock has started. + * + * @note When a SoftDevice is enabled, the LFCLK is always running and the driver cannot control it. + * + * @note The handler item provided by the user cannot be an automatic variable. + * + * @param[in] p_handler_item A pointer to the event handler structure. + */ +void nrf_drv_clock_lfclk_request(nrf_drv_clock_handler_item_t * p_handler_item); + +/** + * @brief Function for releasing the LFCLK. + * + * If there are no more requests, the LFCLK source will be stopped. + * + * @note When a SoftDevice is enabled, the LFCLK is always running. + */ +void nrf_drv_clock_lfclk_release(void); + +/** + * @brief Function for checking the LFCLK state. + * + * @retval true If the LFCLK is running. + * @retval false If the LFCLK is not running. + */ +bool nrf_drv_clock_lfclk_is_running(void); + +/** + * @brief Function for requesting the high-accuracy source HFCLK. + * + * The high-accuracy source + * can be requested by different modules or contexts. The driver ensures that the high-accuracy + * clock will be started only when it is requested the first time. If the clock is not ready + * but it was already started, the handler item that is provided as an input parameter is added + * to the list of handlers that will be notified when the clock is started. + * + * If an event handler is provided, it will be called once the clock is started. If the clock was already + * started at this time, the event handler will be called from the context of this function. Additionally, + * the @ref nrf_drv_clock_hfclk_is_running function can be polled to check if the clock has started. + * + * @note If a SoftDevice is running, the clock is managed by the SoftDevice and all requests are handled by + * the SoftDevice. This function cannot be called from all interrupt priority levels in that case. + * @note The handler item provided by the user cannot be an automatic variable. + * + * @param[in] p_handler_item A pointer to the event handler structure. + */ +void nrf_drv_clock_hfclk_request(nrf_drv_clock_handler_item_t * p_handler_item); + +/** + * @brief Function for releasing the high-accuracy source HFCLK. + * + * If there are no more requests, the high-accuracy source will be released. + */ +void nrf_drv_clock_hfclk_release(void); + +/** + * @brief Function for checking the HFCLK state. + * + * @retval true If the HFCLK is running (for \nRFXX XTAL source). + * @retval false If the HFCLK is not running. + */ +bool nrf_drv_clock_hfclk_is_running(void); + +/** + * @brief Function for starting a single calibration process. + * + * This function can also delay the start of calibration by a user-specified value. The delay will use + * a low-power timer that is part of the CLOCK module. @ref nrf_drv_clock_is_calibrating can be called to + * check if calibration is still in progress. If a handler is provided, the user can be notified when + * calibration is completed. The ext calibration can be started from the handler context. + * + * The calibration process consists of three phases: + * - Delay (optional) + * - Requesting the high-accuracy HFCLK + * - Hardware-supported calibration + * + * @param[in] delay Time after which the calibration will be started (in 0.25 s units). + * @param[in] handler NULL or user function to be called when calibration is completed or aborted. + * + * @retval NRF_SUCCESS If the procedure was successful. + * @retval NRF_ERROR_FORBIDDEN If a SoftDevice is present or the selected LFCLK source is not an RC oscillator. + * @retval NRF_ERROR_INVALID_STATE If the low-frequency clock is off. + * @retval NRF_ERROR_BUSY If calibration is in progress. + */ +ret_code_t nrf_drv_clock_calibration_start(uint8_t delay, nrf_drv_clock_event_handler_t handler); + +/** + * @brief Function for aborting calibration. + * + * This function aborts on-going calibration. If calibration was started, it cannot be stopped. If a handler + * was provided by @ref nrf_drv_clock_calibration_start, this handler will be called once + * aborted calibration is completed. @ref nrf_drv_clock_is_calibrating can also be used to check + * if the system is calibrating. + * + * @retval NRF_SUCCESS If the procedure was successful. + * @retval NRF_ERROR_FORBIDDEN If a SoftDevice is present or the selected LFCLK source is not an RC oscillator. + */ +ret_code_t nrf_drv_clock_calibration_abort(void); + +/** + * @brief Function for checking if calibration is in progress. + * + * This function indicates that the system is + * in calibration if it is in any of the calibration process phases (see @ref nrf_drv_clock_calibration_start). + * + * @param[out] p_is_calibrating True if calibration is in progress, false if not. + * + * @retval NRF_SUCCESS If the procedure was successful. + * @retval NRF_ERROR_FORBIDDEN If a SoftDevice is present or the selected LFCLK source is not an RC oscillator. + */ +ret_code_t nrf_drv_clock_is_calibrating(bool * p_is_calibrating); + +/**@brief Function for returning a requested task address for the clock driver module. + * + * @param[in] task One of the peripheral tasks. + * + * @return Task address. + */ +__STATIC_INLINE uint32_t nrf_drv_clock_ppi_task_addr(nrf_clock_task_t task); + +/**@brief Function for returning a requested event address for the clock driver module. + * + * @param[in] event One of the peripheral events. + * + * @return Event address. + */ +__STATIC_INLINE uint32_t nrf_drv_clock_ppi_event_addr(nrf_clock_event_t event); + +/** + * @brief Function called by the SoftDevice handler if an @ref nrf_soc event is received from the SoftDevice. + */ +#ifdef SOFTDEVICE_PRESENT +void nrf_drv_clock_on_soc_event(uint32_t evt_id); +#endif +/** + *@} + **/ + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION +__STATIC_INLINE uint32_t nrf_drv_clock_ppi_task_addr(nrf_clock_task_t task) +{ + return nrf_clock_task_address_get(task); +} + +__STATIC_INLINE uint32_t nrf_drv_clock_ppi_event_addr(nrf_clock_event_t event) +{ + return nrf_clock_event_address_get(event); +} +#endif //SUPPRESS_INLINE_IMPLEMENTATION + +/*lint --flb "Leave library region" */ +#endif // NRF_CLOCK_H__ diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/common/nrf_drv_common.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/common/nrf_drv_common.c new file mode 100644 index 0000000000..8aa1ce1e42 --- /dev/null +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/common/nrf_drv_common.c @@ -0,0 +1,208 @@ +/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ + +#include +#include "nrf_drv_common.h" +#include "nrf_assert.h" +#include "app_util_platform.h" + +#ifdef SOFTDEVICE_PRESENT +#include "nrf_soc.h" +#endif + + +#if PERIPHERAL_RESOURCE_SHARING_ENABLED + +typedef struct { + nrf_drv_irq_handler_t handler; + bool acquired; +} shared_resource_t; + +// SPIM0, SPIS0, SPI0, TWIM0, TWIS0, TWI0 +#if (SPI0_ENABLED || SPIS0_ENABLED || TWI0_ENABLED || TWIS0_ENABLED) + #define SERIAL_BOX_0_IN_USE + // [this checking may need a different form in unit tests, hence macro] + #ifndef IS_SERIAL_BOX_0 + #define IS_SERIAL_BOX_0(p_per_base) (p_per_base == NRF_SPI0) + #endif + + static shared_resource_t m_serial_box_0 = { .acquired = false }; + void SPI0_TWI0_IRQHandler(void) + { + ASSERT(m_serial_box_0.handler); + m_serial_box_0.handler(); + } +#endif // (SPI0_ENABLED || SPIS0_ENABLED || TWI0_ENABLED || TWIS0_ENABLED) + +// SPIM1, SPIS1, SPI1, TWIM1, TWIS1, TWI1 +#if (SPI1_ENABLED || SPIS1_ENABLED || TWI1_ENABLED || TWIS1_ENABLED) + #define SERIAL_BOX_1_IN_USE + // [this checking may need a different form in unit tests, hence macro] + #ifndef IS_SERIAL_BOX_1 + #define IS_SERIAL_BOX_1(p_per_base) (p_per_base == NRF_SPI1) + #endif + + static shared_resource_t m_serial_box_1 = { .acquired = false }; + void SPI1_TWI1_IRQHandler(void) + { + ASSERT(m_serial_box_1.handler); + m_serial_box_1.handler(); + } +#endif // (SPI1_ENABLED || SPIS1_ENABLED || TWI1_ENABLED || TWIS1_ENABLED) + +// SPIM2, SPIS2, SPI2 +#if (SPI2_ENABLED || SPIS2_ENABLED) + #define SERIAL_BOX_2_IN_USE + // [this checking may need a different form in unit tests, hence macro] + #ifndef IS_SERIAL_BOX_2 + #define IS_SERIAL_BOX_2(p_per_base) (p_per_base == NRF_SPI2) + #endif + + static shared_resource_t m_serial_box_2 = { .acquired = false }; + void SPIM2_SPIS2_SPI2_IRQHandler(void) + { + ASSERT(m_serial_box_2.handler); + m_serial_box_2.handler(); + } +#endif // (SPI2_ENABLED || SPIS2_ENABLED) + +// COMP, LPCOMP +#if (COMP_ENABLED || LPCOMP_ENABLED) + #define COMP_LPCOMP_IN_USE + + #ifndef IS_COMP_LPCOMP + #define IS_COMP_LPCOMP(p_per_base) ((p_per_base) == NRF_LPCOMP) + #endif + + static shared_resource_t m_comp_lpcomp = { .acquired = false }; + void LPCOMP_IRQHandler(void) + { + ASSERT(m_comp_lpcomp.handler); + m_comp_lpcomp.handler(); + } +#endif // (COMP_ENABLED || LPCOMP_ENABLED) + +#if defined(SERIAL_BOX_0_IN_USE) || \ + defined(SERIAL_BOX_1_IN_USE) || \ + defined(SERIAL_BOX_2_IN_USE) || \ + defined(COMP_LPCOMP_IN_USE) +static ret_code_t acquire_shared_resource(shared_resource_t * p_resource, + nrf_drv_irq_handler_t handler) +{ + bool busy = false; + + CRITICAL_REGION_ENTER(); + if (p_resource->acquired) + { + busy = true; + } + else + { + p_resource->acquired = true; + } + CRITICAL_REGION_EXIT(); + + if (busy) + { + return NRF_ERROR_BUSY; + } + + p_resource->handler = handler; + return NRF_SUCCESS; +} +#endif + +ret_code_t nrf_drv_common_per_res_acquire(void const * p_per_base, + nrf_drv_irq_handler_t handler) +{ +#ifdef SERIAL_BOX_0_IN_USE + if (IS_SERIAL_BOX_0(p_per_base)) + { + return acquire_shared_resource(&m_serial_box_0, handler); + } +#endif + +#ifdef SERIAL_BOX_1_IN_USE + if (IS_SERIAL_BOX_1(p_per_base)) + { + return acquire_shared_resource(&m_serial_box_1, handler); + } +#endif + +#ifdef SERIAL_BOX_2_IN_USE + if (IS_SERIAL_BOX_2(p_per_base)) + { + return acquire_shared_resource(&m_serial_box_2, handler); + } +#endif + +#ifdef COMP_LPCOMP_IN_USE + if (IS_COMP_LPCOMP(p_per_base)) + { + return acquire_shared_resource(&m_comp_lpcomp, handler); + } +#endif + + return NRF_ERROR_INVALID_PARAM; +} + +void nrf_drv_common_per_res_release(void const * p_per_base) +{ +#ifdef SERIAL_BOX_0_IN_USE + if (IS_SERIAL_BOX_0(p_per_base)) + { + m_serial_box_0.acquired = false; + } + else +#endif + +#ifdef SERIAL_BOX_1_IN_USE + if (IS_SERIAL_BOX_1(p_per_base)) + { + m_serial_box_1.acquired = false; + } + else +#endif + +#ifdef SERIAL_BOX_2_IN_USE + if (IS_SERIAL_BOX_2(p_per_base)) + { + m_serial_box_2.acquired = false; + } + else +#endif + +#ifdef COMP_LPCOMP_IN_USE + if (IS_COMP_LPCOMP(p_per_base)) + { + m_comp_lpcomp.acquired = false; + } + else +#endif + + {} +} + +#endif // PERIPHERAL_RESOURCE_SHARING_ENABLED + + +void nrf_drv_common_irq_enable(IRQn_Type IRQn, uint8_t priority) +{ + +#ifdef SOFTDEVICE_PRESENT + ASSERT((priority == APP_IRQ_PRIORITY_LOW) || (priority == APP_IRQ_PRIORITY_HIGH)); +#endif + + NVIC_SetPriority(IRQn, priority); + NVIC_ClearPendingIRQ(IRQn); + NVIC_EnableIRQ(IRQn); +} diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/common/nrf_drv_common.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/common/nrf_drv_common.h new file mode 100644 index 0000000000..77785d8f54 --- /dev/null +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/common/nrf_drv_common.h @@ -0,0 +1,194 @@ +/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ + +#ifndef NRF_DRV_COMMON_H__ +#define NRF_DRV_COMMON_H__ + +#include +#include +#include "nrf.h" +#include "sdk_errors.h" +#include "nrf_drv_config.h" + + +/** + * @brief Offset of event registers in every peripheral instance + * + * This is the offset where event registers start in the every peripheral. + */ +#define NRF_DRV_COMMON_EVREGS_OFFSET 0x100U + +/** + * @brief Driver state. + */ +typedef enum +{ + NRF_DRV_STATE_UNINITIALIZED, /**< Uninitialized. */ + NRF_DRV_STATE_INITIALIZED, /**< Initialized but powered off. */ + NRF_DRV_STATE_POWERED_ON +} nrf_drv_state_t; + +/** + * @brief Driver power state selection. + */ +typedef enum +{ + NRF_DRV_PWR_CTRL_ON, /**< Power on request. */ + NRF_DRV_PWR_CTRL_OFF /**< Power off request. */ +} nrf_drv_pwr_ctrl_t; + +/** + * @brief IRQ handler type. + */ +typedef void (*nrf_drv_irq_handler_t)(void); + + +#if PERIPHERAL_RESOURCE_SHARING_ENABLED + +/** + * @brief Function for acquiring shared peripheral resources associated with + * the specified peripheral. + * + * Certain resources and registers are shared among peripherals that have + * the same ID (for example: SPI0, SPIM0, SPIS0, TWI0, TWIM0, and TWIS0). + * Only one of them can be utilized at a given time. This function reserves + * proper resources to be used by the specified peripheral. + * If PERIPHERAL_RESOURCE_SHARING_ENABLED is set to a non-zero value, IRQ + * handlers for peripherals that are sharing resources with others are + * implemented by the nrf_drv_common module instead of individual drivers. + * The drivers must then specify their interrupt handling routines and + * register them by using this function. + * + * @param[in] p_per_base Requested peripheral base pointer. + * @param[in] handler Interrupt handler to register. May be NULL + * if interrupts are not used for the peripheral. + * + * @retval NRF_SUCCESS If resources were acquired successfully. + * @retval NRF_ERROR_BUSY If resources were already acquired. + * @retval NRF_ERROR_INVALID_PARAM If the specified peripheral is not enabled + * or the peripheral does not share resources + * with other peripherals. + */ +ret_code_t nrf_drv_common_per_res_acquire(void const * p_per_base, + nrf_drv_irq_handler_t handler); + +/** + * @brief Function for releasing shared resources reserved previously by + * @ref nrf_drv_common_per_res_acquire() for the specified peripheral. + * + * @param[in] p_per_base Requested peripheral base pointer. + */ +void nrf_drv_common_per_res_release(void const * p_per_base); + +#endif // PERIPHERAL_RESOURCE_SHARING_ENABLED + + +/** + * @brief Function sets priority and enables NVIC interrupt + * + * @note Function checks if correct priority is used when softdevice is present + * + * @param[in] IRQn Interrupt id + * @param[in] priority Interrupt priority + */ +void nrf_drv_common_irq_enable(IRQn_Type IRQn, uint8_t priority); + +/** + * @brief Function disables NVIC interrupt + * + * @param[in] IRQn Interrupt id + */ +__STATIC_INLINE void nrf_drv_common_irq_disable(IRQn_Type IRQn); + +/** + * @brief Convert bit position to event code + * + * Function for converting the bit position in INTEN register to event code + * that is equivalent to the offset of the event register from the beginning + * of peripheral instance. + * + * For example the result of this function can be casted directly to + * the types like @ref nrf_twis_event_t or @ref nrf_rng_events_t... + * + * @param bit Bit position in INTEN register + * @return Event code to be casted to the right enum type or to be used in functions like + * @ref nrf_rng_event_get + * + * @sa nrf_drv_event_to_bitpos + */ +__STATIC_INLINE uint32_t nrf_drv_bitpos_to_event(uint32_t bit); + +/** + * @brief Convert event code to bit position + * + * This function can be used to get bit position in INTEN register from event code. + * + * @param event Event code that may be casted from enum values from types like + * @ref nrf_twis_event_t or @ref nrf_rng_events_t + * @return Bit position in INTEN register that corresponds to the given code. + * + * @sa nrf_drv_bitpos_to_event + */ +__STATIC_INLINE uint32_t nrf_drv_event_to_bitpos(uint32_t event); + +/** + * @brief Get interrupt number connected with given instance + * + * Function returns interrupt number for a given instance of any peripheral. + * @param[in] pinst Pointer to peripheral registry + * @return Interrupt number + */ +__STATIC_INLINE IRQn_Type nrf_drv_get_IRQn(void const * const pinst); + +/** + * @brief Check if given object is in RAM + * + * Function for analyzing if given location is placed in RAM. + * This function is used to determine if we have address that can be supported by EasyDMA. + * @param[in] ptr Pointer to the object + * @retval true Object is located in RAM + * @retval false Object is not located in RAM + */ +__STATIC_INLINE bool nrf_drv_is_in_RAM(void const * const ptr); + + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION + +__STATIC_INLINE void nrf_drv_common_irq_disable(IRQn_Type IRQn) +{ + NVIC_DisableIRQ(IRQn); +} + +__STATIC_INLINE uint32_t nrf_drv_bitpos_to_event(uint32_t bit) +{ + return NRF_DRV_COMMON_EVREGS_OFFSET + bit * sizeof(uint32_t); +} + +__STATIC_INLINE uint32_t nrf_drv_event_to_bitpos(uint32_t event) +{ + return (event - NRF_DRV_COMMON_EVREGS_OFFSET) / sizeof(uint32_t); +} + +__STATIC_INLINE IRQn_Type nrf_drv_get_IRQn(void const * const pinst) +{ + uint8_t ret = (uint8_t)((uint32_t)pinst>>12U); + return (IRQn_Type) ret; +} + +__STATIC_INLINE bool nrf_drv_is_in_RAM(void const * const ptr) +{ + return ((((uintptr_t)ptr) & 0xE0000000u) == 0x20000000u); +} + +#endif // SUPPRESS_INLINE_IMPLEMENTATION + +#endif // NRF_DRV_COMMON_H__ diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/hal/nrf_clock.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/hal/nrf_clock.h new file mode 100644 index 0000000000..d61d260387 --- /dev/null +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/hal/nrf_clock.h @@ -0,0 +1,414 @@ +/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ + +#ifndef NRF_CLOCK_H__ +#define NRF_CLOCK_H__ + +#include +#include + +#include "nrf.h" + +/** + * @defgroup nrf_clock_hal Clock HAL + * @{ + * @ingroup nrf_clock + * @brief Hardware access layer for managing the low-frequency clock (LFCLK) and the high-frequency clock (HFCLK). + */ + +#define NRF_CLOCK_TASK_TRIGGER (1UL) +#define NRF_CLOCK_EVENT_CLEAR (0UL) + +/** + * @brief Low-frequency clock sources. + * @details Used by LFCLKSRC, LFCLKSTAT, and LFCLKSRCCOPY registers. + */ +typedef enum +{ + NRF_CLOCK_LFCLK_RC = CLOCK_LFCLKSRC_SRC_RC, /**< Internal 32 kHz RC oscillator. */ + NRF_CLOCK_LFCLK_Xtal = CLOCK_LFCLKSRC_SRC_Xtal, /**< External 32 kHz crystal. */ + NRF_CLOCK_LFCLK_Synth = CLOCK_LFCLKSRC_SRC_Synth /**< Internal 32 kHz synthesizer from HFCLK system clock. */ +} nrf_clock_lfclk_t; + +/** + * @brief High-frequency clock sources. + */ +typedef enum +{ + NRF_CLOCK_HFCLK_LOW_ACCURACY = CLOCK_HFCLKSTAT_SRC_RC, /**< Internal 16 MHz RC oscillator. */ + NRF_CLOCK_HFCLK_HIGH_ACCURACY = CLOCK_HFCLKSTAT_SRC_Xtal /**< External 16 MHz/32 MHz crystal oscillator. */ +} nrf_clock_hfclk_t; + +/** + * @brief Trigger status of task LFCLKSTART/HFCLKSTART. + * @details Used by LFCLKRUN and HFCLKRUN registers. + */ +typedef enum +{ + NRF_CLOCK_START_TASK_NOT_TRIGGERED = CLOCK_LFCLKRUN_STATUS_NotTriggered, /**< Task LFCLKSTART/HFCLKSTART has not been triggered. */ + NRF_CLOCK_START_TASK_TRIGGERED = CLOCK_LFCLKRUN_STATUS_Triggered /**< Task LFCLKSTART/HFCLKSTART has been triggered. */ +} nrf_clock_start_task_status_t; + +/** + * @brief Crystal frequency selection. + */ +typedef enum +{ +#ifdef NRF51 + NRF_CLOCK_XTALFREQ_Default = CLOCK_XTALFREQ_XTALFREQ_16MHz, /**< Default. 32 MHz. */ + NRF_CLOCK_XTALFREQ_16MHz = CLOCK_XTALFREQ_XTALFREQ_16MHz, /**< 16 MHz crystal. */ + NRF_CLOCK_XTALFREQ_32MHz = CLOCK_XTALFREQ_XTALFREQ_32MHz /**< 32 MHz crystal. */ +#elif defined NRF52 + NRF_CLOCK_XTALFREQ_Default, /**< Default. 64MHz. */ +#endif +} nrf_clock_xtalfreq_t; + +/** + * @brief Interrupts. + */ +typedef enum +{ + NRF_CLOCK_INT_HF_STARTED_MASK = CLOCK_INTENSET_HFCLKSTARTED_Msk, /**< Interrupt on HFCLKSTARTED event. */ + NRF_CLOCK_INT_LF_STARTED_MASK = CLOCK_INTENSET_LFCLKSTARTED_Msk, /**< Interrupt on LFCLKSTARTED event. */ + NRF_CLOCK_INT_DONE_MASK = CLOCK_INTENSET_DONE_Msk, /**< Interrupt on DONE event. */ + NRF_CLOCK_INT_CTTO_MASK = CLOCK_INTENSET_CTTO_Msk /**< Interrupt on CTTO event. */ +} nrf_clock_int_mask_t; + +/** + * @brief Tasks. + * + * @details The NRF_CLOCK_TASK_LFCLKSTOP task cannot be set when the low-frequency clock is not running. + * The NRF_CLOCK_TASK_HFCLKSTOP task cannot be set when the high-frequency clock is not running. + */ +typedef enum /*lint -save -e30 -esym(628,__INTADDR__) */ +{ + NRF_CLOCK_TASK_HFCLKSTART = offsetof(NRF_CLOCK_Type, TASKS_HFCLKSTART), /**< Start HFCLK clock source.*/ + NRF_CLOCK_TASK_HFCLKSTOP = offsetof(NRF_CLOCK_Type, TASKS_HFCLKSTOP), /**< Stop HFCLK clock source.*/ + NRF_CLOCK_TASK_LFCLKSTART = offsetof(NRF_CLOCK_Type, TASKS_LFCLKSTART), /**< Start LFCLK clock source.*/ + NRF_CLOCK_TASK_LFCLKSTOP = offsetof(NRF_CLOCK_Type, TASKS_LFCLKSTOP), /**< Stop LFCLK clock source.*/ + NRF_CLOCK_TASK_CAL = offsetof(NRF_CLOCK_Type, TASKS_CAL), /**< Start calibration of LFCLK RC oscillator.*/ + NRF_CLOCK_TASK_CTSTART = offsetof(NRF_CLOCK_Type, TASKS_CTSTART), /**< Start calibration timer.*/ + NRF_CLOCK_TASK_CTSTOP = offsetof(NRF_CLOCK_Type, TASKS_CTSTOP) /**< Stop calibration timer.*/ +} nrf_clock_task_t; /*lint -restore */ + +/** + * @brief Events. + */ +typedef enum /*lint -save -e30 -esym(628,__INTADDR__) */ +{ + NRF_CLOCK_EVENT_HFCLKSTARTED = offsetof(NRF_CLOCK_Type, EVENTS_HFCLKSTARTED), /**< HFCLK oscillator started.*/ + NRF_CLOCK_EVENT_LFCLKSTARTED = offsetof(NRF_CLOCK_Type, EVENTS_LFCLKSTARTED), /**< LFCLK oscillator started.*/ + NRF_CLOCK_EVENT_DONE = offsetof(NRF_CLOCK_Type, EVENTS_DONE), /**< Calibration of LFCLK RC oscillator completed.*/ + NRF_CLOCK_EVENT_CTTO = offsetof(NRF_CLOCK_Type, EVENTS_CTTO) /**< Calibration timer time-out.*/ +} nrf_clock_event_t; /*lint -restore */ + +/** + * @brief Function for enabling a specific interrupt. + * + * @param[in] int_mask Interrupt. + */ +__STATIC_INLINE void nrf_clock_int_enable(uint32_t int_mask); + +/** + * @brief Function for disabling a specific interrupt. + * + * @param[in] int_mask Interrupt. + */ +__STATIC_INLINE void nrf_clock_int_disable(uint32_t int_mask); + +/** + * @brief Function for retrieving the state of a specific interrupt. + * + * @param[in] int_mask Interrupt. + * + * @retval true If the interrupt is enabled. + * @retval false If the interrupt is not enabled. + */ +__STATIC_INLINE bool nrf_clock_int_enable_check(nrf_clock_int_mask_t int_mask); + +/** + * @brief Function for retrieving the address of a specific task. + * @details This function can be used by the PPI module. + * + * @param[in] task Task. + * + * @return Address of the requested task register. + */ +__STATIC_INLINE uint32_t nrf_clock_task_address_get(nrf_clock_task_t task); + +/** + * @brief Function for setting a specific task. + * + * @param[in] task Task. + */ +__STATIC_INLINE void nrf_clock_task_trigger(nrf_clock_task_t task); + +/** + * @brief Function for retrieving the address of a specific event. + * @details This function can be used by the PPI module. + * + * @param[in] event Event. + * + * @return Address of the requested event register. + */ +__STATIC_INLINE uint32_t nrf_clock_event_address_get(nrf_clock_event_t event); + +/** + * @brief Function for clearing a specific event. + * + * @param[in] event Event. + */ +__STATIC_INLINE void nrf_clock_event_clear(nrf_clock_event_t event); + +/** + * @brief Function for retrieving the state of a specific event. + * + * @param[in] event Event. + * + * @retval true If the event is set. + * @retval false If the event is not set. + */ +__STATIC_INLINE bool nrf_clock_event_check(nrf_clock_event_t event); + +/** + * @brief Function for changing the low-frequency clock source. + * @details This function cannot be called when the low-frequency clock is running. + * + * @param[in] source New low-frequency clock source. + * + */ +__STATIC_INLINE void nrf_clock_lf_src_set(nrf_clock_lfclk_t source); + +/** + * @brief Function for retrieving the selected source for the low-frequency clock. + * + * @retval NRF_CLOCK_LFCLK_RC If the internal 32 kHz RC oscillator is the selected source for the low-frequency clock. + * @retval NRF_CLOCK_LFCLK_Xtal If an external 32 kHz crystal oscillator is the selected source for the low-frequency clock. + * @retval NRF_CLOCK_LFCLK_Synth If the internal 32 kHz synthesizer from the HFCLK is the selected source for the low-frequency clock. + */ +__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_src_get(void); + +/** + * @brief Function for retrieving the active source of the low-frequency clock. + * + * @retval NRF_CLOCK_LFCLK_RC If the internal 32 kHz RC oscillator is the active source of the low-frequency clock. + * @retval NRF_CLOCK_LFCLK_Xtal If an external 32 kHz crystal oscillator is the active source of the low-frequency clock. + * @retval NRF_CLOCK_LFCLK_Synth If the internal 32 kHz synthesizer from the HFCLK is the active source of the low-frequency clock. + */ +__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_actv_src_get(void); + +/** + * @brief Function for retrieving the clock source for the LFCLK clock when the task LKCLKSTART is triggered. + * + * @retval NRF_CLOCK_LFCLK_RC If the internal 32 kHz RC oscillator is running and generating the LFCLK clock. + * @retval NRF_CLOCK_LFCLK_Xtal If an external 32 kHz crystal oscillator is running and generating the LFCLK clock. + * @retval NRF_CLOCK_LFCLK_Synth If the internal 32 kHz synthesizer from the HFCLK is running and generating the LFCLK clock. + */ +__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_srccopy_get(void); + +/** + * @brief Function for retrieving the state of the LFCLK clock. + * + * @retval false If the LFCLK clock is not running. + * @retval true If the LFCLK clock is running. + */ +__STATIC_INLINE bool nrf_clock_lf_is_running(void); + +/** + * @brief Function for retrieving the trigger status of the task LFCLKSTART. + * + * @retval NRF_CLOCK_START_TASK_NOT_TRIGGERED If the task LFCLKSTART has not been triggered. + * @retval NRF_CLOCK_START_TASK_TRIGGERED If the task LFCLKSTART has been triggered. + */ +__STATIC_INLINE nrf_clock_start_task_status_t nrf_clock_lf_start_task_status_get(void); + +/** + * @brief Function for retrieving the active source of the high-frequency clock. + * + * @retval NRF_CLOCK_HFCLK_LOW_ACCURACY If the internal 16 MHz RC oscillator is the active source of the high-frequency clock. + * @retval NRF_CLOCK_HFCLK_HIGH_ACCURACY If an external 16 MHz/32 MHz crystal oscillator is the active source of the high-frequency clock. + */ +__STATIC_INLINE nrf_clock_hfclk_t nrf_clock_hf_src_get(void); + +/** + * @brief Function for retrieving the state of the HFCLK clock. + * + * @param[in] clk_src Clock source to be checked. + * + * @retval false If the HFCLK clock is not running. + * @retval true If the HFCLK clock is running. + */ +__STATIC_INLINE bool nrf_clock_hf_is_running(nrf_clock_hfclk_t clk_src); + +/** + * @brief Function for retrieving the trigger status of the task HFCLKSTART. + * + * @retval NRF_CLOCK_START_TASK_NOT_TRIGGERED If the task HFCLKSTART has not been triggered. + * @retval NRF_CLOCK_START_TASK_TRIGGERED If the task HFCLKSTART has been triggered. + */ +__STATIC_INLINE nrf_clock_start_task_status_t nrf_clock_hf_start_task_status_get(void); + +/** + * @brief Function for retrieving the frequency selection of the external crystal. + * + * @retval NRF_CLOCK_XTALFREQ_16MHz If a 16 MHz crystal is used as source for the HFCLK oscillator. + * @retval NRF_CLOCK_XTALFREQ_32MHz If a 32 MHz crystal is used as source for the HFCLK oscillator. + */ +__STATIC_INLINE nrf_clock_xtalfreq_t nrf_clock_xtalfreq_get(void); + +/** + * @brief Function for changing the frequency selection of the external crystal. + * + * @param[in] xtalfreq New frequency selection for the external crystal. + */ +__STATIC_INLINE void nrf_clock_xtalfreq_set(nrf_clock_xtalfreq_t xtalfreq); + +/** + * @brief Function for changing the calibration timer interval. + * + * @param[in] interval New calibration timer interval in 0.25 s resolution (range: 0.25 seconds to 31.75 seconds). + */ +__STATIC_INLINE void nrf_clock_cal_timer_timeout_set(uint32_t interval); + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION + +__STATIC_INLINE void nrf_clock_int_enable(uint32_t int_mask) +{ + NRF_CLOCK->INTENSET = int_mask; +} + +__STATIC_INLINE void nrf_clock_int_disable(uint32_t int_mask) +{ + NRF_CLOCK->INTENCLR = int_mask; +} + +__STATIC_INLINE bool nrf_clock_int_enable_check(nrf_clock_int_mask_t int_mask) +{ + return (bool)(NRF_CLOCK->INTENCLR & int_mask); +} + +__STATIC_INLINE uint32_t nrf_clock_task_address_get(nrf_clock_task_t task) +{ + return ((uint32_t )NRF_CLOCK + task); +} + +__STATIC_INLINE void nrf_clock_task_trigger(nrf_clock_task_t task) +{ + *((volatile uint32_t *)((uint8_t *)NRF_CLOCK + task)) = NRF_CLOCK_TASK_TRIGGER; +} + +__STATIC_INLINE uint32_t nrf_clock_event_address_get(nrf_clock_event_t event) +{ + return ((uint32_t)NRF_CLOCK + event); +} + +__STATIC_INLINE void nrf_clock_event_clear(nrf_clock_event_t event) +{ + *((volatile uint32_t *)((uint8_t *)NRF_CLOCK + event)) = NRF_CLOCK_EVENT_CLEAR; +#if __CORTEX_M == 0x04 + volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)NRF_CLOCK + event)); + (void)dummy; +#endif +} + +__STATIC_INLINE bool nrf_clock_event_check(nrf_clock_event_t event) +{ + return (bool)*((volatile uint32_t *)((uint8_t *)NRF_CLOCK + event)); +} + +__STATIC_INLINE void nrf_clock_lf_src_set(nrf_clock_lfclk_t source) +{ + NRF_CLOCK->LFCLKSRC = + (uint32_t)((source << CLOCK_LFCLKSRC_SRC_Pos) & CLOCK_LFCLKSRC_SRC_Msk); +} + +__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_src_get(void) +{ + return (nrf_clock_lfclk_t)((NRF_CLOCK->LFCLKSRC & + CLOCK_LFCLKSRC_SRC_Msk) >> CLOCK_LFCLKSRC_SRC_Pos); +} + +__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_actv_src_get(void) +{ + return (nrf_clock_lfclk_t)((NRF_CLOCK->LFCLKSTAT & + CLOCK_LFCLKSTAT_SRC_Msk) >> CLOCK_LFCLKSTAT_SRC_Pos); +} + +__STATIC_INLINE nrf_clock_lfclk_t nrf_clock_lf_srccopy_get(void) +{ + return (nrf_clock_lfclk_t)((NRF_CLOCK->LFCLKSRCCOPY & + CLOCK_LFCLKSRCCOPY_SRC_Msk) >> CLOCK_LFCLKSRCCOPY_SRC_Pos); +} + +__STATIC_INLINE bool nrf_clock_lf_is_running(void) +{ + return ((NRF_CLOCK->LFCLKSTAT & + CLOCK_LFCLKSTAT_STATE_Msk) >> CLOCK_LFCLKSTAT_STATE_Pos); +} + +__STATIC_INLINE nrf_clock_start_task_status_t nrf_clock_lf_start_task_status_get(void) +{ + return (nrf_clock_start_task_status_t)((NRF_CLOCK->LFCLKRUN & + CLOCK_LFCLKRUN_STATUS_Msk) >> + CLOCK_LFCLKRUN_STATUS_Pos); +} + +__STATIC_INLINE nrf_clock_hfclk_t nrf_clock_hf_src_get(void) +{ + return (nrf_clock_hfclk_t)((NRF_CLOCK->HFCLKSTAT & + CLOCK_HFCLKSTAT_SRC_Msk) >> CLOCK_HFCLKSTAT_SRC_Pos); +} + +__STATIC_INLINE bool nrf_clock_hf_is_running(nrf_clock_hfclk_t clk_src) +{ + return (NRF_CLOCK->HFCLKSTAT & (CLOCK_HFCLKSTAT_STATE_Msk | CLOCK_HFCLKSTAT_SRC_Msk)) == + (CLOCK_HFCLKSTAT_STATE_Msk | (clk_src << CLOCK_HFCLKSTAT_SRC_Pos)); +} + +__STATIC_INLINE nrf_clock_start_task_status_t nrf_clock_hf_start_task_status_get(void) +{ + return (nrf_clock_start_task_status_t)((NRF_CLOCK->HFCLKRUN & + CLOCK_HFCLKRUN_STATUS_Msk) >> + CLOCK_HFCLKRUN_STATUS_Pos); +} + +__STATIC_INLINE nrf_clock_xtalfreq_t nrf_clock_xtalfreq_get(void) +{ +#ifdef NRF51 + return (nrf_clock_xtalfreq_t)((NRF_CLOCK->XTALFREQ & + CLOCK_XTALFREQ_XTALFREQ_Msk) >> CLOCK_XTALFREQ_XTALFREQ_Pos); +#elif defined NRF52 + return NRF_CLOCK_XTALFREQ_Default; +#endif +} + +__STATIC_INLINE void nrf_clock_xtalfreq_set(nrf_clock_xtalfreq_t xtalfreq) +{ +#ifdef NRF51 + NRF_CLOCK->XTALFREQ = + (uint32_t)((xtalfreq << CLOCK_XTALFREQ_XTALFREQ_Pos) & CLOCK_XTALFREQ_XTALFREQ_Msk); +#elif defined NRF52 + return; +#endif +} + +__STATIC_INLINE void nrf_clock_cal_timer_timeout_set(uint32_t interval) +{ + NRF_CLOCK->CTIV = ((interval << CLOCK_CTIV_CTIV_Pos) & CLOCK_CTIV_CTIV_Msk); +} + +#endif // SUPPRESS_INLINE_IMPLEMENTATION + +/** + *@} + **/ +#endif // NRF_CLOCK_H__