Boron Low ADC Readings

Tags: #<Tag:0x00007fe21ef710b8>


Yup that’s how I have it. No breadboard. I was only powering it with USB. Let me add a Lipo that is charged and then test it.


I’ve tried both USB and USB+LiPo and get 4095 in all cases with this code

SerialLogHandler serLog(LOG_LEVEL_WARN, {{"app", LOG_LEVEL_INFO}});

void setup() {
  Serial.begin(115200); //open serial console
  pinMode(D2, OUTPUT);

void loop() {
  int adc_value = 0;

  digitalWrite(D2, HIGH);
  adc_value = analogRead(A2);"ADC: %d", adc_value);


so I have plugged in a LiPO and USB and it is still reading around 4030. I swapped out and tried another Boron and now get values around 4060?
0000051476 [app] INFO: ADC: 4070
0000058478 [app] INFO: ADC: 4060
0000065479 [app] INFO: ADC: 4062
0000072481 [app] INFO: ADC: 4062
0000079481 [app] INFO: ADC: 4057
0000086483 [app] INFO: ADC: 4060
0000093484 [app] INFO: ADC: 4057
0000100485 [app] INFO: ADC: 4061
0000107487 [app] INFO: ADC: 4059
0000114488 [app] INFO: ADC: 4058
0000121490 [app] INFO: ADC: 4060
0000128491 [app] INFO: ADC: 4057
0000135492 [app] INFO: ADC: 4062

Do I need to make some sort of adjustment to factor for this difference? The voltage coming into the pin is still 3.3V.


That shouldn’t be required.
Have you tested with my code? I can’t make any of my Gen3 devices report anything but 4095 (occasionally 4094) with that code and a D2-A2 bridge :confused:


Yep I am using your code. I have 3 Borons doing the same thing. BUT I tested the same setup and code on an Argon and it works fine, 4095. Its hard for me to believe I have 3 bad Borons?


That is rather peculiar - maybe @marekparticle can take this one from here.

BTW, can you post a photo of your Boron setup?


Here is a picture of the setup. The USB cable is going to my MacBook Pro.


I see you have no antenna attached - if you have the cell module on you should not do that. These modules are not meant to be running without load on the output stage.


I actually did not know that. I do have SYSTEM_MODE(SEMI_AUTOMATIC); at the top of my code. Does this change things?


When the radio is not on (as in SEMI_AUTOMATIC) it shouldn’t matter.


I’m seeing similar results with a Boron LTE that was shipped recently.
All tests with Cellular Antenna Connected, USB powered, and Li-Po connected.

// Using 3V3 Pin Bridge
0000013954 [app] INFO: ADC: 4079
0000018955 [app] INFO: ADC: 4075
0000023955 [app] INFO: ADC: 4081
0000028956 [app] INFO: ADC: 4082
0000033957 [app] INFO: ADC: 4078
0000038957 [app] INFO: ADC: 4085
0000043958 [app] INFO: ADC: 4083
0000048958 [app] INFO: ADC: 4081
0000053959 [app] INFO: ADC: 4079
0000058959 [app] INFO: ADC: 4079
0000063960 [app] INFO: ADC: 4081
0000068961 [app] INFO: ADC: 4078

// Using D2 Pin Bridge
0000035008 [app] INFO: ADC: 4081
0000040009 [app] INFO: ADC: 4088
0000045009 [app] INFO: ADC: 4079
0000050010 [app] INFO: ADC: 4082
0000055010 [app] INFO: ADC: 4074
0000060011 [app] INFO: ADC: 4071
0000065012 [app] INFO: ADC: 4087
0000070012 [app] INFO: ADC: 4085
0000075013 [app] INFO: ADC: 4079
0000080013 [app] INFO: ADC: 4081
0000085014 [app] INFO: ADC: 4076


Huh? :flushed:

That’s something @marekparticle and @oddwires1 may want to chime in on - that seems rather wrong to me.


Hi @Particle9 - sorry to be getting to you so late, had a break for the holiday weekend (thanks for the ping, @ScruffR). I can’t reproduce this on my own device, so it looks like something must be up hardware-wise. Would you mind creating a support ticket ( and we can determine whether or not a replacement is in order?


@marekparticle, I’m reproducing this with “replacement” Boron’s that were recently shipped to me.
Note: This ADC error isn’t a concern for me personally, but I wanted you to be aware.
Do you have a Boron from a recent production run to try ?

I switched to A3 Pin, and disconnected the Li-Po during the test, no significant change:

// A3 to 3V3 Pin Bridge
0000014060 [app] INFO: ADC: 4088
0000019060 [app] INFO: ADC: 4079
0000024061 [app] INFO: ADC: 4088
0000029062 [app] INFO: ADC: 4079
0000034062 [app] INFO: ADC: 4077
// Disconnected the Li-Po, Boron was Re-Charging previously
0000039063 [app] INFO: ADC: 4075
0000044063 [app] INFO: ADC: 4078
0000049064 [app] INFO: ADC: 4088
0000054065 [app] INFO: ADC: 4082
0000059065 [app] INFO: ADC: 4074


@rickkas7 - should we expect any variance from 4095 when analogRead()ing a pin grabbing 3.3V from itself?


@marekparticle, the ADC reference is the 3.3v rail so measuring 3.3v on an analog pin should result in only a one bit error at most.


@peekay123, understood. But, I’m struck by the fact that this has occurred on more than one Boron. I… must be missing something.


@marekparticle, it is incredibly odd. It may be worth looking at the 3.3v rail to make sure it is clean. It might be worth testing with a known-clean external 3.3v source. You may also want to look at the boards for any manufacturing anomalies like excess flux, etc. My understanding is that all things being equal (DeviceOS, app), “older” Borons work fine but now these “new” ones. So software issues can most likely be eliminated.


@Rftop - can you PM me device IDs so I can check mfg date?


I tried this out on a Boron LTE running 1.4.2. I connected A2 to 3V3 and the values are not 4095.

0000012309 [app] INFO: ADC: 4090
0000019311 [app] INFO: ADC: 4087
0000026312 [app] INFO: ADC: 4092
0000033314 [app] INFO: ADC: 4094
0000040316 [app] INFO: ADC: 4087
0000047318 [app] INFO: ADC: 4091
0000054319 [app] INFO: ADC: 4093
0000061321 [app] INFO: ADC: 4092
0000068323 [app] INFO: ADC: 4094
0000075325 [app] INFO: ADC: 4089
0000082326 [app] INFO: ADC: 4095
0000089327 [app] INFO: ADC: 4087

This was also the case with the other ADC inputs, and also using D2 as an output.

By the way, using a GPIO as a voltage reference is not guaranteed to work with the nRF52, because the output voltage spec says VOH,SD can be from VDD-0.4 to VDD volts. In other words, GPIO HIGH may not be exactly VDD.

However, after forcing the calibration of the nRF52 SAADC, I got much better values. There were a few outliers, but they were generally close to 4095 and less frequent:

0000003070 [app] INFO: calibration complete
0000003072 [app] INFO: A2=4095
0000004074 [app] INFO: A2=4095
0000005076 [app] INFO: A2=4095
0000006077 [app] INFO: A2=4094
0000007079 [app] INFO: A2=4095
0000008080 [app] INFO: A2=4095
0000009082 [app] INFO: A2=4079
0000010084 [app] INFO: A2=4095
0000011085 [app] INFO: A2=4095
0000012087 [app] INFO: A2=4093
0000013088 [app] INFO: A2=4095
0000014090 [app] INFO: A2=4095
0000015091 [app] INFO: A2=4095
0000016093 [app] INFO: A2=4095
0000017095 [app] INFO: A2=4095
0000018097 [app] INFO: A2=4095
0000019099 [app] INFO: A2=4095
0000020101 [app] INFO: A2=4095
0000021102 [app] INFO: A2=4095
0000022104 [app] INFO: A2=4093
0000023106 [app] INFO: A2=4095

Here’s the code:

#include "Particle.h"

#include "nrfx_saadc.h"

SerialLogHandler logHandler;


void adcCalibrate();

void setup() {

	// Wait for a USB serial connection for up to 10 seconds
	waitFor(Serial.isConnected, 10000);

	// Calibrate the ADC at startup. You might want to do this after large temperature
	// changes as well.

void loop() {
	int a2 = analogRead(A2);"A2=%d", a2);

static void adcCallback(nrfx_saadc_evt_t const *event) {
	// We just poll for done during calibration instead of using this event but the
	// callback still needs to be defined.

void adcCalibrate() {
	nrfx_err_t err;

	// IMPORTANT: You must detach the IRQ handler from the system firmware and re-attach it to
	// user firmware, or this won't work right.
	attachInterruptDirect(SAADC_IRQn, nrfx_saadc_irq_handler, false);

	nrfx_saadc_config_t saadcConfig = NRFX_SAADC_DEFAULT_CONFIG;
	saadcConfig.low_power_mode = false;
	saadcConfig.resolution = NRF_SAADC_RESOLUTION_12BIT;
	saadcConfig.oversample = NRF_SAADC_OVERSAMPLE_DISABLED;
	saadcConfig.interrupt_priority = APP_IRQ_PRIORITY_LOW;

	// Initialize SAADC
	err = nrfx_saadc_init(&saadcConfig, adcCallback);
	if (err) {
		Log.error("nrfx_saadc_init err=%lu", err);

	// Now calibrate it. This does not require a channel be initialized first.
	err = nrfx_saadc_calibrate_offset();
	if (err == NRFX_SUCCESS) {
		while(nrfx_saadc_is_busy()) {
		}"calibration complete");
	else {"calibrate failed err=%lu", err);

We should probably put ADC calibration right into Device OS, but this is probably a reasonable thing to play around with and see if it helps in your case to be sure that’s what the problem is.