I'm trying to set up the ADC to read a battery voltage but am unable to get the adc result to change regardless of whether the input line is connected to VDD or GND. I'm using the nRF51-DK, and am configuring AIN5 for my ADC input. I'm reading the ADC on a timer interrupt. The timer works fine and I can set a breakpoint there to verify the ADC read occurs every 10 seconds. Every ADC read gives me a result of around 0xCC whether AIN5 is connected to GND or VDD (~2.9V). Looking at the nRF51422 Product Spec, it says that AIN5 is P0.04. This is the pin that I am switching between GND and VDD. I've also verified that LPCOMP is disabled so there is no contention here. I'm using SDK9 with the S110 SoftDevice. Here's my ADC configuration code - battery_init() is called from main(). Am I missing a configuration somewhere? Thanks.
#include <stdint.h>
#include "nordic_common.h"
#include "nrf.h"
#include "nrf_soc.h"
#include "nrf_adc.h"
#include "app_error.h"
#include "nrf51_bitfields.h"
#include "app_timer.h"
#define ADC_REF_VOLTAGE_IN_MILLIVOLTS 1200 /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
#define ADC_PRE_SCALING_COMPENSATION 3 /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
#define BATTERY_LEVEL_MEAS_INTERVAL APP_TIMER_TICKS(10000, APP_TIMER_PRESCALER) /**< Battery level measurement interval (ticks). This value corresponds to 10 seconds. */
#define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
((((ADC_VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLTS) / 255) * ADC_PRE_SCALING_COMPENSATION)
static app_timer_id_t _battery_timer_id;
static void adc_configure(void);
static void battery_level_meas_timeout_handler(void * p_context);
void battery_init(void)
{
uint32_t err_code;
// Create battery timer.
err_code = app_timer_create(&_battery_timer_id,
APP_TIMER_MODE_REPEATED,
battery_level_meas_timeout_handler);
APP_ERROR_CHECK(err_code);
adc_configure();
// Start battery timer
err_code = app_timer_start(_battery_timer_id, BATTERY_LEVEL_MEAS_INTERVAL, NULL);
APP_ERROR_CHECK(err_code);
}
static void adc_configure(void)
{
uint32_t err_code;
nrf_adc_config_t adc_config = NRF_ADC_CONFIG_DEFAULT;
// Configure ADC
adc_config.reference = NRF_ADC_CONFIG_REF_VBG;
adc_config.resolution = NRF_ADC_CONFIG_RES_8BIT;
adc_config.scaling = NRF_ADC_CONFIG_SCALING_SUPPLY_ONE_THIRD;
nrf_adc_configure(&adc_config);
// Select the battery level input
nrf_adc_input_select(NRF_ADC_CONFIG_INPUT_5);
// Enable ADC interrupt
nrf_adc_int_enable(ADC_INTENSET_END_Msk);
err_code = sd_nvic_ClearPendingIRQ(ADC_IRQn);
APP_ERROR_CHECK(err_code);
err_code = sd_nvic_SetPriority(ADC_IRQn, NRF_APP_PRIORITY_LOW);
APP_ERROR_CHECK(err_code);
err_code = sd_nvic_EnableIRQ(ADC_IRQn);
APP_ERROR_CHECK(err_code);
}
static void battery_level_meas_timeout_handler(void * p_context)
{
UNUSED_PARAMETER(p_context);
nrf_adc_start();
}
void ADC_IRQHandler(void)
{
if (nrf_adc_conversion_finished())
{
uint8_t adc_result;
static volatile uint16_t batt_lvl_in_milli_volts;
nrf_adc_conversion_event_clean();
adc_result = nrf_adc_result_get();
batt_lvl_in_milli_volts = ADC_RESULT_IN_MILLI_VOLTS(adc_result);
}
}