Merge branch 'nordic_sdk_integration' into hal_improvements

# Conflicts:
#	hal/targets.json
pull/2234/head
Głąbek, Andrzej 2016-06-28 12:13:50 +02:00
commit 3ff34ef58d
7 changed files with 1075 additions and 34 deletions

View File

@ -1375,7 +1375,7 @@
"supported_form_factors": ["ARDUINO"],
"inherits": ["MCU_NRF51_32K"],
"progen": {"target": "nrf51-dk"},
"device_has": ["ERROR_PATTERN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH"]
"device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH"]
},
"NRF51_DK_BOOT": {
"supported_form_factors": ["ARDUINO"],

View File

@ -12,17 +12,18 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
*/
#include "mbed_assert.h"
#include "analogin_api.h"
#include "cmsis.h"
#include "pinmap.h"
#include "nrf_drv_adc.h"
#ifdef DEVICE_ANALOGIN
#define ANALOGIN_MEDIAN_FILTER 1
#define ADC_10BIT_RANGE 0x3FF
#define ADC_RANGE ADC_10BIT_RANGE
#define ADC_10BIT_RANGE 0x3FF
#define ADC_RANGE ADC_10BIT_RANGE
static const PinMap PinMap_ADC[] = {
{p1, ADC0_0, 4},
@ -38,47 +39,42 @@ static const PinMap PinMap_ADC[] = {
{NC, NC, 0}
};
void analogin_init(analogin_t *obj, PinName pin)
{
int analogInputPin = 0;
const PinMap *map = PinMap_ADC;
obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC); //(NRF_ADC_Type *)
obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
MBED_ASSERT(obj->adc != (ADCName)NC);
while (map->pin != NC) {
if (map->pin == pin) {
analogInputPin = map->function;
break;
}
map++;
}
obj->adc_pin = (uint8_t)analogInputPin;
NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
NRF_ADC->CONFIG = (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos) |
(ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) |
(ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling << ADC_CONFIG_REFSEL_Pos) |
(analogInputPin << ADC_CONFIG_PSEL_Pos) |
(ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
uint32_t pinFunc = pinmap_function(pin, PinMap_ADC);
MBED_ASSERT(pinFunc != (uint32_t)NC);
obj->adc_pin = pinFunc;
ret_code_t ret_code;
// p_config, event_handler
ret_code = nrf_drv_adc_init(NULL , NULL); // select blocking mode
MBED_ASSERT(ret_code == NRF_SUCCESS);
}
uint16_t analogin_read_u16(analogin_t *obj)
{
NRF_ADC->CONFIG &= ~ADC_CONFIG_PSEL_Msk;
NRF_ADC->CONFIG |= obj->adc_pin << ADC_CONFIG_PSEL_Pos;
NRF_ADC->EVENTS_END = 0;
NRF_ADC->TASKS_START = 1;
nrf_adc_value_t adc_value;
nrf_drv_adc_channel_t adc_channel = NRF_DRV_ADC_DEFAULT_CHANNEL(obj->adc_pin);
while (!NRF_ADC->EVENTS_END) {
}
return (uint16_t)NRF_ADC->RESULT; // 10 bit
ret_code_t ret_code;
ret_code = nrf_drv_adc_sample_convert( &adc_channel, &adc_value);
MBED_ASSERT(ret_code == NRF_SUCCESS);
return adc_value;
}
float analogin_read(analogin_t *obj)
{
uint16_t value = analogin_read_u16(obj);
return (float)value * (1.0f / (float)ADC_RANGE);
}

View File

@ -138,7 +138,7 @@ void pwmout_init(pwmout_t *obj, PinName pin)
void pwmout_free(pwmout_t *obj)
{
MBED_ASSERT(obj->pwm != (PWMName)NC);
MBED_ASSERT(obj->pwm_name != (PWMName)NC);
MBED_ASSERT(obj->pwm_channel < PWM_CHANNELS_PER_INSTANCE);
pwm_t * pwm = (pwm_t *) obj->pwm_struct;
@ -160,7 +160,8 @@ void pwmout_write(pwmout_t *obj, float value)
if (value > 1.0f) {
value = 1.0f;
}
uint16_t ticks = (uint16_t)((float)app_pwm_cycle_ticks_get(pwm->instance) * value);
app_pwm_channel_duty_set(pwm->instance, obj->pwm_channel, (app_pwm_duty_t)(value * 100.0f) );
}
float pwmout_read(pwmout_t *obj)

View File

@ -0,0 +1,253 @@
/* 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_adc.h"
#include "nrf_drv_common.h"
#include "nrf_assert.h"
#include "app_util_platform.h"
#include "app_util.h"
typedef struct
{
nrf_drv_adc_event_handler_t event_handler;
nrf_drv_adc_channel_t * p_head;
nrf_drv_adc_channel_t * p_current_conv;
nrf_adc_value_t * p_buffer;
uint8_t size;
uint8_t idx;
nrf_drv_state_t state;
} adc_cb_t;
static adc_cb_t m_cb;
static const nrf_drv_adc_config_t m_default_config = NRF_DRV_ADC_DEFAULT_CONFIG;
ret_code_t nrf_drv_adc_init(nrf_drv_adc_config_t const * p_config,
nrf_drv_adc_event_handler_t event_handler)
{
if (m_cb.state != NRF_DRV_STATE_UNINITIALIZED)
{
return NRF_ERROR_INVALID_STATE;
}
nrf_adc_event_clear(NRF_ADC_EVENT_END);
if (event_handler)
{
if (!p_config)
{
p_config = (nrf_drv_adc_config_t *)&m_default_config;
}
nrf_drv_common_irq_enable(ADC_IRQn, p_config->interrupt_priority);
}
m_cb.event_handler = event_handler;
m_cb.state = NRF_DRV_STATE_INITIALIZED;
return NRF_SUCCESS;
}
void nrf_drv_adc_uninit(void)
{
m_cb.p_head = NULL;
nrf_drv_common_irq_disable(ADC_IRQn);
nrf_adc_int_disable(NRF_ADC_INT_END_MASK);
nrf_adc_task_trigger(NRF_ADC_TASK_STOP);
m_cb.state = NRF_DRV_STATE_UNINITIALIZED;
}
void nrf_drv_adc_channel_enable(nrf_drv_adc_channel_t * const p_channel)
{
ASSERT(mp_state == NRF_DRV_STATE_INITIALIZED);
ASSERT(!is_address_from_stack(p_channel));
p_channel->p_next = NULL;
if (m_cb.p_head == NULL)
{
m_cb.p_head = p_channel;
}
else
{
nrf_drv_adc_channel_t * p_curr_channel = m_cb.p_head;
while (p_curr_channel->p_next != NULL)
{
ASSERT(p_channel != p_curr_channel);
p_curr_channel = p_curr_channel->p_next;
}
p_curr_channel->p_next = p_channel;
}
}
void nrf_drv_adc_channel_disable(nrf_drv_adc_channel_t * const p_channel)
{
ASSERT(mp_state == NRF_DRV_STATE_INITIALIZED);
ASSERT(m_cb.p_head);
nrf_drv_adc_channel_t * p_curr_channel = m_cb.p_head;
nrf_drv_adc_channel_t * p_prev_channel = NULL;
while(p_curr_channel != p_channel)
{
p_prev_channel = p_curr_channel;
p_curr_channel = p_curr_channel->p_next;
ASSERT(p_curr_channel == NULL);
}
if (p_prev_channel)
{
p_prev_channel->p_next = p_curr_channel->p_next;
}
else
{
m_cb.p_head = p_curr_channel->p_next;
}
}
void nrf_drv_adc_sample(void)
{
ASSERT(mp_state != NRF_DRV_STATE_UNINITIALIZED);
ASSERT(!nrf_adc_is_busy());
nrf_adc_start();
}
ret_code_t nrf_drv_adc_sample_convert(nrf_drv_adc_channel_t const * const p_channel,
nrf_adc_value_t * p_value)
{
ASSERT(mp_state != NRF_DRV_STATE_UNINITIALIZED);
if(m_cb.state == NRF_DRV_STATE_POWERED_ON)
{
return NRF_ERROR_BUSY;
}
else
{
m_cb.state = NRF_DRV_STATE_POWERED_ON;
nrf_adc_config_set(p_channel->config.data);
nrf_adc_enable();
nrf_adc_int_disable(NRF_ADC_INT_END_MASK);
nrf_adc_start();
if (p_value)
{
while(!nrf_adc_event_check(NRF_ADC_EVENT_END)) {}
nrf_adc_event_clear(NRF_ADC_EVENT_END);
*p_value = (nrf_adc_value_t)nrf_adc_result_get();
nrf_adc_disable();
m_cb.state = NRF_DRV_STATE_INITIALIZED;
}
else
{
ASSERT(m_cb.event_handler);
m_cb.p_buffer = NULL;
nrf_adc_int_enable(NRF_ADC_INT_END_MASK);
}
return NRF_SUCCESS;
}
}
static bool adc_sample_process()
{
nrf_adc_event_clear(NRF_ADC_EVENT_END);
nrf_adc_disable();
m_cb.p_buffer[m_cb.idx] = (nrf_adc_value_t)nrf_adc_result_get();
m_cb.idx++;
if (m_cb.idx < m_cb.size)
{
bool task_trigger = false;
if (m_cb.p_current_conv->p_next == NULL)
{
m_cb.p_current_conv = m_cb.p_head;
}
else
{
m_cb.p_current_conv = m_cb.p_current_conv->p_next;
task_trigger = true;
}
nrf_adc_config_set(m_cb.p_current_conv->config.data);
nrf_adc_enable();
if (task_trigger)
{
//nrf_adc_start();
nrf_adc_task_trigger(NRF_ADC_TASK_START);
}
return false;
}
else
{
return true;
}
}
ret_code_t nrf_drv_adc_buffer_convert(nrf_adc_value_t * buffer, uint16_t size)
{
ASSERT(mp_state != NRF_DRV_STATE_UNINITIALIZED);
if(m_cb.state == NRF_DRV_STATE_POWERED_ON)
{
return NRF_ERROR_BUSY;
}
else
{
m_cb.state = NRF_DRV_STATE_POWERED_ON;
m_cb.p_current_conv = m_cb.p_head;
m_cb.size = size;
m_cb.idx = 0;
m_cb.p_buffer = buffer;
nrf_adc_config_set(m_cb.p_current_conv->config.data);
nrf_adc_event_clear(NRF_ADC_EVENT_END);
nrf_adc_enable();
if (m_cb.event_handler)
{
nrf_adc_int_enable(NRF_ADC_INT_END_MASK);
}
else
{
while(1)
{
while(!nrf_adc_event_check(NRF_ADC_EVENT_END)){}
if (adc_sample_process())
{
m_cb.state = NRF_DRV_STATE_INITIALIZED;
break;
}
}
}
return NRF_SUCCESS;
}
}
bool nrf_drv_adc_is_busy(void)
{
ASSERT(mp_state != NRF_DRV_STATE_UNINITIALIZED);
return (m_cb.state == NRF_DRV_STATE_POWERED_ON) ? true : false;
}
void ADC_IRQHandler(void)
{
if (m_cb.p_buffer == NULL)
{
nrf_adc_event_clear(NRF_ADC_EVENT_END);
nrf_adc_int_disable(NRF_ADC_INT_END_MASK);
nrf_adc_disable();
nrf_drv_adc_evt_t evt;
evt.type = NRF_DRV_ADC_EVT_SAMPLE;
evt.data.sample.sample = (nrf_adc_value_t)nrf_adc_result_get();
m_cb.state = NRF_DRV_STATE_INITIALIZED;
m_cb.event_handler(&evt);
}
else if (adc_sample_process())
{
nrf_adc_int_disable(NRF_ADC_INT_END_MASK);
nrf_drv_adc_evt_t evt;
evt.type = NRF_DRV_ADC_EVT_DONE;
evt.data.done.p_buffer = m_cb.p_buffer;
evt.data.done.size = m_cb.size;
m_cb.state = NRF_DRV_STATE_INITIALIZED;
m_cb.event_handler(&evt);
}
}

View File

@ -0,0 +1,297 @@
/* 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_adc.h"
#include "nrf_drv_config.h"
#include "sdk_errors.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup nrf_adc ADC HAL and driver
* @ingroup nrf_drivers
* @brief Analog-to-digital converter (ADC) APIs.
* @details The ADC HAL provides basic APIs for accessing the registers of the analog-to-digital converter.
* The ADC driver provides APIs on a higher level.
*
* @defgroup nrf_adc_drv ADC driver
* @{
* @ingroup nrf_adc
* @brief Analog-to-digital converter (ADC) driver.
*/
/**
* @brief Driver event types.
*/
typedef enum
{
NRF_DRV_ADC_EVT_DONE, ///< Event generated when the buffer is filled with samples.
NRF_DRV_ADC_EVT_SAMPLE, ///< Event generated when the requested channel is sampled.
} nrf_drv_adc_evt_type_t;
typedef int16_t nrf_adc_value_t;
/**
* @brief Analog-to-digital converter driver DONE event.
*/
typedef struct
{
nrf_adc_value_t * p_buffer; ///< Pointer to buffer with converted samples.
uint16_t size; ///< Number of samples in the buffer.
} nrf_drv_adc_done_evt_t;
/**
* @brief Analog-to-digital converter driver SAMPLE event.
*/
typedef struct
{
nrf_adc_value_t sample; ///< Converted sample.
} nrf_drv_adc_sample_evt_t;
/**
* @brief Analog-to-digital converter driver event.
*/
typedef struct
{
nrf_drv_adc_evt_type_t type; ///< Event type.
union
{
nrf_drv_adc_done_evt_t done; ///< Data for DONE event.
nrf_drv_adc_sample_evt_t sample; ///< Data for SAMPLE event.
} data;
} nrf_drv_adc_evt_t;
/**@brief Macro for initializing the ADC channel with the default configuration. */
#define NRF_DRV_ADC_DEFAULT_CHANNEL(analog_input) \
{{{ \
.resolution = NRF_ADC_CONFIG_RES_10BIT, \
.input = NRF_ADC_CONFIG_SCALING_INPUT_FULL_SCALE, \
.reference = NRF_ADC_CONFIG_REF_VBG, \
.ain = (analog_input) \
}}, NULL}
/**
* @brief ADC channel configuration.
*
* @note The bit fields reflect bit fields in the ADC CONFIG register.
*/
typedef struct
{
uint32_t resolution :2; ///< 8-10 bit resolution.
uint32_t input :3; ///< Input selection and scaling.
uint32_t reference :2; ///< Reference source.
uint32_t reserved :1; ///< Unused bit fields.
uint32_t ain :8; ///< Analog input.
uint32_t external_reference:2; ///< Eternal reference source.
}nrf_drv_adc_channel_config_t;
// Forward declaration of the nrf_drv_adc_channel_t type.
typedef struct nrf_drv_adc_channel_s nrf_drv_adc_channel_t;
/**
* @brief ADC channel.
*
* This structure is defined by the user and used by the driver. Therefore, it should
* not be defined on the stack as a local variable.
*/
struct nrf_drv_adc_channel_s
{
union
{
nrf_drv_adc_channel_config_t config; ///< Channel configuration.
uint32_t data; ///< Raw value.
} config;
nrf_drv_adc_channel_t * p_next; ///< Pointer to the next enabled channel (for internal use).
};
/**
* @brief ADC configuration.
*/
typedef struct
{
uint8_t interrupt_priority; ///< Priority of ADC interrupt.
} nrf_drv_adc_config_t;
/** @brief ADC default configuration. */
#define NRF_DRV_ADC_DEFAULT_CONFIG \
{ \
.interrupt_priority = ADC_CONFIG_IRQ_PRIORITY \
}
/**
* @brief User event handler prototype.
*
* This function is called when the requested number of samples has been processed.
*
* @param p_event Event.
*/
typedef void (*nrf_drv_adc_event_handler_t)(nrf_drv_adc_evt_t const * p_event);
/**
* @brief Function for initializing the ADC.
*
* If a valid event handler is provided, the driver is initialized in non-blocking mode.
* If event_handler is NULL, the driver works in blocking mode.
*
* @param[in] p_config Driver configuration.
* @param[in] event_handler Event handler provided by the user.
*
* @retval NRF_SUCCESS If initialization was successful.
* @retval NRF_ERROR_INVALID_STATE If the driver is already initialized.
*/
ret_code_t nrf_drv_adc_init(nrf_drv_adc_config_t const * p_config,
nrf_drv_adc_event_handler_t event_handler);
/**
* @brief Function for uninitializing the ADC.
*
* This function stops all ongoing conversions and disables all channels.
*/
void nrf_drv_adc_uninit(void);
/**
* @brief Function for enabling an ADC channel.
*
* This function configures and enables the channel. When @ref nrf_drv_adc_buffer_convert is
* called, all channels that have been enabled with this function are sampled.
*
* @note The channel instance variable @p p_channel is used by the driver as an item
* in a list. Therefore, it cannot be an automatic variable, and an assertion fails if it is
* an automatic variable (if asserts are enabled).
*/
void nrf_drv_adc_channel_enable(nrf_drv_adc_channel_t * const p_channel);
/**
* @brief Function for disabling an ADC channel.
*/
void nrf_drv_adc_channel_disable(nrf_drv_adc_channel_t * const p_channel);
/**
* @brief Function for starting ADC sampling.
*
* This function triggers single ADC sampling. If more than one channel is enabled, the driver
* emulates scanning and all channels are sampled in the order they were enabled.
*/
void nrf_drv_adc_sample(void);
/**
* @brief Function for executing a single ADC conversion.
*
* This function selects the desired input and starts a single conversion. If a valid pointer
* is provided for the result, the function blocks until the conversion is completed. Otherwise, the
* function returns when the conversion is started, and the result is provided in an event (driver
* must be initialized in non-blocking mode otherwise an assertion will fail). The function will fail if
* ADC is busy. The channel does not need to be enabled to perform a single conversion.
*
* @param[in] p_channel Channel.
* @param[out] p_value Pointer to the location where the result should be placed. Unless NULL is
* provided, the function is blocking.
*
* @retval NRF_SUCCESS If conversion was successful.
* @retval NRF_ERROR_BUSY If the ADC driver is busy.
*/
ret_code_t nrf_drv_adc_sample_convert(nrf_drv_adc_channel_t const * const p_channel,
nrf_adc_value_t * p_value);
/**
* @brief Function for converting data to the buffer.
*
* If the driver is initialized in non-blocking mode, this function returns when the first conversion
* is set up. When the buffer is filled, the application is notified by the event handler. If the
* driver is initialized in blocking mode, the function returns when the buffer is filled.
*
* Conversion is done on all enabled channels, but it is not triggered by this
* function. This function will prepare the ADC for sampling and then
* wait for the SAMPLE task. Sampling can be triggered manually by the @ref
* nrf_drv_adc_sample function or by PPI using the @ref NRF_ADC_TASK_START task.
*
* @note If more than one channel is enabled, the function emulates scanning, and
* a single START task will trigger conversion on all enabled channels. For example:
* If 3 channels are enabled and the user requests 6 samples, the completion event
* handler will be called after 2 START tasks.
* @note The application must adjust the sampling frequency. The maximum frequency
* depends on the sampling timer and the maximum latency of the ADC interrupt. If
* an interrupt is not handled before the next sampling is triggered, the sample
* will be lost.
*
* @param[in] buffer Result buffer.
* @param[in] size Buffer size in samples.
*
* @retval NRF_SUCCESS If conversion was successful.
* @retval NRF_ERROR_BUSY If the driver is busy.
*/
ret_code_t nrf_drv_adc_buffer_convert(nrf_adc_value_t * buffer, uint16_t size);
/**
* @brief Function for retrieving the ADC state.
*
* @retval true If the ADC is busy.
* @retval false If the ADC is ready.
*/
bool nrf_drv_adc_is_busy(void);
/**
* @brief Function for getting the address of the ADC START task.
*
* This function is used to get the address of the START task, which can be used to trigger ADC
* conversion.
*
* @return Start task address.
*/
__STATIC_INLINE uint32_t nrf_drv_adc_start_task_get(void);
/**
* @brief Function for converting a GPIO pin number to an analog input pin mask to be used in
* the ADC channel configuration.
*
* @param[in] pin GPIO pin.
*
* @return Analog input pin mask. The function returns @ref NRF_ADC_CONFIG_INPUT_DISABLED
* if the specified pin is not an analog input.
*/
__STATIC_INLINE nrf_adc_config_input_t nrf_drv_adc_gpio_to_ain(uint32_t pin);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE uint32_t nrf_drv_adc_start_task_get(void)
{
return nrf_adc_task_address_get(NRF_ADC_TASK_START);
}
__STATIC_INLINE nrf_adc_config_input_t nrf_drv_adc_gpio_to_ain(uint32_t pin)
{
// AIN2 - AIN7
if (pin >= 1 && pin <= 6)
{
return (nrf_adc_config_input_t)(1 << (pin+1));
}
// AIN0 - AIN1
else if (pin >= 26 && pin <= 27)
{
return (nrf_adc_config_input_t)(1 <<(pin - 26));
}
else
{
return NRF_ADC_CONFIG_INPUT_DISABLED;
}
}
#ifdef __cplusplus
}
#endif
#endif
/** @} */

View File

@ -0,0 +1,78 @@
/* Copyright (c) 2014 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.
*
*/
/**
* @file
* @brief ADC HAL implementation
*/
#include "nrf_adc.h"
#ifndef NRF52
/**
* @brief Function for configuring ADC.
*
* This function powers on ADC and configures it. ADC is in DISABLE state after configuration,
* so it should be enabled before using it.
*
* @param[in] config Requested configuration.
*/
void nrf_adc_configure(nrf_adc_config_t * config)
{
uint32_t config_reg = 0;
config_reg |= ((uint32_t)config->resolution << ADC_CONFIG_RES_Pos) & ADC_CONFIG_RES_Msk;
config_reg |= ((uint32_t)config->scaling << ADC_CONFIG_INPSEL_Pos) & ADC_CONFIG_INPSEL_Msk;
config_reg |= ((uint32_t)config->reference << ADC_CONFIG_REFSEL_Pos) & ADC_CONFIG_REFSEL_Msk;
if (config->reference & ADC_CONFIG_EXTREFSEL_Msk)
{
config_reg |= config->reference & ADC_CONFIG_EXTREFSEL_Msk;
}
/* select input */
nrf_adc_input_select(NRF_ADC_CONFIG_INPUT_DISABLED);
/* set new configuration keeping selected input */
NRF_ADC->CONFIG = config_reg | (NRF_ADC->CONFIG & ADC_CONFIG_PSEL_Msk);
}
/**
* @brief Blocking function for executing single ADC conversion.
*
* This function selects the desired input, starts a single conversion,
* waits for it to finish, and returns the result.
* ADC is left in STOP state, the given input is selected.
* This function does not check if ADC is initialized and powered.
*
* @param[in] input Requested input to be selected.
*
* @return Conversion result
*/
int32_t nrf_adc_convert_single(nrf_adc_config_input_t input)
{
int32_t val;
nrf_adc_input_select(input);
nrf_adc_start();
while (!nrf_adc_conversion_finished())
{
}
nrf_adc_conversion_event_clean();
val = nrf_adc_result_get();
nrf_adc_stop();
return val;
}
#endif

View File

@ -0,0 +1,416 @@
/* Copyright (c) 2014 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_ADC_H_
#define NRF_ADC_H_
/**
* @defgroup nrf_adc_hal ADC HAL
* @{
* @ingroup nrf_adc
* @brief @tagAPI51 Hardware access layer for managing the analog-to-digital converter (ADC).
*/
#include <stdbool.h>
#include <stddef.h>
#include "nrf.h"
#ifndef NRF52
/**
* @enum nrf_adc_config_resolution_t
* @brief Resolution of the analog-to-digital converter.
*/
/**
* @brief ADC interrupts.
*/
typedef enum
{
NRF_ADC_INT_END_MASK = ADC_INTENSET_END_Msk, /**< ADC interrupt on END event. */
} nrf_adc_int_mask_t;
typedef enum
{
NRF_ADC_CONFIG_RES_8BIT = ADC_CONFIG_RES_8bit, /**< 8 bit resolution. */
NRF_ADC_CONFIG_RES_9BIT = ADC_CONFIG_RES_9bit, /**< 9 bit resolution. */
NRF_ADC_CONFIG_RES_10BIT = ADC_CONFIG_RES_10bit, /**< 10 bit resolution. */
} nrf_adc_config_resolution_t;
/**
* @enum nrf_adc_config_scaling_t
* @brief Scaling factor of the analog-to-digital conversion.
*/
typedef enum
{
NRF_ADC_CONFIG_SCALING_INPUT_FULL_SCALE = ADC_CONFIG_INPSEL_AnalogInputNoPrescaling, /**< Full scale input. */
NRF_ADC_CONFIG_SCALING_INPUT_TWO_THIRDS = ADC_CONFIG_INPSEL_AnalogInputTwoThirdsPrescaling, /**< 2/3 scale input. */
NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD = ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling, /**< 1/3 scale input. */
NRF_ADC_CONFIG_SCALING_SUPPLY_TWO_THIRDS = ADC_CONFIG_INPSEL_SupplyTwoThirdsPrescaling, /**< 2/3 of supply. */
NRF_ADC_CONFIG_SCALING_SUPPLY_ONE_THIRD = ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling /**< 1/3 of supply. */
} nrf_adc_config_scaling_t;
/**
* @enum nrf_adc_config_reference_t
* @brief Reference selection of the analog-to-digital converter.
*/
typedef enum
{
NRF_ADC_CONFIG_REF_VBG = ADC_CONFIG_REFSEL_VBG, /**< 1.2 V reference. */
NRF_ADC_CONFIG_REF_SUPPLY_ONE_HALF = ADC_CONFIG_REFSEL_SupplyOneHalfPrescaling, /**< 1/2 of power supply. */
NRF_ADC_CONFIG_REF_SUPPLY_ONE_THIRD = ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling, /**< 1/3 of power supply. */
NRF_ADC_CONFIG_REF_EXT_REF0 = ADC_CONFIG_REFSEL_External |
ADC_CONFIG_EXTREFSEL_AnalogReference0 <<
ADC_CONFIG_EXTREFSEL_Pos, /**< External reference 0. */
NRF_ADC_CONFIG_REF_EXT_REF1 = ADC_CONFIG_REFSEL_External |
ADC_CONFIG_EXTREFSEL_AnalogReference1 << ADC_CONFIG_EXTREFSEL_Pos, /**< External reference 0. */
} nrf_adc_config_reference_t;
/**
* @enum nrf_adc_config_input_t
* @brief Input selection of the analog-to-digital converter.
*/
typedef enum
{
NRF_ADC_CONFIG_INPUT_DISABLED = ADC_CONFIG_PSEL_Disabled, /**< No input selected. */
NRF_ADC_CONFIG_INPUT_0 = ADC_CONFIG_PSEL_AnalogInput0, /**< Input 0. */
NRF_ADC_CONFIG_INPUT_1 = ADC_CONFIG_PSEL_AnalogInput1, /**< Input 1. */
NRF_ADC_CONFIG_INPUT_2 = ADC_CONFIG_PSEL_AnalogInput2, /**< Input 2. */
NRF_ADC_CONFIG_INPUT_3 = ADC_CONFIG_PSEL_AnalogInput3, /**< Input 3. */
NRF_ADC_CONFIG_INPUT_4 = ADC_CONFIG_PSEL_AnalogInput4, /**< Input 4. */
NRF_ADC_CONFIG_INPUT_5 = ADC_CONFIG_PSEL_AnalogInput5, /**< Input 5. */
NRF_ADC_CONFIG_INPUT_6 = ADC_CONFIG_PSEL_AnalogInput6, /**< Input 6. */
NRF_ADC_CONFIG_INPUT_7 = ADC_CONFIG_PSEL_AnalogInput7, /**< Input 7. */
} nrf_adc_config_input_t;
/**
* @enum nrf_adc_task_t
* @brief Analog-to-digital converter tasks.
*/
typedef enum
{
/*lint -save -e30*/
NRF_ADC_TASK_START = offsetof(NRF_ADC_Type, TASKS_START), /**< ADC start sampling task. */
NRF_ADC_TASK_STOP = offsetof(NRF_ADC_Type, TASKS_STOP) /**< ADC stop sampling task. */
/*lint -restore*/
} nrf_adc_task_t;
/**
* @enum nrf_adc_event_t
* @brief Analog-to-digital converter events.
*/
typedef enum /*lint -save -e30 -esym(628,__INTADDR__) */
{
/*lint -save -e30*/
NRF_ADC_EVENT_END = offsetof(NRF_ADC_Type, EVENTS_END) /**< End of conversion event. */
/*lint -restore*/
} nrf_adc_event_t;
/**@brief Analog-to-digital converter configuration. */
typedef struct
{
nrf_adc_config_resolution_t resolution; /**< ADC resolution. */
nrf_adc_config_scaling_t scaling; /**< ADC scaling factor. */
nrf_adc_config_reference_t reference; /**< ADC reference. */
} nrf_adc_config_t;
/** Default ADC configuration. */
#define NRF_ADC_CONFIG_DEFAULT { NRF_ADC_CONFIG_RES_10BIT, \
NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD, \
NRF_ADC_CONFIG_REF_VBG }
/**
* @brief Function for configuring ADC.
*
* This function powers on the analog-to-digital converter and configures it.
* After the configuration, the ADC is in DISABLE state and must be
* enabled before using it.
*
* @param[in] config Configuration parameters.
*/
void nrf_adc_configure(nrf_adc_config_t * config);
/**
* @brief Blocking function for executing a single ADC conversion.
*
* This function selects the desired input, starts a single conversion,
* waits for it to finish, and returns the result.
* After the input is selected, the analog-to-digital converter
* is left in STOP state.
* The function does not check if the ADC is initialized and powered.
*
* @param[in] input Input to be selected.
*
* @return Conversion result.
*/
int32_t nrf_adc_convert_single(nrf_adc_config_input_t input);
/**
* @brief Function for selecting ADC input.
*
* This function selects the active input of ADC. Ensure that
* the ADC is powered on and in IDLE state before calling this function.
*
* @param[in] input Input to be selected.
*/
__STATIC_INLINE void nrf_adc_input_select(nrf_adc_config_input_t input)
{
NRF_ADC->CONFIG =
((uint32_t)input << ADC_CONFIG_PSEL_Pos) | (NRF_ADC->CONFIG & ~ADC_CONFIG_PSEL_Msk);
if (input != NRF_ADC_CONFIG_INPUT_DISABLED)
{
NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled << ADC_ENABLE_ENABLE_Pos;
}
else
{
NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled << ADC_ENABLE_ENABLE_Pos;
}
}
/**
* @brief Function for retrieving the ADC conversion result.
*
* This function retrieves and returns the last analog-to-digital conversion result.
*
* @return Last conversion result.
*/
__STATIC_INLINE int32_t nrf_adc_result_get(void)
{
return (int32_t)NRF_ADC->RESULT;
}
/**
* @brief Function for checking whether the ADC is busy.
*
* This function checks whether the analog-to-digital converter is busy with a conversion.
*
* @retval true If the ADC is busy.
* @retval false If the ADC is not busy.
*/
__STATIC_INLINE bool nrf_adc_is_busy(void)
{
return ( (NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) == ADC_BUSY_BUSY_Msk);
}
/**
* @brief Function for getting the ADC's enabled interrupts.
*
* @param[in] mask Mask of interrupts to check.
*
* @return State of the interrupts selected by the mask.
*
* @sa nrf_adc_int_enable()
* @sa nrf_adc_int_disable()
*/
__STATIC_INLINE uint32_t nrf_adc_int_get(uint32_t mask)
{
return (NRF_ADC->INTENSET & mask); // when read this register will return the value of INTEN.
}
/**
* @brief Function for starting conversion.
*
* @sa nrf_adc_stop()
*
*/
__STATIC_INLINE void nrf_adc_start(void)
{
NRF_ADC->TASKS_START = 1;
}
/**
* @brief Function for stopping conversion.
*
* If the analog-to-digital converter is in inactive state, power consumption is reduced.
*
* @sa nrf_adc_start()
*
*/
__STATIC_INLINE void nrf_adc_stop(void)
{
NRF_ADC->TASKS_STOP = 1;
}
/**
* @brief Function for checking if the requested ADC conversion has ended.
*
* @retval true If the task has finished.
* @retval false If the task is still running.
*/
__STATIC_INLINE bool nrf_adc_conversion_finished(void)
{
return ((bool)NRF_ADC->EVENTS_END);
}
/**
* @brief Function for clearing the conversion END event.
*/
__STATIC_INLINE void nrf_adc_conversion_event_clean(void)
{
NRF_ADC->EVENTS_END = 0;
}
/**
* @brief Function for getting the address of an ADC task register.
*
* @param[in] adc_task ADC task.
*
* @return Address of the specified ADC task.
*/
__STATIC_INLINE uint32_t nrf_adc_task_address_get(nrf_adc_task_t adc_task);
/**
* @brief Function for getting the address of a specific ADC event register.
*
* @param[in] adc_event ADC event.
*
* @return Address of the specified ADC event.
*/
__STATIC_INLINE uint32_t nrf_adc_event_address_get(nrf_adc_event_t adc_event);
/**
* @brief Function for setting the CONFIG register in ADC.
*
* @param[in] configuration Value to be written to the CONFIG register.
*/
__STATIC_INLINE void nrf_adc_config_set(uint32_t configuration);
/**
* @brief Function for clearing an ADC event.
*
* @param[in] event Event to clear.
*/
__STATIC_INLINE void nrf_adc_event_clear(nrf_adc_event_t event);
/**
* @brief Function for checking state of an ADC event.
*
* @param[in] event Event to check.
*
* @retval true If the event is set.
* @retval false If the event is not set.
*/
__STATIC_INLINE bool nrf_adc_event_check(nrf_adc_event_t event);
/**
* @brief Function for enabling specified interrupts.
*
* @param[in] int_mask Interrupts to enable.
*/
__STATIC_INLINE void nrf_adc_int_enable(uint32_t int_mask);
/**
* @brief Function for disabling specified interrupts.
*
* @param[in] int_mask Interrupts to disable.
*/
__STATIC_INLINE void nrf_adc_int_disable(uint32_t int_mask);
/**
* @brief Function for retrieving the state of a given interrupt.
*
* @param[in] int_mask Interrupt to check.
*
* @retval true If the interrupt is enabled.
* @retval false If the interrupt is not enabled.
*/
__STATIC_INLINE bool nrf_adc_int_enable_check(nrf_adc_int_mask_t int_mask);
/**
* @brief Function for activating a specific ADC task.
*
* @param[in] task Task to activate.
*/
__STATIC_INLINE void nrf_adc_task_trigger(nrf_adc_task_t task);
/**
* @brief Function for enabling ADC.
*
*/
__STATIC_INLINE void nrf_adc_enable(void);
/**
* @brief Function for disabling ADC.
*
*/
__STATIC_INLINE void nrf_adc_disable(void);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE uint32_t nrf_adc_task_address_get(nrf_adc_task_t adc_task)
{
return (uint32_t)((uint8_t *)NRF_ADC + adc_task);
}
__STATIC_INLINE uint32_t nrf_adc_event_address_get(nrf_adc_event_t adc_event)
{
return (uint32_t)((uint8_t *)NRF_ADC + adc_event);
}
__STATIC_INLINE void nrf_adc_config_set(uint32_t configuration)
{
NRF_ADC->CONFIG = configuration;
}
__STATIC_INLINE void nrf_adc_event_clear(nrf_adc_event_t event)
{
*((volatile uint32_t *)((uint8_t *)NRF_ADC + (uint32_t)event)) = 0x0UL;
}
__STATIC_INLINE bool nrf_adc_event_check(nrf_adc_event_t event)
{
return (bool)*(volatile uint32_t *)((uint8_t *)NRF_ADC + (uint32_t)event);
}
__STATIC_INLINE void nrf_adc_int_enable(uint32_t int_mask)
{
NRF_ADC->INTENSET = int_mask;
}
__STATIC_INLINE void nrf_adc_int_disable(uint32_t int_mask)
{
NRF_ADC->INTENCLR = int_mask;
}
__STATIC_INLINE bool nrf_adc_int_enable_check(nrf_adc_int_mask_t int_mask)
{
return (bool)(NRF_ADC->INTENSET & int_mask);
}
__STATIC_INLINE void nrf_adc_task_trigger(nrf_adc_task_t task)
{
*((volatile uint32_t *)((uint8_t *)NRF_ADC + (uint32_t)task)) = 0x1UL;
}
__STATIC_INLINE void nrf_adc_enable(void)
{
NRF_ADC->ENABLE = 1;
}
__STATIC_INLINE void nrf_adc_disable(void)
{
NRF_ADC->ENABLE = 0;
}
#endif
#endif /* NRF52 */
/**
*@}
**/
#endif /* NRF_ADC_H_ */