Hello
I am using nrf52840 and am trying to determine the parameters of a voltage divider using the SAADC. Vin is the VDD voltage of the chip, R1 is 4640 ohms and R2 is 38600 ohms (measured by using a multimeter). I have attached the Vout voltage to the AIN0 (P0.02) pin of the board and successfully did the ADC conversion of its value by calling the function value_of_voltage_on_resistor_2_in_volts(). I have managed to successfully display the value of Vout (the voltage on the resistor R2) to the RTT viewer terminal and the value is correct. Since I know the values of VDD (because I measured it with a multimeter, its value is 2.974 volts), R1 and R2, I calculated the value of Vout and determined that it has the value of 2.65 volts (I have also checked that value with a multimeter), and it turns out that I did that part correctly since that value was displayed on the RTT viewer. The problem is when I try to do the ADC conversion of the VDD voltage because for some reason on the terminal is outputted 2 volts instead of 2.97 volts. I do not know why am I not doing it correctly and also for some reason I cannot display the next line of NRF_LOG_INFO() to the terminal. Can somebody please help me find the error? I posted the code, terminal output and the schematic picture of the circuit below. The code is not very long and I tried to make it easy to read.
//ADC.h #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include <math.h> #include "nrf.h" #include "nrf_drv_saadc.h" #include "nrf_drv_ppi.h" #include "nrf_drv_timer.h" #include "boards.h" #include "app_error.h" #include "nrf_delay.h" #include "app_util_platform.h" #include "nrf_pwr_mgmt.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "SEGGER_RTT.h" #include "bsp.h" #define ANALOGUE_PIN_0 0 //P0.02 (analogue input pin on the board) #define ANALOGUE_PIN_1 1 //P0.03 (analogue input pin on the board) #define NUMBER_OF_ADC_CONVERSIONS 2 //number of input analgue pins from which will the samples be taken #define VOLTAGE_ON_RESISTOR_2 0 //this is used for storying ADC conversion value to result[VOLTAGE_ON_RESISTOR_2] #define VOLTAGE_VDD 1 //this is used for storying ADC conversion value to result[VOLTAGE_VDD] extern const float value_of_resistance_of_resistor_1; //this is the known value of resistor 1 in OHMS determined by meausring the resistance of resistor 1 using a multimeter extern volatile unsigned short result[NUMBER_OF_ADC_CONVERSIONS]; //a buffer in which will be stored the values of ADC conversions void ADC_configuration_of_analogue_pin(unsigned char analogue_pin, unsigned long input_voltage_to_the_analgue_pin); void calibrate_ADC(void); void ADC_initialize(void); float ADC_make_a_sample(unsigned long input_voltage); //this function returns a sample of the the value of voltage in VOLTS on the chosen input analogue pin float value_of_voltage_on_resistor_2_in_volts(void); //this function returns the current value of voltage on resistor 2 in VOLTS float value_of_voltage_of_VDD_in_volts(void); //this function returns the voltage of VDD on the microcontroller float value_of_resistance_of_resistor_2_in_ohms(void); //this function returns the value of resistance of the resistor 2 in OHMS
//ADC.c
#include "ADC.h"
const float value_of_resistance_of_resistor_1 = 4640.0f; //OHMS
volatile unsigned short result[NUMBER_OF_ADC_CONVERSIONS] = {0,0};
void ADC_configuration_of_analogue_pin(unsigned char analogue_pin, unsigned long input_voltage_to_the_analgue_pin){
NRF_SAADC->CH[analogue_pin].CONFIG = (SAADC_CH_CONFIG_GAIN_Gain1_6 << SAADC_CH_CONFIG_GAIN_Pos) |
(SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) |
(SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) |
(SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos) |
(SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos) |
(SAADC_CH_CONFIG_TACQ_10us << SAADC_CH_CONFIG_TACQ_Pos);
NRF_SAADC->CH[analogue_pin].PSELP = input_voltage_to_the_analgue_pin << SAADC_CH_PSELP_PSELP_Pos;
NRF_SAADC->CH[analogue_pin].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos;
}
void calibrate_ADC(void){
NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;
while (NRF_SAADC->EVENTS_CALIBRATEDONE == 0);
NRF_SAADC->EVENTS_CALIBRATEDONE = 0;
while (NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy <<SAADC_STATUS_STATUS_Pos));
}
void ADC_initialize(void){
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
ADC_configuration_of_analogue_pin(ANALOGUE_PIN_0, SAADC_CH_PSELP_PSELP_AnalogInput0);
ADC_configuration_of_analogue_pin(ANALOGUE_PIN_1, SAADC_CH_PSELP_PSELP_VDD);
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_12bit << SAADC_RESOLUTION_VAL_Pos;
NRF_SAADC->RESULT.MAXCNT = NUMBER_OF_ADC_CONVERSIONS;
NRF_SAADC->RESULT.PTR = (uint32_t)result;
NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos;
NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos;
calibrate_ADC();
}
float ADC_make_a_sample(unsigned long input_voltage){
volatile float voltage[NUMBER_OF_ADC_CONVERSIONS] = {0,0};
calibrate_ADC();
NRF_SAADC->TASKS_START = 1;
while (NRF_SAADC->EVENTS_STARTED == 0);
NRF_SAADC->EVENTS_STARTED = 0;
NRF_SAADC->TASKS_SAMPLE = 1;
while (NRF_SAADC->EVENTS_END == 0);
NRF_SAADC->EVENTS_END = 0;
// Convert the result to voltage
// Result = [V(p) - V(n)] * GAIN/REFERENCE * 2^(RESOLUTION)
// Result = (AIN - 0) * ((1/6) / 0.6) * 2^12
// AIN = Result / 4551.1
voltage[input_voltage] = (float)result[input_voltage] / 4551.1f * 4;
voltage[input_voltage]; // to get rid of set but not used warning
NRF_SAADC->TASKS_STOP = 1;
while (NRF_SAADC->EVENTS_STOPPED == 0);
NRF_SAADC->EVENTS_STOPPED = 0;
return voltage[input_voltage];
}
float value_of_voltage_on_resistor_2_in_volts(void){
return ADC_make_a_sample(VOLTAGE_ON_RESISTOR_2);
}
float value_of_voltage_of_VDD_in_volts(){
return ADC_make_a_sample(VOLTAGE_VDD); //VOLTS
}
float value_of_resistance_of_resistor_2_in_ohms(void){
float value_of_voltage_on_resistor_2 = value_of_voltage_on_resistor_2_in_volts();
//this equation is the eqation of the voltage devider: Vo = Vin * R2 / (R1 + R2) => R2 = Vo * R1 / (VDD - Vo)
return (value_of_voltage_on_resistor_2 * value_of_resistance_of_resistor_1)/(value_of_voltage_of_VDD_in_volts() - value_of_voltage_on_resistor_2);
}
//main.c
#include "ADC.h"
int main(void)
{
uint32_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
ADC_initialize();
while (1)
{
/* NRF_LOG_INFO("Value of voltage on resistor_2 in volts is: " NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(value_of_voltage_on_resistor_2_in_volts()));
NRF_LOG_FLUSH();
nrf_delay_ms(1000);*/
NRF_LOG_INFO("Value of VDD in volts is: " NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(value_of_voltage_of_VDD_in_volts()));
NRF_LOG_FLUSH();
nrf_delay_ms(1000);
NRF_LOG_INFO("Value of resistance in ohms of resistor_2 is: " NRF_LOG_FLOAT_MARKER "\r\n", value_of_resistance_of_resistor_2_in_ohms());
NRF_LOG_FLUSH();
nrf_delay_ms(1000);
}
}

