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