Feedback
Feedback

If you are having issues with the exercises, please create a ticket on DevZone: devzone.nordicsemi.com
Click or drag files to this area to upload. You can upload up to 2 files.

Exercise 2 – Interfacing with ADC using nrfx driver and software timers

In this exercise, we will explore the simple mode of the nrfx SAADC driver to measure battery voltage on the chip supply (VDD) at a regular interval, using a software timer.

Exercise steps

Open the code base of the exercise by navigating to Create a new application in the nRF Connect for VS Code extension, select Copy a sample, and search for Lesson 6 – Exercise 2.

1. Let’s enable the SAADC driver by adding the following line into the application configuration file prj.conf.

2. Add SAADC related header file by including the following line at the top (include section) of the main.c

#include <nrfx_saadc.h>

3. We need to declare some objects that will be used later in the initialization process.

3.1 Declare the struct to hold the configuration for the SAADC channel used to sample the battery voltage. The macro will assign default configuration parameters for a single-ended input. The configuration can be changed later. Add this line close to the top of the main.c:

static nrfx_saadc_channel_t channel = NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN0, 0);

Connect a battery between GND and analog input 0 (AIN0). Check the Hardware and Layout ->Pin assignment chapter in the Product specification to know which Pin is connected to the analog inputs on your choice of SoC/SiP. You can also connect a jumper wire between analog input 0 and VDD if you do not have a battery available.

3.2 Declare the buffer where the SAADC sample value will be stored during sampling. Add this line below code from the last point:

static int16_t sample;

Note

Make sure that the voltage applied to the analog input does not exceed VDD. If you have a battery with a higher voltage level than VDD, you need to use a voltage divider between the battery and the input.

If you want to measure battery voltage directly from VDD, you can replace NRF_SAADC_INPUT_AIN0 with NRF_SAADC_INPUT_VDD.

4. We will use a software timer (k_timer) to trigger the sampling.

4.1 Define the sample interval by adding this line close to the top of main.c:

#define BATTERY_SAMPLE_INTERVAL_MS 2000

4.2 Define the timer instance that will be used for sampling:

K_TIMER_DEFINE(battery_sample_timer, battery_sample_timer_handler, NULL);

4.3 Add forward declaration of timer callback handler right before the previous timer definition:

static void battery_sample_timer_handler(struct k_timer * timer);

5. Configure the SAADC driver.

5.1 We will reference the ADC defined in the Zephyr devicetree, to make the code more portable. To connect the SAADC interrupt to SAADC interrupt handler, add these lines:

By default, the ADC is enabled in the board DTS file for all DKs supported by this course, but for custom boards you may have to enable it in your DTS or overlay file using the following code snippet:

5.2 Before using the nrfx SAADC driver, the driver instance must be initialized. We will again refer to the devicetree to get the configured priority of the ADC node and use this for the driver:

nrfx_err_t err = nrfx_saadc_init(DT_IRQ(DT_NODELABEL(adc), priority));
if (err != NRFX_SUCCESS) {
  printk("nrfx_saadc_mode_trigger error: %08x", err);
  return;
}

5.3 Configure the SAADC channel using the previously defined channel configuration structure. The default configuration uses GAIN=1, which is too high to support supply voltage measurements. We need to change the gain config before configuring the channel:

channel.channel_config.gain = NRF_SAADC_GAIN1_6;
err = nrfx_saadc_channels_config(&channel, 1);
if (err != NRFX_SUCCESS) {
  printk("nrfx_saadc_channels_config error: %08x", err);
  return;
}

5.4 Configure SAADC driver in simple mode on channel 0. Passing NULL to the last argument will make the driver operate in blocking mode:

err = nrfx_saadc_simple_mode_set(BIT(0),
                                 NRF_SAADC_RESOLUTION_12BIT,
                                 NRF_SAADC_OVERSAMPLE_DISABLED,
                                 NULL);
if (err != NRFX_SUCCESS) {
  printk("nrfx_saadc_simple_mode_set error: %08x", err);
  return;
}

5.5 Set buffer where the sample will be stored. Since the sample interval is quite long and we only sample one channel, a buffer of one sample is sufficient:

err = nrfx_saadc_buffer_set(&sample, 1);
if (err != NRFX_SUCCESS) {
  printk("nrfx_saadc_buffer_set error: %08x", err);
  return;
}

6. Start the periodic timer for battery sampling at the interval given by BATTERY_SAMPLE_INTERVAL_MS.

Add the following line to the end of the function configure_saadc():

k_timer_start(&battery_sample_timer, K_NO_WAIT, K_MSEC(BATTERY_SAMPLE_INTERVAL_MS));

7. We will now implement the timer callback handler where sampling is triggered and results are printed.

7.1 Add the empty function structure to the main.c file

void battery_sample_timer_handler(struct k_timer *timer)
{

  /* Step 7.2 - Trigger the sampling */

  /* STEP 7.3 - Calculate and print voltage */


}

7.2 Trigger the sampling. The SAADC driver was previously configured in blocking mode, so the sample will be ready when the function returns:

nrfx_err_t err = nrfx_saadc_mode_trigger();
if (err != NRFX_SUCCESS) {
	printk("nrfx_saadc_mode_trigger error: %08x", err);
	return;
}

7.3 Calculate the battery voltage from the sample and print it on console. The formula is based on the Digital output formula in nRF52/nRF53/nRF91 SAADC peripheral chapter and converted to millivolts:

int battery_voltage = ((600*6) * sample) / ((1<<12));

printk("SAADC sample: %d\n", sample);
printk("Battery Voltage: %d mV\n", battery_voltage);

Testing

8. Build the application and flash it to your board.

9. Connect your analog input to a voltage source, just as you did in exercise 1.

This could be a dedicated power supply, a PPK2, a battery, or you can simply connect a wire between the analog input (AIN0) and VDD as shown below.

10. Using a serial terminal, you should see the below output:

The solution for this exercise can be found in the course repository, lesson6/inter_less6_exer2_solution.

Register an account
Already have an account? Log in
(All fields are required unless specified optional)

  • 8 or more characters
  • Upper and lower case letters
  • At least one number or special character

Forgot your password?
Enter the email associated with your account, and we will send you a link to reset your password.