nRF52 ADC

The nRF52 family includes an adjustable 'successive-approximation ADC' which can be configured to convert data with up to 14-bit resolution (0..16383), and the reference voltage can be adjusted up to 3.6V internally.

The default values for the ADC are 10-bit resolution (0..1023) with a 3.6V reference voltage, meaning every digit returned from the ADC = 3600mV/1024 = 3.515625mV.

Analog Reference Voltage

The internal reference voltage is 0.6V with a variable gain setting, and can be adjust via the analogReference(...) function, providing one of the following values:

  • AR_INTERNAL (0.6V Ref * 6 = 0..3.6V) <-- DEFAULT
  • AR_INTERNAL_3_0 (0.6V Ref * 5 = 0..3.0V)
  • AR_INTERNAL_2_4 (0.6V Ref * 4 = 0..2.4V)
  • AR_INTERNAL_1_8 (0.6V Ref * 3 = 0..1.8V)
  • AR_INTERNAL_1_2 (0.6V Ref * 2 = 0..1.6V)
  • AR_VDD4 (VDD/4 REF * 4 = 0..VDD)

For example:

Download: file
// Set the analog reference to 3.0V (default = 3.6V)
analogReference(AR_INTERNAL_3_0);

Analog Resolution

The ADC resolution can be set to 8, 10, 12 or 14 bits using the analogReadResolution(...) function, with the default value being 10-bit:

Download: file
// Set the resolution to 12-bit (0..4095)
analogReadResolution(12); // Can be 8, 10, 12 or 14

Default ADC Example (10-bit, 3.6V Reference)

The original source for this code is included in the nRF52 BSP and can be viewed online here.

int adcin    = A5;
int adcvalue = 0;
float mv_per_lsb = 3600.0F/1024.0F; // 10-bit ADC with 3.6V input range

void setup() {
  Serial.begin(115200);
  while ( !Serial ) delay(10);   // for nrf52840 with native usb
}

void loop() {
  // Get a fresh ADC value
  adcvalue = analogRead(adcin);

  // Display the results
  Serial.print(adcvalue);
  Serial.print(" [");
  Serial.print((float)adcvalue * mv_per_lsb);
  Serial.println(" mV]");

  delay(100);
}

Advanced Example (12-bit, 3.0V Reference)

The original source for this code is included in the nRF52 BSP and can be viewed online here.

#include <Arduino.h>

uint32_t vbat_pin = PIN_VBAT;             // A7 for feather nRF52832, A6 for nRF52840

#define VBAT_MV_PER_LSB   (0.73242188F)   // 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096

#ifdef NRF52840_XXAA    // if this is for nrf52840
#define VBAT_DIVIDER      (0.5F)               // 150K + 150K voltage divider on VBAT
#define VBAT_DIVIDER_COMP (2.0F)          // Compensation factor for the VBAT divider
#else
#define VBAT_DIVIDER      (0.71275837F)   // 2M + 0.806M voltage divider on VBAT = (2M / (0.806M + 2M))
#define VBAT_DIVIDER_COMP (1.403F)        // Compensation factor for the VBAT divider
#endif

#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)


float readVBAT(void) {
  float raw;

  // Set the analog reference to 3.0V (default = 3.6V)
  analogReference(AR_INTERNAL_3_0);

  // Set the resolution to 12-bit (0..4095)
  analogReadResolution(12); // Can be 8, 10, 12 or 14

  // Let the ADC settle
  delay(1);

  // Get the raw 12-bit, 0..3000mV ADC value
  raw = analogRead(vbat_pin);

  // Set the ADC back to the default settings
  analogReference(AR_DEFAULT);
  analogReadResolution(10);

  // Convert the raw value to compensated mv, taking the resistor-
  // divider into account (providing the actual LIPO voltage)
  // ADC range is 0..3000mV and resolution is 12-bit (0..4095)
  return raw * REAL_VBAT_MV_PER_LSB;
}

uint8_t mvToPercent(float mvolts) {
  if(mvolts<3300)
    return 0;

  if(mvolts <3600) {
    mvolts -= 3300;
    return mvolts/30;
  }

  mvolts -= 3600;
  return 10 + (mvolts * 0.15F );  // thats mvolts /6.66666666
}

void setup() {
  Serial.begin(115200);
  while ( !Serial ) delay(10);   // for nrf52840 with native usb

  // Get a single ADC sample and throw it away
  readVBAT();
}

void loop() {
  // Get a raw ADC reading
  float vbat_mv = readVBAT();

  // Convert from raw mv to percentage (based on LIPO chemistry)
  uint8_t vbat_per = mvToPercent(vbat_mv);

  // Display the results

  Serial.print("LIPO = ");
  Serial.print(vbat_mv);
  Serial.print(" mV (");
  Serial.print(vbat_per);
  Serial.println("%)");

  delay(1000);
}
This guide was first published on Mar 22, 2017. It was last updated on Mar 22, 2017. This page (nRF52 ADC) was last updated on May 23, 2019.