Added missing SDK drivers, added SOFTDEVICE_PRESENT macros in targets definitions.

pull/2234/head
Głąbek, Andrzej 2016-06-15 17:51:40 +01:00
parent 6afe131cfa
commit 2eaa468c50
6 changed files with 1544 additions and 3 deletions

View File

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

View File

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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#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__

View File

@ -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 <stddef.h>
#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);
}

View File

@ -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 <stdint.h>
#include <stdbool.h>
#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__

View File

@ -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 <stddef.h>
#include <stdbool.h>
#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__