This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF52 ADC Sampling multiple Signals

Hello everyone

I'm the proud owner of a nRF52 Prev. DK and trying to get my project to work. I would like to sample 3 to 5 analog signals using the ADC on the DevKit, followed by sending it to an app, using Ble. The sampled signals would be 3V, 5V if possible. To begin my adventure in this new world, I took the ble proximity example and modified it. At the moment, the ADC samples channel AIN0 and shows the value, as the battery value, on the Nordic toolkit app. Sampling the GND output pin gives me values around 253, the 5V pin gives me values around 60 and the VDD pin (+- 3V) gives me values around 56. I can't seem to figure out from where the nRF is getting those values. I would expect values going from 0 to 1023 (10bit ADC)? The ADC is configurated as a default channel.

Also how should I configurate the ADC (when) using Scan Mode?

UPDATE 14/01/2016

I fixed all the errors and it's compiling perfectly. When I program the code on the nRF, bluetooth doesn't seem to advertise anymore. It seems like the nRF keeps sampling the AIN0 - 2 channels and doesn't come out of it so that the rest of the code can be 'launched'. So the advertising_init(); doesn't get started. Need to find a way how I can let all the channels sample once and then continu the rest of the code.

UPDATE 15/01/2016

Using timer 1 seems to do the trick. Code runs, samples and shows some values on the app.


Question 18/01/2016

Stefan, using the timer ADC code to workaround the Scan Mode issue we init, sample and uninit each channel one by one. Is it still possible to sample the VDD voltage on a different timer? E.g. my compare event timer is set to 2 seconds, so after 2 seconds channel one is getting sampled. Another two seconds later, channel 2 is getting sampled and so on. Let's say I want to sample my VDD every 10 seconds in tandem with the 'two second sampler', is this still possible with this workaround? The only option I see is to config a 4th channel which samples the VDD when 'm_adc_channel_enabled == 3'.


The safest and easiest way is to implement a 4th channel to sample the Vdd.

Question 26/01/2016

When I run the ADC sample code, implemented in the ble_app_rscs, it seems that the measurement_timeout_handler doesn't get activated anymore. Because of this, my ADC-values aren't getting updated on my smartphone app. When I use the simulated values in my code, the app does get updated. Can this be due to the usage of timer 1 and bluetooth using timer 0 ?

Question 8/02/2016

I changed to code of the saadc_sample_from_three_pins - timer mode application so that the buffer holds 10 measurements and prints the average output. The only disadvantage I experience now is that the printing of the code through UART is very slow. Can this be boosted?

At the moment I use 10 ms to compare every event, for 25 samples in buffer. Aren't these 'extreme' values?

Question 01/04/2016

First of all, thank you or the extra sampling code examples. I took a look at them and for my purpose, using 'oversample' seems to be good enough. Everything runs like I want it to, except the 'timing'.

My code has 3 timers running (and more)

  • Battery (10000ms). After 10 seconds the battery handler will be called and will send the new sampled battery value using: ble_bas_battery_level_update;

  • SampleUpdate (5000ms) This handler will send all te current values of the sensors to my app;

  • SampleTimer (125ms with OVERSAMPLE_8X). After 1000 ms, a channel gets sampled and stored in a variable. 1000ms later, the next channel, ...

What I would expect now is that each time the SampleUpdate timer expires, my values in my application are getting updated. But this happens way faster. If I look at the timestamp in my database, I get the next picture:

image description

The timestamp gets 'calculated' each time my application recieves an update so this means the Nordic sends the data faster than 5000ms.

Could I have missed something in the bluetooth settings? Or maybe a timers issue?

UPDATE Question 01/04/2016

I somehow seem to have fixed the problem. While I was debugging each part of the code the problem suddenly disappeared.

image description

One thing I noticed is that when I choose 125ms as sampling timer, the timing sometimes seems to be out of sync. The database shows me timestamps like these:

image description

When I take 250 ms as SamplingTimer, the problem is solved. Which will do for this application!

Kind regards and thank you for all the help,


  • Hi

    What is your gain setting? If you have selected 1/6 gain setting, then the SAADC range should be 0V-3.6V.

    Also, what is the resistance of the circuit you are measuring? You should adjust the SAADC acquisition time depending on the resistance of the measured circuit?

    How have you configured other SAADC parameters?

    Note the errata for the SAADC which is valid when acquisition time is 5us or less. To avoid it set acquisition time to a higher value.

  • Hello Stefan,

    I took the ble_app_proximity as an example and didn't change much except the input channel from the ADC and let the ble_bas_battery_level_update update the battery value with the sampled value. As the code was configurated with the default settings, the gain is 1/6th. I haven't changed other parameters yet, because i'm still learning how the libs and drivers work and how to program the nRF52. Today I managed to let the adc sample AIN0 (P0.02) and show as the 'cadence' value in the RSC application from the nRFToolBox. These values are still the same as in my first post, which I still find odd. The signal I eventually want to measure is the voltage (max 3V), coming from a voltage divider with a pressure sensor as one of the resistors.

    Is it maybe possible to provide me with an example code or explane how to configurate the ADC, using 2 analog inputs and using scan mode? I can't seem to simply sample 2 different inputs and store them in two variables.

    Kind regards,


  • Hi

    Here is a SAADC code that runs on PCA10036 and samples on two pins, the AIN0 pin (P0.02) and the AIN2 pin (P0.04). It runs on nRF52 SDK 0.9.2. It works but the code is blocking, i.e. the SAADC does not use EasyDMA and RAM buffers to collect samples, but rather starts sampling on one pin, then waits for that sample to finish, then stars sampling on the second pin, and waits for the second sample to finish. The sampled result is then output on the UART.

    saadc_sample_from_two_pins -

    The UART messages can be received with e.g. RealTerm, or any other UART terminal program. The configuration should be as described here

    Update 8.1.2016 Scan mode is not supposed to work on two analog input pins for the preview kit, see nRF52832 Engineering A Errata v1.0, anomaly #28. Scan mode on different analog input pins should be functional however for the nRF52832 Engineering B (present on nRF51-DK PCA10040 board) chip however. I find the following non-blocking code to work for nRF51-DK kit (PCA10040), but it does not work for the nRF51-DK preveiw kit (PCA10036)

    saadc_sample_from_two_pins - scan

    Update 11.1.2016 I created a saadc example that samples from three pins but only configures one channel channel. i.e. :

    1. Initialize SAADC and configure SAADC channel 0
    2. Configure TIMER to periodically start SAADC sampling
    3. When sampling on channel 0 is complete, unconfigure channel 0 and then configure channel 1
    4. When sampling on channel 1 is complete, unconfigure channel 1 and then configure channel 2
    5. When sampling on channel 2 is complete, unconfigure channel 2 and then configure channel 0

    saadc_sample_from_three_pins - timer

    This example is non-blocking example and uses a single RAM buffer. A callback is received after each SAADC sample since the RAM buffer size holds only one sample. This method seems to work fine for the nRF51-DK preveiw kit (PCA10036)

    Update 3.3.2016 I attach a few more examples to play with. they are based on the saadc example in nRF52 SDK 0.9.2. The following example uses oversampling and burst mode to get more stable saadc reading. See also this thread.

    The following example uses the internal SAADC timer to generate 200 kHz sampling frequency

  • Hello Stefan

    Thank you for your fast response and all your help! :) Your code works perfectly and gives me the results like I expected them to be.

    At the moment i'm trying to integrate this in the ble_app_rscs app, so that the 'Cadence' shows the value from AIN0 and speed the value from AIN1. I tried it as follows:

    First we configurate de ADC and the channels (adc init with saadc_event_handler, AIN0 as channel init0 and AIN1 as channel init1). Then when the ADC_Timer expires, I call up the nrf_drv_saadc_sample() function. Using the saadc_event_handler I store the ADC value from data.done.p_buffer[0] in my variable and use the ble_update command to update the value. This works perfectly for only 1 channel. When I try to sample both the channels and store them in the buffer, It ain't working. Well it works but the results seems a combination from AIN0 and AIN1? Should I store the value from AIN0 in buffer[0] and the value from AIN1 in buffer [1] and read them out? Is it also possible to store the first 10 samples values from AIN0 in buffer[0-9] and the first 10 values from AIN1 in buffer[10-19]?

    Edit 1:

    For sending and showing the 3 sampled values on a smartphone app, the easiest way is defining a new UUID and ble_service?

    Kind regards,


    P.S Thank you for helping me solve my problems.

  • UPDATE 10/01/2016

    I tried the scan mode code and like you said, it ain't working on the nRF52. Is it possible to work around this problem by using 3 times, with different ticks? So when timer 1 expires, channel 1 gets sampled, when timer 2 expires ... Long story short, is it possible to sample 3 analog inputs and send the value to a smartphone app, using my NRF52 or do I need to buy a new Nordicsemi board?

    Kind regards,

    Legend. p.s. Thank you for you time!