diff --git a/hal/targets.json b/hal/targets.json index 5d6e036bdf..3c48cbfd93 100644 --- a/hal/targets.json +++ b/hal/targets.json @@ -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"], diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/analogin_api.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/analogin_api.c index 44d5342831..ac349e0d36 100644 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/analogin_api.c +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/analogin_api.c @@ -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); } diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/pwmout_api.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/pwmout_api.c index 063b94d37b..2b4d27f3c6 100644 --- a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/pwmout_api.c +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/pwmout_api.c @@ -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) diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/sdk/drivers_nrf/adc/nrf_drv_adc.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/sdk/drivers_nrf/adc/nrf_drv_adc.c new file mode 100644 index 0000000000..1c4a0f163b --- /dev/null +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/sdk/drivers_nrf/adc/nrf_drv_adc.c @@ -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); + } +} diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/sdk/drivers_nrf/adc/nrf_drv_adc.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/sdk/drivers_nrf/adc/nrf_drv_adc.h new file mode 100644 index 0000000000..fddd43d2f6 --- /dev/null +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF51822/sdk/drivers_nrf/adc/nrf_drv_adc.h @@ -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 +/** @} */ diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/hal/nrf_adc.c b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/hal/nrf_adc.c new file mode 100644 index 0000000000..e408ca7007 --- /dev/null +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/hal/nrf_adc.c @@ -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 diff --git a/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/hal/nrf_adc.h b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/hal/nrf_adc.h new file mode 100644 index 0000000000..c697a22415 --- /dev/null +++ b/hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/drivers_nrf/hal/nrf_adc.h @@ -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_ */