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

Using SAADC to determine parameters of a voltage devider

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);		
  }
}





Related