Dialog DA14531 — ADC

An Analog to Digital Converter transforms an analog signal to a digital form which can be used by/operated upon by any computing element. The analog signal is sampled periodically to recreate it digitally.

Image for post

The DA14531 has 10 bit ADC with 4input single ended channels(or 2 differential channels). The 4 input channels can be chosen from 4 GPIOs, a temperature sensor, VBAT_HIGH rail, VBAT_LOW rail and VDD. It also has a configurable attenuator with 4 options which are1x, 2x, 3x and 4x. With the attenuator at 4x, it can sample a maximum voltage range of -3.45V to +3.45V .

Image for post

Project setup

The project with the code for this tutorial is available on Github at https://github.com/vicara-hq/da14531-tutorials

Download the project and copy it. The project has to be placed inside the Dialog SDK6 folder. Navigate to <SDK6_ROOT>/projects/target_apps/template and paste it in this folder. The project is a modified version of the empty_peripheral_template project provided by Dialog. But to keep this tutorial series as open source as possible, all the following steps will use the SmartSnippets Studio.

Hardware overview

We will use a DA145xx Pro motherboard with a DA14531 Tiny module daughterboard, few jumpers and a breadboard. You will also need 2 resistors of equal value or you can also use a potentiometer(you will need a multimeter to verify the output).


Image for post

I used 2 4.7 kOhm resistors and 3V rail on the DA14531 motherboard as VCC.

Code Overview

The aim of this tutorial is to sample a voltage and show the basic usage of the ADC in the DA14531.

First, we need to configure P0_7 as an ADC pin. This is done in the user_periph_setup.c file.

void GPIO_reservations(void) {
 RESERVE_GPIO(BUTTON, GPIO_PORT_0, GPIO_PIN_7, PID_ADC);
}void set_pad_functions(void) {
 GPIO_ConfigurePin(GPIO_PORT_0, GPIO_PIN_7, INPUT, PID_ADC, false);
}

The below block of code configures the ADC.

adc_config_t adc_cfg = {
 .input_mode = ADC_INPUT_MODE_SINGLE_ENDED,
 .input = ADC_INPUT_SE_P0_7,
 .smpl_time_mult = 2,
 .continuous = false,
 .interval_mult = 0,
 .input_attenuator = ADC_INPUT_ATTN_2X,
 .chopping = false,
 .oversampling = 0
};adc_offset_calibrate(ADC_INPUT_MODE_SINGLE_ENDED);adc_init( &adc_cfg);

In the configuration structure, we set the mode to single ended and the attenuation to 2x as the expected voltage is around 1.5V . The function to also calibrate the ADC is called before initializing it.

We call the function to sample the voltage in the custom app_on_init callback. For more details about the custom callback, take a look at my tutorial on GPIOs, buttons and LEDs.

uint16_t adc_sample;void user_app_on_init(void) {
 adc_sample = adc_get_sample();
 adc_sample = adc_correct_sample(adc_sample);  default_app_on_init();
}

Testing

The easiest way to test this is to run the debugger and add the variable adc_sample to the Expressions watch window. To add a variable to the Expressions watch window and to check it’s value:

  • Select the variable
  • Right click on it and choose “Add watch expression”.
  • Click on “OK” in the window which opens up
  • Pause the debugger after few seconds and check the value of the variable.

Image for post

The value I got was 0x3A0. The reference voltage of the ADC is 0.9V and since it’s a 10 bit ADC, the value corresponds to:

0x3A0 = 928 (in decimal)2 * 928 * (0.9/1024) = 1.63V

The value I got is a bit higher than expected. This error can be reduced by using techniques like oversampling but that’s an advanced topic for another tutorial.